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
2 changes: 0 additions & 2 deletions components/src/Switcher/Switcher.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@
asChild
play={async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
console.log(canvas);
await step('Options are displayed in a row', async () => {
const list = canvas.getByRole('list');
expect(list.classList).toContain('layout-row');
Expand All @@ -84,7 +83,6 @@
asChild
play={async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
console.log(canvas);
await step('Options are displayed in a row', async () => {
const list = canvas.getByRole('list');
expect(list.classList).toContain('layout-column');
Expand Down
35 changes: 23 additions & 12 deletions components/src/maplibre/Map/Map.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
type ProjectionSpecification,
type StyleSpecification
} from 'maplibre-gl';

import { type Location } from '../types';

import { onMount, onDestroy, type Snippet, getContext, hasContext } from 'svelte';

import { createMapContext, MapContext } from '../context.svelte.js';
import { type Location } from '../types';
import FallbackStyle from './FallbackStyle';
import { de } from './locale';

Expand All @@ -33,7 +36,7 @@
showDebug?: boolean;
options?: any;
/**
* Set the mouse cursor. `""` (empty string) restores Maplibre's default behaviour. See VectorLayer/Default for a common usage example
* Set the mouse cursor. `""` (empty string) restores Maplibre's default behaviour. See VectorLayer/Default for a usage example
*/
cursor?: string;
mapContext?: MapContext;
Expand Down Expand Up @@ -75,21 +78,23 @@
}: MapProps = $props();

let container: HTMLElement;
mapContext = createMapContext();

// Initial location is determined by (in order of precedence) :
// 1. An arbitrary default location
// 2. initialLocation prop
// 3. initialLocation context (notably set by <WithLinkLocation/>)

// Merge initial location with default object so individual
// properties (like pitch) can be omitted by the caller
let initialLocation = {
let contextLocation = getContext('initialLocation');

let initialLocation = $derived({
lat: 51.3,
lng: 10.2,
zoom: 5,
pitch: 0,
...receivedInitialLocation
};

mapContext = createMapContext();
if (getContext('initialLocation') !== undefined && getContext('initialLocation') !== false) {
initialLocation = getContext('initialLocation');
}
...receivedInitialLocation,
...contextLocation
});

onMount(() => {
mapContext.map = new maplibre.Map({
Expand Down Expand Up @@ -151,6 +156,12 @@
}
});

$effect(() => {
mapContext.map?.jumpTo({
center: [initialLocation.lng, initialLocation.lat],
zoom: initialLocation.zoom
});
});
$effect(() => {
if (allowZoom === false) {
mapContext.map?.scrollZoom.disable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
>
<VectorTileSource
id="demo-source"
url={`https://static.datenhub.net/data/p118_correctiv_waermewende/heating_merged_2.versatiles?{z}/{x}/{y}`}
tiles={["https://static.datenhub.net/data/p118_correctiv_waermewende/heating_merged_2.versatiles?{z}/{x}/{y}"]}
attribution="Demo attribution"
/>

Expand Down Expand Up @@ -150,7 +150,7 @@
<GeocoderControl languages="de" service="maptiler" key="V32kPHZjMa0Mkn6YvSzA" />
<VectorTileSource
id="ev-infra-source"
url={`https://static.datenhub.net/data/p109_besser_wohnen/rent_merged_4.versatiles?{z}/{x}/{y}`}
tiles={["https://static.datenhub.net/data/p109_besser_wohnen/rent_merged_4.versatiles?{z}/{x}/{y}"]}
attribution="Demo attribution"
/>

Expand Down
12 changes: 9 additions & 3 deletions components/src/maplibre/Tooltip/Tooltip.stories.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
>
<VectorTileSource
id="ev-infra-source"
url={`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`}
tiles={[
`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`
]}
/>
<VectorLayer
sourceId="ev-infra-source"
Expand Down Expand Up @@ -103,7 +105,9 @@
>
<VectorTileSource
id="ev-infra-source"
url={`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`}
tiles={[
`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`
]}
/>
<VectorLayer
sourceId="ev-infra-source"
Expand Down Expand Up @@ -187,7 +191,9 @@
>
<VectorTileSource
id="ev-infra-source"
url={`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`}
tiles={[
`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`
]}
/>
<VectorLayer
sourceId="ev-infra-source"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
<Map showDebug={true} style={SWRDataLabLight()} cursor={hovered ? 'pointer' : ''}>
<VectorTileSource
id="ev-infra-source"
url={`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`}
tiles={[
`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`
]}
/>
<VectorLayer
onmousemove={handleMouseMove}
Expand Down Expand Up @@ -125,7 +127,9 @@
<Map showDebug={true} style={SWRDataLabLight()}>
<VectorTileSource
id="ev-infra-source"
url={`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`}
tiles={[
`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`
]}
/>
<VectorLayer
sourceId="ev-infra-source"
Expand Down
38 changes: 33 additions & 5 deletions components/src/maplibre/VectorTileSource/VectorTileSource.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,43 @@ import * as VectorTileSourceStories from './VectorTileSource.stories.svelte';

# VectorTileSource

Loads tiled vector data from a tileserver. Any mablibre-supported tileserver will work, but we'll typically use tiles served by `versatiles-rs` or `versatiles-node-static-proxy`.
Loads tiled vector data from a tileserver.

Any mablibre-supported tileserver will work, but we typically use tiles served by `versatiles-rs` or `versatiles-node-static-proxy`.

## Using a TileJSON

You should generally load tile data by pointing to a [TileJSON](https://github.com/mapbox/tilejson-spec/blob/master/3.0.0/README.md) file. These are generated by most tile servers and contain useful metadata like `attribution`, `bounds`, `minzoom` and `maxzoom` in addition to the tile data itself.

```jsx
<Map style={SWRDataLabLight()}>
<VectorTileSource id="test-source" url="https://tiles.datenhub.net/tiles/hillshade/tiles.json" />
<VectorLayer
sourceId="test-source"
sourceLayer="boundaries"
id="test-layer"
type="line"
paint={{ 'line-color': shades.red.base, 'line-width': 2 }}
/>
<AttributionControl position="bottom-left" />
</Map>
```

- This component includes a workaround to support for [TileJSON data with relative URLs](https://docs.versatiles.org/compendium/specification_extended_tilejson.html#relaxed-rule-for-tiles) as produced by versatiles-rs.
- TileJSON data can by overridden by passing the relevant props to the component directly.

## Using tile URLs directly

Alternatively, you can point to a tile URL directly using the `tiles` prop:

```jsx
<Map>
<Map style={SWRDataLabLight()}>
<VectorTileSource
url="https://static.datenhub.net/rent_merged.versatiles?{z}/{x}/{y}"
id="chargers"
tiles={['https://static.datenhub.net/rent_merged.versatiles?{z}/{x}/{y}']}
attribution="Demo attribution"
id="test-source"
/>
<VectorLayer sourceId="chargers" />
<VectorLayer sourceId="test-source" />
</Map>
```

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script context="module" lang="ts">
import { defineMeta } from '@storybook/addon-svelte-csf';
import DesignTokens from '../../DesignTokens/DesignTokens.svelte';
import { shades } from '../../DesignTokens/Tokens.ts';

import VectorTileSource from './VectorTileSource.svelte';
import VectorLayer from '../VectorLayer/VectorLayer.svelte';
import Map from '../Map/Map.svelte';
Expand All @@ -14,12 +16,56 @@
</script>

<Story asChild name="Default">
<DesignTokens theme="light">
<div class="container">
<Map showDebug={true} style={SWRDataLabLight()}>
<VectorTileSource id="test-source" url="https://tiles.datenhub.net/tiles/osm/tiles.json" />
<VectorLayer
sourceId="test-source"
sourceLayer="boundaries"
id="test-layer"
type="line"
paint={{
'line-color': shades.red.base,
'line-width': 2
}}
/>
<AttributionControl position="bottom-left" />
</Map>
</div>
</DesignTokens>
</Story>

<Story asChild name="TileJSON with absolute URLs">
<DesignTokens theme="light">
<div class="container">
<Map showDebug={true} style={SWRDataLabLight()}>
<VectorTileSource id="test-source" url="https://demotiles.maplibre.org/tiles/tiles.json" />
<VectorLayer
sourceId="test-source"
sourceLayer="countries"
id="test-layer"
type="line"
paint={{
'line-color': shades.red.base,
'line-width': 2
}}
/>
<AttributionControl position="bottom-left" />
</Map>
</div>
</DesignTokens>
</Story>

<Story asChild name="Usign bare tile URL">
<DesignTokens theme="light">
<div class="container">
<Map showDebug={true} style={SWRDataLabLight()}>
<VectorTileSource
id="ev-infra-source"
url={`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`}
tiles={[
`https://static.datenhub.net/data/p108_e_auto_check/ev_infra_merged.versatiles?{z}/{x}/{y}`
]}
attribution="Demo attribution"
/>
<VectorLayer
Expand All @@ -28,9 +74,8 @@
id="ev-infra-outline"
type="line"
paint={{
'line-width': 0.5,
'line-color': 'purple',
'line-opacity': 1
'line-width': 1,
'line-color': shades.red.base
}}
/>
<AttributionControl position="bottom-left" />
Expand Down
36 changes: 26 additions & 10 deletions components/src/maplibre/VectorTileSource/VectorTileSource.svelte
Original file line number Diff line number Diff line change
@@ -1,27 +1,43 @@
<script lang="ts">
import { type SourceSpecification } from 'maplibre-gl';
import { type PromoteIdSpecification, type VectorSourceSpecification } from 'maplibre-gl';
import type { TileJsonData } from './types';

import MapSource from '../Source/MapSource.svelte';
import fetchTileJSON from './fetchTileJson';

interface VectorTileSourceProps {
id: string;
url: string;
url?: string;
tiles?: string[];
minZoom?: number;
maxZoom?: number;
/**
* Attribution string for your data, usually rendered using an `<AttributionControl>`
* Attribution string for your data, usually rendered using an `<AttributionControl/>`
*/
attribution?: string;
promoteId?: PromoteIdSpecification;
}

const { minZoom = 0, maxZoom = 24, id, url, attribution = '' }: VectorTileSourceProps = $props();
const {
minZoom,
maxZoom,
id,
url,
tiles,
attribution,
promoteId
}: VectorTileSourceProps = $props();

let tileJsonData = $derived(url ? await fetchTileJSON(url) : {});

const sourceSpec: SourceSpecification = {
const sourceSpec: VectorSourceSpecification = $derived({
type: 'vector',
tiles: [url],
maxzoom: maxZoom,
minzoom: minZoom,
attribution
};
tiles: tiles || tileJsonData.tiles || [],
maxzoom: maxZoom || tileJsonData.maxZoom || 24,
minzoom: minZoom || tileJsonData.minZoom || 0,
attribution: attribution || tileJsonData.attribution || '',
promoteId
});
</script>

<MapSource {id} {sourceSpec} />
20 changes: 20 additions & 0 deletions components/src/maplibre/VectorTileSource/fetchTileJson.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { type TileJsonData } from './types';

// Workaround for https://github.com/versatiles-org/versatiles-rs/issues/184
// Drop when/if this lands: https://github.com/maplibre/maplibre-gl-js/issues/182

export default async function fetchTileJSON(url: string): Promise<TileJsonData> {
const u = new URL(url);
const res = await fetch(u);
const data = await res.json();

// Simple heuristic for absolute URLs
const re = /(((http)s?)):\/\/.*/gi;

return {
tiles: data?.tiles.map((path: string) => (re.test(path) ? path : `${u.origin}${path}`)),
attribution: data?.attribution || data?.author,
minZoom: data?.minzoom,
maxZoom: data?.maxzoom
};
}
8 changes: 8 additions & 0 deletions components/src/maplibre/VectorTileSource/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
interface TileJsonData {
tiles?: string[];
attribution?: string;
minZoom?: number;
maxZoom?: number;
}

export { type TileJsonData };
2 changes: 2 additions & 0 deletions components/src/maplibre/WithLinkLocation/WithLinkLocation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import * as WithLinkLocationStories from './WithLinkLocation.stories.svelte';

# WithLinkLocation

This component allows you to set a map's initial location using a forward-geocoded URL parameter, as in: [http://localhost:6006/iframe.html?id=maplibre-extras-withlinklocation--default&viewMode=story&location=berlin](http://localhost:6006/iframe.html?id=maplibre-extras-withlinklocation--default&viewMode=story&location=berlin) (note `location` parameter at the end of the URL).This can be useful for multi-page visualisation scenarios.

<Controls />

<Stories />
Loading