diff --git a/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx b/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx index 9a1193e..65dc1e1 100644 --- a/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx +++ b/src/pages/Route/route-preview/webgl-prototype/WebGLRouteMapPrototype.tsx @@ -364,16 +364,19 @@ const computeViewTransform = ( return { scale, translation }; }; -const getAnchorFromOffset = ( - offsetX: number, - offsetY: number -): { x: number; y: number } => { - const length = Math.hypot(offsetX, offsetY); +const getAnchorFromOffset = (align: number): { x: number; y: number } => { + let anchorX: number; + if (align === 1) { + anchorX = 0; + } else if (align === 3) { + anchorX = 1; + } else { + anchorX = 0.5; + } - const nx = offsetX / length; - const ny = offsetY / length; + const anchorY = 0.5; - return { x: (1 - nx) / 2, y: (1 - ny) / 2 }; + return { x: anchorX, y: anchorY }; }; const backgroundColor = toColor(BACKGROUND_COLOR); @@ -665,24 +668,8 @@ export const WebGLRouteMapPrototype = observer(() => { next: Transform, options?: { immediate?: boolean; skipClamp?: boolean } ) => { - console.log("🔄 updateTransform вызван", { - inputTransform: next, - options, - stackTrace: new Error().stack?.split("\n").slice(1, 4).join("\n"), - }); - const adjusted = options?.skipClamp ? next : clampTransformScale(next); - if (adjusted !== next && !options?.skipClamp) { - console.log( - "🔄 updateTransform: transform изменен после clampTransformScale", - { - before: next, - after: adjusted, - } - ); - } - transformRef.current = adjusted; if (options?.immediate) { flushSync(() => { @@ -732,18 +719,21 @@ export const WebGLRouteMapPrototype = observer(() => { event.preventDefault(); - const world = getWorldPosition( - event.clientX, - event.clientY, - state.camera - ); - if (!world) return; + const stationScreenX = + state.rotatedBase.x * state.camera.scale + state.camera.translation.x; + const stationScreenY = + state.rotatedBase.y * state.camera.scale + state.camera.translation.y; - const adjustedWorldX = world.x - state.pointerDelta.x; - const adjustedWorldY = world.y - state.pointerDelta.y; + const canvas = canvasRef.current; + if (!canvas) return; + const rect = canvas.getBoundingClientRect(); + const scaleX = canvas.width / Math.max(rect.width, 1); + const scaleY = canvas.height / Math.max(rect.height, 1); + const pointerScreenX = (event.clientX - rect.left) * scaleX; + const pointerScreenY = (event.clientY - rect.top) * scaleY; - const newOffsetX = adjustedWorldX - state.rotatedBase.x; - const newOffsetY = adjustedWorldY - state.rotatedBase.y; + const newOffsetX = pointerScreenX - stationScreenX - state.pointerDelta.x; + const newOffsetY = pointerScreenY - stationScreenY - state.pointerDelta.y; state.lastOffset = { x: newOffsetX, y: newOffsetY }; setLiveStationOffsets((prev) => { @@ -810,19 +800,25 @@ export const WebGLRouteMapPrototype = observer(() => { suppressAutoFitRef.current = true; - const pointerWorld = getWorldPosition( - event.clientX, - event.clientY, - camera - ); - const labelWorldX = rotatedBase.x + currentOffset.x; - const labelWorldY = rotatedBase.y + currentOffset.y; - const pointerDelta = pointerWorld - ? { - x: pointerWorld.x - labelWorldX, - y: pointerWorld.y - labelWorldY, - } - : { x: 0, y: 0 }; + const stationScreenX = + rotatedBase.x * camera.scale + camera.translation.x; + const stationScreenY = + rotatedBase.y * camera.scale + camera.translation.y; + const labelScreenX = stationScreenX + currentOffset.x; + const labelScreenY = stationScreenY + currentOffset.y; + + const canvas = canvasRef.current; + if (!canvas) return; + const rect = canvas.getBoundingClientRect(); + const scaleX = canvas.width / Math.max(rect.width, 1); + const scaleY = canvas.height / Math.max(rect.height, 1); + const pointerScreenX = (event.clientX - rect.left) * scaleX; + const pointerScreenY = (event.clientY - rect.top) * scaleY; + + const pointerDelta = { + x: pointerScreenX - labelScreenX, + y: pointerScreenY - labelScreenY, + }; const captureTarget = event.currentTarget; if (captureTarget.setPointerCapture) { @@ -1050,7 +1046,6 @@ export const WebGLRouteMapPrototype = observer(() => { canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); if (!(gl instanceof WebGLRenderingContext)) { - console.error("WebGL is not supported in this browser"); return; } @@ -1074,7 +1069,7 @@ export const WebGLRouteMapPrototype = observer(() => { lineBufferRef.current = gl.createBuffer(); pointBufferRef.current = gl.createBuffer(); } catch (error) { - console.error("Failed to initialize WebGL", error); + // console.error("Failed to initialize WebGL", error); } }, []); @@ -1912,17 +1907,23 @@ export const WebGLRouteMapPrototype = observer(() => { ? liveStationOffset.y : baseOffsetY; - const labelX = - (rotatedX + offsetX) * camera.scale + camera.translation.x; - const labelY = - (rotatedY + offsetY) * camera.scale + camera.translation.y; + const stationScreenX = + rotatedX * camera.scale + camera.translation.x; + const stationScreenY = + rotatedY * camera.scale + camera.translation.y; - const anchor = getAnchorFromOffset(offsetX, offsetY); + const labelX = stationScreenX + offsetX; + const labelY = stationScreenY + offsetY; + + const backendAlign = station.align; + + const anchor = getAnchorFromOffset(backendAlign ?? 2); const transformCss = `translate(${-anchor.x * 100}%, ${ -anchor.y * 100 }%)`; const dpr = Math.max(1, window.devicePixelRatio || 1); + const cssX = labelX / dpr; const cssY = labelY / dpr; const rotationCss = `${rotationAngle}rad`; @@ -1943,7 +1944,6 @@ export const WebGLRouteMapPrototype = observer(() => { const secondaryMarginTop = 5 * fontScale; - const backendAlign = station.align; const alignmentFromData: StationAlignment = backendAlign === 1 ? "left" @@ -1969,151 +1969,154 @@ export const WebGLRouteMapPrototype = observer(() => { : 3; return ( -
setHoveredStationId(station.id)} - onMouseLeave={() => - setHoveredStationId((prev) => - prev === station.id ? null : prev - ) - } - onPointerDown={(event) => - handleStationPointerDown( - event, - station.id, - { - x: rotatedX, - y: rotatedY, - }, - { x: offsetX, y: offsetY } - ) - } - style={{ - position: "absolute", - left: cssX, - top: cssY, - transform: transformCss, - color: "#fff", - fontFamily: "Roboto, sans-serif", - textAlign: "left", - pointerEvents: "auto", - cursor: "grab", - userSelect: "none", - touchAction: "none", - }} - > +
setHoveredStationId(station.id)} + onMouseLeave={() => + setHoveredStationId((prev) => + prev === station.id ? null : prev + ) + } + onPointerDown={(event) => + handleStationPointerDown( + event, + station.id, + { + x: rotatedX, + y: rotatedY, + }, + { x: offsetX, y: offsetY } + ) + } style={{ - pointerEvents: "none", - transformOrigin: "left center", - transform: `rotate(${rotationCss})`, + position: "absolute", + left: cssX, + top: cssY, + transform: transformCss, + color: "#fff", + fontFamily: "Roboto, sans-serif", + textAlign: "left", + pointerEvents: "auto", + cursor: "grab", + userSelect: "none", + touchAction: "none", }} >
- {station.name} -
- {showSecondary ? (
- {translatedStation?.name} + {station.name}
- ) : null} + {showSecondary ? ( +
+ {translatedStation?.name} +
+ ) : null} +
-
- {hoveredStationId === station.id && ( -
e.stopPropagation()} - > + {hoveredStationId === station.id && (
e.stopPropagation()} > - {buttons.map((btn) => ( -
{ - e.stopPropagation(); - setStationAlignments((prev) => { - const next = new Map(prev); - next.set( - station.id, - btn.align as StationAlignment - ); - return next; - }); - setStationAlign(station.id, btn.value); - }} - style={{ - padding: "4px 8px", - fontSize: 12, - cursor: "pointer", - backgroundColor: - alignment === btn.align - ? "#e0e0e0" - : "transparent", - borderRadius: 4, - color: "black", - fontWeight: 500, - userSelect: "none", - }} - > - {btn.label} -
- ))} +
+ {buttons.map((btn) => ( +
{ + e.stopPropagation(); + setStationAlignments((prev) => { + const next = new Map(prev); + next.set( + station.id, + btn.align as StationAlignment + ); + return next; + }); + setStationAlign(station.id, btn.value); + }} + style={{ + padding: "4px 8px", + fontSize: 12, + cursor: "pointer", + backgroundColor: + alignment === btn.align + ? "#e0e0e0" + : "transparent", + borderRadius: 4, + whiteSpace: "nowrap", + color: "black", + fontWeight: 500, + userSelect: "none", + }} + > + {btn.label} +
+ ))} +
-
- )} + )} +
); })} diff --git a/src/shared/store/SnapshotStore/index.ts b/src/shared/store/SnapshotStore/index.ts index 89e173e..5fa022b 100644 --- a/src/shared/store/SnapshotStore/index.ts +++ b/src/shared/store/SnapshotStore/index.ts @@ -283,16 +283,12 @@ class SnapshotStore { { headers: { "X-Request-ID": this.lastRequestId } } ); - // Не ждем здесь, так как статус будет загружен в компоненте - // this.getSnapshotStatus(response.data.ID); - return response.data.ID; }; getSnapshotStatus = async (id: string) => { const response = await authInstance.get(`/snapshots/status/${id}`); - console.log(response.data); runInAction(() => { this.snapshotStatus = response.data; });