diff --git a/src/assets/css/vars.css b/src/assets/css/vars.css index a98aa69..35fd134 100644 --- a/src/assets/css/vars.css +++ b/src/assets/css/vars.css @@ -14,6 +14,7 @@ --color-base-content: 0, 0, 0; --color-map-georeference: 239, 68, 68; + --color-map-aggregate: 249, 115, 22; --color-map-asserted: 249, 115, 22; --color-map-type-material: 51, 136, 255; --color-map-collection-object: 239, 68, 68; diff --git a/src/components/Map/shapes/Aggregate.js b/src/components/Map/shapes/Aggregate.js new file mode 100644 index 0000000..460948b --- /dev/null +++ b/src/components/Map/shapes/Aggregate.js @@ -0,0 +1,7 @@ +export const Aggregate = { + color: 'rgb(var(--color-map-aggregate))', + weight: 1, + dashArray: '3', + dashOffset: '3', + fillOpacity: 0.25 +} diff --git a/src/components/Map/shapes/index.js b/src/components/Map/shapes/index.js index 557a2f6..b5134f6 100644 --- a/src/components/Map/shapes/index.js +++ b/src/components/Map/shapes/index.js @@ -1,3 +1,4 @@ +export * from './Aggregate' export * from './AssertedDistribution' export * from './CollectionObject' export * from './TypeMaterial' diff --git a/src/components/Map/utils/geojsonOptions.js b/src/components/Map/utils/geojsonOptions.js index 35bd0dd..7c67716 100644 --- a/src/components/Map/utils/geojsonOptions.js +++ b/src/components/Map/utils/geojsonOptions.js @@ -5,7 +5,8 @@ const TYPES = [ 'TypeMaterial', 'CollectionObject', 'AssertedDistribution', - 'Georeference' + 'Georeference', + 'Aggregate' ] const DEFAULT_OPTIONS = { diff --git a/src/modules/otus/components/Panel/PanelMap/PanelMap.vue b/src/modules/otus/components/Panel/PanelMap/PanelMap.vue index f7e9817..97f0700 100644 --- a/src/modules/otus/components/Panel/PanelMap/PanelMap.vue +++ b/src/modules/otus/components/Panel/PanelMap/PanelMap.vue @@ -7,7 +7,7 @@ class="h-96 max-h-96" dragging :zoom="zoom" - :geojson="geojson" + :geojson="store.distribution.geojson" @geojson:ready="() => (isLoading = false)" /> @@ -22,23 +22,23 @@
- * {{ errorMessage }} + * {{ store.distribution.errorMessage }}
@@ -54,7 +54,7 @@ diff --git a/src/modules/otus/services/TaxonWorks.js b/src/modules/otus/services/TaxonWorks.js index aae3ceb..5a1aaca 100644 --- a/src/modules/otus/services/TaxonWorks.js +++ b/src/modules/otus/services/TaxonWorks.js @@ -48,7 +48,11 @@ export default class TaxonWorks { } static getOtuDistribution(otuId) { - return makeAPIRequest.get(`/otus/${otuId}/inventory/distribution`) + return makeAPIRequest.get(`/otus/${otuId}/inventory/distribution.json`) + } + + static getOtuGeoJSONDistribution(otuId) { + return makeAPIRequest.get(`/otus/${otuId}/inventory/distribution.geojson`) } static getOtuContent(otuId) { diff --git a/src/modules/otus/store/actions/index.js b/src/modules/otus/store/actions/index.js new file mode 100644 index 0000000..a6a10e4 --- /dev/null +++ b/src/modules/otus/store/actions/index.js @@ -0,0 +1 @@ +export * from './loadDistribution' diff --git a/src/modules/otus/store/actions/loadDistribution.js b/src/modules/otus/store/actions/loadDistribution.js new file mode 100644 index 0000000..7fedd28 --- /dev/null +++ b/src/modules/otus/store/actions/loadDistribution.js @@ -0,0 +1,51 @@ +import { + isRankGrpup, + removeDuplicateShapes, + makeGeoJSONFeature +} from '../../utils' +import TaxonWorks from '../../services/TaxonWorks' + +export const actionLoadDistribution = { + async loadDistribution({ otuId, rankString }) { + const isSpeciesGroup = isRankGrpup('SpeciesGroup', rankString) + + const getAggregateShape = async (otuId) => { + TaxonWorks.getOtuDistribution(otuId) + .then(({ data }) => { + const geojson = JSON.parse(data.cached_map.geo_json) + + this.distribution.currentShapeTypes = ['Aggregate'] + this.distribution.geojson = { + features: [makeGeoJSONFeature(geojson, 'Aggregate')] + } + }) + .catch((e) => { + this.distribution.errorMessage = e.response.data.error + this.distribution.currentShapeTypes = [] + this.distribution.geojson = [] + }) + } + + if (isSpeciesGroup) { + TaxonWorks.getOtuGeoJSONDistribution(otuId) + .then(({ data }) => { + if (data.request_too_large) { + this.distribution.geojson = null + this.distribution.errorMessage = data.message + } else { + const { features, shapeTypes } = removeDuplicateShapes(data) + + this.distribution.currentShapeTypes = shapeTypes + this.distribution.geojson = { + features + } + } + }) + .catch((e) => { + getAggregateShape(otuId) + }) + } else { + getAggregateShape(otuId) + } + } +} diff --git a/src/modules/otus/store/store.js b/src/modules/otus/store/store.js index 9f731cb..033ad33 100644 --- a/src/modules/otus/store/store.js +++ b/src/modules/otus/store/store.js @@ -1,12 +1,18 @@ import { defineStore } from 'pinia' import TaxonWorks from '../services/TaxonWorks' +import { actionLoadDistribution } from './actions' export const useOtuStore = defineStore('otuStore', { state: () => { return { otu: null, taxon: null, - images: null + images: null, + distribution: { + geojson: null, + errorMessage: null, + currentShapeTypes: [] + } } }, actions: { @@ -36,6 +42,8 @@ export const useOtuStore = defineStore('otuStore', { } this.images = (await TaxonWorks.getOtuImages(otuId, params)).data - } - }, -}) \ No newline at end of file + }, + + ...actionLoadDistribution + } +}) diff --git a/src/modules/otus/utils/index.js b/src/modules/otus/utils/index.js new file mode 100644 index 0000000..1094c15 --- /dev/null +++ b/src/modules/otus/utils/index.js @@ -0,0 +1,3 @@ +export * from './isRankGroup' +export * from './makeGeoJSONFeature' +export * from './removeDuplicateShapes' diff --git a/src/modules/otus/utils/isRankGroup.js b/src/modules/otus/utils/isRankGroup.js new file mode 100644 index 0000000..494b968 --- /dev/null +++ b/src/modules/otus/utils/isRankGroup.js @@ -0,0 +1,5 @@ +export function isRankGrpup(compareRank, rank) { + const rankGroup = rank.split('::').at(2) + + return rankGroup === compareRank +} diff --git a/src/modules/otus/utils/makeGeoJSONFeature.js b/src/modules/otus/utils/makeGeoJSONFeature.js new file mode 100644 index 0000000..177e79a --- /dev/null +++ b/src/modules/otus/utils/makeGeoJSONFeature.js @@ -0,0 +1,13 @@ +export function makeGeoJSONFeature(geometry, type) { + return { + type: 'Feature', + geometry, + properties: { + base: [ + { + type + } + ] + } + } +} diff --git a/src/modules/otus/utils/removeDuplicateShapes.js b/src/modules/otus/utils/removeDuplicateShapes.js new file mode 100644 index 0000000..c90bd8f --- /dev/null +++ b/src/modules/otus/utils/removeDuplicateShapes.js @@ -0,0 +1,40 @@ +export function removeDuplicateShapes(data) { + const features = [] + const shapeTypes = [] + + data.features.forEach((feature) => { + const shapeId = feature.properties.shape.id + const shapeType = feature.properties.shape.type + + if (!shapeTypes.includes(feature.properties.base.type)) { + shapeTypes.push(feature.properties.base.type) + } + + const index = features.findIndex( + (item) => + item.properties.shape.id === shapeId && + item.properties.shape.type === shapeType + ) + + if (index > -1) { + const currentFeature = features[index] + + currentFeature.properties.base.push(feature.properties.base) + currentFeature.properties.target.push(feature.properties.target) + } else { + const item = structuredClone(feature) + + item.properties.base = [item.properties.base] + item.properties.target = [item.properties.target] + + features.push(item) + } + }) + + shapeTypes.sort() + + return { + shapeTypes, + features + } +} diff --git a/tailwind.config.cjs b/tailwind.config.cjs index eab272f..15e08db 100644 --- a/tailwind.config.cjs +++ b/tailwind.config.cjs @@ -36,6 +36,7 @@ module.exports = { map: { georeference: withOpacity('--color-map-georeference'), + aggregate: withOpacity('--color-map-aggregate'), asserted: withOpacity('--color-map-asserted'), 'type-material': withOpacity('--color-map-type-material'), 'collection-object': withOpacity('--color-map-collection-object')