Skip to content

Commit

Permalink
encapsulate heatmap logic in useHeatmap hook
Browse files Browse the repository at this point in the history
  • Loading branch information
matewilk committed Apr 8, 2024
1 parent aed1092 commit 2433068
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 244 deletions.
47 changes: 28 additions & 19 deletions visualizations/store-map-viz/components/Markers.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useRef } from "react";
import { Marker } from "react-leaflet";
import MarkerClusterGroup from "react-leaflet-markercluster";
import { useNerdGraphQuery } from "../hooks/useNerdGraphQuery";
import { useCustomColors, Status } from "../hooks/useCustomColors";

import {
createClusterCustomIcon,
Expand All @@ -10,17 +11,23 @@ import {
} from "../utils";
import LocationPopup from "./LocationPopup";
import { useProps } from "../context/VizPropsProvider";
import { DEFAULT_DISABLE_CLUSTER_ZOOM, MARKER_COLOURS } from "../constants";
import { DEFAULT_DISABLE_CLUSTER_ZOOM } from "../constants";

const Markers = () => {
const { markersQuery, disableClusterZoom, markerColors, markerAggregation } =
useProps();

const customColors =
markerColors && markerColors !== "" ? markerColors.split(",") : [];

const { data: locations } = useNerdGraphQuery(markersQuery);

const { customColors } = useCustomColors(markerColors);
const customColorsRef = useRef(customColors);

useEffect(() => {
customColorsRef.current = customColors;
// Update the renderKey when customColors or markerAggregation changes
setRenderKey(Math.random());
}, [customColors, markerAggregation]);

// This is a hack to force a re-render when markers show up for the first time.
const [renderKey, setRenderKey] = useState(Math.random());
useEffect(() => {
Expand All @@ -35,30 +42,32 @@ const Markers = () => {
return null;
}

const getPoligonOptions = () => ({
fillColor: customColors[Status.CLUSTER].borderColor,
color: customColors[Status.CLUSTER].color,
weight: 3,
opacity: 0.9,
fillOpacity: 0.4,
});

return (
<MarkerClusterGroup
key={markerAggregation}
key={`${markerAggregation}`}
singleMarkerMode={true}
spiderfyOnMaxZoom={7}
disableClusteringAtZoom={
disableClusterZoom === "default"
? DEFAULT_DISABLE_CLUSTER_ZOOM
: disableClusterZoom
}
iconCreateFunction={(c) => {
return createClusterCustomIcon(c, customColors, markerAggregation);
}}
polygonOptions={{
fillColor: customColors[0]
? customColors[0] + "70"
: MARKER_COLOURS.groupBorder,
color: customColors[0]
? customColors[0] + "70"
: MARKER_COLOURS.groupBorder,
weight: 3,
opacity: 0.9,
fillOpacity: 0.4,
iconCreateFunction={(cluster) => {
return createClusterCustomIcon(
cluster,
customColorsRef.current,
markerAggregation
);
}}
polygonOptions={getPoligonOptions()}

This comment has been minimized.

Copy link
@jsbnr

jsbnr Apr 9, 2024

Contributor

spelling... getPoligonOptions -> getPolygonOptions

>
{locations.map((location) => (
<Marker
Expand Down
23 changes: 13 additions & 10 deletions visualizations/store-map-viz/components/Region.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import React, { useMemo } from "react";
import { GeoJSON } from "react-leaflet";
import { regionStatusColor } from "../utils";
import LocationPopup from "./LocationPopup";
import { COLORS } from "../constants";
import { useHeatmap } from "../hooks/useHeatmap";

const Region = ({
key,
region,
location,
tooltipConfig,
defaultHeader,
heatMap,
heatMapSteps,
customColors,
}) => {
heatMapSteps,
getGradientColor,
}: any) => {
const gradientColor = getGradientColor(location.value);

const style = useMemo(() => {
if (location.custom_color) {
return {
Expand All @@ -21,21 +24,21 @@ const Region = ({
opacity: 0.5,
fillOpacity: 0.7,
};
} else if (heatMap != null) {
} else if (heatMapSteps !== 0) {
return {
color: heatMap(location.value),
fillColor: heatMap(location.value),
color: gradientColor,
fillColor: gradientColor,
opacity: 0.5,
fillOpacity: 0.7,
};
} else {
return {
color: regionStatusColor(location.status, customColors).borderColor,
fillColor: regionStatusColor(location.status, customColors).color,
color: COLORS[location.status].borderColor,
fillColor: COLORS[location.status].color,
opacity: 0.7,
};
}
}, [location.value, heatMapSteps, customColors]);
}, [location.value, heatMapSteps, customColors, gradientColor]);

// determine the tooltip title, memoized to avoid unnecessary recalculations
const getTooltipTitle = () => {
Expand Down
76 changes: 16 additions & 60 deletions visualizations/store-map-viz/components/Regions.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,27 @@
import React, { useEffect, useState } from "react";
import Gradient from "javascript-color-gradient";
import React, { useEffect } from "react";

import { MARKER_COLOURS } from "../constants";
import { generateTooltipConfig } from "../utils";
import { useProps } from "../context/VizPropsProvider";
import { useNerdGraphQuery } from "../hooks/useNerdGraphQuery";
import { useHeatmap } from "../hooks/useHeatmap";

import Region from "./Region";
import countries from "../geo/countries.geojson.json";
import geoUSStates from "../geo/us-states/us-states";
import allUKRegions from "../geo/uk-regions/all-uk-regions";

const Regions = () => {
const [HMSteps, setHMSteps] = useState(0);
const [HMColors, setHMColors] = useState([]);
const [customColors, setCustomColors] = useState(null);

const { regionsQuery, heatMapSteps, regionColors } = useProps();
const { regionsQuery, customColors } = useProps();
if (regionsQuery === null || regionsQuery === undefined) {
return null;
}

const { data: regions } = useNerdGraphQuery(regionsQuery);

const { setRange, heatMapSteps, getGradientColor } = useHeatmap();
useEffect(() => {
setHMSteps(
heatMapSteps && heatMapSteps !== "" ? parseInt(heatMapSteps) : 0,
);
setHMColors(
regionColors && regionColors !== ""
? regionColors.split(",")
: MARKER_COLOURS.heatMapDefault,
);
setCustomColors(
regionColors && regionColors !== "" ? regionColors.split(",") : null,
);
}, [heatMapSteps, regionColors]);
setRange(regions);
}, [regions]);

if (!regions || regions.length == 0) {
return null; //no regions to display
Expand All @@ -44,33 +30,6 @@ const Regions = () => {

let geoFeatureLocations = [];

// ---- heat map configuration -------

const gradientSteps = HMSteps;
let getGradientColor = null;

if (gradientSteps > 0) {
let maxValue = -Infinity,
minValue = Infinity;
regions.forEach((location) => {
maxValue = location.value > maxValue ? location.value : maxValue;
minValue = location.value < minValue ? location.value : minValue;
});

if (HMColors.length > 1) {
const gradientArray = new Gradient()
.setColorGradient(...HMColors)
.setMidpoint(gradientSteps)
.getColors();

getGradientColor = (value) => {
let ratio = (value - minValue) / (maxValue - minValue);
let element = Math.floor((gradientSteps - 1) * ratio);
return gradientArray[element];
};
}
}

regions.forEach((location, index) => {
// World Countries
if (location.geoISOCountry && location.geoISOCountry != "") {
Expand All @@ -88,11 +47,10 @@ const Regions = () => {
location={location}
tooltipConfig={tooltipConfig}
defaultHeader={feature.properties.ADMIN}
heatMap={getGradientColor}
heatMapSteps={gradientSteps}
heatMapColors={HMColors}
customColors={customColors}
/>,
heatMapSteps={heatMapSteps}
getGradientColor={getGradientColor}
/>
);
} else {
console.log("Country not found for data, will not render", location);
Expand All @@ -116,11 +74,10 @@ const Regions = () => {
location={location}
tooltipConfig={tooltipConfig}
defaultHeader={feature.properties.NAME}
heatMap={getGradientColor}
heatMapSteps={gradientSteps}
heatMapColors={HMColors}
customColors={customColors}
/>,
heatMapSteps={heatMapSteps}
getGradientColor={getGradientColor}
/>
);
} else {
console.log("US State not found for data, will not render", location);
Expand All @@ -141,17 +98,16 @@ const Regions = () => {
location={location}
tooltipConfig={tooltipConfig}
defaultHeader={region.name}
heatMap={getGradientColor}
heatMapSteps={gradientSteps}
heatMapColors={HMColors}
customColors={customColors}
/>,
heatMapSteps={heatMapSteps}
getGradientColor={getGradientColor}
/>
);
});
} else {
console.log(
"UK Region not found for data, will not render",
location,
location
);
}
}
Expand Down
62 changes: 31 additions & 31 deletions visualizations/store-map-viz/constants.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
export const DEFAULT_ZOOM = 1; // default zoom level
export const DEFAULT_CENTER = [51.5074, 0.1278]; // default map center - London
export const FETCH_INTERVAL_DEFAULT = 300; // fetch interval in ms - 5 minutes
export const MARKER_COLOURS = {
noneColour: "#0c74df", //grey for group
noneBorder: "#0c74df70",
noneText: "#FFF",
noneRegionColour: "#0c74df",
noneRegionColourBorder: "#0c74df70",

criticalColour: "#DF2E23", // Red color for alert
criticalColourBorder: "#DF2E2370",
criticalColourText: "#fff",
criticalRegionColour: "#DF2E23",
criticalRegionColourBorder: "#DF2E2370",

warningColour: "#FFD23D", // Amber color for warning
warningColourBorder: "#FFD23D70",
warningColourText: "#293238",
warningRegionColour: "#FFD23D",
warningRegionColourBorder: "#FFD23D70",

safeColour: "#05865B", // Green color for safe
safeColourBorder: "#05865B70",
safeColourText: "#FFF",
safeRegionColour: "#05865B",
safeRegionColourBorder: "#05865B70",

groupColour: "#757575", //grey for group
groupBorder: "#75757570", //border, including transparency
groupText: "#fff",
export const DEFAULT_DISABLE_CLUSTER_ZOOM = "7"; // default disbale cluserting level

heatMapDefault: ["#420052", "#6C0485", "#8F18AC", "#FFBE35", "#FFA022"],
heatMapStepsDefault: 50,
export const COLORS = {
NONE: {
color: "#0c74df",
borderColor: "#0c74df70",
textColor: "#FFF",
},
CRITICAL: {
color: "#DF2E23",
borderColor: "#DF2E2370",
textColor: "#fff",
},
WARNING: {
color: "#FFD23D",
borderColor: "#FFD23D70",
textColor: "#293238",
},
OK: {
color: "#05865B",
borderColor: "#05865B70",
textColor: "#FFF",
},
CLUSTER: {
color: "#757575",
borderColor: "#75757570",
textColor: "#fff",
},
HEATMAP: {
default: ["#420052", "#6C0485", "#8F18AC", "#FFBE35", "#FFA022"],
steps: 50,
},
};
export const DEFAULT_DISABLE_CLUSTER_ZOOM = "7"; // default disbale cluserting level
Loading

0 comments on commit 2433068

Please sign in to comment.