fix(map): scale flat icons and prioritize relation layers
This commit is contained in:
부모
c31d26124c
커밋
15378ed7ff
@ -182,6 +182,11 @@ const DEPTH_DISABLED_PARAMS = {
|
||||
depthWriteEnabled: false,
|
||||
} as const;
|
||||
|
||||
const FLAT_SHIP_ICON_SIZE = 19;
|
||||
const FLAT_SHIP_ICON_SIZE_SELECTED = 28;
|
||||
const FLAT_LEGACY_HALO_RADIUS = 14;
|
||||
const FLAT_LEGACY_HALO_RADIUS_SELECTED = 18;
|
||||
|
||||
const GLOBE_OVERLAY_PARAMS = {
|
||||
// In globe mode we want depth-testing against the globe so features on the far side don't draw through.
|
||||
// Still disable depth writes so our overlays don't interfere with each other.
|
||||
@ -717,7 +722,12 @@ export function Map3D({
|
||||
if (!map) return;
|
||||
let cancelled = false;
|
||||
let retries = 0;
|
||||
const maxRetries = 6;
|
||||
const maxRetries = 18;
|
||||
|
||||
const getCurrentProjection = () => {
|
||||
const projectionConfig = map.getProjection?.();
|
||||
return projectionConfig && "type" in projectionConfig ? (projectionConfig.type as MapProjectionId | undefined) : undefined;
|
||||
};
|
||||
|
||||
const syncProjectionAndDeck = () => {
|
||||
if (cancelled) return;
|
||||
@ -732,7 +742,9 @@ export function Map3D({
|
||||
|
||||
const next = projection;
|
||||
try {
|
||||
if (getCurrentProjection() !== next) {
|
||||
map.setProjection({ type: next });
|
||||
}
|
||||
map.setRenderWorldCopies(next !== "globe");
|
||||
} catch (e) {
|
||||
if (!cancelled && retries < maxRetries) {
|
||||
@ -781,6 +793,11 @@ export function Map3D({
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
if (!map.getLayer(layer.id) && !cancelled && retries < maxRetries) {
|
||||
retries += 1;
|
||||
window.requestAnimationFrame(() => syncProjectionAndDeck());
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Tear down globe custom layer (if present), restore MapboxOverlay interleaved.
|
||||
@ -1433,7 +1450,7 @@ export function Map3D({
|
||||
return;
|
||||
}
|
||||
|
||||
const before = map.getLayer("ships-globe-halo") ? "ships-globe-halo" : undefined;
|
||||
const before = undefined;
|
||||
|
||||
if (!map.getLayer(layerId)) {
|
||||
try {
|
||||
@ -1525,7 +1542,7 @@ export function Map3D({
|
||||
return;
|
||||
}
|
||||
|
||||
const before = map.getLayer("ships-globe-halo") ? "ships-globe-halo" : undefined;
|
||||
const before = undefined;
|
||||
|
||||
if (!map.getLayer(layerId)) {
|
||||
try {
|
||||
@ -1613,7 +1630,7 @@ export function Map3D({
|
||||
return;
|
||||
}
|
||||
|
||||
const before = map.getLayer("ships-globe-halo") ? "ships-globe-halo" : undefined;
|
||||
const before = undefined;
|
||||
|
||||
if (!map.getLayer(layerId)) {
|
||||
try {
|
||||
@ -1706,7 +1723,7 @@ export function Map3D({
|
||||
return;
|
||||
}
|
||||
|
||||
const before = map.getLayer("ships-globe-halo") ? "ships-globe-halo" : undefined;
|
||||
const before = undefined;
|
||||
|
||||
if (!map.getLayer(layerId)) {
|
||||
try {
|
||||
@ -1805,22 +1822,61 @@ export function Map3D({
|
||||
);
|
||||
}
|
||||
|
||||
if (overlays.fleetCircles && projection !== "globe" && (fleetCircles?.length ?? 0) > 0) {
|
||||
if (settings.showShips && projection !== "globe") {
|
||||
layers.push(
|
||||
new ScatterplotLayer<FleetCircle>({
|
||||
id: "fleet-circles",
|
||||
data: fleetCircles,
|
||||
new IconLayer<AisTarget>({
|
||||
id: "ships",
|
||||
data: shipData,
|
||||
pickable: true,
|
||||
// Keep icons horizontal on the sea surface when view is pitched/rotated.
|
||||
billboard: false,
|
||||
parameters: overlayParams,
|
||||
iconAtlas: "/assets/ship.svg",
|
||||
iconMapping: SHIP_ICON_MAPPING,
|
||||
getIcon: () => "ship",
|
||||
getPosition: (d) =>
|
||||
[d.lon, d.lat] as [number, number],
|
||||
getAngle: (d) => (isFiniteNumber(d.cog) ? d.cog : 0),
|
||||
sizeUnits: "pixels",
|
||||
getSize: (d) => (selectedMmsi && d.mmsi === selectedMmsi ? FLAT_SHIP_ICON_SIZE_SELECTED : FLAT_SHIP_ICON_SIZE),
|
||||
getColor: (d) => getShipColor(d, selectedMmsi, legacyHits?.get(d.mmsi)?.shipCode ?? null),
|
||||
alphaCutoff: 0.05,
|
||||
updateTriggers: {
|
||||
getSize: [selectedMmsi],
|
||||
getColor: [selectedMmsi, legacyHits],
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (settings.showShips && projection !== "globe" && legacyTargets.length > 0) {
|
||||
layers.push(
|
||||
new ScatterplotLayer<AisTarget>({
|
||||
id: "legacy-halo",
|
||||
data: legacyTargets,
|
||||
pickable: false,
|
||||
billboard: false,
|
||||
// This ring is most prone to z-fighting, so force it into pure painter's-order rendering.
|
||||
parameters: overlayParams,
|
||||
filled: false,
|
||||
stroked: true,
|
||||
radiusUnits: "meters",
|
||||
getRadius: (d) => d.radiusNm * 1852,
|
||||
radiusUnits: "pixels",
|
||||
getRadius: (d) =>
|
||||
(selectedMmsi && d.mmsi === selectedMmsi ? FLAT_LEGACY_HALO_RADIUS_SELECTED : FLAT_LEGACY_HALO_RADIUS),
|
||||
lineWidthUnits: "pixels",
|
||||
getLineWidth: 1,
|
||||
getLineColor: () => [245, 158, 11, 140],
|
||||
getPosition: (d) => d.center,
|
||||
getLineWidth: 2,
|
||||
getLineColor: (d) => {
|
||||
const l = legacyHits?.get(d.mmsi);
|
||||
const rgb = l ? LEGACY_CODE_COLORS[l.shipCode] : null;
|
||||
if (!rgb) return [245, 158, 11, 200];
|
||||
return [rgb[0], rgb[1], rgb[2], 200];
|
||||
},
|
||||
getPosition: (d) =>
|
||||
[d.lon, d.lat] as [number, number],
|
||||
updateTriggers: {
|
||||
getRadius: [selectedMmsi],
|
||||
getLineColor: [legacyHits],
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -1878,60 +1934,22 @@ export function Map3D({
|
||||
);
|
||||
}
|
||||
|
||||
if (settings.showShips && projection !== "globe" && legacyTargets.length > 0) {
|
||||
if (overlays.fleetCircles && projection !== "globe" && (fleetCircles?.length ?? 0) > 0) {
|
||||
layers.push(
|
||||
new ScatterplotLayer<AisTarget>({
|
||||
id: "legacy-halo",
|
||||
data: legacyTargets,
|
||||
new ScatterplotLayer<FleetCircle>({
|
||||
id: "fleet-circles",
|
||||
data: fleetCircles,
|
||||
pickable: false,
|
||||
billboard: false,
|
||||
// This ring is most prone to z-fighting, so force it into pure painter's-order rendering.
|
||||
parameters: overlayParams,
|
||||
filled: false,
|
||||
stroked: true,
|
||||
radiusUnits: "pixels",
|
||||
getRadius: (d) => (selectedMmsi && d.mmsi === selectedMmsi ? 22 : 16),
|
||||
radiusUnits: "meters",
|
||||
getRadius: (d) => d.radiusNm * 1852,
|
||||
lineWidthUnits: "pixels",
|
||||
getLineWidth: 2,
|
||||
getLineColor: (d) => {
|
||||
const l = legacyHits?.get(d.mmsi);
|
||||
const rgb = l ? LEGACY_CODE_COLORS[l.shipCode] : null;
|
||||
if (!rgb) return [245, 158, 11, 200];
|
||||
return [rgb[0], rgb[1], rgb[2], 200];
|
||||
},
|
||||
getPosition: (d) =>
|
||||
[d.lon, d.lat] as [number, number],
|
||||
updateTriggers: {
|
||||
getRadius: [selectedMmsi],
|
||||
getLineColor: [legacyHits],
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (settings.showShips && projection !== "globe") {
|
||||
layers.push(
|
||||
new IconLayer<AisTarget>({
|
||||
id: "ships",
|
||||
data: shipData,
|
||||
pickable: true,
|
||||
// Keep icons horizontal on the sea surface when view is pitched/rotated.
|
||||
billboard: false,
|
||||
parameters: overlayParams,
|
||||
iconAtlas: "/assets/ship.svg",
|
||||
iconMapping: SHIP_ICON_MAPPING,
|
||||
getIcon: () => "ship",
|
||||
getPosition: (d) =>
|
||||
[d.lon, d.lat] as [number, number],
|
||||
getAngle: (d) => (isFiniteNumber(d.cog) ? d.cog : 0),
|
||||
sizeUnits: "pixels",
|
||||
getSize: (d) => (selectedMmsi && d.mmsi === selectedMmsi ? 34 : 22),
|
||||
getColor: (d) => getShipColor(d, selectedMmsi, legacyHits?.get(d.mmsi)?.shipCode ?? null),
|
||||
alphaCutoff: 0.05,
|
||||
updateTriggers: {
|
||||
getSize: [selectedMmsi],
|
||||
getColor: [selectedMmsi, legacyHits],
|
||||
},
|
||||
getLineWidth: 1,
|
||||
getLineColor: () => [245, 158, 11, 140],
|
||||
getPosition: (d) => d.center,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user