import { useEffect, useRef } from 'react' import 'ol/ol.css' import { Container, Stack, Tabs } from '@mantine/core' import OlMap from 'ol/Map' import { v4 as uuidv4 } from 'uuid' import TileLayer from 'ol/layer/Tile' import { OSM } from 'ol/source' import View from 'ol/View' import { transform } from 'ol/proj' import VectorLayer from 'ol/layer/Vector' import VectorSource from 'ol/source/Vector' import Feature from 'ol/Feature' import { LineString } from 'ol/geom' import { Stroke, Style, Text } from 'ol/style' const center = [14443331.466543002, 8878970.176309839] const style = new Style({ stroke: new Stroke({ color: 'blue', width: 2 }), text: new Text({ font: 'bold 14px', placement: 'line', offsetY: -14 }), }) const MapLineTest = () => { const lines = [ { name: 'A', points: [[100, 100], [200, 200]] }, { name: 'B', points: [[200, 200], [300, 200]] }, { name: 'X', points: [[200, 200], [300, 300]] }, { name: 'L', points: [[300, 300], [350, 300]] }, { name: 'N', points: [[300, 300], [250, 300]] }, { name: 'I', points: [[300, 200], [300, 100]] }, { name: 'J', points: [[300, 100], [250, 50]] }, { name: 'C', points: [[300, 200], [400, 150]] }, { name: 'D', points: [[400, 150], [400, 100]] }, ] const map = useRef(null) const vectorLayer = useRef(new VectorLayer({ source: new VectorSource(), style: feature => { style.getText()?.setText(feature.get('label')) return style } })) const mapElement = useRef(null) useEffect(() => { map.current = new OlMap({ controls: [], layers: [ new TileLayer({ source: new OSM(), properties: { id: uuidv4(), name: 'OpenStreetMap' } }), vectorLayer.current ] }) map.current.setTarget(mapElement.current as HTMLDivElement) map.current.setView(new View({ center: transform([129.7466541, 62.083504], 'EPSG:4326', 'EPSG:3857'), zoom: 16, maxZoom: 21, })) }, []) useEffect(() => { if (map.current) { const graph = new Map() // build graph adjacency list lines.forEach(({ points }) => { const [start, end] = points.map(pt => pt.join(',')) const distance = Math.hypot(points[1][0] - points[0][0], points[1][1] - points[0][1]) if (!graph.has(start)) graph.set(start, []) if (!graph.has(end)) graph.set(end, []) graph.get(start)?.push({ node: end, distance }) graph.get(end)?.push({ node: start, distance }) }) // perform DFS to calculate distances from "A" const startNode = lines[0].points[0].join(',') const distances = new Map() const dfs = (node: string, currentDist: number) => { if (distances.has(node) && distances.get(node)! <= currentDist) return distances.set(node, currentDist) for (const { node: neighbor, distance } of graph.get(node) || []) { dfs(neighbor, currentDist + distance) } } dfs(startNode, 0) // render features lines.forEach(({ name, points }) => { const lineCoords = points.map(point => [point[0] + center[0], point[1] + center[1]]) const feature = new Feature(new LineString(lineCoords)) const lastNode = points[1].join(',') const label = `${name} ${feature.getGeometry()?.getLength().toFixed(2)} (${distances.get(lastNode)?.toFixed(1) ?? '∞'})` feature.set('label', label) vectorLayer.current.getSource()?.addFeature(feature) }) } }, []) return ( Map ) } export default MapLineTest