1
2
3
4
5
6
7
8
9import { MapView } from "mapgpu";
10import { RasterTileLayer } from "mapgpu/layers";
11import { RenderEngine } from "mapgpu/render";
12
13import type { RunResultObject } from "@/components/examples/ExampleCanvas";
14
15type City = {
16 label: string;
17 center: [number, number];
18 zoom: number;
19
20 pitch: number;
21
22 bearing: number;
23};
24
25const CITIES: Record<string, City> = {
26 istanbul: { label: "Istanbul", center: [29.02, 41.01], zoom: 13, pitch: 55, bearing: -15 },
27 london: { label: "London", center: [-0.127, 51.507], zoom: 13, pitch: 55, bearing: 10 },
28 tokyo: { label: "Tokyo", center: [139.767, 35.681], zoom: 13, pitch: 55, bearing: -25 },
29};
30
31
32
33const WORLD_BOUNDS: [number, number, number, number] = [-180, -60, 180, 75];
34
35export async function run(container: HTMLElement): Promise<RunResultObject> {
36 const view = new MapView({
37 container,
38 renderEngine: new RenderEngine(),
39 mode: "2d",
40 center: [0, 20],
41 zoom: 2,
42 minZoom: 1,
43 maxZoom: 18,
44 backgroundColor: "transparent",
45 });
46
47 view.map.add(
48 new RasterTileLayer({
49 id: "osm",
50 urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
51 maxZoom: 19,
52 attribution: "© OpenStreetMap contributors",
53 }),
54 );
55
56 await view.when();
57
58
59
60 const fly = (city: City) =>
61 view.flyTo(
62 {
63 center: city.center,
64 zoom: city.zoom,
65 pitch: city.pitch,
66 bearing: city.bearing,
67 },
68 { duration: 1800 },
69 );
70
71 return {
72 dispose: () => view.destroy(),
73 controls: [
74 {
75 kind: "toggle",
76 id: "mode",
77 labels: ["2D", "3D"],
78 initial: false,
79 onChange: async (on) => {
80 await view.switchTo(on ? "3d" : "2d");
81 },
82 },
83 ...Object.entries(CITIES).map(([id, city]) => ({
84 kind: "button" as const,
85 id,
86 label: city.label,
87 onClick: () => fly(city),
88 })),
89 {
90 kind: "button",
91 id: "fit-world",
92 label: "Fit world",
93 onClick: () => view.fitBounds(WORLD_BOUNDS, { padding: 40, duration: 1200 }),
94 },
95 ],
96 };
97}