1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
import { Feature, Map, View } from "ol";
import { defaults } from "ol/control";
import { Point } from "ol/geom";
import TileLayer from "ol/layer/Tile";
import VectorLayer from "ol/layer/Vector";
import { fromLonLat, transformExtent } from "ol/proj";
import { OSM } from "ol/source";
import VectorSource from "ol/source/Vector";
import Fill from "ol/style/Fill";
import Icon from "ol/style/Icon";
import Stroke from "ol/style/Stroke";
import Style from "ol/style/Style";
import Text from "ol/style/Text";
import { useEffect, useRef } from "react";
import robotMarker from "../assets/robot-head.svg";
import "../styles/dashboard.css";
import type { Robot } from "../types/robot";
type Props = {
robots: Robot[];
};
function CityMap({ robots }: Props) {
const mapRef = useRef<HTMLDivElement | null>(null);
const mapInstance = useRef<Map | null>(null);
const markerLayer = useRef<VectorLayer<VectorSource> | null>(null);
useEffect(() => {
if (mapInstance.current) return; // prevent re-init
markerLayer.current = new VectorLayer({
source: new VectorSource(),
});
const leipzigCenter = fromLonLat([12.375919, 51.340863]);
const leipzigArea = transformExtent(
// west, south, east, north; transform from WGS84 lat-long system to Web Mercator system
[12.22, 51.26, 12.54, 51.44],
"EPSG:4326",
"EPSG:3857"
);
mapInstance.current = new Map({
target: mapRef.current as HTMLDivElement,
controls: defaults({ attribution: false }),
layers: [
new TileLayer({
source: new OSM(),
}),
markerLayer.current,
],
view: new View({
center: leipzigCenter,
zoom: 15,
extent: leipzigArea,
}),
});
}, []);
useEffect(() => {
if (!markerLayer.current) return;
const source = markerLayer.current.getSource();
if (!source) return;
source.clear();
robots?.forEach((robot) => {
const feature = new Feature({
geometry: new Point(
fromLonLat([parseFloat(robot?.lon), parseFloat(robot?.lat)])
),
robotId: robot?.id,
});
feature.setStyle(
new Style({
image: new Icon({
src: robotMarker,
scale: 1.2,
anchor: [0.5, 0.4], // anchor label bottom center of icon
}),
text: new Text({
text: robot?.name,
font: "bold 14px sans-serif",
fill: new Fill({ color: "#000" }),
stroke: new Stroke({ color: "#fff", width: 3 }), // outline for better visibility
offsetY: -25, // move label above the marker
}),
})
);
source.addFeature(feature);
});
}, [robots]);
return <div id="map" ref={mapRef}></div>;
}
export default CityMap;
|