Skip to content

Commit

Permalink
support visibleLayerGroups in carto styles
Browse files Browse the repository at this point in the history
  • Loading branch information
zbigg committed May 6, 2024
1 parent 173c2a4 commit f8ec0c8
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 16 deletions.
21 changes: 11 additions & 10 deletions modules/carto/src/api/basemap.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import {cartoBasemapsBaseUrl} from '../basemap';
import {getCartoBasemapStyle} from '../basemap';
import {KeplerMapConfig} from './types';

const CUSTOM_STYLE_ID_PREFIX = 'custom:';
const DEFAULT_CARTO_STYLE = 'positron';
const CARTO_MAP_STYLES = ['positron', 'dark-matter', 'voyager'];
const CARTO_MAP_ATRRIBUTION = `© <a href="https://carto.com/about-carto/" target="_blank" rel="noopener noreferrer">CARTO</a>, ©
<a href="http://www.openstreetmap.org/copyright" target="_blank" rel="noopener noreferrer">OpenStreetMap</a> contributors`;

export function getBasemapSettings(config: KeplerMapConfig) {
type BasemapProps = {
style: string | unknown;
attribution?: string;
};

export async function getBasemapProps(config: KeplerMapConfig): Promise<BasemapProps | null> {
const {mapStyle} = config;
const styleType = mapStyle.styleType || DEFAULT_CARTO_STYLE;
if (styleType.startsWith('custom:')) {
if (styleType.startsWith(CUSTOM_STYLE_ID_PREFIX)) {
const currentCustomStyle = config.customBaseMaps?.customStyle;
if (currentCustomStyle) {
return {
Expand All @@ -19,12 +23,9 @@ export function getBasemapSettings(config: KeplerMapConfig) {
}
}
if (CARTO_MAP_STYLES.includes(styleType)) {
const {label} = mapStyle.visibleLayerGroups;
const labelSuffix = label ? '' : '-nolabels';
const styleUrl = `${cartoBasemapsBaseUrl}${styleType}${labelSuffix}-gl-style/style.json`;
const {visibleLayerGroups} = mapStyle;
return {
style: styleUrl,
attribution: CARTO_MAP_ATRRIBUTION
style: await getCartoBasemapStyle({styleType, visibleLayerGroups})
};
}
return null;
Expand Down
12 changes: 9 additions & 3 deletions modules/carto/src/api/fetch-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {parseMap} from './parse-map';
import {requestWithParameters} from './request-with-parameters';
import {assert} from '../utils';
import type {APIErrorContext, Format, MapType, QueryParameters} from './types';
import {getBasemapProps} from './basemap';

type Dataset = {
id: string;
Expand Down Expand Up @@ -272,12 +273,17 @@ export async function fetchMap({
}
});

// Mutates map.datasets so that dataset.data contains data
await fillInMapDatasets(map, clientId, apiBaseUrl, headers);
const [basemap] = await Promise.all([
getBasemapProps(map.keplerMapConfig.config),

// Mutates map.datasets so that dataset.data contains data
fillInMapDatasets(map, clientId, apiBaseUrl, headers)
]);

// Mutates attributes in visualChannels to contain tile stats
await fillInTileStats(map, apiBaseUrl);
const out = {...parseMap(map), ...{stopAutoRefresh}};

const out = {...parseMap(map), basemap, ...{stopAutoRefresh}};

const textLayers = out.layers.filter(layer => {
const pointType = layer.props.pointType || '';
Expand Down
2 changes: 0 additions & 2 deletions modules/carto/src/api/parse-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import PointLabelLayer from '../layers/point-label-layer';
import {CollisionFilterExtension} from '@deck.gl/extensions';
import {assert} from '../utils';
import {KeplerMapConfig, MapDataset, MapLayerConfig, VisualChannels} from './types';
import {getBasemapSettings} from './basemap';

const collisionFilterExtension = new CollisionFilterExtension();

Expand All @@ -35,7 +34,6 @@ export function parseMap(json) {
updatedAt: json.updatedAt,
initialViewState: mapState,
mapStyle,
basemap: getBasemapSettings(keplerMapConfig.config),
token,
layers: layers.reverse().map(({id, type, config, visualChannels}) => {
try {
Expand Down
91 changes: 91 additions & 0 deletions modules/carto/src/basemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,97 @@ export const cartoBasemapsBaseUrl = 'https://basemaps.cartocdn.com/gl';

const baseUrl = `${cartoBasemapsBaseUrl}/{basemap}-gl-style/style.json`;

export const cartoStyleLayerGroups = [
{
slug: 'label',
filter: ({id}: {id: string}) =>
Boolean(
id.match(/(?=(label|_label|place-|place_|poi-|poi_|watername_|roadname_|housenumber))/)
),
defaultVisibility: true
},
{
slug: 'road',
filter: ({id}: {id: string}) =>
Boolean(id.match(/(?=(road|railway|tunnel|street|bridge))(?!.*label)/)),
defaultVisibility: true
},
{
slug: 'border',
filter: ({id}: {id: string}) => Boolean(id.match(/border|boundaries|boundary_/)),
defaultVisibility: false
},
{
slug: 'building',
filter: ({id}: {id: string}) => Boolean(id.match(/building/)),
defaultVisibility: true
},
{
slug: 'water',
filter: ({id}: {id: string}) => Boolean(id.match(/(?=(water|stream|ferry))/)),
defaultVisibility: true
},
{
slug: 'land',
filter: ({id}: {id: string}) =>
Boolean(id.match(/(?=(parks|landcover|industrial|sand|hillshade|park_))/)),
defaultVisibility: true
}
];

export function applyCartoLayerGroupFilters(style, visibleLayerGroups: Record<string, boolean>) {
if (!Array.isArray(style?.layers)) {
return style;
}

const visibleFilters = cartoStyleLayerGroups
.filter(lg => visibleLayerGroups[lg.slug])
.map(lg => lg.filter);

const filteredLayers = style.layers.filter(layer => visibleFilters.some(match => match(layer)));

return {
...style,
layers: filteredLayers
};
}

function someLayersFilteredOut(visibleLayerGroups?: Record<string, boolean>) {
return (
visibleLayerGroups &&
Object.values(visibleLayerGroups).some(filteredOut => filteredOut === false)
);
}

export async function getCartoBasemapStyle({
styleType,
visibleLayerGroups
}: {
styleType: string;
visibleLayerGroups?: Record<string, boolean>;
}) {
/* global fetch, console */
const styleUrl = `${cartoBasemapsBaseUrl}/${styleType}-gl-style/style.json`;
let style = styleUrl;

if (visibleLayerGroups && someLayersFilteredOut(visibleLayerGroups)) {
try {
const originalStyle = await fetch(styleUrl, {
mode: 'cors',
credentials: 'omit'
}).then(res => res.json());
style = applyCartoLayerGroupFilters(originalStyle, visibleLayerGroups);
} catch (error) {
// eslint-disable-next-line no-console
console.error(
'Error fetching CARTO basemap style, falling back to not-filtered style',
error
);
}
}
return style;
}

export default {
VOYAGER: baseUrl.replace('{basemap}', 'voyager'),
POSITRON: baseUrl.replace('{basemap}', 'positron'),
Expand Down
6 changes: 5 additions & 1 deletion modules/carto/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ export {
VectorTileLayer
};

export {default as BASEMAP} from './basemap';
export {
default as BASEMAP,
getCartoBasemapStyle as _getCartoBasemapStyle,
cartoStyleLayerGroups as _cartoStyleLayerGroups
} from './basemap';
export {default as colorBins} from './style/color-bins-style';
export {default as colorCategories} from './style/color-categories-style';
export {default as colorContinuous} from './style/color-continuous-style';
Expand Down

0 comments on commit f8ec0c8

Please sign in to comment.