All examplesbasicsimagery-providers
§ examples · basics

Imagery Providers

Cycle between OSM, ArcGIS Imagery, CartoDB Dark and OpenTopoMap — one add/remove per swap. The new basemap crossfades over the previous tiles via `raster-fade-duration`.

slugimagery-providers
source96 lines
statuslive
tsexamples-src/imagery-providers.ts
1/**
2 * Imagery Providers — swap between four XYZ raster basemaps. Each click
3 * removes the current RasterTileLayer and adds the new one; mapgpu's
4 * tile manager streams the replacement tiles in, and the fade-in you
5 * see on the new basemap comes from `raster-fade-duration`-style
6 * crossfade in the delegate.
7 */
8 
9import { MapView } from "mapgpu";
10import { RasterTileLayer, type RasterTileLayerOptions } from "mapgpu/layers";
11import { RenderEngine } from "mapgpu/render";
12 
13import type { RunResultObject } from "@/components/examples/ExampleCanvas";
14 
15type ProviderId = "osm" | "arcgis" | "carto-dark" | "opentopo";
16 
17// Each descriptor is everything RasterTileLayer needs to render one
18// basemap. Attribution lines follow the provider's license requirements.
19const PROVIDERS: Record<ProviderId, RasterTileLayerOptions> = {
20 osm: {
21 id: "osm",
22 urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
23 maxZoom: 19,
24 attribution: "© OpenStreetMap contributors",
25 },
26 arcgis: {
27 id: "arcgis",
28 urlTemplate:
29 "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
30 maxZoom: 19,
31 attribution: "© Esri · DigitalGlobe · GeoEye · Earthstar Geographics",
32 },
33 "carto-dark": {
34 id: "carto-dark",
35 urlTemplate: "https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png",
36 subdomains: ["a", "b", "c", "d"],
37 maxZoom: 19,
38 attribution: "© CARTO · © OpenStreetMap contributors",
39 },
40 opentopo: {
41 id: "opentopo",
42 urlTemplate: "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
43 subdomains: ["a", "b", "c"],
44 maxZoom: 17,
45 attribution: "© OpenTopoMap (CC-BY-SA) · © OpenStreetMap contributors",
46 },
47};
48 
49export async function run(container: HTMLElement): Promise<RunResultObject> {
50 const view = new MapView({
51 container,
52 renderEngine: new RenderEngine(),
53 mode: "2d",
54 center: [32.866, 39.925],
55 zoom: 6,
56 minZoom: 2,
57 maxZoom: 18,
58 backgroundColor: "transparent",
59 });
60 
61 // One active layer at a time; we rebuild it on every switch. The
62 // alternative — keep all four layers added with `.visible = false`
63 // except one — would avoid re-fetching when the user cycles back, but
64 // remove/add makes the source swap visible via the delegate's
65 // fade-in so it's a better demo of both APIs.
66 let active: RasterTileLayer = new RasterTileLayer(PROVIDERS.osm);
67 view.map.add(active);
68 
69 await view.when();
70 
71 const switchTo = (next: ProviderId) => {
72 const incoming = new RasterTileLayer(PROVIDERS[next]);
73 view.map.remove(active);
74 view.map.add(incoming);
75 active = incoming;
76 };
77 
78 return {
79 dispose: () => view.destroy(),
80 controls: [
81 {
82 kind: "segmented",
83 id: "basemap",
84 initial: "osm",
85 options: [
86 { value: "osm", label: "OSM" },
87 { value: "arcgis", label: "Satellite" },
88 { value: "carto-dark", label: "Dark" },
89 { value: "opentopo", label: "Topo" },
90 ],
91 onChange: (value) => switchTo(value as ProviderId),
92 },
93 ],
94 };
95}