From 3dfc598c0aac5db5282daa0727288cb747a0e64f Mon Sep 17 00:00:00 2001 From: frozenhelium Date: Mon, 11 Mar 2024 11:12:17 +0545 Subject: [PATCH] Refactor LineLayer, MapboxLayer and TileLayer --- lib/src/components/Map/Layers/LineLayer.tsx | 102 ++++++++++-------- lib/src/components/Map/Layers/MapboxLayer.tsx | 81 ++++++++------ lib/src/components/Map/Layers/TileLayer.tsx | 67 ++++++++---- .../{MaskLayer => _MaskLayer}/index.tsx | 0 .../styles.module.css | 0 .../{SymbolLayer.tsx => _SymbolLayer.tsx} | 0 .../{VectorLayer.tsx => _VectorLayer.tsx} | 0 lib/src/components/Map/index.tsx | 8 +- 8 files changed, 161 insertions(+), 97 deletions(-) rename lib/src/components/Map/Layers/{MaskLayer => _MaskLayer}/index.tsx (100%) rename lib/src/components/Map/Layers/{MaskLayer => _MaskLayer}/styles.module.css (100%) rename lib/src/components/Map/Layers/{SymbolLayer.tsx => _SymbolLayer.tsx} (100%) rename lib/src/components/Map/Layers/{VectorLayer.tsx => _VectorLayer.tsx} (100%) diff --git a/lib/src/components/Map/Layers/LineLayer.tsx b/lib/src/components/Map/Layers/LineLayer.tsx index d0701789..3ee76305 100644 --- a/lib/src/components/Map/Layers/LineLayer.tsx +++ b/lib/src/components/Map/Layers/LineLayer.tsx @@ -1,4 +1,5 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useMemo, useRef } from 'react'; +import { isNotDefined } from '@togglecorp/fujs'; import { Map as MapFromLib } from 'ol'; import OLVectorLayer from 'ol/layer/Vector'; import { Vector as VectorSource } from 'ol/source'; @@ -10,6 +11,8 @@ import { import { LineLayer } from '../index'; import { rgba } from '../helpers'; +const DEFAULT_STROKE_COLOR = '#787878'; + interface Props extends Pick { map: MapFromLib | undefined; source: VectorSource; @@ -24,57 +27,68 @@ function LineLayer(props: Props) { opacity = 1, } = props; - const [lineLayer, setLineLayer] = useState(undefined); + const configRef = useRef({ + zIndex, + opacity, + }); // line vectors - useEffect(() => { - if (!map) return undefined; - const styles = []; - - const lineDash = style.strokeType === 'dash' - ? [style.dashSpacing / 3, style.dashSpacing] - : undefined; - - const stroke = new Stroke({ - width: style.strokeWidth, - color: rgba(style.stroke), - lineDash, - }); - - if (style) { - styles.push( - new Style({ stroke }), - ); - } + const lineLayer = useMemo( + () => { + const styles: Style[] = []; + + const lineDash = style.strokeType === 'dash' + ? [style.dashSpacing / 3, style.dashSpacing] + : undefined; - const vLayer = new OLVectorLayer({ - source, - style() { - return styles; - }, - }); - - map.addLayer(vLayer); - vLayer.setZIndex(zIndex); - vLayer.setOpacity(opacity); - setLineLayer(vLayer); - - return () => { - if (map) { - map.removeLayer(vLayer); + const stroke = new Stroke({ + width: style.strokeWidth, + color: rgba(style.stroke) ?? DEFAULT_STROKE_COLOR, + lineDash, + }); + + if (style) { + styles.push( + new Style({ stroke }), + ); } - }; - }, [map, JSON.stringify(style)]); - useEffect(() => { - if (!lineLayer) return; - lineLayer.setOpacity(opacity); - }, [lineLayer, opacity]); + return new OLVectorLayer({ + source, + style: styles, + zIndex: configRef.current.zIndex, + opacity: configRef.current.opacity, + }); + }, + [source, style], + ); + + useEffect( + () => { + const currentMap = map; + const addedLayer = lineLayer; + + if (isNotDefined(currentMap) || isNotDefined(addedLayer)) { + return undefined; + } + + currentMap.addLayer(addedLayer); + + return () => { + currentMap.removeLayer(addedLayer); + }; + }, + [map, lineLayer], + ); useEffect(() => { - if (!lineLayer) return; + if (isNotDefined(lineLayer)) { + return; + } + + lineLayer.setOpacity(opacity); lineLayer.setZIndex(zIndex); - }, [lineLayer, zIndex]); + }, [lineLayer, opacity, zIndex]); return null; } diff --git a/lib/src/components/Map/Layers/MapboxLayer.tsx b/lib/src/components/Map/Layers/MapboxLayer.tsx index 4984ba03..59e8d23a 100644 --- a/lib/src/components/Map/Layers/MapboxLayer.tsx +++ b/lib/src/components/Map/Layers/MapboxLayer.tsx @@ -1,49 +1,70 @@ -import { useState, useEffect } from 'react'; +import { useEffect, useRef, useMemo } from 'react'; +import { isNotDefined } from '@togglecorp/fujs'; +import { Map as MapFromLib } from 'ol'; import TileLayer from 'ol/layer/Tile'; import { XYZ } from 'ol/source'; -function MapboxLayer({ - map, zIndex = 1, opacity = 1, styleUrl, accessToken, -}) { - const [mapboxLayer, setMapboxLayer] = useState(undefined); +import { MapboxLayer } from '../index'; - useEffect(() => { - if (!map) return undefined; +interface Props extends Pick { + map: MapFromLib | undefined; + styleUrl: string; +} + +function MapboxLayer(props: Props) { + const { + map, + zIndex = 1, + opacity = 1, + styleUrl, + accessToken, + } = props; + + const configRef = useRef({ + zIndex, + opacity, + }); + + const mapboxLayer = useMemo( + () => { + let styleUrlParsed = styleUrl.replace('mapbox://', ''); + styleUrlParsed = styleUrlParsed.replace('styles/', 'styles/v1/'); - let styleUrlParsed = styleUrl.replace('mapbox://', ''); - styleUrlParsed = styleUrlParsed.replace('styles/', 'styles/v1/'); + return new TileLayer({ + source: new XYZ({ + url: `https://api.mapbox.com/${styleUrlParsed}/tiles/{z}/{x}/{y}?access_token=${accessToken}`, + tileSize: 512, + // preload: 10, + crossOrigin: 'anonymous', + }), + zIndex: configRef.current.zIndex, + opacity: configRef.current.opacity, + }); + }, + [styleUrl, accessToken], + ); - const layer = new TileLayer({ - source: new XYZ({ - url: `https://api.mapbox.com/${styleUrlParsed}/tiles/{z}/{x}/{y}?access_token=${accessToken}`, - tileSize: 512, - preload: 10, - crossOrigin: 'anonymous', - }), - }); + useEffect(() => { + const currentMap = map; + const addedLayer = mapboxLayer; - map.addLayer(layer); - layer.setZIndex(zIndex); - layer.setOpacity(opacity); + if (isNotDefined(currentMap) || isNotDefined(addedLayer)) { + return undefined; + } - setMapboxLayer(layer); + currentMap.addLayer(addedLayer); return () => { - if (map) { - map.removeLayer(layer); - } + currentMap.removeLayer(addedLayer); }; - }, [map, styleUrl, accessToken]); + }, [map, styleUrl, accessToken, mapboxLayer]); useEffect(() => { if (!mapboxLayer) return; - mapboxLayer.setOpacity(opacity); - }, [mapboxLayer, opacity]); - useEffect(() => { - if (!mapboxLayer) return; + mapboxLayer.setOpacity(opacity); mapboxLayer.setZIndex(zIndex); - }, [mapboxLayer, zIndex]); + }, [mapboxLayer, opacity, zIndex]); return null; } diff --git a/lib/src/components/Map/Layers/TileLayer.tsx b/lib/src/components/Map/Layers/TileLayer.tsx index 93825b59..0acb59f5 100644 --- a/lib/src/components/Map/Layers/TileLayer.tsx +++ b/lib/src/components/Map/Layers/TileLayer.tsx @@ -1,35 +1,62 @@ -import { useState, useEffect } from 'react'; +import { useEffect, useMemo, useRef } from 'react'; +import { isNotDefined } from '@togglecorp/fujs'; +import { Map as MapFromLib } from 'ol'; import OLTileLayer from 'ol/layer/Tile'; +import TileSource from 'ol/source/Tile'; -function TileLayer({ - map, source, zIndex = 0, opacity = 1, -}) { - const [tileLayer, setTileLayer] = useState(undefined); +import { OsmBackgroundLayer } from '../index'; + +interface Props extends Pick { + map: MapFromLib | undefined; + source: TileSource; +} +function TileLayer(props: Props) { + const { + map, + source, + zIndex = 1, + opacity = 1, + } = props; + + const configRef = useRef({ + zIndex, + opacity, + }); + + const tileLayer = useMemo( + () => ( + new OLTileLayer({ + source, + zIndex: configRef.current.zIndex, + opacity: configRef.current.opacity, + }) + ), + [source], + ); useEffect(() => { - if (!map) return undefined; + const currentMap = map; + const addedLayer = tileLayer; - const tileRasterLayer = new OLTileLayer({ - source, - zIndex, - }); - map.addLayer(tileRasterLayer); - tileRasterLayer.setZIndex(zIndex); - tileRasterLayer.setOpacity(opacity); + if (isNotDefined(currentMap) || isNotDefined(addedLayer)) { + return undefined; + } - setTileLayer(tileRasterLayer); + currentMap.addLayer(addedLayer); return () => { - if (map) { - map.removeLayer(tileRasterLayer); - } + currentMap.removeLayer(addedLayer); }; - }, [map, JSON.stringify(source.urls)]); + }, [map, tileLayer]); useEffect(() => { - if (!tileLayer) return; + if (isNotDefined(tileLayer)) { + return; + } + tileLayer.setOpacity(opacity); - }, [opacity]); + tileLayer.setZIndex(zIndex); + }, [tileLayer, opacity, zIndex]); return null; } diff --git a/lib/src/components/Map/Layers/MaskLayer/index.tsx b/lib/src/components/Map/Layers/_MaskLayer/index.tsx similarity index 100% rename from lib/src/components/Map/Layers/MaskLayer/index.tsx rename to lib/src/components/Map/Layers/_MaskLayer/index.tsx diff --git a/lib/src/components/Map/Layers/MaskLayer/styles.module.css b/lib/src/components/Map/Layers/_MaskLayer/styles.module.css similarity index 100% rename from lib/src/components/Map/Layers/MaskLayer/styles.module.css rename to lib/src/components/Map/Layers/_MaskLayer/styles.module.css diff --git a/lib/src/components/Map/Layers/SymbolLayer.tsx b/lib/src/components/Map/Layers/_SymbolLayer.tsx similarity index 100% rename from lib/src/components/Map/Layers/SymbolLayer.tsx rename to lib/src/components/Map/Layers/_SymbolLayer.tsx diff --git a/lib/src/components/Map/Layers/VectorLayer.tsx b/lib/src/components/Map/Layers/_VectorLayer.tsx similarity index 100% rename from lib/src/components/Map/Layers/VectorLayer.tsx rename to lib/src/components/Map/Layers/_VectorLayer.tsx diff --git a/lib/src/components/Map/index.tsx b/lib/src/components/Map/index.tsx index 81ecce80..adf7dab1 100644 --- a/lib/src/components/Map/index.tsx +++ b/lib/src/components/Map/index.tsx @@ -22,7 +22,6 @@ import { createTheme } from '@mui/material/styles'; import grey from '@mui/material/colors/grey'; import './ol.css'; -import styles from './styles.module.css'; import { osm, vector, @@ -40,6 +39,7 @@ import HeatmapLayer from './Layers/HeatmapLayer'; import HexbinLayer from './Layers/HexbinLayer'; import OlMap from './OlMap'; import ColorScale from '../ColorScale'; +import styles from './styles.module.css'; // FIXME: may need to update rollup configuration to include files import cdcf from './assets/logos/cdcf.jpg'; @@ -140,7 +140,8 @@ interface ShadedMaskLayer { strokeWidth: number; }; } -interface OsmBackgroundLayer { + +export interface OsmBackgroundLayer { id: number; name: string; opacity: number; @@ -148,7 +149,8 @@ interface OsmBackgroundLayer { visible: number; zIndex: number; } -interface MapboxLayer { + +export interface MapboxLayer { accessToken: string; // FIXME: Not sure if we need to pass this id: number; name: string;