All exampleslayersimage-video-overlay
§ examples · layers

Image & Video Overlay

ImageOverlay drapes a static bitmap over Türkiye at geographic bounds; VideoOverlay composites a streaming video over a smaller quad. Both follow the same `bounds: [lon,lat,lon,lat]` contract.

slugimage-video-overlay
source81 lines
statuslive
tsexamples-src/image-video-overlay.ts
1/**
2 * Image & Video Overlay — drape a static bitmap or a streaming video on
3 * a georeferenced quad. Both layers share the `bounds: [minLon, minLat,
4 * maxLon, maxLat]` contract; the engine GPU-composites them with the
5 * raster basemap every frame.
6 */
7 
8import { MapView } from "mapgpu";
9import { ImageOverlay, RasterTileLayer, VideoOverlay } from "mapgpu/layers";
10import { RenderEngine } from "mapgpu/render";
11 
12import type { RunResultObject } from "@/components/examples/ExampleCanvas";
13 
14export async function run(container: HTMLElement): Promise<RunResultObject> {
15 const view = new MapView({
16 container,
17 renderEngine: new RenderEngine(),
18 mode: "2d",
19 center: [29.2, 41.0],
20 zoom: 9,
21 minZoom: 2,
22 maxZoom: 18,
23 backgroundColor: "transparent",
24 });
25 
26 const basemap = new RasterTileLayer({
27 id: "osm",
28 urlTemplate: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
29 maxZoom: 19,
30 attribution: "© OpenStreetMap contributors",
31 });
32 view.map.add(basemap);
33 
34 // Flagcdn delivers CORS-enabled country flag PNGs; the Turkish flag
35 // draped over a box west of the Bosphorus.
36 const image = new ImageOverlay({
37 id: "tr-flag",
38 url: "https://flagcdn.com/w640/tr.png",
39 bounds: [28.8, 40.9, 29.2, 41.15],
40 });
41 image.opacity = 0.85;
42 view.map.add(image);
43 
44 // CORS-friendly MDN sample video draped east of the flag.
45 const video = new VideoOverlay({
46 id: "flower",
47 url: "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm",
48 bounds: [29.2, 40.9, 29.6, 41.15],
49 autoplay: true,
50 loop: true,
51 muted: true,
52 });
53 view.map.add(video);
54 
55 await view.when();
56 
57 return {
58 dispose: () => view.destroy(),
59 controls: [
60 {
61 kind: "toggle",
62 id: "image",
63 labels: ["image off", "image on"],
64 initial: true,
65 onChange: (on) => {
66 image.visible = on;
67 },
68 },
69 {
70 kind: "toggle",
71 id: "video",
72 labels: ["video off", "video on"],
73 initial: true,
74 onChange: (on) => {
75 video.visible = on;
76 },
77 },
78 ],
79 };
80}