fix: map preview scale

This commit is contained in:
2026-03-26 23:43:15 +03:00
parent 442160ba38
commit dd5aee58e6

View File

@@ -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;