Skip to content

Commit

Permalink
Improve performance by caching data and avoiding a memory leak (#127)
Browse files Browse the repository at this point in the history
  • Loading branch information
ebrelsford authored Dec 14, 2023
1 parent d41fc05 commit f926c85
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 43 deletions.
8 changes: 4 additions & 4 deletions vacs-map-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vacs-map-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"d3": "^7.8.5",
"d3-geo-projection": "^4.0.0",
"jsdom": "^22.1.0",
"mapbox-gl": "^3.0.0-rc.2",
"mapbox-gl": "^3.0.1",
"pinia": "^2.1.7",
"qs": "^6.11.2",
"slugify": "^1.6.6",
Expand Down
6 changes: 5 additions & 1 deletion vacs-map-app/src/components/BaseMap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</template>

<script setup>
import { onMounted, ref, shallowRef, watch } from 'vue'
import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'
import mapboxgl from 'mapbox-gl'
import 'mapbox-gl/dist/mapbox-gl.css'
import { INITIAL_MAP_BOUNDS, MAPBOX_GL_ACCESS_TOKEN, MAPBOX_STYLE } from '@/constants'
Expand Down Expand Up @@ -47,6 +47,10 @@ onMounted(() => {
if (mapPadding.value) map.value.setPadding(mapPadding.value)
})
onUnmounted(() => {
map.value.remove();
});
watch(mapPadding, () => {
if (mapPadding.value) map.value.setPadding(mapPadding.value)
})
Expand Down
43 changes: 9 additions & 34 deletions vacs-map-app/src/components/GridSource.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<template></template>

<script setup>
import { computed, onMounted, toRefs, watch } from 'vue'
import { onMounted, toRefs, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { point, featureCollection } from '@turf/helpers'
import { useCropYieldsStore } from '@/stores/cropYields'
import { useJoinedCropDataStore } from '@/stores/joinedCropData'
import { useGridStore } from '@/stores/grid'
const props = defineProps({
Expand All @@ -28,40 +28,15 @@ const { id, map, mapReady } = toRefs(props)
const cropYieldsStore = useCropYieldsStore()
const gridStore = useGridStore()
const joinedCropDataStore = useJoinedCropDataStore()
const { data: cropYieldsData } = storeToRefs(cropYieldsStore)
const { data: gridData } = storeToRefs(gridStore)
const { gridFeatureCollection } = storeToRefs(joinedCropDataStore);
onMounted(() => {
gridStore.load()
cropYieldsStore.load()
})
// TODO do this stuff in another store?
const joinData = (grid, yields) => {
const joined = Object.fromEntries(grid.map((row) => [row.id, row]))
yields.forEach((row) => {
if (joined[row.id]) {
joined[row.id] = { ...joined[row.id], ...row }
}
})
return Object.values(joined)
}
const joinedData = computed(() => {
if (!gridData.value) return []
if (cropYieldsData.value) {
return joinData(gridData.value, cropYieldsData.value)
}
return gridData.value
})
const joinedGeoJson = computed(() => {
return featureCollection(
joinedData.value.map((row) => point([row.X, row.Y], row, { id: row.id }))
)
})
const addSource = (geoJson) => {
if (!map.value || !mapReady.value || map.value.getSource(id.value)) return
Expand All @@ -72,13 +47,13 @@ const addSource = (geoJson) => {
}
watch(mapReady, () => {
if (!joinedGeoJson.value) return
addSource(joinedGeoJson.value)
if (!gridFeatureCollection.value) return
addSource(gridFeatureCollection.value)
})
watch(joinedGeoJson, () => {
if (!joinedGeoJson.value) return
addSource(joinedGeoJson.value)
watch(gridFeatureCollection, () => {
if (!gridFeatureCollection.value) return
addSource(gridFeatureCollection.value)
})
</script>

Expand Down
10 changes: 7 additions & 3 deletions vacs-map-app/src/stores/cropYields.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,27 @@ export const useCropYieldsStore = defineStore('cropYields', () => {
const yieldKeys = Object.keys(transformedData[0]).filter((k) => k.startsWith('yield'))

transformedData = transformedData.map((d, i) => {
const rowWithYields = { ...d }
const rowWithYields = Object.fromEntries(
Object.entries(d).filter(([k, v]) => v !== null)
)

yieldKeys.forEach((k) => {
const [_, crop, timeframe, scenario] = k.split('_')
if (timeframe === 'historical') return

// NB: abbreviating these could get more performance improvements
const historicalKey = ['yield', crop, 'historical'].join('_')

if (!yieldKeys.includes(historicalKey)) return

const yieldRatioKey = ['yieldratio', crop, timeframe, scenario].join('_')

let yieldRatioValue = null
if (d[k] !== null && d[historicalKey] !== null && d[historicalKey]) {
yieldRatioValue = (d[k] - d[historicalKey]) / d[historicalKey]
if (rowWithYields[k] !== null && rowWithYields[historicalKey] !== null && rowWithYields[historicalKey]) {
yieldRatioValue = (rowWithYields[k] - rowWithYields[historicalKey]) / rowWithYields[historicalKey]
}

if (yieldRatioValue === null) return
rowWithYields[yieldRatioKey] = yieldRatioValue
})

Expand Down
38 changes: 38 additions & 0 deletions vacs-map-app/src/stores/joinedCropData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { computed } from 'vue';
import { defineStore, storeToRefs } from 'pinia'
import { point, featureCollection } from '@turf/helpers'
import { useCropYieldsStore } from '@/stores/cropYields';
import { useGridStore } from '@/stores/grid';

export const useJoinedCropDataStore = defineStore('joinedCropData', () => {
const gridStore = useGridStore();
const cropYieldsStore = useCropYieldsStore();

const { data: cropYieldsData } = storeToRefs(cropYieldsStore);
const { data: gridData } = storeToRefs(gridStore);

// Provide the feature collection of grid data in one unified place so we
// don't have to recalculate it
const gridFeatureCollection = computed(() => {
if (!(gridData.value && cropYieldsData.value)) return featureCollection([]);

const gridMap = Object.fromEntries(gridData.value.map((row) => [row.id, row]))
const yieldMap = Object.fromEntries(cropYieldsData.value.map((row) => [row.id, row]))

const points = Object.keys(gridMap).map(id => {
const g = gridMap[id];
return point(
[g.X, g.Y],
{
...g,
...yieldMap[id],
},
{ id }
);
});

return Object.freeze(featureCollection(points))
});

return { gridFeatureCollection };
});

0 comments on commit f926c85

Please sign in to comment.