Skip to content

Commit

Permalink
fix map loading bug + add PV map tooltip
Browse files Browse the repository at this point in the history
  • Loading branch information
braddf committed Aug 22, 2024
1 parent 1cc66e8 commit 4252912
Show file tree
Hide file tree
Showing 13 changed files with 272 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ const useGetGspData = (gspId: number) => {

//add new useSWR for gspChartData
const { data: gspForecastDataOneGSP, error: gspForecastDataOneGSPError } =
useLoadDataFromApi<ForecastData>(`${API_PREFIX}/solar/GB/gsp/${gspId}/forecast?UI`);
useLoadDataFromApi<ForecastData>(`${API_PREFIX}/solar/GB/gsp/${gspId}/forecast`, {
dedupingInterval: 1000 * 30
});

//add new useSWR for gspLocationInfo since this is not
const { data: gspLocationInfo, error: gspLocationError } = useLoadDataFromApi<GspEntities>(
Expand Down
26 changes: 25 additions & 1 deletion apps/nowcasting-app/components/helpers/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ export const generateGeoJsonForecastData: (
);
let selectedFC;
let selectedFCValue;
let selectedActualValueMW: number | undefined;
const gspRealData =
combinedData?.allGspRealData as components["schemas"]["GSPYieldGroupByDatetime"][];
if (gspForecastsDataByTimestamp && targetTime) {
selectedFC = gspForecastsDataByTimestamp.find(
(fc) => fc.datetimeUtc.slice(0, 16) === formatISODateString(targetTime)
Expand All @@ -55,20 +58,38 @@ export const generateGeoJsonForecastData: (
selectedFCValue = gspForecastsDataByTimestamp.find(
(fc) => fc.datetimeUtc.slice(0, 16) === latestTimestamp
)?.forecastValues[index];
selectedActualValueMW =
Number(
gspRealData?.find((realData) => realData.datetimeUtc.slice(0, 16) === latestTimestamp)
?.generationKwByGspId?.[String(index + 1)]
) / 1000;
}

const updatedFeatureObj: MapFeatureObject = {
...featureObj,
properties: {
...featureObj.properties,
[SelectedData.expectedPowerGenerationMegawatts]:
selectedFCValue && getRoundedPv(selectedFCValue, false),
[SelectedData.expectedPowerGenerationMegawattsRounded]:
selectedFCValue && getRoundedPv(selectedFCValue),
[SelectedData.expectedPowerGenerationNormalized]:
selectedFCValue &&
getOpacityValueFromPVNormalized(
(selectedFCValue || 0) / (gspSystemInfo?.installedCapacityMw || 1) || 0,
false
),
[SelectedData.expectedPowerGenerationNormalizedRounded]:
selectedFCValue &&
getOpacityValueFromPVNormalized(
(selectedFCValue || 0) / (gspSystemInfo?.installedCapacityMw || 1) || 0
),
[SelectedData.installedCapacityMw]: getRoundedPv(gspSystemInfo?.installedCapacityMw || 0),
[SelectedData.actualPowerGenerationMegawatts]:
selectedActualValueMW && getRoundedPv(Number(selectedActualValueMW), false),
[SelectedData.installedCapacityMw]: getRoundedPv(
gspSystemInfo?.installedCapacityMw || 0,
false
),
gspDisplayName: gspSystemInfo?.regionName || ""
}
};
Expand All @@ -77,8 +98,11 @@ export const generateGeoJsonForecastData: (
updatedFeatureObj.properties = {
...updatedFeatureObj.properties,
[SelectedData.expectedPowerGenerationMegawatts]: currentGspDelta?.delta || 0,
[SelectedData.expectedPowerGenerationMegawattsRounded]: currentGspDelta?.delta || 0,
[SelectedData.expectedPowerGenerationNormalized]:
Number(currentGspDelta?.deltaNormalized) || 0,
[SelectedData.expectedPowerGenerationNormalizedRounded]:
Number(currentGspDelta?.deltaNormalized) || 0,
[SelectedData.delta]: currentGspDelta?.delta || 0,
deltaBucket: currentGspDelta?.deltaBucket || 0
};
Expand Down
49 changes: 20 additions & 29 deletions apps/nowcasting-app/components/helpers/mapUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,35 @@ export const safelyUpdateMapData = (
map: mapboxgl.Map,
updateMapData: (map: mapboxgl.Map) => void
) => {
const mapTitle = map.getContainer().dataset.title;
if (
typeof map !== "object" ||
typeof map.getSource !== "function" ||
// @ts-ignore
map._removed ||
!map.isStyleLoaded()
) {
if (!map.isStyleLoaded()) {
console.warn("📍map style not loaded yet, skipping update");
// -- Check if we've already set a timeout for this map and therefore a check is already pending
const existingTimeout = localStorage.getItem(
`MapTimeoutId-${map.getContainer().dataset.title}`
);
// -- If we have, skip the update and return
if (existingTimeout) {
console.debug("existing timeout running, skipping");
return;
}
// -- Set a new timeout to check whether the map is ready and update the data
console.debug(`setting new map timeout for ${map.getContainer().dataset.title}`);
const newTimeout = setTimeout(() => {
safelyUpdateMapData(map, updateMapData);
// console.log(`clearing new map timeout for ${map.getContainer().dataset.title}`);
localStorage.removeItem(`MapTimeoutId-${map.getContainer().dataset.title}`);
}, 500);
// -- Save the timeout id to local storage
console.debug(
`saving new map timeout id for ${map.getContainer().dataset.title}`,
newTimeout
);
localStorage.setItem(
`MapTimeoutId-${map.getContainer().dataset.title}`,
newTimeout.toString()
);
console.warn(`📍${mapTitle} map & style not loaded yet, skipping update`);
// -- Check if we've already set a timeout for this map and therefore a check is already pending
const existingTimeout = sessionStorage.getItem(`MapTimeoutId-${mapTitle}`);
// -- If we have, skip the update and return
if (existingTimeout) {
console.debug(`existing timeout running for ${mapTitle}, skipping`);
return;
}
return;
// -- Set a new timeout to check whether the map is ready and update the data
console.debug(`setting new map timeout for ${mapTitle}`);
const newTimeout = setTimeout(() => {
// console.log(`clearing new map timeout for ${map.getContainer().dataset.title}`);
sessionStorage.removeItem(`MapTimeoutId-${mapTitle}`);
console.log(`Timer finished, MapTimeoutId-${mapTitle} rerunning...`);
safelyUpdateMapData(map, updateMapData);
}, 500);
// -- Save the timeout id to local storage
console.debug(`saving new map timeout id for ${mapTitle}`, newTimeout);
sessionStorage.setItem(`MapTimeoutId-${mapTitle}`, newTimeout.toString());
} else {
console.debug("🎉 map is ready, updating data");
console.debug(`🎉 ${mapTitle} map is ready, updating data`);
updateMapData(map);
}
};
11 changes: 11 additions & 0 deletions apps/nowcasting-app/components/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,17 @@ export const getRoundedPv = (pv: number, round: boolean = true) => {
// round To: 0, 100, 200, 300, 400, 500
return Math.round(pv / 100) * 100;
};

export const getRoundedPvPercent = (per: number, round: boolean = true) => {
if (!round) return per;
// round to : 0, 0.2, 0.4, 0.6 0.8, 1
let rounded = Math.round(per * 10);
if (rounded % 2) {
if (per * 10 > rounded) return (rounded + 1) / 10;
else return (rounded - 1) / 10;
} else return rounded / 10;
};

export const getOpacityValueFromPVNormalized = (val: number, round: boolean = true) => {
if (!round) return val;
// This function is to rounds the value down and then select the correct opacity
Expand Down
15 changes: 0 additions & 15 deletions apps/nowcasting-app/components/map/deltaMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,6 @@ import dynamic from "next/dynamic";
const yellow = theme.extend.colors["ocf-yellow"].DEFAULT;
const ButtonGroup = dynamic(() => import("../../components/button-group"), { ssr: false });

const getRoundedPv = (pv: number, round: boolean = true) => {
if (!round) return Math.round(pv);
// round To: 0, 100, 200, 300, 400, 500
return Math.round(pv / 100) * 100;
};
const getRoundedPvPercent = (per: number, round: boolean = true) => {
if (!round) return per;
// round to : 0, 0.2, 0.4, 0.6 0.8, 1
let rounded = Math.round(per * 10);
if (rounded % 2) {
if (per * 10 > rounded) return (rounded + 1) / 10;
else return (rounded - 1) / 10;
} else return rounded / 10;
};

type DeltaMapProps = {
className?: string;
combinedData: CombinedData;
Expand Down
9 changes: 5 additions & 4 deletions apps/nowcasting-app/components/map/loadingState.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
const LoadStateMap = ({ children }: { children: React.ReactNode }) => (
<div className="relative h-full">
<div className="absolute top-0 left-0 z-10 px-2 py-3 m-3 min-w-[20rem]">{children}</div>
<div className="map-overlay top"></div>
</div>
<>
<div className="absolute flex items-center justify-center bg-mapbox-black/50 inset-0 z-10 px-2 py-3 m-3 min-w-[20rem]">
{children}
</div>
</>
);

export default LoadStateMap;
1 change: 1 addition & 0 deletions apps/nowcasting-app/components/map/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ const Map: FC<IMap> = ({
// TODO: unsure as to whether react cleans up/ends up with multiple maps when re-rendering
// or whether removing will cause more issues elsewhere in the app.
// Will just keep an eye on performance etc. for now.
//
// return () => map.current?.remove();
}, []);

Expand Down
Loading

0 comments on commit 4252912

Please sign in to comment.