diff --git a/components/src/maplibre/MapStyle/SWRDataLabDark.stories.svelte b/components/src/maplibre/MapStyle/SWRDataLabDark.stories.svelte index 804758df..c9b9d14d 100644 --- a/components/src/maplibre/MapStyle/SWRDataLabDark.stories.svelte +++ b/components/src/maplibre/MapStyle/SWRDataLabDark.stories.svelte @@ -9,7 +9,6 @@ import { SWRDataLabDark, SWRDataLabLight } from './index'; import locations from './storyLocations'; import NavigationControl from '../NavigationControl/NavigationControl.svelte'; - import { type RoadLabelDensity } from './types'; const { Story } = defineMeta({ title: 'Maplibre/Style/SWR Data Lab Dark', @@ -51,7 +50,7 @@
+ + + +
+ {#each ['default'] as s} +
+ {s} + + + +
+ {/each} +
+
+
+
diff --git a/components/src/maplibre/MapStyle/SWRDataLabDark.ts b/components/src/maplibre/MapStyle/SWRDataLabDark.ts index bb855197..79a29d06 100644 --- a/components/src/maplibre/MapStyle/SWRDataLabDark.ts +++ b/components/src/maplibre/MapStyle/SWRDataLabDark.ts @@ -54,7 +54,7 @@ const tokens: styleTokens = { }; const { landuse } = makeLanduse(tokens); -const { placeLabels, boundaryLabels } = makePlaceLabels(tokens); +const { placeLabels, boundaryLabels, placeDots } = makePlaceLabels(tokens, {}); const { airports, transitBridges, transitSurface, transitTunnels } = makeTransit(tokens); const { walkingLabels, walkingTunnels, walkingSurface, walkingBridges } = makeWalking(tokens); const { roadBridges, roadSurface, roadTunnels } = makeRoads(tokens); @@ -158,6 +158,7 @@ const style: styleFunction = (opts) => { // 10. Point labels ...(options.places?.showLabels ? placeLabels : []), + ...(options.places?.showLabels ? placeDots : []), // 11. Admin boundary labels ...(options.admin?.showLabels ? boundaryLabels : []) diff --git a/components/src/maplibre/MapStyle/SWRDataLabLight.stories.svelte b/components/src/maplibre/MapStyle/SWRDataLabLight.stories.svelte index c052e977..04632c12 100644 --- a/components/src/maplibre/MapStyle/SWRDataLabLight.stories.svelte +++ b/components/src/maplibre/MapStyle/SWRDataLabLight.stories.svelte @@ -50,7 +50,7 @@
{ // 10. Point labels ...(options.places?.showLabels ? placeLabels : []), - + ...(options.places?.showLabels ? placeDots : []), // 11. Admin boundary labels ...(options.admin?.showLabels ? boundaryLabels : []) ] diff --git a/components/src/maplibre/MapStyle/components/Hillshade.ts b/components/src/maplibre/MapStyle/components/Hillshade.ts index cb609ae0..54136105 100644 --- a/components/src/maplibre/MapStyle/components/Hillshade.ts +++ b/components/src/maplibre/MapStyle/components/Hillshade.ts @@ -5,6 +5,7 @@ export default function makeHillshade(tokens: styleTokens): any { { id: 'hillshade', type: 'hillshade', + maxzoom: 13, source: 'versatiles-elevation', paint: { 'hillshade-exaggeration': 0.05, diff --git a/components/src/maplibre/MapStyle/components/PlaceLabels.ts b/components/src/maplibre/MapStyle/components/PlaceLabels.ts index bce54300..dc18c1e7 100644 --- a/components/src/maplibre/MapStyle/components/PlaceLabels.ts +++ b/components/src/maplibre/MapStyle/components/PlaceLabels.ts @@ -1,18 +1,18 @@ -import type { SymbolLayerSpecification } from 'maplibre-gl'; +import type { CircleLayerSpecification, SymbolLayerSpecification } from 'maplibre-gl'; import type { styleTokens } from '../../types'; // Hand-authored list of place labes we want to show at low zoom levels // Ideally majorCities would include Frankfurt and Leipzig, but they're not // state capitals so they're not available in the versatiles data until z6 -const majorCities = ['Berlin', 'Stuttgart', 'München', 'Frankfurt', 'Hamburg', 'Mainz']; +const majorCities = ['Berlin', 'Stuttgart', 'München', 'Hamburg', 'Mainz', 'Nürnberg']; // For smaller cities we use the population field to derive our hierarchy, // though that's limited by the fact that versatiles hard-codes population // values for "city" and anything below. // See: https://github.com/versatiles-org/shortbread-tilemaker/blob/69e5d4c586a1d2726b746a24829bfb05d4dbeb91/process.lua#L198-L242 -export default function makePlaceLabels(tokens: styleTokens) { +export default function makePlaceLabels(tokens: styleTokens, options) { const placeLabels: SymbolLayerSpecification[] = [ { id: 'label-place-quarter', @@ -42,7 +42,7 @@ export default function makePlaceLabels(tokens: styleTokens) { ['in', 'kind', 'suburb', 'village', 'hamlet', 'town'], ['<', 'population', 2000] ], - minzoom: 13.5, + minzoom: 12, layout: { 'text-font': tokens.sans_regular, 'text-size': { @@ -50,10 +50,11 @@ export default function makePlaceLabels(tokens: styleTokens) { [13, 13], [16, 17] ] - } + }, + 'text-max-width': 8 }, paint: { - 'text-color': tokens.label_secondary, + 'text-color': tokens.label_tertiary, 'text-halo-color': tokens.background } }, @@ -63,39 +64,43 @@ export default function makePlaceLabels(tokens: styleTokens) { 'all', ['in', 'kind', 'suburb', 'village', 'hamlet', 'town'], ['>=', 'population', 2000], - ['<', 'population', 15_000] + ['<', 'population', 10_000] ], - minzoom: 12, + minzoom: 10, layout: { 'text-font': tokens.sans_regular, + 'text-max-width': 8, 'text-size': { stops: [ - [13, 14], - [16, 18] + [10, 12], + [16, 14] ] } }, paint: { - 'text-color': tokens.label_secondary, - 'text-halo-color': tokens.background + 'text-color': tokens.label_tertiary } }, { id: 'label-place-town', filter: [ 'all', - ['in', 'kind', 'village', 'hamlet', 'town'], - ['<', 'population', 50_000], - ['>', 'population', 15_000] + ['in', 'kind', 'suburb', 'village', 'hamlet', 'town'], + ['>', 'population', 10_000], + ['<', 'population', 50_000] ], - minzoom: 10, + minzoom: 9, layout: { + 'text-max-width': 8, 'text-size': { stops: [ - [10, 14], - [12, 16] + [8, 12], + [12, 15] ] } + }, + paint: { + 'text-color': tokens.label_secondary } }, @@ -108,14 +113,14 @@ export default function makePlaceLabels(tokens: styleTokens) { ['<', 'population', 100_000], ['!in', 'name', ...majorCities] ], - minzoom: 8.5, + minzoom: 8, maxzoom: 13, - layout: { + 'text-max-width': 8, 'text-size': { stops: [ - [8, 14], - [12, 18] + [8, 13], + [12, 16] ] } } @@ -130,13 +135,16 @@ export default function makePlaceLabels(tokens: styleTokens) { ['<', 'population', 400_000], ['!in', 'name', ...majorCities] ], - minzoom: 7.5, + minzoom: 7, maxzoom: 13, layout: { + 'text-variable-anchor': ['bottom', 'bottom-left', 'bottom-right', 'right', 'left'], + 'text-offset': [0.3, 0.4], + 'text-max-width': 10, 'text-size': { stops: [ [7, 13], - [13, 17] + [13, 18] ] } } @@ -147,14 +155,24 @@ export default function makePlaceLabels(tokens: styleTokens) { 'all', ['in', 'kind', 'city', 'town', 'state_capital'], ['>', 'population', 400_000], - ['!in', 'name', ...majorCities] + ['!in', 'name', ...majorCities, 'Frankfurt am Main'] ], minzoom: 7, maxzoom: 12, layout: { + 'text-variable-anchor': [ + 'bottom', + 'bottom-left', + 'top-right', + 'top-left', + 'bottom-right', + 'right', + 'left' + ], + 'text-offset': [0.2, 0.35], 'text-size': { stops: [ - [7, 15], + [7, 14], [15, 20] ] } @@ -169,12 +187,36 @@ export default function makePlaceLabels(tokens: styleTokens) { minzoom: 5.5, maxzoom: 12, layout: { + 'text-variable-anchor': ['bottom', 'bottom-right', 'right', 'left'], + 'text-offset': [0.4, 0.4], 'text-size': { stops: [ - [7, 14], - [15, 25] + [7, 16], + [15, 26] ] - } + }, + 'text-font': tokens.sans_medium + }, + paint: { + 'text-color': tokens.label_secondary + } + }, + { + id: 'label-place-frankfurt', + filter: ['==', 'name', 'Frankfurt am Main'], + minzoom: 5.5, + maxzoom: 12, + layout: { + 'text-variable-anchor': ['bottom', 'bottom-right', 'right', 'left'], + 'text-offset': [0.4, 0.4], + 'text-field': 'Frankfurt', + 'text-size': { + stops: [ + [7, 15], + [15, 26] + ] + }, + 'text-font': tokens.sans_medium }, paint: { 'text-color': tokens.label_secondary @@ -200,7 +242,47 @@ export default function makePlaceLabels(tokens: styleTokens) { 'text-halo-blur': 0.5, ...el.paint } - } as SymbolLayerSpecification; + }; + }); + + const placeDots: CircleLayerSpecification[] = [ + { + id: 'place-dots-minor', + minzoom: 7, + maxzoom: 13, + filter: [ + 'all', + ['in', 'kind', 'city', 'town'], + ['>', 'population', 100_000], + ['<', 'population', 400_000], + ['!in', 'name', ...majorCities] + ], + layout: {}, + paint: { + 'circle-radius': 2, + 'circle-stroke-color': tokens.background, + 'circle-color': tokens.label_tertiary + } + }, + { + id: 'place-dots-major', + filter: ['in', 'name', ...majorCities, 'Frankfurt am Main'], + minzoom: 5.5, + maxzoom: 12, + layout: {}, + paint: { + 'circle-radius': ['interpolate', ['linear'], ['zoom'], 5, 2, 10, 3], + 'circle-stroke-color': tokens.background, + 'circle-color': tokens.label_secondary + } + } + ].map((el) => { + return { + type: 'circle', + source: 'versatiles-osm', + 'source-layer': 'place_labels', + ...el + } as CircleLayerSpecification; }); const boundaryLabels = [ @@ -236,5 +318,5 @@ export default function makePlaceLabels(tokens: styleTokens) { } as SymbolLayerSpecification; }); - return { placeLabels, boundaryLabels }; + return { placeLabels, boundaryLabels, placeDots }; } diff --git a/components/src/maplibre/MapStyle/components/RoadLabels.ts b/components/src/maplibre/MapStyle/components/RoadLabels.ts index 84a4b64e..526ddb95 100644 --- a/components/src/maplibre/MapStyle/components/RoadLabels.ts +++ b/components/src/maplibre/MapStyle/components/RoadLabels.ts @@ -1,8 +1,8 @@ import type { styleTokens } from '../../types'; import type { SymbolLayerSpecification } from 'maplibre-gl'; -import type { RoadLabelDensity } from '../types'; +import type { LabelDensity } from '../types'; -export default function makeRoadLabels(tokens: styleTokens, density: RoadLabelDensity = 'default') { +export default function makeRoadLabels(tokens: styleTokens, density: LabelDensity = 'default') { if (density === 'none') return { roadLabels: [] }; const roadLabels: SymbolLayerSpecification[] = [ diff --git a/components/src/maplibre/MapStyle/components/Roads.ts b/components/src/maplibre/MapStyle/components/Roads.ts index 0b228937..b8efc5cb 100644 --- a/components/src/maplibre/MapStyle/components/Roads.ts +++ b/components/src/maplibre/MapStyle/components/Roads.ts @@ -200,7 +200,10 @@ export default function makeRoads(tokens: styleTokens) { line_width: { stops: [ [14, 0], - [15, 4] + [16, 4], + [18, 26], + [19, 62], + [20, 122] ] }, line_opacity: { diff --git a/components/src/maplibre/MapStyle/types.ts b/components/src/maplibre/MapStyle/types.ts index 4cce57b9..bac32ff6 100644 --- a/components/src/maplibre/MapStyle/types.ts +++ b/components/src/maplibre/MapStyle/types.ts @@ -3,22 +3,23 @@ enum AdminLevel { BUNDESLAND = 4 } -type RoadLabelDensity = 'none' | 'default' | 'dense'; +type LabelDensity = 'none' | 'default' | 'dense'; + type AdminOptions = { show?: boolean | AdminLevel[]; - showLabels?: boolean; + showLabels?: boolean | AdminLevel[]; }; interface StyleOptions { enableBuildingExtrusions?: boolean; enableHillshade?: boolean; places?: { - showLabels?: boolean; + labels: LabelDensity; }; admin?: AdminOptions; roads?: { - labels?: RoadLabelDensity; + labels?: LabelDensity; }; } -export type { StyleOptions, RoadLabelDensity, AdminOptions }; +export type { StyleOptions, LabelDensity, AdminOptions };