fix: fix build errors
This commit is contained in:
4
src/client/src/App.d.ts
vendored
Normal file
4
src/client/src/App.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import React from "react";
|
||||
|
||||
declare const App: React.FC;
|
||||
export default App;
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
GetCityResponse,
|
||||
GetSightArticleResponse,
|
||||
} from "./types";
|
||||
// @ts-ignore
|
||||
import { orderStationsByRoute } from "../../utils/routeStationsUtils";
|
||||
|
||||
class ApiStore {
|
||||
|
||||
@@ -5,6 +5,7 @@ export type GetContextResponse = {
|
||||
};
|
||||
endStopId: string;
|
||||
nearestSightId: string;
|
||||
nearestStationId?: string | null;
|
||||
rawCoordinates: {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
@@ -105,6 +106,7 @@ export type GetRouteSightsResponse = {
|
||||
icon?: string;
|
||||
alt_icon?: string;
|
||||
is_default_icon?: boolean;
|
||||
short_name?: string;
|
||||
}[];
|
||||
|
||||
export type GetRouteStationsResponse = {
|
||||
|
||||
9
src/client/src/api/apiConfig.d.ts
vendored
Normal file
9
src/client/src/api/apiConfig.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { AxiosInstance } from "axios";
|
||||
|
||||
export declare const apiBaseURL: string;
|
||||
export declare const geoBaseURL: string;
|
||||
export declare const weatherBaseURL: string;
|
||||
export declare const getMediaUrl: (id: string) => string;
|
||||
export declare const apiInstance: AxiosInstance;
|
||||
export declare const geoInstance: AxiosInstance;
|
||||
export declare const weatherInstance: AxiosInstance;
|
||||
8
src/client/src/assets/Constants.d.ts
vendored
Normal file
8
src/client/src/assets/Constants.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export declare const UP_SCALE: number;
|
||||
export declare const PATH_WIDTH: number;
|
||||
export declare const STATION_RADIUS: number;
|
||||
export declare const STATION_OUTLINE_WIDTH: number;
|
||||
export declare const SIGHT_SIZE: number;
|
||||
export declare const SCALE_FACTOR: number;
|
||||
export declare const BACKGROUND_COLOR: number;
|
||||
export declare const PATH_COLOR: number;
|
||||
13
src/client/src/components/OverlayScrollbarsWrapper.d.ts
vendored
Normal file
13
src/client/src/components/OverlayScrollbarsWrapper.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import React from "react";
|
||||
|
||||
export declare const OverlayScrollbarsWrapper: React.ForwardRefExoticComponent<
|
||||
React.PropsWithChildren<{
|
||||
className?: string;
|
||||
onScroll?: (event: Event) => void;
|
||||
overflowX?: string;
|
||||
overflowY?: string;
|
||||
scrollbarVisibility?: string;
|
||||
[key: string]: any;
|
||||
}> &
|
||||
React.RefAttributes<HTMLElement>
|
||||
>;
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
import "./ReactMarkdown.css";
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import { FederatedPointerEvent, FederatedWheelEvent } from "pixi.js";
|
||||
import { ReactNode, useEffect, useState, useRef, useCallback } from "react";
|
||||
import { ReactNode, useEffect, useState, useRef } from "react";
|
||||
import { useTransform } from "./transformContext";
|
||||
import { BACKGROUND_COLOR, SCALE_FACTOR } from "../../assets/Constants";
|
||||
import { useApplication } from "@pixi/react";
|
||||
import { useGeolocation } from "../../context/GeolocationContext";
|
||||
import ContentAPI from "../../api/content/content.api";
|
||||
import React from "react";
|
||||
import { useGeolocationStore } from "../../stores/hooks/useGeolocationStore";
|
||||
import { useCameraAnimationStore } from "../../stores";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import debounce from "lodash/debounce";
|
||||
@@ -25,7 +21,6 @@ export const InfiniteCanvas = observer(
|
||||
setIsAutoMode,
|
||||
userActivityTimestamp,
|
||||
updateUserActivity,
|
||||
autoModeStartTimestamp,
|
||||
setAutoModeStartTimestamp,
|
||||
} = useTransform();
|
||||
const [loaded, setLoaded] = useState(false);
|
||||
@@ -49,17 +44,14 @@ export const InfiniteCanvas = observer(
|
||||
position: { x: number; y: number };
|
||||
} | null>(null);
|
||||
// Keep these for backward compatibility, but we'll use pinchStartData for calculations
|
||||
const [initialPinchDistance, setInitialPinchDistance] = useState<
|
||||
number | null
|
||||
>(null);
|
||||
const [initialPinchMidpoint, setInitialPinchMidpoint] = useState<{
|
||||
const [, setInitialPinchDistance] = useState<number | null>(null);
|
||||
const [, setInitialPinchMidpoint] = useState<{
|
||||
x: number;
|
||||
y: number;
|
||||
} | null>(null);
|
||||
|
||||
const [scaleMin, setScaleMin] = useState(0.1); // Default min scale
|
||||
const [scaleMax, setScaleMax] = useState(3); // Default max scale
|
||||
const store = useGeolocationStore();
|
||||
const cameraAnimationStore = useCameraAnimationStore();
|
||||
|
||||
// Add debounced version of syncState to reduce jittering
|
||||
@@ -269,13 +261,14 @@ export const InfiniteCanvas = observer(
|
||||
setInitialPinchMidpoint(null);
|
||||
pinchStartData.current = null;
|
||||
|
||||
if (isDragging) {
|
||||
const newPosition = {
|
||||
x: startPosition.x - startMousePosition.x + e.globalX,
|
||||
y: startPosition.y - startMousePosition.y + e.globalY,
|
||||
};
|
||||
setPosition(newPosition);
|
||||
syncStateDebounced(newPosition, scale);
|
||||
if (isDragging) {
|
||||
const newPosition = {
|
||||
x: startPosition.x - startMousePosition.x + e.globalX,
|
||||
y: startPosition.y - startMousePosition.y + e.globalY,
|
||||
};
|
||||
setPosition(newPosition);
|
||||
syncStateDebounced(newPosition, scale);
|
||||
}
|
||||
}
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
@@ -1,31 +1,20 @@
|
||||
import React, {
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
useMemo,
|
||||
} from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Application, extend } from "@pixi/react";
|
||||
import { extend } from "@pixi/react";
|
||||
import { Container, Graphics, Sprite, Text } from "pixi.js";
|
||||
import { MapDataProvider, useMapData } from "./MapDataContext";
|
||||
import { TransformProvider, useTransform } from "./transformContext";
|
||||
import { InfiniteCanvas } from "./InfiniteCanvas";
|
||||
import { TravelPath } from "./TravelPath";
|
||||
import { Station } from "./Station";
|
||||
import { SightsLayer } from "./Sight";
|
||||
// @ts-ignore
|
||||
import Loader from "../Loader";
|
||||
import {
|
||||
BACKGROUND_COLOR,
|
||||
BUS_COLOR,
|
||||
STATION_OUTLINE_WIDTH,
|
||||
STATION_RADIUS,
|
||||
UP_SCALE,
|
||||
} from "./Constants";
|
||||
import { UP_SCALE } from "./Constants";
|
||||
import "../../styles/MapLayer.css";
|
||||
import { useGeolocationStore, useCameraAnimationStore } from "../../stores";
|
||||
import { useCameraAnimationStore } from "../../stores";
|
||||
import { coordinatesToLocal } from "./utils";
|
||||
import { TramIcon } from "./TramIcon";
|
||||
import { SCALE_FACTOR } from "../../assets/Constants";
|
||||
import { apiStore } from "../../api/ApiStore/store";
|
||||
import WebGLMap from "./WebGLMap";
|
||||
@@ -42,7 +31,7 @@ export function Map() {
|
||||
);
|
||||
}
|
||||
|
||||
function rotatePoint(x, y, originX, originY, angle) {
|
||||
function rotatePoint(x: number, y: number, originX: number, originY: number, angle: number) {
|
||||
const cos = Math.cos(angle);
|
||||
const sin = Math.sin(angle);
|
||||
const dx = x - originX;
|
||||
@@ -53,8 +42,6 @@ function rotatePoint(x, y, originX, originY, angle) {
|
||||
}
|
||||
|
||||
const RouteMap = observer(() => {
|
||||
const store = useGeolocationStore();
|
||||
const { contextData } = store;
|
||||
const {
|
||||
routeData,
|
||||
stationData,
|
||||
@@ -77,7 +64,6 @@ const RouteMap = observer(() => {
|
||||
scale,
|
||||
} = useTransform();
|
||||
const cameraAnimationStore = useCameraAnimationStore();
|
||||
const parentRef = useRef(null);
|
||||
|
||||
const [rotationAngle, setRotationAngle] = useState(0);
|
||||
|
||||
@@ -143,7 +129,7 @@ const RouteMap = observer(() => {
|
||||
const rotationOriginY = 0;
|
||||
|
||||
const transformGeoToMapLocal = useCallback(
|
||||
(latitude, longitude) => {
|
||||
(latitude: number, longitude: number) => {
|
||||
if (centerLat === undefined || centerLon === undefined) {
|
||||
return { x: 0, y: 0 };
|
||||
}
|
||||
@@ -239,99 +225,6 @@ const RouteMap = observer(() => {
|
||||
transformedStations,
|
||||
]);
|
||||
|
||||
const drawActualBusPos = useCallback(
|
||||
(g: Graphics) => {
|
||||
g.clear();
|
||||
if (transformedCurrentCoordinates) {
|
||||
g.circle(
|
||||
transformedCurrentCoordinates.x,
|
||||
transformedCurrentCoordinates.y,
|
||||
STATION_RADIUS / scale < 10
|
||||
? 10
|
||||
: STATION_RADIUS / scale > 20
|
||||
? 20
|
||||
: STATION_RADIUS / scale
|
||||
);
|
||||
g.fill({ color: BUS_COLOR });
|
||||
g.stroke({ color: BACKGROUND_COLOR, width: STATION_OUTLINE_WIDTH });
|
||||
}
|
||||
},
|
||||
[transformedCurrentCoordinates, scale]
|
||||
);
|
||||
|
||||
const scaledPoints = useMemo(() => {
|
||||
if (!routeData?.path) return [];
|
||||
|
||||
return routeData.path.map(([latitude, longitude]) => {
|
||||
const { x, y } = transformGeoToMapLocal(latitude, longitude);
|
||||
return rotatePoint(x, y, rotationOriginX, rotationOriginY, rotationAngle);
|
||||
});
|
||||
}, [
|
||||
routeData?.path,
|
||||
transformGeoToMapLocal,
|
||||
rotationOriginX,
|
||||
rotationOriginY,
|
||||
rotationAngle,
|
||||
]);
|
||||
|
||||
const transformedStationsEn = useMemo(() => {
|
||||
if (!stationDataEn) return [];
|
||||
|
||||
return stationDataEn.map((station) => {
|
||||
const { x, y } = transformGeoToMapLocal(
|
||||
station.latitude,
|
||||
station.longitude
|
||||
);
|
||||
const rotatedCoords = rotatePoint(
|
||||
x,
|
||||
y,
|
||||
rotationOriginX,
|
||||
rotationOriginY,
|
||||
rotationAngle
|
||||
);
|
||||
return {
|
||||
...station,
|
||||
longitude: rotatedCoords.x,
|
||||
latitude: rotatedCoords.y,
|
||||
};
|
||||
});
|
||||
}, [
|
||||
stationDataEn,
|
||||
transformGeoToMapLocal,
|
||||
rotationOriginX,
|
||||
rotationOriginY,
|
||||
rotationAngle,
|
||||
]);
|
||||
|
||||
const transformedStationsZh = useMemo(() => {
|
||||
if (!stationDataZh) return [];
|
||||
|
||||
return stationDataZh.map((station) => {
|
||||
const { x, y } = transformGeoToMapLocal(
|
||||
station.latitude,
|
||||
station.longitude
|
||||
);
|
||||
const rotatedCoords = rotatePoint(
|
||||
x,
|
||||
y,
|
||||
rotationOriginX,
|
||||
rotationOriginY,
|
||||
rotationAngle
|
||||
);
|
||||
return {
|
||||
...station,
|
||||
longitude: rotatedCoords.x,
|
||||
latitude: rotatedCoords.y,
|
||||
};
|
||||
});
|
||||
}, [
|
||||
stationDataZh,
|
||||
transformGeoToMapLocal,
|
||||
rotationOriginX,
|
||||
rotationOriginY,
|
||||
rotationAngle,
|
||||
]);
|
||||
|
||||
if (
|
||||
!routeData ||
|
||||
!stationData ||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// SightsLayer.tsx
|
||||
import React from "react";
|
||||
import { Graphics, Assets, Texture, TextStyle } from "pixi.js";
|
||||
import { useCallback, useEffect, useState, useMemo } from "react";
|
||||
import { useTransform } from "./transformContext";
|
||||
@@ -9,7 +8,6 @@ import { useGeolocationStore } from "../../stores"; // Импортируем us
|
||||
|
||||
const BASE_ICON_SIZE = 30;
|
||||
const CLUSTER_RADIUS_BASE = 10;
|
||||
const CLUSTER_COLOR = 0x1a73e8;
|
||||
|
||||
type Cluster = {
|
||||
id: string;
|
||||
@@ -150,7 +148,7 @@ function SingleSight({
|
||||
readonly sight: SightData;
|
||||
onSightClick: (sightId: string) => void;
|
||||
}) {
|
||||
const { scale } = useTransform();
|
||||
useTransform();
|
||||
const [texture, setTexture] = useState<Texture>(Texture.EMPTY);
|
||||
const store = useGeolocationStore();
|
||||
const { setIsGovernorWidgetOpen } = store;
|
||||
@@ -197,7 +195,7 @@ function SightCluster({
|
||||
}) {
|
||||
const store = useGeolocationStore();
|
||||
const { setIsGovernorWidgetOpen } = store;
|
||||
const { scale } = useTransform();
|
||||
useTransform();
|
||||
const radius = CLUSTER_RADIUS_BASE;
|
||||
const [texture, setTexture] = useState<Texture>(Texture.EMPTY);
|
||||
const fontSize = 14;
|
||||
@@ -334,7 +332,7 @@ export function SightsLayer({
|
||||
sights,
|
||||
pathPoints,
|
||||
}: Readonly<SightsLayerProps>) {
|
||||
const { scale } = useTransform();
|
||||
useTransform();
|
||||
const distanceThreshold = BASE_ICON_SIZE * 3;
|
||||
|
||||
const store = useGeolocationStore(); // Получаем доступ к MobX хранилищу
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from "react";
|
||||
import { Texture, Assets, Graphics } from "pixi.js";
|
||||
import { Texture, Assets } from "pixi.js";
|
||||
import { useEffect, useState, useMemo, useRef } from "react";
|
||||
import { useTransform } from "./transformContext";
|
||||
import { lerp, lerpAngle } from "../../utils/animationUtils";
|
||||
@@ -11,8 +10,6 @@ const basePath = new URL(
|
||||
const tramPath = new URL("../../assets/tramPosition/Tram.svg", import.meta.url)
|
||||
.href;
|
||||
|
||||
// Константы анимации (как в HTML файле)
|
||||
const ANIMATION_DURATION = 1200; // 1.2 секунды
|
||||
const LERP_SPEED = 0.1; // Скорость интерполяции (10% каждый кадр)
|
||||
|
||||
// Функция для проверки расстояния до ближайшей точки маршрута
|
||||
@@ -101,7 +98,7 @@ const getDistanceToStations = (
|
||||
offset_x?: number;
|
||||
offset_y?: number;
|
||||
}[],
|
||||
debug: boolean = false
|
||||
_debug: boolean = false
|
||||
) => {
|
||||
if (!stations || stations.length === 0) {
|
||||
return Infinity;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { lerp, lerpAngle } from "../../utils/animationUtils";
|
||||
import { lerpAngle } from "../../utils/animationUtils";
|
||||
import tramBase from "../../assets/tramPosition/Tram Base.svg";
|
||||
import tramSvg from "../../assets/tramPosition/Tram_Second.svg";
|
||||
import { getMediaUrl } from "../../api/apiConfig";
|
||||
|
||||
@@ -18,8 +18,6 @@ import {
|
||||
BUS_COLOR,
|
||||
BASE_ICON_SIZE,
|
||||
CLUSTER_RADIUS_BASE,
|
||||
CLUSTER_COLOR,
|
||||
ACTIVE_STATION_COLOR,
|
||||
} from "./Constants";
|
||||
import { SCALE_FACTOR } from "../../assets/Constants";
|
||||
import { apiStore } from "../../api/ApiStore/store";
|
||||
@@ -40,7 +38,7 @@ const YELLOW_ICON_FILTER =
|
||||
const clamp = (value: number, min: number, max: number) =>
|
||||
Math.min(max, Math.max(min, value));
|
||||
|
||||
const debugWebglLog = (...args: unknown[]) => {
|
||||
const debugWebglLog = (..._args: unknown[]) => {
|
||||
if (!DEBUG_WEBGL_ROUTE_MAP) return;
|
||||
};
|
||||
|
||||
@@ -424,7 +422,7 @@ export const WebGLMap = observer(() => {
|
||||
}, []);
|
||||
|
||||
const clampPosition = useCallback(
|
||||
(pos: { x: number; y: number }, currentScale: number) => {
|
||||
(pos: { x: number; y: number }, _currentScale: number) => {
|
||||
return pos;
|
||||
},
|
||||
[],
|
||||
@@ -1165,7 +1163,6 @@ export const WebGLMap = observer(() => {
|
||||
gl.enableVertexAttribArray(attribs.a_pos);
|
||||
gl.vertexAttribPointer(attribs.a_pos, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
const vcount = routePath.length / 2;
|
||||
let tramSegIndex = getCurrentSegIndex();
|
||||
|
||||
const dpr = Math.max(1, window.devicePixelRatio || 1);
|
||||
@@ -1452,53 +1449,6 @@ export const WebGLMap = observer(() => {
|
||||
|
||||
const toPointsArray = (arr: number[]) => new Float32Array(arr);
|
||||
|
||||
const pathPts: { x: number; y: number }[] = [];
|
||||
for (let i = 0; i < routePath.length; i += 2)
|
||||
pathPts.push({ x: routePath[i], y: routePath[i + 1] });
|
||||
const getSeg = (px: number, py: number) => {
|
||||
if (pathPts.length < 2) return -1;
|
||||
let best = -1,
|
||||
bestD = Infinity;
|
||||
for (let i = 0; i < pathPts.length - 1; i++) {
|
||||
const p1 = pathPts[i],
|
||||
p2 = pathPts[i + 1];
|
||||
const dx = p2.x - p1.x,
|
||||
dy = p2.y - p1.y;
|
||||
const len2 = dx * dx + dy * dy;
|
||||
if (!len2) continue;
|
||||
const t = ((px - p1.x) * dx + (py - p1.y) * dy) / len2;
|
||||
const tt = Math.max(0, Math.min(1, t));
|
||||
const cx = p1.x + tt * dx,
|
||||
cy = p1.y + tt * dy;
|
||||
const d = Math.hypot(px - cx, py - cy);
|
||||
if (d < bestD) {
|
||||
bestD = d;
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
};
|
||||
|
||||
let tramSegForStations = -1;
|
||||
{
|
||||
const cLat = routeData?.center_latitude,
|
||||
cLon = routeData?.center_longitude;
|
||||
const tram = apiStore?.context?.currentCoordinates as any;
|
||||
if (tram && cLat !== undefined && cLon !== undefined) {
|
||||
const loc = coordinatesToLocal(
|
||||
tram.latitude - cLat,
|
||||
tram.longitude - cLon,
|
||||
);
|
||||
const wx = loc.x * UP_SCALE,
|
||||
wy = loc.y * UP_SCALE;
|
||||
const cosR = Math.cos(rotationAngle),
|
||||
sinR = Math.sin(rotationAngle);
|
||||
const tx = wx * cosR - wy * sinR,
|
||||
ty = wx * sinR + wy * cosR;
|
||||
tramSegForStations = getSeg(tx, ty);
|
||||
}
|
||||
}
|
||||
|
||||
let activeStationIndex = -1;
|
||||
const tramCoords = apiStore?.context?.currentCoordinates;
|
||||
if (
|
||||
@@ -1719,10 +1669,10 @@ export const WebGLMap = observer(() => {
|
||||
const sin = Math.sin(rotationAngle);
|
||||
|
||||
const startStationData = stationData.find(
|
||||
(station) => station.id.toString() === apiStore.context?.startStopId,
|
||||
(station: any) => station.id.toString() === apiStore.context?.startStopId,
|
||||
);
|
||||
const endStationData = stationData.find(
|
||||
(station) => station.id.toString() === apiStore.context?.endStopId,
|
||||
(station: any) => station.id.toString() === apiStore.context?.endStopId,
|
||||
);
|
||||
|
||||
const terminalStations: number[] = [];
|
||||
@@ -2331,11 +2281,10 @@ export const WebGLMap = observer(() => {
|
||||
? { right: 0, transform: "none" }
|
||||
: { left: "50%", transform: "translateX(-50%)" };
|
||||
|
||||
const apiBaseUrl = apiBaseURL;
|
||||
const isMediaIdEmptyResult = isMediaIdEmpty(station?.icon);
|
||||
const iconSrc = isMediaIdEmptyResult
|
||||
? null
|
||||
: `${apiBaseUrl}/media/${station?.icon}/download`;
|
||||
: buildMediaDownloadUrl(mediaBaseUrl, station!.icon!, mediaToken);
|
||||
const iconSizePx = Math.round(primaryFontSize * 1.2);
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,9 +4,7 @@ import React, {
|
||||
useContext,
|
||||
useState,
|
||||
useCallback,
|
||||
useRef,
|
||||
} from "react";
|
||||
import { UP_SCALE } from "./Constants";
|
||||
|
||||
const TransformContext = createContext<{
|
||||
position: { x: number; y: number };
|
||||
|
||||
@@ -231,7 +231,6 @@ export const ThreeView: React.FC<ThreeViewProps> = ({
|
||||
height = "100%",
|
||||
onLoad,
|
||||
onError,
|
||||
onAspectRatioCalculated,
|
||||
controlRef,
|
||||
}) => {
|
||||
return (
|
||||
@@ -244,7 +243,7 @@ export const ThreeView: React.FC<ThreeViewProps> = ({
|
||||
}}
|
||||
camera={{ position: [0, 0, 5], fov: 40 }}
|
||||
style={{ width: "100%", height: "100%" }}
|
||||
onError={(e) => onError?.(e.message)}
|
||||
onError={(e: any) => onError?.(e.message)}
|
||||
>
|
||||
<AutoResize />
|
||||
<TouchController />
|
||||
@@ -269,7 +268,7 @@ export const ThreeView: React.FC<ThreeViewProps> = ({
|
||||
<Stage
|
||||
environment={null}
|
||||
intensity={1}
|
||||
contactShadow={false}
|
||||
castShadow={false}
|
||||
shadows={false}
|
||||
adjustCamera={true}
|
||||
center={{ precise: true }}
|
||||
|
||||
@@ -52,33 +52,6 @@ class CameraAnimationStore {
|
||||
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
||||
}
|
||||
|
||||
private calculateDistance(p1: CameraPosition, p2: CameraPosition): number {
|
||||
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
|
||||
}
|
||||
|
||||
private isNearStation(
|
||||
tramPos: CameraPosition,
|
||||
stations: Station[]
|
||||
): { isNear: boolean; distance: number } {
|
||||
if (!stations || stations.length === 0)
|
||||
return { isNear: false, distance: Infinity };
|
||||
const threshold = 300; // Порог в координатах карты
|
||||
let minDistance = Infinity;
|
||||
|
||||
for (const station of stations) {
|
||||
const distance = this.calculateDistance(tramPos, {
|
||||
x: station.longitude,
|
||||
y: station.latitude,
|
||||
});
|
||||
minDistance = Math.min(minDistance, distance);
|
||||
}
|
||||
|
||||
return {
|
||||
isNear: minDistance < threshold,
|
||||
distance: minDistance,
|
||||
};
|
||||
}
|
||||
|
||||
public setUpdateCallback(
|
||||
callback: ((pos: CameraPosition, zoom: number) => void) | null
|
||||
) {
|
||||
@@ -140,7 +113,7 @@ class CameraAnimationStore {
|
||||
public followTram(
|
||||
tramMapPos: CameraPosition,
|
||||
screenCenter: CameraPosition,
|
||||
stations: Station[] = []
|
||||
_stations: Station[] = []
|
||||
) {
|
||||
// Анимация начинается с текущего зума и плавно переходит к максимальному зуму
|
||||
// для плавного приближения к желтой точке при слежении
|
||||
|
||||
@@ -215,6 +215,8 @@
|
||||
transition:
|
||||
transform 0.3s ease-out,
|
||||
opacity 0.3s ease-out;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.side-menu-sights.slide-in {
|
||||
@@ -227,7 +229,8 @@
|
||||
}
|
||||
|
||||
.side-menu-sights-block {
|
||||
height: calc(100% - 20px);
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
margin-left: 20px;
|
||||
margin-top: 8px;
|
||||
touch-action: none;
|
||||
@@ -236,6 +239,7 @@
|
||||
max-width: calc(100% - 20px);
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.side-menu-sight {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { apiStore } from "../../../client/src/api/ApiStore/store";
|
||||
import App from "../../../client/src/App";
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
SelectArticleModal,
|
||||
UploadMediaDialog,
|
||||
Language,
|
||||
articlesStore,
|
||||
} from "@shared";
|
||||
import {
|
||||
LanguageSwitcher,
|
||||
@@ -85,31 +84,7 @@ export const LeftWidgetTab = observer(
|
||||
) => {
|
||||
setIsSelectArticleDialogOpen(false);
|
||||
|
||||
const ruArticle = await articlesStore.getArticle(articleId, "ru");
|
||||
const enArticle = await articlesStore.getArticle(articleId, "en");
|
||||
const zhArticle = await articlesStore.getArticle(articleId, "zh");
|
||||
|
||||
updateSightInfo("ru", {
|
||||
left: {
|
||||
heading: ruArticle.data.heading,
|
||||
body: ruArticle.data.body,
|
||||
media: ruArticle.data.media || [],
|
||||
},
|
||||
});
|
||||
updateSightInfo("en", {
|
||||
left: {
|
||||
heading: enArticle.data.heading,
|
||||
body: enArticle.data.body,
|
||||
media: enArticle.data.media || [],
|
||||
},
|
||||
});
|
||||
updateSightInfo("zh", {
|
||||
left: {
|
||||
heading: zhArticle.data.heading,
|
||||
body: zhArticle.data.body,
|
||||
media: zhArticle.data.media || [],
|
||||
},
|
||||
});
|
||||
await editSightStore.getLeftArticle(articleId);
|
||||
|
||||
updateSightInfo(
|
||||
languageStore.language,
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user