summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2020-09-04 10:10:18 +0200
committerOskar Nyberg <oskar@mullvad.net>2020-09-10 10:03:47 +0200
commit080ddf5c161c86a2374d0e38e7a9072b0401a607 (patch)
tree0910bf71dc4793ad9a91b16f98ca5c6b8cfd8a0a
parent0c1c4f978e1cd0e73ea8e61eca86f304ad141733 (diff)
downloadmullvadvpn-080ddf5c161c86a2374d0e38e7a9072b0401a607.tar.xz
mullvadvpn-080ddf5c161c86a2374d0e38e7a9072b0401a607.zip
Optimize SvgMap rendering cycles
-rw-r--r--gui/src/renderer/components/SvgMap.tsx53
1 files changed, 38 insertions, 15 deletions
diff --git a/gui/src/renderer/components/SvgMap.tsx b/gui/src/renderer/components/SvgMap.tsx
index aa2a8d430b..27e9c0c6b4 100644
--- a/gui/src/renderer/components/SvgMap.tsx
+++ b/gui/src/renderer/components/SvgMap.tsx
@@ -1,6 +1,6 @@
import { geoMercator, GeoProjection } from 'd3-geo';
import rbush from 'rbush';
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { ComposableMap, Geographies, Geography, Marker, ZoomableGroup } from 'react-simple-maps';
import geographyData from '../../../assets/geo/geometry.json';
@@ -124,6 +124,35 @@ function getCombindedViewportBboxMatch(viewportBboxes: BBox[]) {
};
}
+function sameProps(prevProps: IProps, nextProps: IProps) {
+ return (
+ prevProps.width === nextProps.width &&
+ prevProps.height === nextProps.height &&
+ prevProps.center[0] === nextProps.center[0] &&
+ prevProps.center[1] === nextProps.center[1] &&
+ prevProps.offset[0] === nextProps.offset[0] &&
+ prevProps.offset[1] === nextProps.offset[1] &&
+ prevProps.zoomLevel === nextProps.zoomLevel &&
+ prevProps.showMarker === nextProps.showMarker &&
+ prevProps.markerImagePath === nextProps.markerImagePath
+ );
+}
+
+function useBboxes(bbox: BBox): [BBox[], () => void] {
+ const prev = useRef<BBox[]>([]);
+ const bboxes = useMemo(() => [...prev.current, bbox], [bbox]);
+
+ const keepLast = useCallback(() => {
+ prev.current = prev.current.slice(-1);
+ }, []);
+
+ useEffect(() => {
+ prev.current = [...bboxes];
+ }, [bboxes]);
+
+ return [bboxes, keepLast];
+}
+
export interface IProps {
width: number;
height: number;
@@ -135,29 +164,29 @@ export interface IProps {
}
// @TODO: Calculate zoom level based on (center + span) (aka MKCoordinateSpan)
-export default function SvgMap(props: IProps) {
+function SvgMap(props: IProps) {
const { width, height, zoomLevel } = props;
const center = useMemo(() => props.center, [...props.center]);
const offset = useMemo(() => props.offset, [...props.offset]);
- const [viewportBboxes, setViewportBboxes] = useState<BBox[]>([]);
const projection = useMemo(() => getProjection(width, height, offset, projectionConfig.scale), [
width,
height,
- ...offset,
+ offset,
projectionConfig.scale,
]);
const zoomCenter = useMemo(() => getZoomCenter(center, offset, projection, zoomLevel), [
- ...center,
- ...offset,
+ center,
+ offset,
projection,
zoomLevel,
]);
const viewportBbox = useMemo(
() => getViewportGeoBoundingBox(zoomCenter, width, height, projection, zoomLevel),
- [...zoomCenter, width, height, projection, zoomLevel],
+ [zoomCenter, width, height, projection, zoomLevel],
);
+ const [viewportBboxes, removeOldViewportBboxes] = useBboxes(viewportBbox);
const combinedViewportBboxMatch = useMemo(() => getCombindedViewportBboxMatch(viewportBboxes), [
viewportBboxes,
@@ -170,14 +199,6 @@ export default function SvgMap(props: IProps) {
[combinedViewportBboxMatch],
);
- const removeOldViewportBboxes = useCallback(() => {
- setViewportBboxes((viewportBboxes) => viewportBboxes.slice(-1));
- }, []);
-
- useEffect(() => {
- setViewportBboxes((viewportBboxes) => [...viewportBboxes, viewportBbox]);
- }, [viewportBbox]);
-
return (
<ComposableMap
width={width}
@@ -232,3 +253,5 @@ export default function SvgMap(props: IProps) {
</ComposableMap>
);
}
+
+export default React.memo(SvgMap, sameProps);