Skip to content

Commit

Permalink
Add leaflet-markers-canvas to render custom buoy marker on canvas
Browse files Browse the repository at this point in the history
  • Loading branch information
K-Markopoulos committed Jan 17, 2025
1 parent 1a44314 commit a017895
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 25 deletions.
1 change: 1 addition & 0 deletions packages/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"geolib": "^3.3.4",
"immutable": "^4.0.0-rc.12",
"leaflet": "^1.7.1",
"leaflet-markers-canvas": "^0.2.2",
"leaflet.locatecontrol": "^0.79.0",
"lodash": "^4.17.15",
"luxon": "^3.3.0",
Expand Down
4 changes: 4 additions & 0 deletions packages/website/src/layout/App/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ iframe {
border: 2px solid white;
}

.popup-offset {
margin-bottom: 30px;
}

@media screen and (max-width: 599px) {
.mapbox-wordmark {
bottom: 55px;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import L from 'leaflet';
import 'leaflet-markers-canvas';
import React, { createContext, useContext, useEffect, useState } from 'react';
import { useLeaflet } from 'react-leaflet';

const CanvasIconLayerContext = createContext<L.LayerGroup | null>(null);
export const useCanvasIconLayer = () => {
return useContext(CanvasIconLayerContext);
};

type CanvasMarkersLayerProps = {
children: React.ReactNode | React.ReactNode[];
};
export const CanvasMarkersLayer = ({ children }: CanvasMarkersLayerProps) => {
const { map } = useLeaflet();

const [canvasIconLayer, setCanvasIconLayer] = useState<L.LayerGroup | null>(
null,
);

useEffect(() => {
if (map && !canvasIconLayer) {
// @ts-ignore
const markersCanvas = new L.MarkersCanvas();
markersCanvas.addTo(map);
setCanvasIconLayer(markersCanvas);
}
}, [map, canvasIconLayer]);

return (
<CanvasIconLayerContext.Provider value={canvasIconLayer}>
{children}
</CanvasIconLayerContext.Provider>
);
};
68 changes: 45 additions & 23 deletions packages/website/src/routes/HomeMap/Map/Markers/SiteMarker.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CircleMarker, Marker } from 'react-leaflet';
import { Marker, useLeaflet } from 'react-leaflet';
import { useDispatch, useSelector } from 'react-redux';
import React from 'react';
import React, { useEffect } from 'react';
import { Site } from 'store/Sites/types';
import {
isSelectedOnMapSelector,
Expand All @@ -13,7 +13,9 @@ import {
} from 'helpers/bleachingAlertIntervals';
import { useMarkerIcon } from 'helpers/map';
import { hasDeployedSpotter } from 'helpers/siteUtils';
import L from 'leaflet';
import Popup from '../Popup';
import { useCanvasIconLayer } from './CanvasMarkersLayer';

// To make sure we can see all the sites all the time, and especially
// around -180/+180, we create dummy copies of each site.
Expand All @@ -27,34 +29,54 @@ interface SiteMarkerProps {
* All in one site marker with icon, offset duplicates, and popup built in.
*/
export const CircleSiteMarker = React.memo(({ site }: SiteMarkerProps) => {
const isSelected = useSelector(isSelectedOnMapSelector(site.id));
const dispatch = useDispatch();
const isSelected = useSelector(isSelectedOnMapSelector(site.id));
const { map } = useLeaflet();
const canvasIconLayer = useCanvasIconLayer();
const { tempWeeklyAlert } = site.collectionData || {};
const markerIcon = useMarkerIcon(
hasDeployedSpotter(site),
site.hasHobo,
isSelected,
alertColorFinder(tempWeeklyAlert),
alertIconFinder(tempWeeklyAlert),
);

useEffect(() => {
if (!map || !canvasIconLayer || site.polygon.type !== 'Point') return;
const [lng, lat] = site.polygon.coordinates;
const marker = L.marker([lat, lng], {
icon: markerIcon,
}).on('click', () => {
dispatch(setSearchResult());
dispatch(setSiteOnMap(site));
});
// @ts-ignore
canvasIconLayer.addMarker(marker);
// eslint-disable-next-line consistent-return
return () => {
// @ts-ignore
canvasIconLayer.removeMarker(marker);
};
}, [
map,
canvasIconLayer,
site.polygon.type,
site.polygon.coordinates,
markerIcon,
site,
dispatch,
]);

if (site.polygon.type !== 'Point') return null;

const [lng, lat] = site.polygon.coordinates;

return (
<>
{LNG_OFFSETS.map((offset) => (
<CircleMarker
onclick={() => {
dispatch(setSearchResult());
dispatch(setSiteOnMap(site));
}}
key={`${site.id}-${offset}`}
color={alertColorFinder(tempWeeklyAlert)}
fillOpacity={1}
center={[lat, lng + offset]}
radius={5}
data-alert={tempWeeklyAlert}
>
{isSelected && <Popup site={site} autoOpen={offset === 0} />}
</CircleMarker>
))}
</>
);
return isSelected ? (
<Marker position={[lat, lng]} icon={L.divIcon({ className: 'd-none' })}>
<Popup site={site} autoOpen classes={{ popup: 'popup-offset' }} />
</Marker>
) : null;
});

export const SensorSiteMarker = React.memo(({ site }: SiteMarkerProps) => {
Expand Down
5 changes: 3 additions & 2 deletions packages/website/src/routes/HomeMap/Map/Markers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'react-leaflet-markercluster/dist/styles.min.css';
import { CollectionDetails } from 'store/Collection/types';
import { hasDeployedSpotter } from 'helpers/siteUtils';
import { CircleSiteMarker, SensorSiteMarker } from './SiteMarker';
import { CanvasMarkersLayer } from './CanvasMarkersLayer';

const hasSpotter = (site: Site) => site.hasHobo || hasDeployedSpotter(site);

Expand All @@ -18,15 +19,15 @@ export const SiteMarkers = ({ collection }: SiteMarkersProps) => {
);

return (
<>
<CanvasMarkersLayer>
{sitesList.map((site: Site) =>
sitesList[site.id] && hasSpotter(site) ? (
<SensorSiteMarker key={`${site.id}`} site={site} />
) : (
<CircleSiteMarker key={`${site.id}`} site={site} />
),
)}
</>
</CanvasMarkersLayer>
);
};

Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14334,6 +14334,11 @@ lazystream@^1.0.0:
dependencies:
readable-stream "^2.0.5"

leaflet-markers-canvas@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/leaflet-markers-canvas/-/leaflet-markers-canvas-0.2.2.tgz#fde165d4531c326d9120494aea52b0e753cc48fd"
integrity sha512-UU/98qrmljhU6Xl3lrsUAUke4Qb/p8BCfmhiw7L1hHtkVMxdRYgwk7RwUW9QNoPbhnmuyxsc90whKjWVVP5cNw==

leaflet.locatecontrol@^0.79.0:
version "0.79.0"
resolved "https://registry.yarnpkg.com/leaflet.locatecontrol/-/leaflet.locatecontrol-0.79.0.tgz#0236b87c699a49f9ddb2f289941fbc0d3c3f8b62"
Expand Down

0 comments on commit a017895

Please sign in to comment.