Skip to content

Commit 454177c

Browse files
committed
feat(deckgl): make map tiles configurable
1 parent 0cd3a12 commit 454177c

File tree

9 files changed

+22790
-20912
lines changed

9 files changed

+22790
-20912
lines changed

superset-frontend/package-lock.json

Lines changed: 22655 additions & 20888 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

superset-frontend/packages/superset-ui-core/src/validator/validateMapboxStylesUrl.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,20 @@ import { t } from '../translation';
2121

2222
/**
2323
* Validate a [Mapbox styles URL](https://docs.mapbox.com/help/glossary/style-url/)
24+
* or a title server URL.
2425
* @param v
2526
*/
2627
export default function validateMapboxStylesUrl(v: unknown) {
2728
if (
2829
typeof v === 'string' &&
2930
v.trim().length > 0 &&
30-
v.trim().startsWith('mapbox://styles/')
31+
(v.trim().startsWith('mapbox://styles/') ||
32+
v.trim().startsWith('tile://http'))
3133
) {
3234
return false;
3335
}
3436

35-
return t('is expected to be a Mapbox URL');
37+
return t(
38+
'is expected to be a Mapbox URL (eg. mapbox://styles/...) or a tile server URL (eg. tile://http...)',
39+
);
3640
}

superset-frontend/packages/superset-ui-core/test/validator/validateMapboxStylesUrl.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ describe('validateMapboxStylesUrl', () => {
2929
'mapbox://styles/foobar/clp2dr5r4008a01pcg4ad45m8',
3030
),
3131
).toEqual(false);
32+
expect(
33+
validateMapboxStylesUrl(
34+
'tile://https://c.tile.openstreetmap.org/{z}/{x}/{y}.png',
35+
),
36+
).toEqual(false);
3237
});
3338

3439
[
@@ -40,7 +45,7 @@ describe('validateMapboxStylesUrl', () => {
4045
].forEach(value => {
4146
it(`should not validate ${value}`, () => {
4247
expect(validateMapboxStylesUrl(value)).toEqual(
43-
'is expected to be a Mapbox URL',
48+
'is expected to be a Mapbox URL (eg. mapbox://styles/...) or a tile server URL (eg. tile://http...)',
4449
);
4550
});
4651
});

superset-frontend/plugins/legacy-preset-chart-deckgl/package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@
2424
"lib"
2525
],
2626
"dependencies": {
27-
"@deck.gl/aggregation-layers": "^9.0.38",
28-
"@deck.gl/core": "^9.0.37",
29-
"@deck.gl/layers": "^9.0.38",
30-
"@deck.gl/react": "^9.1.4",
27+
"@deck.gl/aggregation-layers": "^9.1.9",
28+
"@deck.gl/core": "^9.1.9",
29+
"@deck.gl/geo-layers": "^9.1.9",
30+
"@deck.gl/layers": "^9.1.9",
31+
"@deck.gl/react": "^9.1.9",
3132
"@mapbox/geojson-extent": "^1.0.1",
3233
"@math.gl/web-mercator": "^4.1.0",
3334
"@types/d3-array": "^2.0.0",

superset-frontend/plugins/legacy-preset-chart-deckgl/src/DeckGLContainer.tsx

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ import { JsonObject, JsonValue, styled, usePrevious } from '@superset-ui/core';
3737
import Tooltip, { TooltipProps } from './components/Tooltip';
3838
import 'mapbox-gl/dist/mapbox-gl.css';
3939
import { Viewport } from './utils/fitViewport';
40+
import {
41+
MAPBOX_LAYER_PREFIX,
42+
TILE_LAYER_PREFIX,
43+
buildTileLayer,
44+
} from './utils';
4045

4146
const TICK = 250; // milliseconds
4247

@@ -92,6 +97,19 @@ export const DeckGLContainer = memo(
9297
);
9398

9499
const layers = useCallback(() => {
100+
if (
101+
props.mapStyle?.startsWith(TILE_LAYER_PREFIX) &&
102+
props.layers.some(
103+
l => typeof l !== 'function' && l?.id === 'tile-layer',
104+
) === false
105+
) {
106+
props.layers.unshift(
107+
buildTileLayer(
108+
props.mapStyle.replace(TILE_LAYER_PREFIX, ''),
109+
'tile-layer',
110+
),
111+
);
112+
}
95113
// Support for layer factory
96114
if (props.layers.some(l => typeof l === 'function')) {
97115
return props.layers.map(l =>
@@ -100,7 +118,7 @@ export const DeckGLContainer = memo(
100118
}
101119

102120
return props.layers as Layer[];
103-
}, [props.layers]);
121+
}, [props.layers, props.mapStyle]);
104122

105123
const { children = null, height, width } = props;
106124

@@ -115,11 +133,13 @@ export const DeckGLContainer = memo(
115133
viewState={viewState}
116134
onViewStateChange={onViewStateChange}
117135
>
118-
<StaticMap
119-
preserveDrawingBuffer
120-
mapStyle={props.mapStyle || 'light'}
121-
mapboxApiAccessToken={props.mapboxApiAccessToken}
122-
/>
136+
{props.mapStyle?.startsWith(MAPBOX_LAYER_PREFIX) && (
137+
<StaticMap
138+
preserveDrawingBuffer
139+
mapStyle={props.mapStyle || 'light'}
140+
mapboxApiAccessToken={props.mapboxApiAccessToken}
141+
/>
142+
)}
123143
</DeckGL>
124144
{children}
125145
</div>

superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,28 @@ import {
2929
import { D3_FORMAT_OPTIONS, sharedControls } from '@superset-ui/chart-controls';
3030
import { columnChoices, PRIMARY_COLOR } from './controls';
3131

32+
let deckglTiles;
33+
34+
export const DEFAULT_DECKGL_TILES = [
35+
['mapbox://styles/mapbox/streets-v9', 'Streets'],
36+
['mapbox://styles/mapbox/dark-v9', 'Dark'],
37+
['mapbox://styles/mapbox/light-v9', 'Light'],
38+
['mapbox://styles/mapbox/satellite-streets-v9', 'Satellite Streets'],
39+
['mapbox://styles/mapbox/satellite-v9', 'Satellite'],
40+
['mapbox://styles/mapbox/outdoors-v9', 'Outdoors'],
41+
];
42+
43+
const getDeckGLTiles = () => {
44+
if (!deckglTiles) {
45+
const appContainer = document.getElementById('app');
46+
const { common } = JSON.parse(
47+
appContainer?.getAttribute('data-bootstrap') || '{}',
48+
);
49+
deckglTiles = common?.deckgl_tiles ?? DEFAULT_DECKGL_TILES;
50+
}
51+
return deckglTiles;
52+
};
53+
3254
const DEFAULT_VIEWPORT = {
3355
longitude: 6.85236157047845,
3456
latitude: 31.222656842808707,
@@ -372,17 +394,10 @@ export const mapboxStyle = {
372394
renderTrigger: true,
373395
freeForm: true,
374396
validators: [validateMapboxStylesUrl],
375-
choices: [
376-
['mapbox://styles/mapbox/streets-v9', t('Streets')],
377-
['mapbox://styles/mapbox/dark-v9', t('Dark')],
378-
['mapbox://styles/mapbox/light-v9', t('Light')],
379-
['mapbox://styles/mapbox/satellite-streets-v9', t('Satellite Streets')],
380-
['mapbox://styles/mapbox/satellite-v9', t('Satellite')],
381-
['mapbox://styles/mapbox/outdoors-v9', t('Outdoors')],
382-
],
383-
default: 'mapbox://styles/mapbox/light-v9',
397+
choices: getDeckGLTiles(),
398+
default: getDeckGLTiles()[0][0],
384399
description: t(
385-
'Base layer map style. See Mapbox documentation: %s',
400+
'Mapbox base layer map style (see Mapbox documentation: %s) or tile server URL.',
386401
'https://docs.mapbox.com/help/glossary/style-url/',
387402
),
388403
},

superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@ import {
2525
QueryFormData,
2626
SequentialScheme,
2727
} from '@superset-ui/core';
28+
import { GeoBoundingBox, TileLayer } from '@deck.gl/geo-layers';
29+
import { BitmapLayer, PathLayer } from '@deck.gl/layers';
2830
import { hexToRGB } from './utils/colors';
2931

3032
const DEFAULT_NUM_BUCKETS = 10;
3133

34+
export const MAPBOX_LAYER_PREFIX = 'mapbox://';
35+
export const TILE_LAYER_PREFIX = 'tile://';
36+
3237
export type Buckets = {
3338
break_points: string[];
3439
num_buckets: string;
@@ -190,3 +195,42 @@ export function getBuckets(
190195

191196
return buckets;
192197
}
198+
199+
export function buildTileLayer(url: string, id: string) {
200+
interface TileLayerProps {
201+
id: string;
202+
data: string;
203+
minZoom: number;
204+
maxZoom: number;
205+
tileSize: number;
206+
renderSubLayers: (props: any) => (BitmapLayer | PathLayer)[];
207+
}
208+
209+
interface RenderSubLayerProps {
210+
tile: {
211+
bbox: GeoBoundingBox;
212+
};
213+
data: any;
214+
}
215+
216+
return new TileLayer({
217+
data: url,
218+
id,
219+
minZoom: 0,
220+
maxZoom: 19,
221+
tileSize: 256,
222+
223+
renderSubLayers: (props: RenderSubLayerProps): BitmapLayer[] => {
224+
const { west, north, east, south } = props.tile.bbox as GeoBoundingBox;
225+
226+
// Ajouter une BitmapLayer
227+
const bitmapLayer = new BitmapLayer(props, {
228+
data: undefined,
229+
image: props.data,
230+
bounds: [west, south, east, north],
231+
});
232+
233+
return [bitmapLayer];
234+
},
235+
} as TileLayerProps);
236+
}

superset/config.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,27 @@ class D3Format(TypedDict, total=False):
418418
D3_FORMAT: D3Format = {}
419419

420420

421+
# Override the default mapbox tiles
422+
# Default values are equivalent to
423+
# DECKGL_BASE_MAP = [
424+
# ['mapbox://styles/mapbox/streets-v9', 'Streets'],
425+
# ['mapbox://styles/mapbox/dark-v9', 'Dark'],
426+
# ['mapbox://styles/mapbox/light-v9', 'Light'],
427+
# ['mapbox://styles/mapbox/satellite-streets-v9', 'Satellite Streets'],
428+
# ['mapbox://styles/mapbox/satellite-v9', 'Satellite'],
429+
# ['mapbox://styles/mapbox/outdoors-v9', 'Outdoors'],
430+
# ]
431+
# for adding your own map tiles, you can use the following format:
432+
# - tile:// + your_personal_url or openstreetmap_url
433+
# example:
434+
# DECKGL_BASE_MAP = [
435+
# ['tile://https://c.tile.openstreetmap.org/{z}/{x}/{y}.png', 'OpenStreetMap']
436+
# ]
437+
# Enable CORS and set map url in origins option.
438+
# Add also map url in connect-src of TALISMAN_CONFIG variable
439+
DECKGL_BASE_MAP: list[list[str, str]] = None
440+
441+
421442
# Override the default d3 locale for time format
422443
# Default values are equivalent to
423444
# D3_TIME_FORMAT = {
@@ -821,7 +842,7 @@ class D3TimeFormat(TypedDict, total=False):
821842

822843
# CORS Options
823844
# NOTE: enabling this requires installing the cors-related python dependencies
824-
# `pip install .[cors]` or `pip install apache_superset[cors]`, depending
845+
# `pip install .[cors]` or `pip install apache-superset[cors]`, depending
825846
ENABLE_CORS = False
826847
CORS_OPTIONS: dict[Any, Any] = {}
827848

superset/views/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ def cached_common_bootstrap_data( # pylint: disable=unused-argument
337337
"d3_format": conf.get("D3_FORMAT"),
338338
"d3_time_format": conf.get("D3_TIME_FORMAT"),
339339
"currencies": conf.get("CURRENCIES"),
340+
"deckgl_tiles": conf.get("DECKGL_BASE_MAP"),
340341
"feature_flags": get_feature_flags(),
341342
"extra_sequential_color_schemes": conf["EXTRA_SEQUENTIAL_COLOR_SCHEMES"],
342343
"extra_categorical_color_schemes": conf["EXTRA_CATEGORICAL_COLOR_SCHEMES"],

0 commit comments

Comments
 (0)