From ec2bd3b826bc84274a8c45f607e0ba711271aa59 Mon Sep 17 00:00:00 2001 From: William Mai Date: Tue, 23 Aug 2022 18:10:24 +0200 Subject: [PATCH] tmp: Vector tiles experimentations --- .../stories/Map/StudioChoropleth.stories.tsx | 122 ++++++++++++++---- .../src/components/Map/Choropleth.svelte | 54 ++++++-- .../src/components/Map/MapRender.svelte | 24 +++- .../src/components/Map/constants.ts | 8 ++ .../src/components/Map/utils.ts | 45 ++++++- 5 files changed, 206 insertions(+), 47 deletions(-) create mode 100644 packages/visualizations/src/components/Map/constants.ts diff --git a/packages/visualizations-react/stories/Map/StudioChoropleth.stories.tsx b/packages/visualizations-react/stories/Map/StudioChoropleth.stories.tsx index 7499c602..f71471a5 100644 --- a/packages/visualizations-react/stories/Map/StudioChoropleth.stories.tsx +++ b/packages/visualizations-react/stories/Map/StudioChoropleth.stories.tsx @@ -1,7 +1,12 @@ import React from 'react'; import { Meta } from '@storybook/react'; import { Choropleth, Props } from '../../src'; -import { ChoroplethOptions, DataFrame } from '@opendatasoft/visualizations'; +import { + DataFrame, + ChoroplethOptions, + ChoroplethShapeGeoJsonValue, + ChoroplethShapeVectorTilesValue, +} from '@opendatasoft/visualizations'; import { shapes, multiPolygonShapes } from './shapes'; import { IMAGES } from '../utils'; @@ -42,9 +47,11 @@ const StudioChoroplethArgs: Props = { ], }, options: { - style: {}, - parameters: {}, - shapes, + shapes: shapes as ChoroplethShapeGeoJsonValue, + emptyValueColor: 'red', + tooltip: { + label: () => 'Test', + }, aspectRatio: 1, }, }; @@ -60,9 +67,11 @@ const StudioChoroplethMultiPolygonArgs: Props = { ], }, options: { - style: {}, - parameters: {}, - shapes: multiPolygonShapes, + shapes: multiPolygonShapes as ChoroplethShapeGeoJsonValue, + emptyValueColor: 'red', + tooltip: { + label: () => 'Test', + }, aspectRatio: 1, }, }; @@ -78,10 +87,11 @@ const StudioChoroplethEmptyValueArgs: Props = { ], }, options: { - style: {}, - parameters: {}, - shapes, - emptyValueColor: '#f29d9d', + shapes: shapes as ChoroplethShapeGeoJsonValue, + emptyValueColor: 'red', + tooltip: { + label: () => 'Test', + }, aspectRatio: 1, }, }; @@ -98,9 +108,11 @@ const StudioChoroplethGradientArgs: Props = { ], }, options: { - style: {}, - parameters: {}, - shapes, + shapes: shapes as ChoroplethShapeGeoJsonValue, + emptyValueColor: 'red', + tooltip: { + label: () => 'Test', + }, colorsScale: { type: 'gradient', colors: { @@ -127,9 +139,11 @@ const StudioChoroplethPaletteArgs: Props = { ], }, options: { - style: {}, - parameters: {}, - shapes, + shapes: shapes as ChoroplethShapeGeoJsonValue, + emptyValueColor: 'red', + tooltip: { + label: () => 'Test', + }, colorsScale: { type: 'palette', colors: ['#bcf5f9', '#89c5fd', '#3a80ec', '#0229bf'], @@ -149,9 +163,8 @@ const StudioChoroplethCustomTooltipArgs: Props = { value: df, }, options: { - style: {}, - parameters: {}, - shapes, + shapes: shapes as ChoroplethShapeGeoJsonValue, + emptyValueColor: 'red', colorsScale: { type: 'palette', colors: ['#bcf5f9', '#89c5fd', '#3a80ec', '#0229bf'], @@ -179,9 +192,8 @@ const StudioChoroplethComplexTooltipArgs: Props = value: df, }, options: { - style: {}, - parameters: {}, - shapes, + shapes: shapes as ChoroplethShapeGeoJsonValue, + emptyValueColor: 'red', colorsScale: { type: 'palette', colors: ['#bcf5f9', '#89c5fd', '#3a80ec', '#0229bf'], @@ -216,9 +228,11 @@ const StudioChoroplethLongLabelsArgs: Props = { ], }, options: { - style: {}, - parameters: {}, - shapes, + shapes: shapes as ChoroplethShapeGeoJsonValue, + emptyValueColor: 'red', + tooltip: { + label: () => 'Test', + }, colorsScale: { type: 'palette', colors: ['#bcf5f9', '#89c5fd', '#3a80ec', '#1e03fd', '#0229bf'], @@ -230,3 +244,59 @@ const StudioChoroplethLongLabelsArgs: Props = { }, }; StudioChoroplethLongLabels.args = StudioChoroplethLongLabelsArgs; + + +export const StudioVectorTilesChoropleth = Template.bind({}); +const StudioVectorTilesChoroplethArgs: Props = { + data: { + loading: false, + value: [ + { x: '01', y: 10 }, + { x: '02', y: 2 }, + { x: '03', y: 30 }, + { x: '04', y: 4 }, + { x: '05', y: 50 }, + { x: '06', y: 6 }, + { x: '11', y: 100 }, + { x: '24', y: 8 }, + { x: '27', y: 90 }, + { x: '28', y: 10 }, + { x: '32', y: 110 }, + { x: '44', y: 12 }, + { x: '52', y: 130 }, + { x: '53', y: 14 }, + { x: '75', y: 150 }, + { x: '76', y: 16 }, + { x: '84', y: 170 }, + { x: '93', y: 18 }, + { x: '94', y: 190 }, + { x: '975', y: 20 }, + { x: '977', y: 210 }, + { x: '978', y: 22 }, + { x: '984', y: 230 }, + { x: '986', y: 24 }, + { x: '987', y: 250 }, + { x: '988', y: 26 }, + { x: '989', y: 270 }, + ], + }, + options: { + shapes: { + type: 'vtiles', + url: 'https://static.opendatasoft.com/vector-tiles/fr_40_region_2021/{z}/{x}/{y}.pbf', + } as ChoroplethShapeVectorTilesValue, + emptyValueColor: 'red', + tooltip: { + label: (feature) => `value: ${JSON.stringify(feature)}`, + }, + colorsScale: { + type: 'palette', + colors: ['#bcf5f9', '#89c5fd', '#3a80ec', '#1e03fd', '#0229bf'], + }, + aspectRatio: 1, + legend: { + title: 'I Am Legend', + }, + }, +}; +StudioVectorTilesChoropleth.args = StudioVectorTilesChoroplethArgs; diff --git a/packages/visualizations/src/components/Map/Choropleth.svelte b/packages/visualizations/src/components/Map/Choropleth.svelte index d5418cb2..b2f26835 100644 --- a/packages/visualizations/src/components/Map/Choropleth.svelte +++ b/packages/visualizations/src/components/Map/Choropleth.svelte @@ -8,7 +8,8 @@ import type { ColorsScale, DataBounds, Color } from '../types'; import MapRender from './MapRender.svelte'; import { BLANK } from './mapStyles'; - import { colorShapes, LIGHT_GREY, DARK_GREY } from './utils'; + import { colorShapes, mapKeyToColor } from './utils'; + import { DefaultColors } from './constants'; import type { ChoroplethDataValue, ChoroplethLayer, @@ -28,13 +29,11 @@ const defaultColorsScale: ColorsScale = { type: 'gradient', colors: { - start: LIGHT_GREY, - end: DARK_GREY, + start: DefaultColors.LightGrey, + end: DefaultColors.DarkGrey, }, }; - const defaultEmptyValueColor = '#cccccc'; - let aspectRatio: number; let renderTooltip: MapRenderTooltipFunction; let bbox: BBox; @@ -53,7 +52,7 @@ aspectRatio, activeShapes, interactive = defaultInteractive, - emptyValueColor = defaultEmptyValueColor, + emptyValueColor = DefaultColors.EmptyShape, } = options); // Choropleth is always display over a blank map, for readability purposes @@ -67,7 +66,11 @@ newShapes: ChoroplethShapeValue, newColorScale: ColorsScale ) { - if (newShapes.type === 'geojson' && !newShapes.geoJson) { + if ( + (newShapes.type === 'geojson' && !newShapes.geoJson) + || (newShapes.type === 'vtiles' && !newShapes.url) + || !values + ) { // We don't have everything we need yet return; } @@ -93,14 +96,43 @@ paint: { 'fill-color': ['get', 'color'], 'fill-opacity': 0.8, - 'fill-outline-color': '#fff', + 'fill-outline-color': DefaultColors.ShapeOutline, }, }; bbox = turfBbox(newShapes.geoJson); - } else { - // eslint-disable-next-line no-console - console.error('Unknown shapes type', newShapes.type); + } else if (newShapes.type === 'vtiles') { + dataBounds = { min: 1, max: 27 }; // FIXME: don't hardcode this + source = { + type: 'vector', + tiles: [newShapes.url], + }; + + const keyToColor = mapKeyToColor(values, newColorScale); + + const matchExpression = [ + 'match', + ['get', 'reg_code'], // FIXME: Don't hardcode the key + ]; + + Object.entries(keyToColor).forEach(e => matchExpression.push(...e)); + matchExpression.push(DefaultColors.EmptyShape); // Default fallback color + + layer = { + 'type': 'fill', + 'source-layer': 'fr_40_region_2021', // FIXME: Don't hardcode the source layer + 'layout': {}, + 'paint': { + 'fill-color': matchExpression, + 'fill-outline-color': DefaultColors.ShapeOutline, + 'fill-opacity': [ + 'case', + ['boolean', ['feature-state', 'hover'], false], + 1, + 0.5, + ], + } + }; } } diff --git a/packages/visualizations/src/components/Map/MapRender.svelte b/packages/visualizations/src/components/Map/MapRender.svelte index 32ad16d9..3ac7060c 100644 --- a/packages/visualizations/src/components/Map/MapRender.svelte +++ b/packages/visualizations/src/components/Map/MapRender.svelte @@ -2,7 +2,7 @@