Skip to content

Commit

Permalink
Merge pull request #212 from SpeciesFileGroup/development
Browse files Browse the repository at this point in the history
Add map popup for DwC data
  • Loading branch information
jlpereira authored May 27, 2024
2 parents 4854be6 + d8e575c commit 3bba1a3
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 66 deletions.
8 changes: 3 additions & 5 deletions src/assets/css/leaflet.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
saturate(0.3) brightness(0.7);
}

/* @media (prefers-color-scheme: dark) {
.map-tiles {
filter:var(--map-tiles-filter, none);
}
} */
.leaflet-fade-anim .leaflet-popup {
transition: none;
}

.map-point-marker {
opacity: var(--color-map-marker-opacity);
Expand Down
16 changes: 9 additions & 7 deletions src/components/Map/VMap.client.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@

<script setup>
import { computed, onMounted, onUnmounted, ref, watch, nextTick } from 'vue'
import { makeTileFromConfiguration } from './utils/makeTileFromConfiguration'
import L from 'leaflet'
import iconRetina from 'leaflet/dist/images/marker-icon-2x.png'
import iconUrl from 'leaflet/dist/images/marker-icon.png'
import shadowUrl from 'leaflet/dist/images/marker-shadow.png'
import geojsonDefaultOptions from './utils/geojsonOptions'
import { makeTileFromConfiguration } from './utils/makeTileFromConfiguration'
import '@geoman-io/leaflet-geoman-free'
import '@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css'
Expand Down Expand Up @@ -90,7 +90,7 @@ const props = defineProps({
},
geojsonOptions: {
type: Object,
type: Function,
default: () => ({})
},
Expand All @@ -116,12 +116,12 @@ const props = defineProps({
})
const emit = defineEmits([
'geojson:ready',
'geojson',
'add:layer',
'drag:layer',
'draw:start',
'edit:layer',
'drag:layer',
'geojson',
'geojson:ready',
'zoom:change',
'zoom:start'
])
Expand Down Expand Up @@ -318,9 +318,11 @@ onUnmounted(() => {
function setGeoJSON(geojson) {
if (geojson) {
const args = { L }
L.geoJSON(geojson, {
...geojsonDefaultOptions(L),
...props.geojsonOptions
...geojsonDefaultOptions(args),
...props.geojsonOptions(args)
}).addTo(geoJSONGroup)
const bounds = geoJSONGroup.getBounds()
Expand Down
7 changes: 7 additions & 0 deletions src/components/Map/constants/disableLayerOptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const DISABLE_LAYER_OPTIONS = {
allowEditing: false,
allowRemoval: false,
allowCutting: false,
allowRotation: false,
draggable: false
}
1 change: 1 addition & 0 deletions src/components/Map/constants/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './disableLayerOptions'
61 changes: 16 additions & 45 deletions src/components/Map/utils/geojsonOptions.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import * as Icons from '../icons'
import * as Shape from '../shapes'
import { DISABLE_LAYER_OPTIONS } from '../constants'
import {
TYPE_MATERIAL,
COLLECTION_OBJECT,
ASSERTED_DISTRIBUTION,
GEOREFERENCE,
AGGREGATE
} from '@/constants/objectTypes.js'

const TYPES = [
'TypeMaterial',
'CollectionObject',
'AssertedDistribution',
'Georeference',
'Aggregate'
TYPE_MATERIAL,
COLLECTION_OBJECT,
ASSERTED_DISTRIBUTION,
GEOREFERENCE,
AGGREGATE
]

const DEFAULT_OPTIONS = {
allowEditing: false,
allowRemoval: false,
allowCutting: false,
allowRotation: false,
draggable: false
}

function getRelevantType(base) {
const types = base.map((b) => b.type)

Expand All @@ -25,39 +25,10 @@ function getRelevantType(base) {
return types[0]
}

export default (L) => ({
export default ({ L }) => ({
onEachFeature: (feature, layer) => {
const labels = (feature.properties.base || [])
.map((item) => item.label)
.filter(Boolean)

if (!labels.length) {
return
}

const label = `
<div class="max-h-32 overflow-y-auto text-xs">
<ul>
${labels
.map(
(label) =>
`
<li
class="py-2 last:border-0 truncate border-b"
title="${label}"
>
${label}
</li>
`
)
.join('')}
</ul>
</div>`

layer.pm.setOptions(DEFAULT_OPTIONS)
layer.pm.setOptions(DISABLE_LAYER_OPTIONS)
layer.pm.disable()

layer.bindPopup(label)
},

pointToLayer: (feature, latLng) => {
Expand All @@ -67,7 +38,7 @@ export default (L) => ({
icon: L.divIcon(markerStyle)
})

marker.pm.setOptions(DEFAULT_OPTIONS)
marker.pm.setOptions(DISABLE_LAYER_OPTIONS)

return marker
},
Expand Down
5 changes: 5 additions & 0 deletions src/constants/objectTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const TYPE_MATERIAL = 'TypeMaterial'
export const COLLECTION_OBJECT = 'CollectionObject'
export const ASSERTED_DISTRIBUTION = 'AssertedDistribution'
export const GEOREFERENCE = 'Georeference'
export const AGGREGATE = 'Aggregate'
16 changes: 15 additions & 1 deletion src/modules/otus/components/Panel/PanelMap/PanelMap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@
:zoom-bounds="8"
:geojson="store.distribution.geojson"
:cluster-icon-create-function="makeClusterIconFor"
:geojson-options="geojsonOptions"
@geojson:ready="() => (isLoading = false)"
/>

<div ref="popupElement">
<MapPopup
v-if="popupItem"
:items="popupItem.base"
@selected="dwcTableRef.show"
/>
</div>
<VButton
class="h-6 text-sm absolute right-3 top-3 z-[400]"
primary
Expand Down Expand Up @@ -56,15 +63,19 @@
<span>{{ LEGEND[type].label }}</span>
</div>
</div>
<DwcTable ref="dwcTableRef" />
</VCard>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { useDistributionStore } from '@/modules/otus/store/useDistributionStore.js'
import { makeClusterIconFor } from './clusters/makeClusterIconFor'
import { useGeojsonOptions } from './composables/useGeojsonOptions.js'
import MapPopup from './components/MapPopup.vue'
import CachedMap from './components/CachedMap.vue'
import OtuSearch from './components/Search/OtuSearch.vue'
import DwcTable from './components/DwcTable.vue'
const props = defineProps({
otuId: {
Expand All @@ -91,7 +102,10 @@ const props = defineProps({
const zoom = 2
const isLoading = ref(true)
const isOtuSearchVisible = ref(false)
const dwcTableRef = ref(null)
const store = useDistributionStore()
const popupElement = ref(null)
const { popupItem, geojsonOptions } = useGeojsonOptions({ popupElement })
const LEGEND = {
AssertedDistribution: {
Expand Down
58 changes: 58 additions & 0 deletions src/modules/otus/components/Panel/PanelMap/components/DwcTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<template>
<VModal
v-if="isModalVisible"
@close="() => (isModalVisible = false)"
>
<template #header>
<h3 class="font-medium">{{ title }}</h3>
</template>
<VTable class="p-4 pt-0">
<VTableHeader>
<VTableHeaderRow>
<VTableHeaderCell>Field</VTableHeaderCell>
<VTableHeaderCell>Value</VTableHeaderCell>
</VTableHeaderRow>
</VTableHeader>
<VTableBody>
<VTableBodyRow
v-for="(value, key) in dwcData"
:key="key"
>
<VTableBodyCell>{{ key }} </VTableBodyCell>
<VTableBodyCell>{{ value }} </VTableBodyCell>
</VTableBodyRow>
</VTableBody>
</VTable>
<VSpinner v-if="isLoading" />
</VModal>
</template>

<script setup>
import { ref } from 'vue'
import { makeAPIRequest } from '@/utils'
const isLoading = ref(false)
const isModalVisible = ref(false)
const dwcData = ref({})
const title = ref()
function show({ label, id }) {
isModalVisible.value = true
isLoading.value = true
dwcData.value = {}
title.value = label
makeAPIRequest(`/collection_objects/${id}/dwc`)
.then(({ data }) => {
dwcData.value = data
})
.catch(() => {})
.finally(() => {
isLoading.value = false
})
}
defineExpose({
show
})
</script>
32 changes: 32 additions & 0 deletions src/modules/otus/components/Panel/PanelMap/components/MapPopup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<template>
<div class="max-h-32 overflow-y-auto text-xs min-w-80">
<ul>
<li
v-for="item in items"
class="py-2 last:border-0 truncate border-b"
title="label"
>
<span
v-if="item.type === COLLECTION_OBJECT"
class="cursor-pointer text-secondary-color"
v-text="item.label"
@click="() => emit('selected', item)"
/>
<span v-else>{{ item.label }}</span>
</li>
</ul>
</div>
</template>

<script setup>
import { COLLECTION_OBJECT } from '@/constants/objectTypes.js'
defineProps({
items: {
type: Array,
required: true
}
})
const emit = defineEmits(['selected'])
</script>
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
<template>
<div
ref="root"
class="w-screen h-screen fixed top-0 left-0 z-[5000] flex flex-col"
>
<div class="w-screen h-screen fixed top-0 left-0 z-[5000] flex flex-col">
<VSpinner v-if="isLoading" />
<SearchBar
:label="otu.object_tag"
Expand All @@ -23,6 +20,7 @@
:dragging="!disableZoom"
:zoom-bounds="maxZoom"
:geojson="shapes"
:geojsonOptions="geojsonOptions"
@geojson:ready="updateMaxZoom"
@add:layer="(layer) => loadOTUs(JSON.stringify(layer.geometry))"
@edit:layer="(layer) => loadOTUs(JSON.stringify(layer.geometry))"
Expand All @@ -31,6 +29,14 @@
:zoom="4"
/>

<div ref="popupElement">
<MapPopup
v-if="popupItem"
:items="popupItem.base"
@selected="dwcTableRef.show"
/>
</div>

<div
:class="[
'h-full',
Expand All @@ -57,35 +63,42 @@
/>
</div>
</div>
<DwcTable ref="dwcTableRef" />
</div>
</template>

<script setup>
import { computed, ref, onMounted, onUnmounted } from 'vue'
import { useGeojsonOptions } from '../../composables/useGeojsonOptions.js'
import TaxonWorks from '../../../../../services/TaxonWorks.js'
import SearchBar from './SearchBar.vue'
import ListResults from './ListResults.vue'
import MapPopup from '../MapPopup.vue'
import DwcTable from '../DwcTable.vue'
const props = defineProps({
otu: {
type: Array,
shapes: {
type: Object,
default: () => []
},
shapes: {
otu: {
type: Object,
default: undefined
}
})
const root = ref()
const emit = defineEmits(['close'])
const popupElement = ref(null)
const dwcTableRef = ref(null)
const mapRef = ref(null)
const list = ref([])
const isTableVisible = ref(false)
const isLoading = ref()
const maxZoom = ref(6)
const currentZoom = ref(6)
const { popupItem, geojsonOptions } = useGeojsonOptions({ popupElement })
const disableZoom = computed(
() => !!props.shapes && currentZoom.value <= maxZoom.value
)
Expand Down
Loading

0 comments on commit 3bba1a3

Please sign in to comment.