Skip to content

Commit

Permalink
feat(deckgl-map): add tile server layer support
Browse files Browse the repository at this point in the history
In the DeckGL map plugin we can only select a Mapbox style from the [predefined list](https://github.com/apache/superset/blob/2499a1cf5a7f298c1ee2f34b3d67ca1d18bb7457/superset-frontend/plugins/legacy-preset-chart-deckgl/src/utilities/Shared_DeckGL.jsx#L373-L380) or [typing a new Mapbox style URL](#26031).

This change add support for tile server layer making use of Deck.gl [TileLayer](https://deck.gl/docs/api-reference/geo-layers/tile-layer).
The well known OpenStreeMap layer provided by https://[abc].tile.openstreetmap.org/{z}/{x}/{y}.png is added to the list making easier for users not having a Mapbox account to have a background layer on map charts.

It has been tested with other tile server URL eg. tile://https://tile.osm.ch/name-it/{z}/{x}/{y}.png
  • Loading branch information
fxprunayre committed Mar 12, 2024
1 parent 2a5b5fe commit 2aec87e
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,20 @@ import { t } from '../translation';

/**
* Validate a [Mapbox styles URL](https://docs.mapbox.com/help/glossary/style-url/)
* or a tile server URL
* @param v
*/
export default function validateMapboxStylesUrl(v: unknown) {
if (
typeof v === 'string' &&
v.trim().length > 0 &&
v.trim().startsWith('mapbox://styles/')
(v.trim().startsWith('mapbox://styles/') ||
v.trim().startsWith('tile://http'))
) {
return false;
}

return t('is expected to be a Mapbox URL');
return t(
'is expected to be a Mapbox URL (eg. mapbox://styles/...) or a tile server URL (eg. tile://http...)',
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ describe('validateMapboxStylesUrl', () => {
'mapbox://styles/foobar/clp2dr5r4008a01pcg4ad45m8',
),
).toEqual(false);
expect(
validateMapboxStylesUrl(
'tile://https://c.tile.openstreetmap.org/{z}/{x}/{y}.png',
),
).toEqual(false);
});

[
Expand All @@ -40,7 +45,7 @@ describe('validateMapboxStylesUrl', () => {
].forEach(value => {
it(`should not validate ${value}`, () => {
expect(validateMapboxStylesUrl(value)).toEqual(
'is expected to be a Mapbox URL',
'is expected to be a Mapbox URL (eg. mapbox://styles/...) or a tile server URL (eg. tile://http...)',
);
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"lib"
],
"dependencies": {
"@deck.gl/geo-layers": "^8.8.27",
"@deck.gl/layers": "^8.8.27",
"@mapbox/geojson-extent": "^1.0.1",
"@math.gl/web-mercator": "^3.2.2",
"@types/d3-array": "^2.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ import { JsonObject, JsonValue, styled, usePrevious } from '@superset-ui/core';
import Tooltip, { TooltipProps } from './components/Tooltip';
import 'mapbox-gl/dist/mapbox-gl.css';
import { Viewport } from './utils/fitViewport';
import {
buildTileLayer,
TILE_LAYER_PREFIX,
MAPBOX_LAYER_PREFIX,
} from './utils';

const TICK = 250; // milliseconds

Expand Down Expand Up @@ -98,6 +103,11 @@ export const DeckGLContainer = memo(
) as Layer[];
}

if (props.mapStyle?.startsWith(TILE_LAYER_PREFIX)) {
props.layers.unshift(
buildTileLayer(props.mapStyle.replace(TILE_LAYER_PREFIX, '')),
);
}
return props.layers as Layer[];
}, [props.layers]);

Expand All @@ -115,11 +125,28 @@ export const DeckGLContainer = memo(
glOptions={{ preserveDrawingBuffer: true }}
onViewStateChange={onViewStateChange}
>
<StaticMap
preserveDrawingBuffer
mapStyle={props.mapStyle || 'light'}
mapboxApiAccessToken={props.mapboxApiAccessToken}
/>
{props.mapStyle?.startsWith(MAPBOX_LAYER_PREFIX) && (
<StaticMap
preserveDrawingBuffer
mapStyle={props.mapStyle || 'light'}
mapboxApiAccessToken={props.mapboxApiAccessToken}
/>
)}
{props.mapStyle?.indexOf('openstreetmap') !== -1 && (
<div
style={{
position: 'absolute',
left: 0,
bottom: 0,
backgroundColor: 'hsla(0,0%,100%,.5)',
padding: '0 5px',
}}
>
<a href="http://www.openstreetmap.org/copyright">
© OpenStreetMap contributors
</a>
</div>
)}
</DeckGL>
{children}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,10 +380,14 @@ export const mapboxStyle = {
['mapbox://styles/mapbox/satellite-streets-v9', t('Satellite Streets')],
['mapbox://styles/mapbox/satellite-v9', t('Satellite')],
['mapbox://styles/mapbox/outdoors-v9', t('Outdoors')],
[
'tile://https://c.tile.openstreetmap.org/{z}/{x}/{y}.png',
t('OpenStreetMap'),
],
],
default: 'mapbox://styles/mapbox/light-v9',
description: t(
'Base layer map style. See Mapbox documentation: %s',
'Mapbox base layer map style (see Mapbox documentation: %s) or tile server URL.',
'https://docs.mapbox.com/help/glossary/style-url/',
),
},
Expand Down
26 changes: 26 additions & 0 deletions superset-frontend/plugins/legacy-preset-chart-deckgl/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ import {
SequentialScheme,
} from '@superset-ui/core';
import { isNumber } from 'lodash';
import { TileLayer, BitmapLayer } from 'deck.gl/typed';
import { hexToRGB } from './utils/colors';

const DEFAULT_NUM_BUCKETS = 10;

export const TILE_LAYER_PREFIX = 'tile://';
export const MAPBOX_LAYER_PREFIX = 'mapbox://';

export type Buckets = {
break_points: string[];
num_buckets: string;
Expand Down Expand Up @@ -188,3 +192,25 @@ export function getBuckets(

return buckets;
}

export function buildTileLayer(url: string) {
return new TileLayer({
data: url,

minZoom: 0,
maxZoom: 19,
tileSize: 256,

renderSubLayers: props => {
const {
bbox: { west, south, east, north },
} = props.tile;

return new BitmapLayer(props, {
data: null,
image: props.data,
bounds: [west, south, east, north],
});
},
});
}

0 comments on commit 2aec87e

Please sign in to comment.