Skip to content

Commit

Permalink
Merge pull request #4 from EIG6-Geocommuns/code-review
Browse files Browse the repository at this point in the history
refacto: useCallback + encapsulation of map instantiation
  • Loading branch information
maximallain authored Feb 28, 2023
2 parents a0ded3b + ea3d64f commit 0d11679
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 44 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,8 @@
"ts-node": "^10.9.1",
"tss-react": "^4.6.1",
"typescript": "^4.9.5"
},
"dependencies": {
"tsafe": "^1.4.3"
}
}
105 changes: 62 additions & 43 deletions src/hooks/useMap.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { Feature, Map, View } from "ol";
import { fromLonLat, Projection } from "ol/proj";
import { Polygon } from "ol/geom";
Expand All @@ -7,11 +7,11 @@ import { Vector as VectorLayer } from "ol/layer";
import VectorSource from "ol/source/Vector";
import BaseLayer from "ol/layer/Base";
import { makeStyles } from "tss-react/dsfr";
import { assert } from "tsafe/assert";
import { fr } from "@codegouvfr/react-dsfr";

import { createZoomController, createFullScreenController } from "../map/controllers";

import { getIgnWMTSTileLayer, aiPredictionLayer } from "../map/ignTileLayer";
import { fr } from "@codegouvfr/react-dsfr";

export type AvailableLayer = "planIGN" | "ortho" | "admin" | "aiPrediction";

Expand All @@ -22,7 +22,9 @@ const LAYER_TO_OPENLAYER_LAYER: { [key in AvailableLayer]: BaseLayer } = {
"aiPrediction": aiPredictionLayer,
};

const useStyles = makeStyles()(theme => ({
const lightTheme = fr.getColors(false);

const useStyles = makeStyles({ name: "Map" })({
zoomContainer: {
position: "absolute",
display: "flex",
Expand All @@ -37,20 +39,20 @@ const useStyles = makeStyles()(theme => ({
height: fr.spacing("5w"),
width: fr.spacing("5w"),
fontSize: "x-large",
color: theme.decisions.background.actionHigh.blueFrance.default,
backgroundColor: theme.decisions.artwork.background.grey.default,
color: lightTheme.decisions.background.actionHigh.blueFrance.default,
backgroundColor: lightTheme.decisions.artwork.background.grey.default,
border: "1px solid",
borderColor: theme.decisions.background.actionHigh.blueFrance.default,
borderColor: lightTheme.decisions.background.actionHigh.blueFrance.default,
borderRadius: "8px 8px 0px 0px",
},
mapControllersZoomOutButton: {
height: fr.spacing("5w"),
width: fr.spacing("5w"),
fontSize: "x-large",
color: theme.decisions.background.actionHigh.blueFrance.default,
backgroundColor: theme.decisions.artwork.background.grey.default,
color: lightTheme.decisions.background.actionHigh.blueFrance.default,
backgroundColor: lightTheme.decisions.artwork.background.grey.default,
border: "1px solid",
borderColor: theme.decisions.background.actionHigh.blueFrance.default,
borderColor: lightTheme.decisions.background.actionHigh.blueFrance.default,
borderRadius: "0px 0px 8px 8px",
},
fullScreenContainer: {
Expand All @@ -63,28 +65,28 @@ const useStyles = makeStyles()(theme => ({
right: 0,
margin: fr.spacing("4w"),
marginBottom: fr.spacing("15w"),
color: theme.decisions.background.actionHigh.blueFrance.default,
color: lightTheme.decisions.background.actionHigh.blueFrance.default,
borderRadius: 8,
},
activateFullScreen: {
height: fr.spacing("5w"),
width: fr.spacing("5w"),
fontSize: "large",
backgroundColor: theme.decisions.artwork.background.grey.default,
backgroundColor: lightTheme.decisions.artwork.background.grey.default,
border: "1px solid",
borderColor: theme.decisions.background.actionHigh.blueFrance.default,
borderColor: lightTheme.decisions.background.actionHigh.blueFrance.default,
borderRadius: 8,
},
inactivateFullScreen: {
height: fr.spacing("5w"),
width: fr.spacing("5w"),
fontSize: "large",
backgroundColor: theme.decisions.artwork.background.grey.default,
backgroundColor: lightTheme.decisions.artwork.background.grey.default,
border: "1px solid",
borderColor: theme.decisions.background.actionHigh.blueFrance.default,
borderColor: lightTheme.decisions.background.actionHigh.blueFrance.default,
borderRadius: 8,
},
}));
});

export const useMap = (
target: string,
Expand All @@ -93,9 +95,8 @@ export const useMap = (
layers: AvailableLayer[],
) => {
const { classes } = useStyles();
const [map, setMap] = useState<Map | undefined>(undefined);

const mapLayers = layers.map(layer => LAYER_TO_OPENLAYER_LAYER[layer]);
const mapLayers = useMemo(() => layers.map(layer => LAYER_TO_OPENLAYER_LAYER[layer]), [layers]);

const view = useMemo(
() =>
Expand Down Expand Up @@ -126,41 +127,59 @@ export const useMap = (
[classes],
);

useEffect(() => {
const map = new Map({
target,
layers: mapLayers,
view: view,
controls: [zoomController, fullScreenController],
});
setMap(map);
const instantiateMap = () => {
const [map, setMap] = useState<Map | undefined>(undefined);

return () => map.setTarget(undefined);
}, []);
useEffect(() => {
const map = new Map({
target,
layers: mapLayers,
view,
controls: [zoomController, fullScreenController],
});

setMap(map);

return () => map.setTarget(undefined);
}, [zoomController, fullScreenController, mapLayers, view, target]);

return { map };
};

const setNewCenterAndNewZoom = (coordinates: [number, number], zoom: number) => {
const { map } = instantiateMap();

const setNewCenterAndNewZoom = useCallback((coordinates: [number, number], zoom: number) => {
view.setCenter(fromLonLat(coordinates));
view.setZoom(zoom);
};
}, []);

const fitViewToPolygon = (coordinates: Coordinate[][]) => {
const epsg4326 = new Projection({ code: "EPSG:4326" });
const epsg3857 = new Projection({ code: "EPSG:3857" });
// TODO handle multi-polygon like Marseille
const polygon = new Polygon(coordinates).transform(epsg4326, epsg3857);
const fitViewToPolygon = useCallback(
(coordinates: Coordinate[][]) => {
const epsg4326 = new Projection({ code: "EPSG:4326" });
const epsg3857 = new Projection({ code: "EPSG:3857" });
// TODO handle multi-polygon like Marseille
const polygon = new Polygon(coordinates).transform(epsg4326, epsg3857);

view.fit(polygon as Polygon, { padding: [150, 150, 150, 150] });
view.fit(polygon as Polygon, { padding: [150, 150, 150, 150] });

const feature = new Feature(polygon);
const vectorSource = new VectorSource({ features: [feature] });
const layer = new VectorLayer({ source: vectorSource });
map?.addLayer(layer);
};
const feature = new Feature(polygon);
const vectorSource = new VectorSource({ features: [feature] });
const layer = new VectorLayer({ source: vectorSource });

assert(
map !== undefined,
"The map object should have been instantiated (it is after fist render) by the time this function is called",
);

const setLayerOpacity = (layer: AvailableLayer, opacityValue: number) => {
map.addLayer(layer);
},
[map],
);

const setLayerOpacity = useCallback((layer: AvailableLayer, opacityValue: number) => {
const ol_layer = LAYER_TO_OPENLAYER_LAYER[layer];
ol_layer.setOpacity(opacityValue);
};
}, []);

return { setNewCenterAndNewZoom, fitViewToPolygon, setLayerOpacity };
};
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1885,7 +1885,7 @@ ts-node@^10.9.1:
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"

tsafe@^1.4.0:
tsafe@^1.4.0, tsafe@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/tsafe/-/tsafe-1.4.3.tgz#a98ce83616f0d9c01e3c6167a2ead45ba455b2ae"
integrity sha512-KjCdgjIqsbKW9oeJGSMVC23jhWm/VXJwkaZ7jffo/WaTioLGTHJqliHe9dECEVzIACNVNs/fwtKwU8wWK4jY4g==
Expand Down

0 comments on commit 0d11679

Please sign in to comment.