|
5 | 5 | LineLayer,
|
6 | 6 | MapLibre,
|
7 | 7 | Projection,
|
| 8 | + ImageLoader, |
8 | 9 | RasterDEMTileSource,
|
9 | 10 | Sky,
|
10 | 11 | Terrain,
|
| 12 | + GeoJSONSource, |
| 13 | + SymbolLayer, |
11 | 14 | VectorTileSource
|
12 | 15 | } from 'svelte-maplibre-gl';
|
13 | 16 |
|
14 | 17 | import { Label } from '$lib/components/ui/label/index.js';
|
15 | 18 | import * as RadioGroup from '$lib/components/ui/radio-group/index.js';
|
16 | 19 | import { Switch } from '$lib/components/ui/switch/index.js';
|
| 20 | + import type { FeatureCollection } from 'geojson'; |
17 | 21 |
|
18 |
| - const STYLES = [ |
19 |
| - { name: 'Voyager', url: 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json' }, |
20 |
| - { name: 'Positron', url: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json' }, |
21 |
| - { name: 'Dark Matter', url: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json' }, |
22 |
| - { name: 'Demo Tiles', url: 'https://demotiles.maplibre.org/style.json' } |
23 |
| - ]; |
24 |
| - let styleUrl = $state(STYLES[0].url); |
| 22 | + // Base styles |
| 23 | + const STYLES = new Map<string, string | maplibregl.StyleSpecification>([ |
| 24 | + ['Voyager', 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json'], |
| 25 | + ['Positron', 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json'], |
| 26 | + ['Dark Matter', 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json'], |
| 27 | + ['Demo Tiles', 'https://demotiles.maplibre.org/style.json'], |
| 28 | + [ |
| 29 | + 'GSI Seamlessphoto', |
| 30 | + { |
| 31 | + version: 8, |
| 32 | + sources: { |
| 33 | + basemap: { |
| 34 | + type: 'raster', |
| 35 | + tiles: ['https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg'], |
| 36 | + tileSize: 256, |
| 37 | + minzoom: 2, |
| 38 | + maxzoom: 18, |
| 39 | + attribution: |
| 40 | + "<a href='https://maps.gsi.go.jp/development/ichiran.html#seamlessphoto' target='_blank'>GSI, TSIC, AIST, NASA, USGS, GEBCO</a>" |
| 41 | + } |
| 42 | + }, |
| 43 | + layers: [{ id: 'basemap', type: 'raster', source: 'basemap' }] |
| 44 | + } satisfies maplibregl.StyleSpecification |
| 45 | + ], |
| 46 | + [ |
| 47 | + 'GSI Standard', |
| 48 | + { |
| 49 | + version: 8, |
| 50 | + sources: { |
| 51 | + basemap: { |
| 52 | + type: 'raster', |
| 53 | + tiles: ['https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png'], |
| 54 | + tileSize: 256, |
| 55 | + minzoom: 5, |
| 56 | + maxzoom: 18, |
| 57 | + attribution: "<a href='https://maps.gsi.go.jp/development/ichiran.html#std' target='_blank'>GSI</a>" |
| 58 | + } |
| 59 | + }, |
| 60 | + layers: [{ id: 'basemap', type: 'raster', source: 'basemap' }] |
| 61 | + } |
| 62 | + ] |
| 63 | + ]); |
| 64 | + let name = $state('Voyager'); |
| 65 | + let style = $derived(STYLES.get(name)!); |
25 | 66 | let globe = $state(true);
|
| 67 | +
|
| 68 | + let data: FeatureCollection = { |
| 69 | + type: 'FeatureCollection', |
| 70 | + features: [ |
| 71 | + { |
| 72 | + type: 'Feature', |
| 73 | + geometry: { type: 'Point', coordinates: [140, 30] }, |
| 74 | + properties: { imageName: 'osgeo', year: 2024 } |
| 75 | + } |
| 76 | + ] |
| 77 | + }; |
26 | 78 | </script>
|
27 | 79 |
|
28 | 80 | <div class="mb-3 flex items-center justify-between">
|
29 |
| - <RadioGroup.Root bind:value={styleUrl} class="flex flex-row gap-x-3"> |
30 |
| - {#each STYLES as style} |
| 81 | + <RadioGroup.Root bind:value={name} class="flex flex-row gap-x-3"> |
| 82 | + {#each STYLES as [name, _]} |
31 | 83 | <div class="flex items-center space-x-1">
|
32 |
| - <RadioGroup.Item value={style.url} id={style.name} /> |
33 |
| - <Label class="cursor-pointer" for={style.name}>{style.name}</Label> |
| 84 | + <RadioGroup.Item value={name} id={name} /> |
| 85 | + <Label class="cursor-pointer" for={name}>{name}</Label> |
34 | 86 | </div>
|
35 | 87 | {/each}
|
36 | 88 | </RadioGroup.Root>
|
|
41 | 93 | </div>
|
42 | 94 | </div>
|
43 | 95 |
|
44 |
| -<MapLibre class="h-[55vh] min-h-[300px]" style={styleUrl} zoom={4} maxPitch={80} center={{ lng: 137, lat: 36 }}> |
| 96 | +<MapLibre class="h-[55vh] min-h-[300px]" {style} zoom={4} maxPitch={80} center={{ lng: 137, lat: 36 }}> |
| 97 | + <!-- User-defined dynamic styles --> |
45 | 98 | <Projection type={globe ? 'globe' : undefined} />
|
46 | 99 | <Light anchor="map" />
|
47 | 100 | <Sky
|
|
86 | 139 | <Terrain />
|
87 | 140 | </RasterDEMTileSource>
|
88 | 141 | {/if}
|
| 142 | + <ImageLoader |
| 143 | + images={{ |
| 144 | + osgeo: 'https://maplibre.org/maplibre-gl-js/docs/assets/osgeo-logo.png' |
| 145 | + }} |
| 146 | + > |
| 147 | + <GeoJSONSource {data}> |
| 148 | + <!-- Children components will be added after all images have been loaded --> |
| 149 | + <SymbolLayer |
| 150 | + layout={{ |
| 151 | + 'text-field': ['get', 'name'], |
| 152 | + 'icon-image': ['get', 'imageName'], |
| 153 | + 'icon-size': ['number', ['get', 'scale'], 1], |
| 154 | + 'icon-text-fit': 'both', |
| 155 | + 'icon-overlap': 'always', |
| 156 | + 'text-overlap': 'always' |
| 157 | + }} |
| 158 | + /> |
| 159 | + </GeoJSONSource> |
| 160 | + </ImageLoader> |
89 | 161 | </MapLibre>
|
0 commit comments