From b859d48f179b92c4e5d55f8e38e3ae0dfb25d026 Mon Sep 17 00:00:00 2001 From: Demenech Date: Tue, 9 Apr 2024 17:30:45 -0300 Subject: [PATCH] feat: Map component API and docs improvements --- packages/components/src/components/Map.tsx | 32 ++++++++------- packages/components/src/types/properties.ts | 9 ++++- packages/components/stories/Map.stories.ts | 45 ++++++++++++++------- 3 files changed, 56 insertions(+), 30 deletions(-) diff --git a/packages/components/src/components/Map.tsx b/packages/components/src/components/Map.tsx index fcc921f0..722740f7 100644 --- a/packages/components/src/components/Map.tsx +++ b/packages/components/src/components/Map.tsx @@ -2,6 +2,7 @@ import { CSSProperties, useEffect, useState } from 'react'; import LoadingSpinner from './LoadingSpinner'; import loadData from '../lib/loadData'; import chroma from 'chroma-js'; +import { GeospatialData } from '../types/properties'; import { MapContainer, TileLayer, @@ -14,26 +15,25 @@ import * as L from 'leaflet'; export type MapProps = { layers: { - data: string | GeoJSON.GeoJSON; + data: GeospatialData; name: string; colorScale?: { starting: string; ending: string; }; tooltip?: - | { - propNames: string[]; - } - | boolean; - _id?: number; + | { + propNames: string[]; + } + | boolean; }[]; title?: string; center?: { latitude: number | undefined; longitude: number | undefined }; zoom?: number; style?: CSSProperties; autoZoomConfiguration?: { - layerName: string - } + layerName: string; + }; }; export function Map({ @@ -56,17 +56,19 @@ export function Map({ useEffect(() => { const loadDataPromises = layers.map(async (layer) => { + const url = layer.data.url; + const geojson = layer.data.geojson; let layerData: any; - if (typeof layer.data === 'string') { + if (url) { // If "data" is string, assume it's a URL setIsLoading(true); - layerData = await loadData(layer.data).then((res: any) => { + layerData = await loadData(url).then((res: any) => { return JSON.parse(res); }); } else { // Else, expect raw GeoJSON - layerData = layer.data; + layerData = geojson; } if (layer.colorScale) { @@ -111,23 +113,23 @@ export function Map({ // Create the title box var info = new L.Control() as any; - info.onAdd = function() { + info.onAdd = function () { this._div = L.DomUtil.create('div', 'info'); this.update(); return this._div; }; - info.update = function() { + info.update = function () { this._div.innerHTML = `

${title}

`; }; if (title) info.addTo(map.target); - if(!autoZoomConfiguration) return; + if (!autoZoomConfiguration) return; let layerToZoomBounds = L.latLngBounds(L.latLng(0, 0), L.latLng(0, 0)); layers.forEach((layer) => { - if(layer.name === autoZoomConfiguration.layerName) { + if (layer.name === autoZoomConfiguration.layerName) { const data = layersData.find( (layerData) => layerData.name === layer.name )?.data; diff --git a/packages/components/src/types/properties.ts b/packages/components/src/types/properties.ts index 35dc93e0..8805e3bb 100644 --- a/packages/components/src/types/properties.ts +++ b/packages/components/src/types/properties.ts @@ -4,8 +4,15 @@ * Based on vega. * */ + +type URL = string; // Just in case we want to transform it into an object with configurations export interface Data { - url?: string; + url?: URL; values?: { [key: string]: number | string }[]; csv?: string; } + +export interface GeospatialData { + url?: URL; + geojson?: GeoJSON.GeoJSON; +} diff --git a/packages/components/stories/Map.stories.ts b/packages/components/stories/Map.stories.ts index 0cdbd8a6..c7bc8081 100644 --- a/packages/components/stories/Map.stories.ts +++ b/packages/components/stories/Map.stories.ts @@ -10,7 +10,11 @@ const meta: Meta = { argTypes: { layers: { description: - 'Data to be displayed.\n\n GeoJSON Object \n\nOR\n\n URL to GeoJSON Object', + 'Array of layers to be displayed on the map. Should be an object with: \n\n \ +`data`: object with either a `url` property pointing to a GeoJSON file or a `geojson` property with a GeoJSON object. \n\n \ +`name`: name of the layer. \n\n \ +`colorscale`: object with a `starting` and `ending` colors that will be used to create a gradient and color the map. \n\n \ +`tooltip`: `true` to show all available features on the tooltip, object with a `propNames` property as an array of strings to choose which features to display. \n\n', }, title: { description: 'Title to display on the map.', @@ -19,14 +23,15 @@ const meta: Meta = { description: 'Initial coordinates of the center of the map', }, zoom: { - description: 'Zoom level', + description: 'Initial zoom level', }, style: { - description: "Styles for the container" + description: "CSS styles to be applied to the map's container.", }, autoZoomConfiguration: { - description: "Configuration to auto zoom in the specified layer data" - } + description: + "Pass a layer's name to automatically zoom to the bounding area of a layer.", + }, }, }; @@ -40,7 +45,9 @@ export const GeoJSONPolygons: Story = { args: { layers: [ { - data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson', + data: { + url: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson', + }, name: 'Polygons', tooltip: { propNames: ['name'] }, colorScale: { @@ -60,7 +67,9 @@ export const GeoJSONPoints: Story = { args: { layers: [ { - data: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson', + data: { + url: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson', + }, name: 'Points', tooltip: { propNames: ['Location'] }, }, @@ -76,12 +85,16 @@ export const GeoJSONMultipleLayers: Story = { args: { layers: [ { - data: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson', + data: { + url: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson', + }, name: 'Points', tooltip: true, }, { - data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson', + data: { + url: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson', + }, name: 'Polygons', tooltip: true, colorScale: { @@ -94,19 +107,23 @@ export const GeoJSONMultipleLayers: Story = { center: { latitude: 45, longitude: 0 }, zoom: 2, }, -} +}; export const GeoJSONMultipleLayersWithAutoZoomInSpecifiedLayer: Story = { name: 'GeoJSON polygons and points map with auto zoom in the points layer', args: { layers: [ { - data: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson', + data: { + url: 'https://opendata.arcgis.com/datasets/9c58741995174fbcb017cf46c8a42f4b_25.geojson', + }, name: 'Points', tooltip: true, }, { - data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson', + data: { + url: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_geography_marine_polys.geojson', + }, name: 'Polygons', tooltip: true, colorScale: { @@ -119,7 +136,7 @@ export const GeoJSONMultipleLayersWithAutoZoomInSpecifiedLayer: Story = { center: { latitude: 45, longitude: 0 }, zoom: 2, autoZoomConfiguration: { - layerName: 'Points' - } + layerName: 'Points', + }, }, };