Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<Story asChild name="Default">
<DesignTokens>
<div class="container">
<Map style={SWRDataLabLight} initialLocation={{ lat: 51, lng: 10, zoom: 20 }}>
<Map style={SWRDataLabLight()} initialLocation={{ lat: 51, lng: 10, zoom: 20 }}>
<AttributionControl customAttribution="SWR Data Lab" position="bottom-left" />
</Map>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
>
<DesignTokens>
<div class="container">
<Map style={SWRDataLabLight} initialLocation={{ lat: 51, lng: 10, zoom: 20 }}>
<Map style={SWRDataLabLight()} initialLocation={{ lat: 51, lng: 10, zoom: 20 }}>
<GeocoderControl languages="de" service="maptiler" key="V32kPHZjMa0Mkn6YvSzA" />
</Map>
</div>
Expand All @@ -58,7 +58,7 @@
>
<DesignTokens>
<div class="container">
<Map style={SWRDataLabLight} initialLocation={{ lat: 51, lng: 10, zoom: 20 }}>
<Map style={SWRDataLabLight()} initialLocation={{ lat: 51, lng: 10, zoom: 20 }}>
<GeocoderControl
placeholder="My placeholder text"
languages="de"
Expand All @@ -73,7 +73,7 @@
<Story asChild name="Long input">
<DesignTokens>
<div class="container">
<Map style={SWRDataLabLight} initialLocation={{ lat: 51, lng: 10, zoom: 20 }}>
<Map style={SWRDataLabLight()} initialLocation={{ lat: 51, lng: 10, zoom: 20 }}>
<GeocoderControl
placeholder="This is an input with a very long placeholder text"
languages="de"
Expand Down
4 changes: 2 additions & 2 deletions components/src/maplibre/Map/Map.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
>
<div class="container">
<DesignTokens>
<Map style={SWRDataLabLight}>
<Map style={SWRDataLabLight()}>
<ScaleControl />
<AttributionControl />
<NavigationControl showCompass visualizePitch />
Expand All @@ -79,7 +79,7 @@
<div class="container dark">
<DesignTokens>
<Map
style={SWRDataLabLight}
style={SWRDataLabLight()}
showDebug
projection={{ type: 'globe' }}
pitch={52}
Expand Down
16 changes: 13 additions & 3 deletions components/src/maplibre/Map/Map.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,21 @@
allowRotation = false,
allowZoom = true,
showDebug = false,
initialLocation = { lat: 51.3, lng: 10.2, zoom: 5 }
initialLocation: receivedInitialLocation
}: MapProps = $props();

let container: HTMLElement;

// Merge initial location with default object so individual
// properties (like pitch) can be omitted by the caller
let initialLocation = {
lat: 51.3,
lng: 10.2,
zoom: 5,
pitch: 0,
...receivedInitialLocation
};

const mapContext = createMapContext();
if (getContext('initialLocation') !== undefined && getContext('initialLocation') !== false) {
initialLocation = getContext('initialLocation');
Expand All @@ -54,11 +64,11 @@
style,
minZoom,
maxZoom,
pitch,
bearing,
attributionControl: false, // Added via component
center: [initialLocation.lng, initialLocation.lat],
zoom: initialLocation.zoom,
pitch: initialLocation.pitch,
...options
});

Expand Down Expand Up @@ -107,7 +117,7 @@
{/if}
{#if showDebug}
<pre class="debug">
{Object.entries({ ...center, zoom, allowZoom, allowRotation })
{Object.entries({ ...center, zoom, pitch, allowZoom, allowRotation })
.map(([key, val]) => `${key}: ${val}`)
.join('\n')}</pre>
{/if}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
});

const themes: ThemeMap = {
'SWRDL Light': SWRDataLabLight,
'SWRDL Light': SWRDataLabLight(),
Eclipse: eclipseStyle
};

Expand Down
28 changes: 26 additions & 2 deletions components/src/maplibre/MapStyle/SWRDataLabLight.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,38 @@ Light-themed general-purpose basemap using SWR colours and typefaces based on

- Data sources
- Vector data: [versatiles-osm](https://download.versatiles.org/) in the [Shortbread schema](https://shortbread-tiles.org/) served from `tiles.versatiles.org`
- Building footprints with heights: [basemap-de](https://basemap.de/produkte-und-dienste/web-vektor/) vector tiles served from `sgx.geodatenzentrum.de`
- Typefaces: SWR Sans served from `https://static.datenhub.net/maps/fonts/`.
- Layer count: {SWRDataLabLight.layers.length}
- Layer count: {SWRDataLabLight({enableBuildingExtrusions: true}).layers.length} (including building extrusions)

<Story of={MapStyleStories.Default} />

<br />

### Design Notes
## Usage

Call `SWRDataLabLight()` to construct a style document and pass the result to the `<Map>` component's `style` prop.

```jsx
<script>
import {
Map,
SWRDataLabLight,
} from '@swr-data-lab/components';
</script>

<Map style={SWRDataLabLight()}>...</Map>
```

`SWRDataLabLight()` takes an optional `options` parameter of the following shape:

```ts
interface StyleOptions {
enableBuildingExtrusions?: boolean;
}
```

## Design Notes

We take a two-step design approach:

Expand Down
25 changes: 24 additions & 1 deletion components/src/maplibre/MapStyle/SWRDataLabLight.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<div class="grid">
<div class="container">
<Map
style={SWRDataLabLight}
style={SWRDataLabLight()}
initialLocation={{ lng: 8.239451072800875, lat: 48.75692609731408, zoom: 14.99 }}
>
<GeocoderControl languages="de" service="maptiler" key="V32kPHZjMa0Mkn6YvSzA" />
Expand All @@ -27,6 +27,29 @@
</div>
</DesignTokens>
</Story>
<Story asChild name="Building Extrusions">
<DesignTokens>
<div class="grid">
<div class="container">
<Map
showDebug
style={SWRDataLabLight({ enableBuildingExtrusions: true })}
enableBuildingExtrusions
maxZoom={20}
initialLocation={{
lng: 9.180503103314436,
lat: 48.77521391139953,
zoom: 16,
pitch: 45
}}
>
<GeocoderControl languages="de" service="maptiler" key="V32kPHZjMa0Mkn6YvSzA" />
<AttributionControl position="bottom-left" />
</Map>
</div>
</div>
</DesignTokens>
</Story>

<style>
.grid {
Expand Down
127 changes: 81 additions & 46 deletions components/src/maplibre/MapStyle/SWRDataLabLight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,65 +8,100 @@ import makePlaceLabels from './components/PlaceLabels';
import makeWalking from './components/Walking';
import makeRoads from './components/Roads';

const { buildings } = makeBuildings();
const { buildingFootprints, buildingExtrusions, structureExtrusions } = makeBuildings();
const { landuse } = makeLanduse();
const { placeLabels } = makePlaceLabels();
const { admin } = makeAdmin();
const { airports, transitBridges, transitSurface, transitTunnels } = makeTransit();
const { walkingLabels, walkingTunnels, walkingSurface, walkingBridges } = makeWalking();
const { roadLabels, roadBridges, roadSurface, roadTunnels } = makeRoads();

const style: StyleSpecification = {
version: 8,
name: 'swr-datalab-light',
metadata: { license: 'https://creativecommons.org/publicdomain/zero/1.0/' },
glyphs: 'https://static.datenhub.net/maps/fonts/{fontstack}/{range}.pbf',
sources: {
'versatiles-osm': {
attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
tiles: ['https://tiles.versatiles.org/tiles/osm/{z}/{x}/{y}'],
bounds: [-180, -85.0511287798066, 180, 85.0511287798066],
type: 'vector',
scheme: 'xyz',
minzoom: 0,
maxzoom: 14
}
},
sky: {
'atmosphere-blend': ['interpolate', ['linear'], ['zoom'], 0, 0.1, 5, 0.1, 7, 0]
},
layers: [
// 1. Landuse
...landuse,
...airports,
interface StyleOptions {
enableBuildingExtrusions?: boolean;
}

// 2. Buildings
...buildings,
interface styleFunction {
(options?: StyleOptions): StyleSpecification;
}

// 3. Tunnels
...walkingTunnels,
...roadTunnels,
...transitTunnels,
const style: styleFunction = (opts) => {
const options = {
enableBuildingExtrusions: false,
...opts
} as StyleOptions;

// 4. Surface ways
...walkingSurface,
...roadSurface,
...transitSurface,
return {
version: 8,
name: 'swr-datalab-light',
metadata: { license: 'https://creativecommons.org/publicdomain/zero/1.0/' },
glyphs: 'https://static.datenhub.net/maps/fonts/{fontstack}/{range}.pbf',
sources: {
'versatiles-osm': {
attribution:
'<a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
tiles: ['https://tiles.versatiles.org/tiles/osm/{z}/{x}/{y}'],
bounds: [-180, -85.0511287798066, 180, 85.0511287798066],
type: 'vector',
scheme: 'xyz',
minzoom: 0,
maxzoom: 14
},
...(options.enableBuildingExtrusions && {
'basemap-de': {
attribution: 'GeoBasis-DE',
type: 'vector',
bounds: [5.8, 47.2, 15.1, 55.1],
maxzoom: 15,
minzoom: 0,
scheme: 'xyz',
tiles: [
'https://sgx.geodatenzentrum.de/gdz_basemapde_vektor/tiles/v2/bm_web_de_3857/{z}/{x}/{y}.pbf'
]
}
})
},
sky: {
'atmosphere-blend': ['interpolate', ['linear'], ['zoom'], 0, 0.1, 5, 0.1, 7, 0]
},
light: { anchor: 'viewport', color: 'white', intensity: 0.175 },
layers: [
// 1. Landuse
...landuse,
...airports,

// 5. Bridges ways
...walkingBridges,
...roadBridges,
...transitBridges,
// 2. Building footprints + Structures (ie. bridges)
...(!options.enableBuildingExtrusions ? [buildingFootprints] : []),
...(options.enableBuildingExtrusions ? [structureExtrusions] : []),

// 6. Admin boundaries
...admin,
// 3. Tunnels
...walkingTunnels,
...roadTunnels,
...transitTunnels,

// 7. Labels
...walkingLabels,
...roadLabels,
...placeLabels
]
// 4. Surface ways
...walkingSurface,
...roadSurface,
...transitSurface,

// 5. Bridges ways
...walkingBridges,
...roadBridges,
...transitBridges,

// 6. Admin boundaries
...admin,

// 7. Labels
...walkingLabels,
...roadLabels,

// 8. Building extrusions
...(options.enableBuildingExtrusions ? [buildingExtrusions] : []),

// 8. Point labels
...placeLabels
]
};
};

export default style;
54 changes: 38 additions & 16 deletions components/src/maplibre/MapStyle/components/Buildings.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,45 @@
import { type Layer } from '../../types';
import tokens from '../tokens';

const extrusionLayer = {
source: 'basemap-de',
type: 'fill-extrusion',
minzoom: 14,
maxzoom: 20,
paint: {
'fill-extrusion-color': tokens.building,
'fill-extrusion-opacity': ['interpolate', ['linear'], ['zoom'], 14.5, 0, 15, 1],
'fill-extrusion-height': ['interpolate', ['linear'], ['zoom'], 14.5, 0, 15, ['get', 'hoehe']]
}
};

export default function makeBuildings(): any {
const buildings: Layer[] = [
{
id: 'building-fill',
type: 'fill',
source: 'versatiles-osm',
'source-layer': 'buildings',
paint: {
'fill-color': 'hsl(240, 4%, 95%)',
'fill-opacity': {
stops: [
[14, 0],
[15, 1]
]
}
const buildingFootprints: Layer = {
id: 'building-footprints',
type: 'fill',
source: 'versatiles-osm',
'source-layer': 'buildings',
paint: {
'fill-color': tokens.building,
'fill-opacity': {
stops: [
[14, 0],
[15, 1]
]
}
}
];
};
const structureExtrusions = {
id: 'building-extrusions-structures',
'source-layer': 'Bauwerksflaeche',
...extrusionLayer
} as Layer;

const buildingExtrusions = {
id: 'building-extrusions-buildings',
'source-layer': 'Gebaeudeflaeche',
...extrusionLayer
} as Layer;

return { buildings };
return { buildingFootprints, buildingExtrusions, structureExtrusions };
}
Loading