update the import statement for sitePoints to match the correct file name (sitepoints instead of sitePoints)
This commit is contained in:
@ -1,9 +1,6 @@
|
|||||||
import { useEffect, useRef, useState, useMemo } from 'react';
|
import { useEffect, useRef, useState, useMemo } from 'react';
|
||||||
import L from 'leaflet';
|
import L from 'leaflet';
|
||||||
import 'leaflet/dist/leaflet.css';
|
import 'leaflet/dist/leaflet.css';
|
||||||
import 'leaflet.markercluster';
|
|
||||||
import 'leaflet.markercluster/dist/MarkerCluster.css';
|
|
||||||
import 'leaflet.markercluster/dist/MarkerCluster.Default.css';
|
|
||||||
import { sitePoints, SitePoint } from '../sitepoints';
|
import { sitePoints, SitePoint } from '../sitepoints';
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -11,9 +8,13 @@ import { sitePoints, SitePoint } from '../sitepoints';
|
|||||||
// pin for every Cell/Sector row from the uploaded Excel
|
// pin for every Cell/Sector row from the uploaded Excel
|
||||||
// (Sites_Coordinates_untuk_CC.xlsm -> "site coordinates 4G").
|
// (Sites_Coordinates_untuk_CC.xlsm -> "site coordinates 4G").
|
||||||
//
|
//
|
||||||
|
// No clustering — every site is shown as its own blue pin, directly at its
|
||||||
|
// real coordinates (previously multi-sector sites used a marker cluster
|
||||||
|
// plugin, which rendered green/yellow/orange group bubbles; that's removed).
|
||||||
|
//
|
||||||
// SETUP REQUIRED:
|
// SETUP REQUIRED:
|
||||||
// npm install leaflet leaflet.markercluster
|
// npm install leaflet
|
||||||
// npm install --save-dev @types/leaflet @types/leaflet.markercluster
|
// npm install --save-dev @types/leaflet
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const DILI_CENTER: [number, number] = [-8.5586, 125.5736];
|
const DILI_CENTER: [number, number] = [-8.5586, 125.5736];
|
||||||
@ -30,12 +31,11 @@ const groupByCoordinate = (points: SitePoint[]) => {
|
|||||||
return map;
|
return map;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Signal-tower badge icon: colored circle background + white "broadcast
|
// Signal-tower badge icon: blue circle background + white "broadcast tower"
|
||||||
// tower" glyph, sized up slightly for pins that represent more than one
|
// glyph. Same size/style for every site pin.
|
||||||
// cell/sector at the same coordinates.
|
const pinIcon = () => {
|
||||||
const pinIcon = (multi: boolean) => {
|
const size = 28;
|
||||||
const size = multi ? 30 : 26;
|
const bg = '#2563eb';
|
||||||
const bg = multi ? '#2563eb' : '#ef4444';
|
|
||||||
|
|
||||||
return L.divIcon({
|
return L.divIcon({
|
||||||
className: '',
|
className: '',
|
||||||
@ -65,8 +65,8 @@ const pinIcon = (multi: boolean) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// "Signal detail" popup (blue pins only) — mimics the tabbed
|
// "Signal detail" popup — tabbed Signal / RAN 2G / RAN 3G / Alarm dialog,
|
||||||
// Signal / RAN 2G / RAN 3G / Alarm dialog from the reference screenshot.
|
// shown for every pin.
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
const QUALITY_LEVELS = ['Low', 'Moderate', 'Good', 'Very Good', 'Excellent'];
|
const QUALITY_LEVELS = ['Low', 'Moderate', 'Good', 'Very Good', 'Excellent'];
|
||||||
@ -206,7 +206,6 @@ const wireSignalPopup = (container: HTMLElement, site: string) => {
|
|||||||
const SitesSatelliteMap = () => {
|
const SitesSatelliteMap = () => {
|
||||||
const mapContainerRef = useRef<HTMLDivElement | null>(null);
|
const mapContainerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const mapRef = useRef<L.Map | null>(null);
|
const mapRef = useRef<L.Map | null>(null);
|
||||||
const clusterRef = useRef<L.MarkerClusterGroup | null>(null);
|
|
||||||
const markerByKeyRef = useRef<Map<string, L.Marker>>(new Map());
|
const markerByKeyRef = useRef<Map<string, L.Marker>>(new Map());
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const [selectedCount, setSelectedCount] = useState(sitePoints.length);
|
const [selectedCount, setSelectedCount] = useState(sitePoints.length);
|
||||||
@ -239,39 +238,15 @@ const SitesSatelliteMap = () => {
|
|||||||
{ maxZoom: 19, opacity: 0.9 }
|
{ maxZoom: 19, opacity: 0.9 }
|
||||||
).addTo(map);
|
).addTo(map);
|
||||||
|
|
||||||
const cluster = L.markerClusterGroup({ maxClusterRadius: 50 });
|
// Every site gets its own blue pin placed directly on the map — no
|
||||||
clusterRef.current = cluster;
|
// clustering, no group bubbles.
|
||||||
|
|
||||||
grouped.forEach((points, key) => {
|
grouped.forEach((points, key) => {
|
||||||
const [lat, lng] = key.split(',').map(Number);
|
const [lat, lng] = key.split(',').map(Number);
|
||||||
const isMulti = points.length > 1;
|
const marker = L.marker([lat, lng], { icon: pinIcon() }).addTo(map);
|
||||||
const marker = L.marker([lat, lng], { icon: pinIcon(isMulti) });
|
marker.bindPopup(buildSignalPopupHtml(points, lat, lng), { maxWidth: 320, minWidth: 290 });
|
||||||
|
|
||||||
if (isMulti) {
|
|
||||||
// Blue pin -> rich "Signal" dialog.
|
|
||||||
marker.bindPopup(buildSignalPopupHtml(points, lat, lng), { maxWidth: 320, minWidth: 290 });
|
|
||||||
} else {
|
|
||||||
// Red pin -> simple cell/sector info (unchanged).
|
|
||||||
const site = points[0].site;
|
|
||||||
const location = points[0].location;
|
|
||||||
const rows = points
|
|
||||||
.map((p) => `<tr><td style="padding-right:8px;">${p.cell}</td><td>${p.sector}</td></tr>`)
|
|
||||||
.join('');
|
|
||||||
marker.bindPopup(`
|
|
||||||
<div style="font-family: Arial, sans-serif; font-size: 13px; max-width: 240px;">
|
|
||||||
<div style="font-weight:600; margin-bottom:2px;">${site}</div>
|
|
||||||
<div style="color:#666; margin-bottom:6px;">${location} · ${lat.toFixed(5)}, ${lng.toFixed(5)}</div>
|
|
||||||
<table style="width:100%; border-collapse:collapse;">${rows}</table>
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
}
|
|
||||||
|
|
||||||
markerByKeyRef.current.set(key, marker);
|
markerByKeyRef.current.set(key, marker);
|
||||||
cluster.addLayer(marker);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
map.addLayer(cluster);
|
|
||||||
|
|
||||||
// Wire up the rich popup's interactive bits (tabs + buttons) every time
|
// Wire up the rich popup's interactive bits (tabs + buttons) every time
|
||||||
// one is opened, since Leaflet re-renders the DOM content on each open.
|
// one is opened, since Leaflet re-renders the DOM content on each open.
|
||||||
const onPopupOpen = (e: L.PopupEvent) => {
|
const onPopupOpen = (e: L.PopupEvent) => {
|
||||||
@ -287,7 +262,6 @@ const SitesSatelliteMap = () => {
|
|||||||
map.off('popupopen', onPopupOpen);
|
map.off('popupopen', onPopupOpen);
|
||||||
map.remove();
|
map.remove();
|
||||||
mapRef.current = null;
|
mapRef.current = null;
|
||||||
clusterRef.current = null;
|
|
||||||
markerByKeyRef.current.clear();
|
markerByKeyRef.current.clear();
|
||||||
};
|
};
|
||||||
}, [grouped]);
|
}, [grouped]);
|
||||||
@ -314,9 +288,7 @@ const SitesSatelliteMap = () => {
|
|||||||
const key = `${first.lat.toFixed(6)},${first.lng.toFixed(6)}`;
|
const key = `${first.lat.toFixed(6)},${first.lng.toFixed(6)}`;
|
||||||
mapRef.current.setView([first.lat, first.lng], 17);
|
mapRef.current.setView([first.lat, first.lng], 17);
|
||||||
const marker = markerByKeyRef.current.get(key);
|
const marker = markerByKeyRef.current.get(key);
|
||||||
if (marker && clusterRef.current) {
|
if (marker) marker.openPopup();
|
||||||
clusterRef.current.zoomToShowLayer(marker, () => marker.openPopup());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user