-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
205 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
<script lang="ts"> | ||
import { MapLibre, CustomLayer } from 'svelte-maplibre-gl'; | ||
import maplibregl from 'maplibre-gl'; | ||
class CustomLayerImpl implements Omit<maplibregl.CustomLayerInterface, 'id' | 'type'> { | ||
program: WebGLProgram | null = null; | ||
aPos: number = 0; | ||
buffer: WebGLBuffer | null = null; | ||
onAdd(_map: maplibregl.Map, gl: WebGL2RenderingContext) { | ||
//create GLSL source for vertex shader | ||
const vertexSource = `#version 300 es | ||
uniform mat4 u_matrix; | ||
in vec2 a_pos; | ||
void main() { | ||
gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); | ||
}`; | ||
// create GLSL source for fragment shader | ||
const fragmentSource = `#version 300 es | ||
out highp vec4 fragColor; | ||
void main() { | ||
fragColor = vec4(1.0, 0.0, 0.0, 0.5); | ||
}`; | ||
// create a vertex shader | ||
const vertexShader = gl.createShader(gl.VERTEX_SHADER)!; | ||
gl.shaderSource(vertexShader, vertexSource); | ||
gl.compileShader(vertexShader); | ||
// create a fragment shader | ||
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)!; | ||
gl.shaderSource(fragmentShader, fragmentSource); | ||
gl.compileShader(fragmentShader); | ||
// link the two shaders into a WebGL program | ||
this.program = gl.createProgram()!; | ||
gl.attachShader(this.program, vertexShader); | ||
gl.attachShader(this.program, fragmentShader); | ||
gl.linkProgram(this.program); | ||
this.aPos = gl.getAttribLocation(this.program, 'a_pos'); | ||
// define vertices of the triangle to be rendered in the custom style layer | ||
const helsinki = maplibregl.MercatorCoordinate.fromLngLat({ lng: 25.004, lat: 60.239 }); | ||
const berlin = maplibregl.MercatorCoordinate.fromLngLat({ lng: 13.403, lat: 52.562 }); | ||
const kyiv = maplibregl.MercatorCoordinate.fromLngLat({ lng: 30.498, lat: 50.541 }); | ||
console.log(helsinki, berlin, kyiv); | ||
// create and initialize a WebGLBuffer to store vertex and color data | ||
this.buffer = gl.createBuffer(); | ||
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer); | ||
gl.bufferData( | ||
gl.ARRAY_BUFFER, | ||
new Float32Array([helsinki.x, helsinki.y, berlin.x, berlin.y, kyiv.x, kyiv.y]), | ||
gl.STATIC_DRAW | ||
); | ||
} | ||
// method fired on each animation frame | ||
render(gl: WebGL2RenderingContext | WebGLRenderingContext, options: maplibregl.CustomRenderMethodInput) { | ||
gl.useProgram(this.program); | ||
gl.uniformMatrix4fv( | ||
gl.getUniformLocation(this.program!, 'u_matrix'), | ||
false, | ||
options.defaultProjectionData.mainMatrix | ||
); | ||
gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer); | ||
gl.enableVertexAttribArray(this.aPos); | ||
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 0, 0); | ||
gl.enable(gl.BLEND); | ||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); | ||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 3); | ||
} | ||
} | ||
const customLayerImpl = new CustomLayerImpl(); | ||
</script> | ||
|
||
<MapLibre | ||
class="h-[60vh] min-h-[300px]" | ||
style="https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json" | ||
zoom={3} | ||
center={[20, 58]} | ||
antialias | ||
> | ||
<CustomLayer implementation={customLayerImpl} /> | ||
</MapLibre> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
--- | ||
title: Custom style layer | ||
description: Use a custom style layer to render custom WebGL content. | ||
--- | ||
|
||
<script lang="ts"> | ||
import Demo from "./CustomLayer.svelte"; | ||
import demoRaw from "./CustomLayer.svelte?raw"; | ||
import CodeBlock from "../../CodeBlock.svelte"; | ||
let { shiki } = $props(); | ||
</script> | ||
|
||
<Demo /> | ||
|
||
<CodeBlock content={demoRaw} shiki={shiki} /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
<script lang="ts"> | ||
// https://maplibre.org/maplibre-gl-js/docs/API/interfaces/CustomLayerInterface/ | ||
import { onDestroy, type Snippet } from 'svelte'; | ||
import maplibregl from 'maplibre-gl'; | ||
import { getMapContext } from '../contexts.svelte.js'; | ||
import { generateLayerID, resetLayerEventListener } from '../utils.js'; | ||
import type { MapLayerEventProps } from './common.js'; | ||
interface Props extends MapLayerEventProps { | ||
id?: string; | ||
beforeId?: string; | ||
implementation: Omit<maplibregl.CustomLayerInterface, 'id' | 'type'>; | ||
children?: Snippet; | ||
} | ||
let { | ||
id: _id, | ||
beforeId, | ||
implementation, | ||
children, | ||
// Events | ||
// https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapLayerEventType/ | ||
onclick, | ||
ondblclick, | ||
onmousedown, | ||
onmouseup, | ||
onmousemove, | ||
onmouseenter, | ||
onmouseleave, | ||
onmouseover, | ||
onmouseout, | ||
oncontextmenu, | ||
ontouchstart, | ||
ontouchend, | ||
ontouchcancel | ||
}: Props = $props(); | ||
const mapCtx = getMapContext(); | ||
if (!mapCtx.map) throw new Error('Map instance is not initialized.'); | ||
const id = _id ?? generateLayerID(); | ||
(implementation as maplibregl.CustomLayerInterface).id ??= id; | ||
(implementation as maplibregl.CustomLayerInterface).type = 'custom'; | ||
let firstRun = true; | ||
mapCtx.waitForStyleLoaded(() => { | ||
mapCtx.addLayer(implementation as maplibregl.CustomLayerInterface, beforeId); | ||
}); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'click', id, onclick)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'dblclick', id, ondblclick)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'mousedown', id, onmousedown)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'mouseup', id, onmouseup)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'mousemove', id, onmousemove)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'mouseenter', id, onmouseenter)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'mouseleave', id, onmouseleave)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'mouseover', id, onmouseover)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'mouseout', id, onmouseout)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'contextmenu', id, oncontextmenu)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'touchstart', id, ontouchstart)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'touchend', id, ontouchend)); | ||
$effect(() => resetLayerEventListener(mapCtx.map, 'touchcancel', id, ontouchcancel)); | ||
$effect(() => { | ||
if (beforeId && !firstRun) { | ||
mapCtx.waitForStyleLoaded((map) => { | ||
map.moveLayer(id, beforeId); | ||
}); | ||
} | ||
}); | ||
$effect(() => { | ||
firstRun = false; | ||
}); | ||
onDestroy(() => { | ||
mapCtx.removeLayer(id); | ||
}); | ||
</script> | ||
|
||
{@render children?.()} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters