diff --git a/modern/src/map/MapPositions.js b/modern/src/map/MapPositions.js index 49639e8d6d..68073fab5a 100644 --- a/modern/src/map/MapPositions.js +++ b/modern/src/map/MapPositions.js @@ -11,13 +11,14 @@ import { useAttributePreference, usePreference } from '../common/util/preference const MapPositions = ({ positions, onClick, showStatus, selectedPosition, titleField }) => { const id = useId(); const clusters = `${id}-clusters`; - const direction = `${id}-direction`; + const selected = `${id}-selected`; const theme = useTheme(); const desktop = useMediaQuery(theme.breakpoints.up('md')); const iconScale = useAttributePreference('iconScale', desktop ? 0.75 : 1); const devices = useSelector((state) => state.devices.items); + const selectedDeviceId = useSelector((state) => state.devices.selectedId); const mapCluster = useAttributePreference('mapCluster', true); const hours12 = usePreference('twelveHourFormat'); @@ -93,27 +94,53 @@ const MapPositions = ({ positions, onClick, showStatus, selectedPosition, titleF clusterMaxZoom: 14, clusterRadius: 50, }); - map.addLayer({ - id, - type: 'symbol', - source: id, - filter: ['!has', 'point_count'], - layout: { - 'icon-image': '{category}-{color}', - 'icon-size': iconScale, - 'icon-allow-overlap': true, - 'text-field': `{${titleField || 'name'}}`, - 'text-allow-overlap': true, - 'text-anchor': 'bottom', - 'text-offset': [0, -2 * iconScale], - 'text-font': findFonts(map), - 'text-size': 12, - }, - paint: { - 'text-halo-color': 'white', - 'text-halo-width': 1, + map.addSource(selected, { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: [], }, }); + [id, selected].forEach((id) => { + map.addLayer({ + id, + type: 'symbol', + source: id, + filter: ['!has', 'point_count'], + layout: { + 'icon-image': '{category}-{color}', + 'icon-size': iconScale, + 'icon-allow-overlap': true, + 'text-field': `{${titleField || 'name'}}`, + 'text-allow-overlap': true, + 'text-anchor': 'bottom', + 'text-offset': [0, -2 * iconScale], + 'text-font': findFonts(map), + 'text-size': 12, + }, + paint: { + 'text-halo-color': 'white', + 'text-halo-width': 1, + }, + }); + map.addLayer({ + id: `direction-${id}`, + type: 'symbol', + source: id, + filter: [ + 'all', + ['!has', 'point_count'], + ['==', 'direction', true], + ], + layout: { + 'icon-image': 'direction', + 'icon-size': iconScale, + 'icon-allow-overlap': true, + 'icon-rotate': ['get', 'rotation'], + 'icon-rotation-alignment': 'map', + }, + }); + }); map.addLayer({ id: clusters, type: 'symbol', @@ -127,23 +154,6 @@ const MapPositions = ({ positions, onClick, showStatus, selectedPosition, titleF 'text-size': 14, }, }); - map.addLayer({ - id: direction, - type: 'symbol', - source: id, - filter: [ - 'all', - ['!has', 'point_count'], - ['==', 'direction', true], - ], - layout: { - 'icon-image': 'direction', - 'icon-size': iconScale, - 'icon-allow-overlap': true, - 'icon-rotate': ['get', 'rotation'], - 'icon-rotation-alignment': 'map', - }, - }); map.on('mouseenter', id, onMouseEnter); map.on('mouseleave', id, onMouseLeave); @@ -162,34 +172,40 @@ const MapPositions = ({ positions, onClick, showStatus, selectedPosition, titleF map.off('click', clusters, onClusterClick); map.off('click', onMapClick); - if (map.getLayer(id)) { - map.removeLayer(id); - } + [id, selected].forEach((id) => { + if (map.getLayer(id)) { + map.removeLayer(id); + } + if (map.getLayer(`direction-${id}`)) { + map.removeLayer(`direction-${id}`); + } + }); if (map.getLayer(clusters)) { map.removeLayer(clusters); } - if (map.getLayer(direction)) { - map.removeLayer(direction); - } if (map.getSource(id)) { map.removeSource(id); } }; - }, [mapCluster, clusters, direction, onMarkerClick, onClusterClick]); + }, [mapCluster, clusters, onMarkerClick, onClusterClick]); useEffect(() => { - map.getSource(id)?.setData({ - type: 'FeatureCollection', - features: positions.filter((it) => devices.hasOwnProperty(it.deviceId)).map((position) => ({ - type: 'Feature', - geometry: { - type: 'Point', - coordinates: [position.longitude, position.latitude], - }, - properties: createFeature(devices, position, selectedPosition && selectedPosition.id), - })), + [id, selected].forEach((source) => { + map.getSource(source)?.setData({ + type: 'FeatureCollection', + features: positions.filter((it) => devices.hasOwnProperty(it.deviceId)) + .filter((it) => (source === id ? it.deviceId !== selectedDeviceId : it.deviceId === selectedDeviceId)) + .map((position) => ({ + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [position.longitude, position.latitude], + }, + properties: createFeature(devices, position, selectedPosition && selectedPosition.id), + })), + }); }); - }, [mapCluster, clusters, direction, onMarkerClick, onClusterClick, devices, positions, selectedPosition]); + }, [mapCluster, clusters, onMarkerClick, onClusterClick, devices, positions, selectedPosition]); return null; };