Skip to content

Commit

Permalink
feat: dont reload map when theme or selected map changes (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tschonti authored Nov 20, 2024
1 parent 98032e4 commit 7fa061b
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 41 deletions.
26 changes: 21 additions & 5 deletions src/components/Map/VectorTileLayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'mapbox-gl/dist/mapbox-gl.css';
import { LeafletContextInterface, useLeafletContext } from '@react-leaflet/core';
import mapboxgl from 'mapbox-gl'; // eslint-disable-line import/no-webpack-loader-syntax
import { useTheme } from 'next-themes';
import React, { RefObject, useEffect, useRef } from 'react';
import React, { RefObject, useEffect, useRef, useState } from 'react';

import { useSelectedMap } from '@/domain/contexts/SelectedMapContext';
import { MapProps } from '@/domain/props/MapProps';
Expand All @@ -14,6 +14,7 @@ export default function VectorTileLayer({ countries, disputedAreas }: MapProps)
const context: LeafletContextInterface = useLeafletContext();
const mapContainer: RefObject<HTMLDivElement> = useRef<HTMLDivElement>(null);
const { selectedMapType } = useSelectedMap();
const [map, setMap] = useState<mapboxgl.Map>();

mapboxgl.accessToken = process.env.NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN as string;

Expand All @@ -23,18 +24,33 @@ export default function VectorTileLayer({ countries, disputedAreas }: MapProps)
{ countries, disputedAreas },
mapContainer
);
baseMap.on('load', () => setMap(baseMap));
MapOperations.setMapInteractionFunctionality(baseMap);
MapOperations.synchronizeLeafletMapbox(baseMap, mapContainer, context);
// The following layers currently don't work due to CORS issues.
MapOperations.addRainfallLayer(baseMap, selectedMapType);
MapOperations.addVegetationLayer(baseMap, selectedMapType);
MapOperations.addFCSLayer(baseMap, selectedMapType);
MapOperations.initRainfallLayer(baseMap);
MapOperations.initVegetationLayer(baseMap);
MapOperations.initFCSLayer(baseMap);

return () => {
baseMap.remove();
context.map.off('move');
setMap(undefined);
};
}, [context, theme, selectedMapType]);
}, [context]);

useEffect(() => {
if (map) {
MapOperations.removeActiveMapLayer(map);
MapOperations.addMapAsLayer(map, selectedMapType);
}
}, [map, selectedMapType]);

useEffect(() => {
if (map) {
MapOperations.changeMapTheme(map, theme === 'dark');
}
}, [theme]);

return <div ref={mapContainer} style={{ width: '100%', height: '100%', zIndex: 2 }} />;
}
111 changes: 75 additions & 36 deletions src/operations/map/MapOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,70 +192,109 @@ export class MapOperations {
});
}

static addFCSLayer(baseMap: mapboxgl.Map, selectedMapType: GlobalInsight) {
static changeMapTheme(baseMap: mapboxgl.Map, isDark: boolean) {
const mapColors: MapColorsType = getColors(isDark);
baseMap.setPaintProperty('ocean', 'background-color', mapColors.ocean);
baseMap.setPaintProperty('countries-base', 'fill-color', mapColors.countriesBase);
baseMap.setPaintProperty('countries-inactive', 'fill-color', mapColors.inactiveCountriesOverlay);
baseMap.setPaintProperty('countries-hover', 'fill-color', mapColors.outline);
baseMap.setPaintProperty('country-borders', 'line-color', mapColors.outline);
baseMap.setPaintProperty('mapbox-roads', 'line-color', mapColors.roads);
}

static FCS_RASTER = 'fcsRaster';

static FCS_LAYER = 'fcsLayer';

static RAINFALL_RASTER = 'rainfallRaster';

static RAINFALL_LAYER = 'rainfallLayer';

static VEGETATION_RASTER = 'vegetationRaster';

static VEGETATION_LAYER = 'vegetationLayer';

static initFCSLayer(baseMap: mapboxgl.Map) {
baseMap.on('load', () => {
baseMap.addSource('fcsRaster', {
baseMap.addSource(this.FCS_RASTER, {
type: 'raster',
tiles: ['https://static.hungermapdata.org/proteus_tiles/{z}/{x}/{y}.png'],
tileSize: 256,
scheme: 'tms',
});

baseMap.addLayer(
{
id: 'fcsLayer',
type: 'raster',
source: 'fcsRaster',
layout: { visibility: selectedMapType === GlobalInsight.FOOD ? 'visible' : 'none' },
},
'countries-inactive'
);
});
}

static addRainfallLayer(baseMap: mapboxgl.Map, selectedMapType: GlobalInsight) {
static initRainfallLayer(baseMap: mapboxgl.Map) {
baseMap.on('load', () => {
baseMap.addSource('rainfallRaster', {
baseMap.addSource(this.RAINFALL_RASTER, {
type: 'raster',
tiles: [`https://dev.api.earthobservation.vam.wfp.org/tiles/latest/r3q_dekad/{z}/{x}/{y}.png`],
tileSize: 256,
scheme: 'xyz',
maxzoom: 7,
bounds: [-180, -49, 180, 49],
});

baseMap.addLayer(
{
id: 'rainfallLayer',
type: 'raster',
source: 'rainfallRaster',
layout: { visibility: selectedMapType === GlobalInsight.RAINFALL ? 'visible' : 'none' },
},
'countries-inactive'
);
});
}

static addVegetationLayer(baseMap: mapboxgl.Map, selectedMapType: GlobalInsight) {
static initVegetationLayer(baseMap: mapboxgl.Map) {
baseMap.on('load', () => {
baseMap.addSource('vegetationRaster', {
baseMap.addSource(this.VEGETATION_RASTER, {
type: 'raster',
tiles: [`https://dev.api.earthobservation.vam.wfp.org/tiles/latest/viq_dekad/{z}/{x}/{y}.png`],
tileSize: 256,
scheme: 'xyz',
maxzoom: 7,
bounds: [-180, -60, 180, 80],
});

baseMap.addLayer(
{
id: 'vegetationLayer',
type: 'raster',
source: 'vegetationRaster',
layout: { visibility: selectedMapType === GlobalInsight.VEGETATION ? 'visible' : 'none' },
},
'countries-inactive'
);
});
}

static addMapAsLayer(baseMap: mapboxgl.Map, selectedMap: GlobalInsight) {
switch (selectedMap) {
case GlobalInsight.FOOD:
baseMap.addLayer(
{
id: this.FCS_LAYER,
type: 'raster',
source: this.FCS_RASTER,
},
'countries-inactive'
);
break;
case GlobalInsight.VEGETATION:
baseMap.addLayer(
{
id: this.VEGETATION_LAYER,
type: 'raster',
source: this.VEGETATION_RASTER,
},
'countries-inactive'
);
break;
case GlobalInsight.RAINFALL:
baseMap.addLayer(
{
id: this.RAINFALL_LAYER,
type: 'raster',
source: this.RAINFALL_RASTER,
},
'countries-inactive'
);
break;
default:
}
}

static removeActiveMapLayer(baseMap: mapboxgl.Map) {
const layers = baseMap.getStyle()?.layers;
if (!layers) return;
const layerToRemove = layers.find((layer) =>
// TODO make sure to update this list with the new layers!
[this.FCS_LAYER, this.VEGETATION_LAYER, this.RAINFALL_LAYER].includes(layer.id)
);
if (!layerToRemove) return;
baseMap.removeLayer(layerToRemove.id);
}
}

0 comments on commit 7fa061b

Please sign in to comment.