fix: map preview scale
This commit is contained in:
@@ -216,6 +216,12 @@ const rotateVertices = (
|
|||||||
const DRAG_THRESHOLD_PX = 4;
|
const DRAG_THRESHOLD_PX = 4;
|
||||||
const ICON_SIZE_MIN = 1;
|
const ICON_SIZE_MIN = 1;
|
||||||
const ICON_SIZE_MAX = 300;
|
const ICON_SIZE_MAX = 300;
|
||||||
|
const DEBUG_WEBGL_ROUTE_MAP = true;
|
||||||
|
|
||||||
|
const debugWebglLog = (...args: unknown[]) => {
|
||||||
|
if (!DEBUG_WEBGL_ROUTE_MAP) return;
|
||||||
|
console.log("[WebGLRouteMapPrototype]", ...args);
|
||||||
|
};
|
||||||
|
|
||||||
type StationDragState = {
|
type StationDragState = {
|
||||||
stationId: number;
|
stationId: number;
|
||||||
@@ -735,7 +741,16 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
next: Transform,
|
next: Transform,
|
||||||
options?: { immediate?: boolean; skipClamp?: boolean },
|
options?: { immediate?: boolean; skipClamp?: boolean },
|
||||||
) => {
|
) => {
|
||||||
|
const prevTransform = transformRef.current;
|
||||||
const adjusted = options?.skipClamp ? next : clampTransformScale(next);
|
const adjusted = options?.skipClamp ? next : clampTransformScale(next);
|
||||||
|
debugWebglLog("updateTransform", {
|
||||||
|
immediate: Boolean(options?.immediate),
|
||||||
|
skipClamp: Boolean(options?.skipClamp),
|
||||||
|
prevScale: prevTransform?.scale ?? null,
|
||||||
|
nextScale: adjusted.scale,
|
||||||
|
prevTranslation: prevTransform?.translation ?? null,
|
||||||
|
nextTranslation: adjusted.translation,
|
||||||
|
});
|
||||||
|
|
||||||
transformRef.current = adjusted;
|
transformRef.current = adjusted;
|
||||||
if (options?.immediate) {
|
if (options?.immediate) {
|
||||||
@@ -1268,10 +1283,7 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const safePercent = Math.max(ICON_SIZE_MIN, currentPercent);
|
const safePercent = Math.max(ICON_SIZE_MIN, currentPercent);
|
||||||
const baseSizePxAt100 = Math.max(
|
const baseSizePxAt100 = Math.max(1, initialSizePx / (safePercent / 100));
|
||||||
1,
|
|
||||||
initialSizePx / (safePercent / 100),
|
|
||||||
);
|
|
||||||
|
|
||||||
sightIconResizeStateRef.current = {
|
sightIconResizeStateRef.current = {
|
||||||
sightId,
|
sightId,
|
||||||
@@ -1376,6 +1388,10 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
|
|
||||||
if (typeof ResizeObserver === "undefined") {
|
if (typeof ResizeObserver === "undefined") {
|
||||||
const handleResize = () => {
|
const handleResize = () => {
|
||||||
|
debugWebglLog("container resize (fallback)", {
|
||||||
|
width: container.clientWidth,
|
||||||
|
height: container.clientHeight,
|
||||||
|
});
|
||||||
setCanvasSize({
|
setCanvasSize({
|
||||||
width: container.clientWidth,
|
width: container.clientWidth,
|
||||||
height: container.clientHeight,
|
height: container.clientHeight,
|
||||||
@@ -1389,6 +1405,7 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
const observer = new ResizeObserver((entries) => {
|
const observer = new ResizeObserver((entries) => {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
const { width, height } = entry.contentRect;
|
const { width, height } = entry.contentRect;
|
||||||
|
debugWebglLog("container resize", { width, height });
|
||||||
setCanvasSize({ width, height });
|
setCanvasSize({ width, height });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1418,6 +1435,15 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
const dpr = Math.max(1, window.devicePixelRatio || 1);
|
const dpr = Math.max(1, window.devicePixelRatio || 1);
|
||||||
const displayWidth = Math.max(1, Math.floor(canvasSize.width * dpr));
|
const displayWidth = Math.max(1, Math.floor(canvasSize.width * dpr));
|
||||||
const displayHeight = Math.max(1, Math.floor(canvasSize.height * dpr));
|
const displayHeight = Math.max(1, Math.floor(canvasSize.height * dpr));
|
||||||
|
debugWebglLog("drawScene:start", {
|
||||||
|
cssCanvasWidth: canvasSize.width,
|
||||||
|
cssCanvasHeight: canvasSize.height,
|
||||||
|
dpr,
|
||||||
|
displayWidth,
|
||||||
|
displayHeight,
|
||||||
|
routeVerticesCount: rotatedRouteVertices.length / 2,
|
||||||
|
stationVerticesCount: rotatedStationVertices.length / 2,
|
||||||
|
});
|
||||||
|
|
||||||
if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
|
if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
|
||||||
canvas.width = displayWidth;
|
canvas.width = displayWidth;
|
||||||
@@ -1531,6 +1557,11 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { scale, translation } = transform;
|
const { scale, translation } = transform;
|
||||||
|
debugWebglLog("drawScene:transform", {
|
||||||
|
scale,
|
||||||
|
translation,
|
||||||
|
scaleLimits: scaleLimitsRef.current,
|
||||||
|
});
|
||||||
|
|
||||||
const desiredRouteWidthCss = 7;
|
const desiredRouteWidthCss = 7;
|
||||||
const desiredStationDiameterCss = 12;
|
const desiredStationDiameterCss = 12;
|
||||||
@@ -1545,6 +1576,11 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
rotatedRouteVertices,
|
rotatedRouteVertices,
|
||||||
lineWidth,
|
lineWidth,
|
||||||
);
|
);
|
||||||
|
debugWebglLog("drawScene:route", {
|
||||||
|
desiredRouteWidthCss,
|
||||||
|
lineWidthWorldUnits: lineWidth,
|
||||||
|
thickVerticesCount: thickVertices.length / 2,
|
||||||
|
});
|
||||||
if (thickVertices.length === 0) {
|
if (thickVertices.length === 0) {
|
||||||
gl.bufferData(gl.ARRAY_BUFFER, rotatedRouteVertices, gl.STATIC_DRAW);
|
gl.bufferData(gl.ARRAY_BUFFER, rotatedRouteVertices, gl.STATIC_DRAW);
|
||||||
} else {
|
} else {
|
||||||
@@ -1635,6 +1671,10 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
pointOuterSizePx,
|
pointOuterSizePx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
debugWebglLog("drawScene:stations", {
|
||||||
|
pointOuterSizePx,
|
||||||
|
pointInnerSizePx,
|
||||||
|
});
|
||||||
if (pointProgram.uniformLocations.u_color) {
|
if (pointProgram.uniformLocations.u_color) {
|
||||||
gl.uniform4f(
|
gl.uniform4f(
|
||||||
pointProgram.uniformLocations.u_color,
|
pointProgram.uniformLocations.u_color,
|
||||||
@@ -1814,6 +1854,87 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
drawScene();
|
drawScene();
|
||||||
}, [drawScene]);
|
}, [drawScene]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const camera =
|
||||||
|
transformState ?? transformRef.current ?? lastTransformRef.current;
|
||||||
|
if (!camera || !sightData?.length) return;
|
||||||
|
|
||||||
|
const routeIconSizePercent =
|
||||||
|
routeData?.icon_size ?? originalRouteData?.icon_size ?? 100;
|
||||||
|
|
||||||
|
for (const sight of sightData) {
|
||||||
|
const shouldUseCustomSightIcon =
|
||||||
|
sight.is_default_icon === false && !isMediaIdEmpty(sight.icon);
|
||||||
|
if (!shouldUseCustomSightIcon) continue;
|
||||||
|
|
||||||
|
const customSightIconScaleFactor =
|
||||||
|
camera.scale / Math.max(customSightIconBaseScaleRef.current ?? 1, 1e-6);
|
||||||
|
const sightIconSizePercent =
|
||||||
|
liveSightIconSizes.get(sight.id) ??
|
||||||
|
(typeof sight.icon_size === "number" && Number.isFinite(sight.icon_size)
|
||||||
|
? sight.icon_size
|
||||||
|
: routeIconSizePercent);
|
||||||
|
const iconSizePx =
|
||||||
|
30 *
|
||||||
|
clamp(sightIconSizePercent / 100, 0.1, 10) *
|
||||||
|
customSightIconScaleFactor;
|
||||||
|
|
||||||
|
debugWebglLog("custom sight icon size", {
|
||||||
|
sightId: sight.id,
|
||||||
|
cameraScale: camera.scale,
|
||||||
|
baseScale: customSightIconBaseScaleRef.current,
|
||||||
|
scaleFactor: customSightIconScaleFactor,
|
||||||
|
iconPercent: sightIconSizePercent,
|
||||||
|
iconSizePx,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
sightData,
|
||||||
|
liveSightIconSizes,
|
||||||
|
transformState,
|
||||||
|
routeData?.icon_size,
|
||||||
|
originalRouteData?.icon_size,
|
||||||
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!stationData?.ru?.length) return;
|
||||||
|
|
||||||
|
const fontSizePercent =
|
||||||
|
routeData?.font_size ?? originalRouteData?.font_size ?? 100;
|
||||||
|
const fontScale = fontSizePercent / 100;
|
||||||
|
const baseStationIconSizePx = 16 * fontScale * 1.2;
|
||||||
|
|
||||||
|
for (const station of stationData.ru) {
|
||||||
|
const hasCustomStationIcon = !isMediaIdEmpty(station.icon);
|
||||||
|
if (!hasCustomStationIcon) continue;
|
||||||
|
|
||||||
|
const stationIconSizePercent =
|
||||||
|
liveStationIconSizes.get(station.id) ??
|
||||||
|
(typeof station.icon_size === "number" && Number.isFinite(station.icon_size)
|
||||||
|
? station.icon_size
|
||||||
|
: 100);
|
||||||
|
const iconSizePx = Math.max(
|
||||||
|
1,
|
||||||
|
Math.round(
|
||||||
|
baseStationIconSizePx * clamp(stationIconSizePercent / 100, 0.1, 10),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
debugWebglLog("custom station icon size", {
|
||||||
|
stationId: station.id,
|
||||||
|
fontSizePercent,
|
||||||
|
baseStationIconSizePx,
|
||||||
|
iconPercent: stationIconSizePercent,
|
||||||
|
iconSizePx,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
stationData?.ru,
|
||||||
|
liveStationIconSizes,
|
||||||
|
routeData?.font_size,
|
||||||
|
originalRouteData?.font_size,
|
||||||
|
]);
|
||||||
|
|
||||||
const applyCenterFromCoordinates = useCallback(
|
const applyCenterFromCoordinates = useCallback(
|
||||||
(latitude: number, longitude: number) => {
|
(latitude: number, longitude: number) => {
|
||||||
const roundedLat = Math.round(latitude * 1e6) / 1e6;
|
const roundedLat = Math.round(latitude * 1e6) / 1e6;
|
||||||
@@ -2572,8 +2693,7 @@ export const WebGLRouteMapPrototype = observer(() => {
|
|||||||
const cssX = labelX / dpr;
|
const cssX = labelX / dpr;
|
||||||
const cssY = labelY / dpr;
|
const cssY = labelY / dpr;
|
||||||
const shouldUseCustomSightIcon =
|
const shouldUseCustomSightIcon =
|
||||||
sight.is_default_icon === false &&
|
sight.is_default_icon === false && !isMediaIdEmpty(sight.icon);
|
||||||
!isMediaIdEmpty(sight.icon);
|
|
||||||
const sightIconUrl = shouldUseCustomSightIcon
|
const sightIconUrl = shouldUseCustomSightIcon
|
||||||
? `${mediaBaseUrl}${sight.icon}/download?token=${mediaToken}`
|
? `${mediaBaseUrl}${sight.icon}/download?token=${mediaToken}`
|
||||||
: SIGHT_ICON_URL;
|
: SIGHT_ICON_URL;
|
||||||
|
|||||||
Reference in New Issue
Block a user