Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CustomLayer component #41

Merged
merged 2 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions src/content/CodeBlock.svelte
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
<script lang="ts" module>
import type { HighlighterCore } from 'shiki';
import {
createHighlighterCoreSync,
createOnigurumaEngine,
createJavaScriptRegexEngine,
type HighlighterCore
} from 'shiki';
import svelte from 'shiki/langs/svelte.mjs';
import dark from 'shiki/themes/github-dark-default.mjs';
import { browser } from '$app/environment';

const shiki2 = createHighlighterCoreSync({
themes: [dark],
langs: [svelte],
// Use the WASM version of Oniguruma on the browser, and the JS engine on the server
engine: browser ? await createOnigurumaEngine(import('shiki/wasm')) : createJavaScriptRegexEngine()
});
</script>

<script lang="ts">
let {
content,
shiki
content
}: {
content: string;
shiki: HighlighterCore;
} = $props();

const highlighted = $derived.by(() => {
return shiki.codeToHtml(content.trim(), { lang: 'svelte', theme: 'github-dark-default' });
return shiki2.codeToHtml(content.replaceAll('\t', ' ').trim(), { lang: 'svelte', theme: 'github-dark-default' });
});
</script>

Expand All @@ -36,6 +49,6 @@
margin-right: 1.5rem;
display: inline-block;
text-align: right;
color: rgba(115, 138, 148, 0.4);
color: rgba(115, 138, 148, 0.5);
}
</style>
3 changes: 2 additions & 1 deletion src/content/examples/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
'/examples/geolocate': 'Locate the User',
'/examples/image-loader': 'Load Images from URLs',
'/examples/custom-control': 'Custom Control',
'/examples/custom-protocol': 'Custom Protocols'
'/examples/custom-protocol': 'Custom Protocols',
'/examples/custom-layer': 'Custom Layer'
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion src/content/examples/animate-images/AnimateImages.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</script>

<MapLibre
class="h-[60vh] min-h-[300px]"
class="h-[55vh] min-h-[300px]"
style="https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json"
zoom={5}
center={[-76, 43]}
Expand Down
3 changes: 1 addition & 2 deletions src/content/examples/animate-images/content.svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ description: Use a series of image sources to create an animation.
import Demo from "./AnimateImages.svelte";
import demoRaw from "./AnimateImages.svelte?raw";
import CodeBlock from "../../CodeBlock.svelte";
let { shiki } = $props();
</script>

<Demo />

<CodeBlock content={demoRaw} shiki={shiki} />
<CodeBlock content={demoRaw} />
2 changes: 1 addition & 1 deletion src/content/examples/basestyle/BaseStyle.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
</div>
</div>

<MapLibre class="h-[60vh] min-h-[300px]" style={styleUrl} zoom={4} maxPitch={80} center={{ lng: 137, lat: 36 }}>
<MapLibre class="h-[55vh] min-h-[300px]" style={styleUrl} zoom={4} maxPitch={80} center={{ lng: 137, lat: 36 }}>
<Projection type={globe ? 'globe' : undefined} />
<Light anchor="map" />
<Sky
Expand Down
3 changes: 1 addition & 2 deletions src/content/examples/basestyle/content.svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ description: Dynamic contents must be preserved when the base style is changed.
import Demo from "./BaseStyle.svelte";
import demoRaw from "./BaseStyle.svelte?raw";
import CodeBlock from "../../CodeBlock.svelte";
let { shiki } = $props();
</script>

<Demo />

<CodeBlock content={demoRaw} shiki={shiki} />
<CodeBlock content={demoRaw} />
2 changes: 1 addition & 1 deletion src/content/examples/canvas-source/Canvas.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<canvas bind:this={canvas} class="hidden" width={SIZE} height={SIZE}>Canvas not supported</canvas>

<MapLibre
class="h-[60vh] min-h-[300px]"
class="h-[55vh] min-h-[300px]"
style="https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"
zoom={2}
center={{ lng: 135, lat: 35 }}
Expand Down
3 changes: 1 addition & 2 deletions src/content/examples/canvas-source/content.svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ description: Add a canvas source to the map.
import Demo from "./Canvas.svelte";
import demoRaw from "./Canvas.svelte?raw";
import CodeBlock from "../../CodeBlock.svelte";
let { shiki } = $props();
</script>

<Demo />

<CodeBlock content={demoRaw} shiki={shiki} />
<CodeBlock content={demoRaw} />
2 changes: 1 addition & 1 deletion src/content/examples/clusters/Clusters.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</div>

<MapLibre
class="h-[60vh] min-h-[300px]"
class="h-[55vh] min-h-[300px]"
style="https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json"
zoom={2}
center={{ lng: 180, lat: 35 }}
Expand Down
3 changes: 1 addition & 2 deletions src/content/examples/clusters/content.svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ description: Use MapLibre's built-in functions to visualize points as clusters.
import Demo from "./Clusters.svelte";
import demoRaw from "./Clusters.svelte?raw";
import CodeBlock from "../../CodeBlock.svelte";
let { shiki } = $props();
</script>

<Demo />

<CodeBlock content={demoRaw} shiki={shiki} />
<CodeBlock content={demoRaw} />
2 changes: 1 addition & 1 deletion src/content/examples/complex/Complex.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@
</div>

<MapLibre
class="h-[60vh] min-h-[300px]"
class="h-[55vh] min-h-[300px]"
bind:map
bind:zoom
bind:center
Expand Down
3 changes: 1 addition & 2 deletions src/content/examples/complex/content.svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ description: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiu
import Demo from "./Complex.svelte";
import demoRaw from "./Complex.svelte?raw";
import CodeBlock from "../../CodeBlock.svelte";
let { shiki } = $props();
</script>

<Demo />

<CodeBlock content={demoRaw} shiki={shiki} />
<CodeBlock content={demoRaw} />
2 changes: 1 addition & 1 deletion src/content/examples/contour/Contour.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</script>

<MapLibre
class="h-[60vh] min-h-[300px]"
class="h-[55vh] min-h-[300px]"
style="https://demotiles.maplibre.org/styles/osm-bright-gl-style/style.json"
zoom={12}
minZoom={10}
Expand Down
3 changes: 1 addition & 2 deletions src/content/examples/contour/content.svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ description: Render contour lines from a raster DEM source using maplibre-contou
import Demo from "./Contour.svelte";
import demoRaw from "./Contour.svelte?raw";
import CodeBlock from "../../CodeBlock.svelte";
let { shiki } = $props();
</script>

<Demo />

<CodeBlock content={demoRaw} shiki={shiki} />
<CodeBlock content={demoRaw} />
2 changes: 1 addition & 1 deletion src/content/examples/custom-control/CustomControl.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
});
</script>

<MapLibre class="h-[50vh] min-h-[200px]" style={mapStyle} zoom={12} pitch={40} maxPitch={85} bind:center>
<MapLibre class="h-[55vh] min-h-[200px]" style={mapStyle} zoom={12} pitch={40} maxPitch={85} bind:center>
<!-- inject IControl (useful for plugin) -->
<CustomControl position="top-left" control={myControl} />

Expand Down
4 changes: 2 additions & 2 deletions src/content/examples/custom-control/content.svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ description: Custom Control allows to easily create user defined controls.
---

<script lang="ts">
import CustomControl from "./CustomControl.svelte";
import Demo from "./CustomControl.svelte";
import demoRaw from "./CustomControl.svelte?raw";
import CodeBlock from "../../CodeBlock.svelte";
</script>

<CustomControl />
<Demo />

<CodeBlock content={demoRaw} />
87 changes: 87 additions & 0 deletions src/content/examples/custom-layer/CustomLayer.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<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);
Comment on lines +27 to +40
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for shader compilation and program linking

To ensure the robustness of the application, it's important to check if the shaders compile successfully and if the program links correctly. Without these checks, shader compilation or linking failures may go unnoticed, making debugging difficult.

Apply this diff to add error handling:

 gl.compileShader(vertexShader);
+if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
+  console.error('Vertex shader compilation failed:', gl.getShaderInfoLog(vertexShader));
+}

 gl.compileShader(fragmentShader);
+if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
+  console.error('Fragment shader compilation failed:', gl.getShaderInfoLog(fragmentShader));
+}

 gl.linkProgram(this.program);
+if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {
+  console.error('Program linking failed:', gl.getProgramInfoLog(this.program));
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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);
const vertexShader = gl.createShader(gl.VERTEX_SHADER)!;
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
console.error('Vertex shader compilation failed:', gl.getShaderInfoLog(vertexShader));
}
// create a fragment shader
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)!;
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
console.error('Fragment shader compilation failed:', gl.getShaderInfoLog(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);
if (!gl.getProgramParameter(this.program, gl.LINK_STATUS)) {
console.error('Program linking failed:', gl.getProgramInfoLog(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 });

// 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);
}
Comment on lines +60 to +73
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ensure compatibility with WebGL1 contexts

The render method accepts both WebGL2RenderingContext and WebGLRenderingContext, but the shaders use WebGL2-specific features (e.g., #version 300 es). If the context is WebGL1, the shaders will fail to compile. Please ensure that the application handles cases where gl is a WebGL1 context or enforce that a WebGL2 context is used.

Consider updating the code to check if gl is a WebGL2RenderingContext and handle accordingly.

}

const customLayerImpl = new CustomLayerImpl();
</script>

<MapLibre
class="h-[55vh] min-h-[300px]"
style="https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"
zoom={3}
center={[20, 58]}
antialias
>
<CustomLayer implementation={customLayerImpl} />
</MapLibre>
14 changes: 14 additions & 0 deletions src/content/examples/custom-layer/content.svelte.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
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";
</script>

<Demo />

<CodeBlock content={demoRaw} />
2 changes: 1 addition & 1 deletion src/content/examples/custom-protocol/CustomProtocol.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<Protocol scheme="myprotocol" loadFn={myProtocolLoadFn} />

<!-- Use custom protocols -->
<MapLibre class="h-[50vh] min-h-[200px]" zoom={6} center={{ lng: 140.0, lat: 37.5 }}>
<MapLibre class="h-[55vh] min-h-[200px]" zoom={6} center={{ lng: 140.0, lat: 37.5 }}>
<VectorTileSource url="pmtiles://https://tile.openstreetmap.jp/static/planet.pmtiles">
<LineLayer sourceLayer="transportation" paint={{ 'line-color': 'orange' }} />
<FillLayer sourceLayer="water" paint={{ 'fill-color': 'dodgerblue' }} />
Expand Down
4 changes: 2 additions & 2 deletions src/content/examples/custom-protocol/content.svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ description: How to add custom protocols.
---

<script lang="ts">
import CustomProtocol from "./CustomProtocol.svelte";
import Demo from "./CustomProtocol.svelte";
import demoRaw from "./CustomProtocol.svelte?raw";
import CodeBlock from "../../CodeBlock.svelte";
</script>

<CustomProtocol />
<Demo />

<CodeBlock content={demoRaw} />
2 changes: 1 addition & 1 deletion src/content/examples/deckgl-overlay/DeckGL.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
</script>

<MapLibre
class="h-[60vh] min-h-[300px]"
class="h-[55vh] min-h-[300px]"
style="https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"
zoom={15}
pitch={60}
Expand Down
3 changes: 1 addition & 2 deletions src/content/examples/deckgl-overlay/content.svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ description: Interleaving deck.gl with MapLibre layers
import Demo from "./DeckGL.svelte";
import demoRaw from "./DeckGL.svelte?raw";
import CodeBlock from "../../CodeBlock.svelte";
let { shiki } = $props();
</script>

<Demo />

<CodeBlock content={demoRaw} shiki={shiki} />
<CodeBlock content={demoRaw} />
2 changes: 1 addition & 1 deletion src/content/examples/dynamic-image/DynamicImage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</script>

<MapLibre
class="h-[60vh] min-h-[300px]"
class="h-[55vh] min-h-[300px]"
style="https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"
zoom={4}
center={{ lng: 137, lat: 36 }}
Expand Down
3 changes: 1 addition & 2 deletions src/content/examples/dynamic-image/content.svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ description: Add an icon to the map that was generated at runtime.
import Demo from "./DynamicImage.svelte";
import demoRaw from "./DynamicImage.svelte?raw";
import CodeBlock from "../../CodeBlock.svelte";
let { shiki } = $props();
</script>

<Demo />

<CodeBlock content={demoRaw} shiki={shiki} />
<CodeBlock content={demoRaw} />
2 changes: 1 addition & 1 deletion src/content/examples/fullscreen/Fullscreen.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
</script>

<MapLibre
class="h-[60vh] min-h-[300px] border-8 border-slate-500"
class="h-[55vh] min-h-[300px] border-8 border-slate-500"
style="https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"
>
<FullScreenControl position="top-left" />
Expand Down
3 changes: 1 addition & 2 deletions src/content/examples/fullscreen/content.svelte.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ description: View a fullscreen map
import Demo from "./Fullscreen.svelte";
import demoRaw from "./Fullscreen.svelte?raw";
import CodeBlock from "../../CodeBlock.svelte";
let { shiki } = $props();
</script>

<Demo />

<CodeBlock content={demoRaw} shiki={shiki} />
<CodeBlock content={demoRaw} />
2 changes: 1 addition & 1 deletion src/content/examples/geolocate/Geolocate.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
}
</script>

<div class="flex h-[60vh] min-h-[300px] overflow-hidden rounded-md">
<div class="flex h-[55vh] min-h-[300px] overflow-hidden rounded-md">
<pre class="m-0 flex-1 rounded-none">{logString}</pre>
<MapLibre class="flex-1" style="https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json">
<GeolocateControl
Expand Down
Loading
Loading