import { useEffect, useState } from "react"; import { useTransform } from "./TransformContext"; import { SightData } from "./types"; import { Assets, FederatedMouseEvent, Texture } from "pixi.js"; import { SIGHT_SIZE, UP_SCALE } from "./Constants"; import { coordinatesToLocal, localToCoordinates } from "./utils"; import { useMapData } from "./MapDataContext"; interface SightProps { sight: SightData; id: number; } export const Sight = ({ sight, id }: Readonly) => { const { rotation, scale } = useTransform(); const { setSightCoordinates, setSelectedSight } = useMapData(); const [position, setPosition] = useState( coordinatesToLocal(sight.latitude, sight.longitude) ); const [isDragging, setIsDragging] = useState(false); const [isPointerDown, setIsPointerDown] = useState(false); const [startPosition, setStartPosition] = useState({ x: 0, y: 0 }); const [startMousePosition, setStartMousePosition] = useState({ x: 0, y: 0 }); const handlePointerDown = (e: FederatedMouseEvent) => { setIsPointerDown(true); setIsDragging(false); setStartPosition({ x: position.x, y: position.y, }); setStartMousePosition({ x: e.globalX, y: e.globalY, }); e.stopPropagation(); }; const handlePointerMove = (e: FederatedMouseEvent) => { if (!isPointerDown) return; if (!isDragging) { const dx = e.globalX - startMousePosition.x; const dy = e.globalY - startMousePosition.y; if (Math.abs(dx) > 2 || Math.abs(dy) > 2) { setIsDragging(true); } else { return; } } const dx = (e.globalX - startMousePosition.x) / scale / UP_SCALE; const dy = (e.globalY - startMousePosition.y) / scale / UP_SCALE; const cos = Math.cos(rotation); const sin = Math.sin(rotation); const newPosition = { x: startPosition.x + dx * cos + dy * sin, y: startPosition.y - dx * sin + dy * cos, }; setPosition(newPosition); const coordinates = localToCoordinates(newPosition.x, newPosition.y); setSightCoordinates(sight.id, coordinates.latitude, coordinates.longitude); e.stopPropagation(); }; const handlePointerUp = (e: FederatedMouseEvent) => { setIsPointerDown(false); // Если не было перетаскивания, то это клик if (!isDragging) { setSelectedSight(sight); } setIsDragging(false); e.stopPropagation(); }; const [texture, setTexture] = useState(Texture.EMPTY); useEffect(() => { Assets.load("/SightIcon.png").then(setTexture); }, []); useEffect(() => { console.log( `Rendering Sight ${id + 1} at [${sight.latitude}, ${sight.longitude}]` ); }, [id, sight.latitude, sight.longitude]); if (!sight) { console.error("sight is null"); return null; } // Компенсируем масштаб для сохранения постоянного размера const compensatedSize = SIGHT_SIZE / scale; const compensatedFontSize = 24 / scale; return ( { g.clear(); g.circle(0, 0, 20 / scale); g.fill({ color: "#000" }); }} x={compensatedSize} y={0} /> ); };