Skip to content

Commit

Permalink
Merge pull request #82 from earthrise-media/add-tooltips
Browse files Browse the repository at this point in the history
Add map tooltips
  • Loading branch information
Martin Bernard authored Nov 29, 2023
2 parents cbb37f9 + 0a814d1 commit edc4468
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 54 deletions.
2 changes: 1 addition & 1 deletion vacs-map-app/src/LandingPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<LayoutOpen>
<div class="video-wrapper">
<video autoplay loop muted>
<source src="@/assets/img/homepage-video.mp4" type="video/mp4">
<source src="@/assets/img/homepage-video.mp4" type="video/mp4" />
</video>
</div>

Expand Down
8 changes: 5 additions & 3 deletions vacs-map-app/src/MapExplorer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
</div>
</div>
</div>
<MapTooltip />
</LayoutOverview>
</template>

Expand All @@ -39,9 +40,10 @@ import MapContainerColorSoil from '@/components/MapContainerColorSoil.vue'
import MapContainerColorSand from '@/components/MapContainerColorSand.vue'
import MapContainerColorPopulation from '@/components/MapContainerColorPopulation.vue'
import { useMapExploreStore } from '@/stores/mapExplore'
import LayoutOverview from './components/layouts/LayoutOverview.vue'
import ExploreSidebar from './components/ExploreSidebar.vue'
import RegionPicker from './components/RegionPicker.vue'
import LayoutOverview from '@/components/layouts/LayoutOverview.vue'
import ExploreSidebar from '@/components/ExploreSidebar.vue'
import RegionPicker from '@/components/RegionPicker.vue'
import MapTooltip from '@/components/MapTooltip.vue'
import MapLegend from '@/components/MapLegend.vue'
const availableMaps = [
Expand Down
4 changes: 4 additions & 0 deletions vacs-map-app/src/assets/img/info.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions vacs-map-app/src/components/ContentModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ onClickOutside(contentInnerRef, () => emit('close'))
overflow-y: auto;
max-width: 50%;
padding: 2.5rem;
white-space: pre-line;
}
.header {
Expand Down
2 changes: 1 addition & 1 deletion vacs-map-app/src/components/DistributionPlot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ const draw = () => {
//draw hovered
if (hoveredId.value) {
const cell = gridCells?.value.find(d => d.id === hoveredId.value);
const cell = gridCells?.value.find((d) => d.id === hoveredId.value)
context.value.fillStyle = 'white'
context.value.fillRect(cell.x, 0, 3, height.value)
}
Expand Down
41 changes: 35 additions & 6 deletions vacs-map-app/src/components/ExploreSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,15 @@
</div>

<div class="sidebar-section grow">
<span class="sidebar-header"> What are {{ selectedCropInfo?.label }}'s characteristics?</span>
<span class="sidebar-header">
What are {{ selectedCropInfo?.label }}'s characteristics?
<img
class="info"
src="@/assets/img/info.svg"
alt=""
@click="openChartModal('fingerprint')"
/>
</span>
<div class="crop-fingerprint">
<CropFingerprint :crop-id="selectedCrop" />
</div>
Expand All @@ -23,8 +31,14 @@
<div class="sidebar-section shrink">
<div class="scenarios">
<span class="sidebar-header">
How will climate change affect {{ selectedCropInfo?.label }}?</span
>
How will climate change affect {{ selectedCropInfo?.label }}?
<img
class="info"
src="@/assets/img/info.svg"
alt=""
@click="openChartModal('distribution')"
/>
</span>
<CardWrapper
v-for="scenario in futureScenarios"
:key="scenario"
Expand All @@ -33,7 +47,7 @@
:is-active="selectedModel === scenario"
:handle-click="() => (selectedModel = scenario)"
:show-more-info="true"
@show-info="() => openModal(scenario)"
@show-info="() => openScenarioModal(scenario)"
>
<DistributionPlot :scenario="scenario" />
</CardWrapper>
Expand Down Expand Up @@ -81,7 +95,13 @@ const getCropsByGroup = (group) => {
return cropInformation?.value?.filter((crop) => crop.crop_group === group)
}
const openModal = (s) => {
const openChartModal = (chartType) => {
modalOpen.value = true
modalHeader.value = 'How do I interpret this chart?'
modalContent.value = copy.value[chartType + '_chart']
}
const openScenarioModal = (s) => {
modalOpen.value = true
modalHeader.value = copy.value[`${s}_label`] + ' scenario' + ` (${s.split('_')[1].toUpperCase()})`
modalContent.value = copy.value[`${s}_long`]
Expand Down Expand Up @@ -112,11 +132,20 @@ const openModal = (s) => {
}
.sidebar-header {
font-size: 1rem;
font-size: 0.925rem;
font-weight: 600;
line-height: 120%;
}
.info {
vertical-align: top;
cursor: pointer;
}
.info:hover {
opacity: 0.7;
}
.grow {
flex-grow: 1;
}
Expand Down
72 changes: 31 additions & 41 deletions vacs-map-app/src/components/GridOverlay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import * as d3 from 'd3'
import { computed, toRefs, watch } from 'vue'
import { divergingScheme } from '@/utils/colors'
import { storeToRefs } from 'pinia';
import { useMapExploreStore } from '../stores/mapExplore';
import { storeToRefs } from 'pinia'
import { useMapExploreStore } from '../stores/mapExplore'
const props = defineProps({
id: {
Expand Down Expand Up @@ -84,8 +84,8 @@ const {
stroke
} = toRefs(props)
const mapExploreStore = useMapExploreStore();
const { hoveredId } = storeToRefs(mapExploreStore);
const mapExploreStore = useMapExploreStore()
const { hoveredId } = storeToRefs(mapExploreStore)
const addLayer = () => {
if (!map.value || !mapReady.value || map.value.getLayer(id.value)) return
Expand All @@ -99,19 +99,9 @@ const addLayer = () => {
'circle-stroke-width': fill.value ? 0.2 : 1.5,
'circle-stroke-color': getCircleStrokeColor(),
'circle-stroke-opacity': fill.value ? 0 : 0.8,
'circle-opacity': [
'case',
['boolean', ['feature-state', 'hovered'], false],
0.5,
1
],
'circle-opacity': ['case', ['boolean', ['feature-state', 'hovered'], false], 0.5, 1],
'circle-color': getCircleFillColor(),
'circle-blur': [
'case',
['boolean', ['feature-state', 'hovered'], false],
0,
0.5
],
'circle-blur': ['case', ['boolean', ['feature-state', 'hovered'], false], 0, 0.5]
}
},
'settlement-subdivision-label'
Expand All @@ -122,23 +112,23 @@ const addLayer = () => {
const addHoverListeners = () => {
if (!map.value || !mapReady.value || !map.value.getLayer(id.value)) return
map.value.on('mousemove', id.value, (event) => {
if (!event?.features?.length) return;
const feature = event?.features[0];
if (!event?.features?.length) return
const feature = event?.features[0]
if (feature?.id) {
if (!feature.properties[colorColumn.value]) return;
hoveredId.value = feature.properties.id;
if (!feature.properties[colorColumn.value]) return
hoveredId.value = feature.properties.id
}
});
})
map.value.on('mouseleave', id.value, (event) => {
hoveredId.value = null;
});
hoveredId.value = null
})
}
const updateHoveredFeatureState = (elementId, hovered) => {
if (!id) return;
if (!id.value) return
map.value.setFeatureState(
{
source: sourceId.value,
Expand All @@ -147,7 +137,7 @@ const updateHoveredFeatureState = (elementId, hovered) => {
{
hovered
}
);
)
}
const getCircleColorQuintiles = (quintiles) => {
Expand Down Expand Up @@ -266,22 +256,22 @@ const getCircleColorDiverging = (extent, center) => {
return [
'case',
['!=', ['get', colorColumn.value], null],
[
'case',
['boolean', ['feature-state', 'hovered'], false],
'white',
[
'case',
['boolean', ['feature-state', 'hovered'], false],
'white',
[
'interpolate',
['linear'],
['get', colorColumn.value],
min,
getColor(0),
center,
divergingScheme.center,
max,
getColor(1)
],
],
'interpolate',
['linear'],
['get', colorColumn.value],
min,
getColor(0),
center,
divergingScheme.center,
max,
getColor(1)
]
],
'transparent'
]
}
Expand Down
54 changes: 54 additions & 0 deletions vacs-map-app/src/components/MapTooltip.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<template>
<TooltipWrapper v-if="hoveredId">
{{ sentence }}
</TooltipWrapper>
</template>

<script setup>
import * as d3 from 'd3'
import { computed } from 'vue'
import TooltipWrapper from '@/components/TooltipWrapper.vue'
import { storeToRefs } from 'pinia'
import { useMapExploreStore } from '@/stores/mapExplore'
import { useCropYieldsStore } from '@/stores/cropYields'
import { useFiltersStore } from '@/stores/filters'
import { useContentStore } from '@/stores/siteContent'
import { useCropInformationStore } from '@/stores/cropInformation'
const filtersStore = useFiltersStore()
const cropYieldsStore = useCropYieldsStore()
const mapExploreStore = useMapExploreStore()
const contentStore = useContentStore()
const cropInformationStore = useCropInformationStore()
const { hoveredId } = storeToRefs(mapExploreStore)
const { data: yieldData } = storeToRefs(cropYieldsStore)
const { selectedCrop, selectedModel } = storeToRefs(filtersStore)
const { copy } = storeToRefs(contentStore)
const { data: cropInfo } = storeToRefs(cropInformationStore)
const sentence = computed(() => {
const cropName = cropInfo.value?.find((d) => d.id === selectedCrop.value)?.label
const modelDescriptor =
selectedModel.value === 'future_ssp126'
? 'a low emissions scenario'
: 'a high emissions scenario'
return `In ${modelDescriptor}, ${cropName} has a yield ratio of ${hoveredValue.value} at this location`
})
const hoveredValue = computed(() => {
if (!yieldData.value || !selectedCrop.value || !selectedModel.value || !hoveredId.value) return ''
const columnName = `yieldratio_${selectedCrop.value}_${selectedModel.value}`
const cellObject = yieldData.value.find((d) => d.id === hoveredId.value)
if (!cellObject) return ''
return vFormat(cellObject[columnName])
})
const vFormat = (value) => {
return d3.format('.2f')(value)
}
</script>
<style scoped></style>
Loading

0 comments on commit edc4468

Please sign in to comment.