From dd5aee58e6a5d2264b50739386922936ecb34ee5 Mon Sep 17 00:00:00 2001 From: itoshi Date: Thu, 26 Mar 2026 23:43:15 +0300 Subject: [PATCH] fix: map preview scale --- .../WebGLRouteMapPrototype.tsx | 132 +++++++++++++++++- 1 file changed, 126 insertions(+), 6 deletions(-) diff --git a/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx b/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx index 923dd75..8a5aa0b 100644 --- a/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx +++ b/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx @@ -216,6 +216,12 @@ const rotateVertices = ( const DRAG_THRESHOLD_PX = 4; const ICON_SIZE_MIN = 1; 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 = { stationId: number; @@ -735,7 +741,16 @@ export const WebGLRouteMapPrototype = observer(() => { next: Transform, options?: { immediate?: boolean; skipClamp?: boolean }, ) => { + const prevTransform = transformRef.current; 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; if (options?.immediate) { @@ -1268,10 +1283,7 @@ export const WebGLRouteMapPrototype = observer(() => { } const safePercent = Math.max(ICON_SIZE_MIN, currentPercent); - const baseSizePxAt100 = Math.max( - 1, - initialSizePx / (safePercent / 100), - ); + const baseSizePxAt100 = Math.max(1, initialSizePx / (safePercent / 100)); sightIconResizeStateRef.current = { sightId, @@ -1376,6 +1388,10 @@ export const WebGLRouteMapPrototype = observer(() => { if (typeof ResizeObserver === "undefined") { const handleResize = () => { + debugWebglLog("container resize (fallback)", { + width: container.clientWidth, + height: container.clientHeight, + }); setCanvasSize({ width: container.clientWidth, height: container.clientHeight, @@ -1389,6 +1405,7 @@ export const WebGLRouteMapPrototype = observer(() => { const observer = new ResizeObserver((entries) => { for (const entry of entries) { const { width, height } = entry.contentRect; + debugWebglLog("container resize", { width, height }); setCanvasSize({ width, height }); } }); @@ -1418,6 +1435,15 @@ export const WebGLRouteMapPrototype = observer(() => { const dpr = Math.max(1, window.devicePixelRatio || 1); const displayWidth = Math.max(1, Math.floor(canvasSize.width * 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) { canvas.width = displayWidth; @@ -1531,6 +1557,11 @@ export const WebGLRouteMapPrototype = observer(() => { } const { scale, translation } = transform; + debugWebglLog("drawScene:transform", { + scale, + translation, + scaleLimits: scaleLimitsRef.current, + }); const desiredRouteWidthCss = 7; const desiredStationDiameterCss = 12; @@ -1545,6 +1576,11 @@ export const WebGLRouteMapPrototype = observer(() => { rotatedRouteVertices, lineWidth, ); + debugWebglLog("drawScene:route", { + desiredRouteWidthCss, + lineWidthWorldUnits: lineWidth, + thickVerticesCount: thickVertices.length / 2, + }); if (thickVertices.length === 0) { gl.bufferData(gl.ARRAY_BUFFER, rotatedRouteVertices, gl.STATIC_DRAW); } else { @@ -1635,6 +1671,10 @@ export const WebGLRouteMapPrototype = observer(() => { pointOuterSizePx, ); } + debugWebglLog("drawScene:stations", { + pointOuterSizePx, + pointInnerSizePx, + }); if (pointProgram.uniformLocations.u_color) { gl.uniform4f( pointProgram.uniformLocations.u_color, @@ -1814,6 +1854,87 @@ export const WebGLRouteMapPrototype = observer(() => { 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( (latitude: number, longitude: number) => { const roundedLat = Math.round(latitude * 1e6) / 1e6; @@ -2572,8 +2693,7 @@ export const WebGLRouteMapPrototype = observer(() => { const cssX = labelX / dpr; const cssY = labelY / dpr; const shouldUseCustomSightIcon = - sight.is_default_icon === false && - !isMediaIdEmpty(sight.icon); + sight.is_default_icon === false && !isMediaIdEmpty(sight.icon); const sightIconUrl = shouldUseCustomSightIcon ? `${mediaBaseUrl}${sight.icon}/download?token=${mediaToken}` : SIGHT_ICON_URL;