-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19 from MIERUNE/feat/custom-control
Add CustomControl components
- Loading branch information
Showing
8 changed files
with
215 additions
and
3 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
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,88 @@ | ||
<script lang="ts"> | ||
import { HillshadeLayer, MapLibre, RasterDEMTileSource, Terrain, CustomControl } from 'svelte-maplibre-gl'; | ||
import maplibregl from 'maplibre-gl'; | ||
import Sun from 'lucide-svelte/icons/sun'; | ||
import Moon from 'lucide-svelte/icons/moon'; | ||
import ArrowUpLeft from 'lucide-svelte/icons/arrow-up-left'; | ||
import ArrowUpRight from 'lucide-svelte/icons/arrow-up-right'; | ||
import ArrowDownLeft from 'lucide-svelte/icons/arrow-down-left'; | ||
import ArrowDownRight from 'lucide-svelte/icons/arrow-down-right'; | ||
import { MyControl } from './MyControl.js'; | ||
let isHillshadeVisible = $state(true); | ||
let isTerrainVisible = $state(true); | ||
let isDarkMode = $state(false); | ||
const mapStyle = $derived( | ||
isDarkMode | ||
? 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json' | ||
: 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json' | ||
); | ||
let center = $state({ lng: 11.09085, lat: 47.3 }); | ||
let controlPosition: maplibregl.ControlPosition = $state('top-left'); | ||
const myControl = new MyControl({ | ||
toggleHillshade: () => { | ||
isHillshadeVisible = !isHillshadeVisible; | ||
return isHillshadeVisible; | ||
}, | ||
toggleTerrain: () => { | ||
isTerrainVisible = !isTerrainVisible; | ||
return isTerrainVisible; | ||
} | ||
}); | ||
</script> | ||
|
||
<MapLibre class="h-[50vh] min-h-[200px]" style={mapStyle} zoom={12} pitch={40} maxPitch={85} bind:center> | ||
<!-- inject IControl (useful for plugin) --> | ||
<CustomControl position="top-left" control={myControl} /> | ||
|
||
<!-- Control / Group / Icon --> | ||
<CustomControl position="bottom-left"> | ||
<button onclick={() => (isDarkMode = !isDarkMode)} class="grid place-items-center text-gray-900"> | ||
{#if isDarkMode} | ||
<Moon class="w-5" /> | ||
{:else} | ||
<Sun class="w-5" /> | ||
{/if} | ||
</button> | ||
</CustomControl> | ||
|
||
<!-- Group --> | ||
<CustomControl position={controlPosition} class="text-gray-900"> | ||
<button class="place-items-center" onclick={() => (controlPosition = 'top-left')} | ||
><ArrowUpLeft class="w-5" /></button | ||
> | ||
<button class="place-items-center" onclick={() => (controlPosition = 'top-right')} | ||
><ArrowUpRight class="w-5" /></button | ||
> | ||
<button class="place-items-center" onclick={() => (controlPosition = 'bottom-right')} | ||
><ArrowDownRight class="w-5" /></button | ||
> | ||
<button class="place-items-center" onclick={() => (controlPosition = 'bottom-left')} | ||
><ArrowDownLeft class="w-5" /></button | ||
> | ||
</CustomControl> | ||
|
||
<!-- Control / Group / any svelte elements --> | ||
<CustomControl position="top-right"> | ||
<div class="p-2 text-yellow-700">Arbitrary HTML</div> | ||
<div class="border-t border-t-[#ddd] p-2 text-center text-yellow-700"> | ||
({center.lat.toFixed(4)}, {center.lat.toFixed(4)}) | ||
</div> | ||
</CustomControl> | ||
|
||
<RasterDEMTileSource | ||
id="terrain" | ||
tiles={['https://demotiles.maplibre.org/terrain-tiles/{z}/{x}/{y}.png']} | ||
minzoom={0} | ||
maxzoom={12} | ||
attribution="<a href='https://earth.jaxa.jp/en/data/policy/'>AW3D30 (JAXA)</a>" | ||
> | ||
{#if isTerrainVisible} | ||
<Terrain /> | ||
{/if} | ||
{#if isHillshadeVisible} | ||
<HillshadeLayer /> | ||
{/if} | ||
</RasterDEMTileSource> | ||
</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,58 @@ | ||
interface MyControlConstructorOptions { | ||
toggleTerrain: () => boolean; | ||
toggleHillshade: () => boolean; | ||
} | ||
|
||
class MyControl implements maplibregl.IControl { | ||
private _container: HTMLElement | undefined; | ||
private _toggleTerrain: () => boolean; | ||
private _toggleHillshade: () => boolean; | ||
|
||
constructor(options: MyControlConstructorOptions) { | ||
this._toggleTerrain = options.toggleTerrain; | ||
this._toggleHillshade = options.toggleHillshade; | ||
} | ||
|
||
onAdd() { | ||
this._container = document.createElement('div'); | ||
this._container.className = 'maplibregl-ctrl maplibregl-ctrl-group p-2 rounded flex w-[240px] gap-x-2'; | ||
|
||
const toggleTerrain = document.createElement('button'); | ||
toggleTerrain.textContent = 'Disable Terrain'; | ||
toggleTerrain.type = 'button'; | ||
toggleTerrain.style.backgroundColor = 'red'; | ||
toggleTerrain.style.color = 'white'; | ||
toggleTerrain.style.width = '50%'; | ||
toggleTerrain.style.height = '100%'; | ||
toggleTerrain.style.borderRadius = '0.25rem'; | ||
toggleTerrain.addEventListener('click', () => { | ||
const newState = this._toggleTerrain(); | ||
toggleTerrain.textContent = newState ? 'Disable Terrain' : 'Enable Terrain'; | ||
}); | ||
|
||
const toggleHillshade = document.createElement('button'); | ||
toggleHillshade.textContent = 'Disable Hillshade'; | ||
toggleHillshade.type = 'button'; | ||
toggleHillshade.style.backgroundColor = 'blue'; | ||
toggleHillshade.style.color = 'white'; | ||
toggleHillshade.style.height = '100%'; | ||
toggleHillshade.style.width = '50%'; | ||
toggleHillshade.style.borderRadius = '0.25rem'; | ||
toggleHillshade.addEventListener('click', () => { | ||
const newState = this._toggleHillshade(); | ||
toggleHillshade.textContent = newState ? 'Disable Hillshade' : 'Enable Hillshade'; | ||
}); | ||
|
||
this._container.appendChild(toggleTerrain); | ||
this._container.appendChild(toggleHillshade); | ||
return this._container!; | ||
} | ||
|
||
onRemove() { | ||
if (this._container && this._container.parentNode) { | ||
this._container.parentNode.removeChild(this._container); | ||
} | ||
} | ||
} | ||
|
||
export { MyControl }; |
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,14 @@ | ||
--- | ||
title: Custom Control | ||
description: Custom Control allows to easily create user defined controls. | ||
--- | ||
|
||
<script lang="ts"> | ||
import CustomControl from "./CustomControl.svelte"; | ||
import demoRaw from "./CustomControl.svelte?raw"; | ||
import CodeBlock from "../../CodeBlock.svelte"; | ||
</script> | ||
|
||
<CustomControl /> | ||
|
||
<CodeBlock content={demoRaw} /> |
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,52 @@ | ||
<script lang="ts"> | ||
// https://maplibre.org/maplibre-gl-js/docs/API/interfaces/IControl/ | ||
import type { Snippet } from 'svelte'; | ||
import maplibregl from 'maplibre-gl'; | ||
import { getMapContext } from '../contexts.svelte.js'; | ||
interface Props { | ||
position?: maplibregl.ControlPosition; | ||
control?: maplibregl.IControl; | ||
group?: boolean; | ||
class?: string; | ||
children?: Snippet; | ||
} | ||
let { position, control: givenControl, class: className, group = true, children }: Props = $props(); | ||
if (!givenControl && !children) throw new Error('You must provide either control or children.'); | ||
const mapCtx = getMapContext(); | ||
if (!mapCtx.map) throw new Error('Map instance is not initialized.'); | ||
let el: HTMLDivElement | undefined = $state(); | ||
let control = $derived.by(() => { | ||
if (givenControl) { | ||
return givenControl; | ||
} | ||
return { | ||
onAdd: () => { | ||
return el!; | ||
}, | ||
onRemove: () => { | ||
el?.parentNode?.removeChild(el); | ||
} | ||
}; | ||
}); | ||
$effect(() => { | ||
if (control) { | ||
mapCtx.map?.addControl(control, position); | ||
} | ||
return () => { | ||
control && mapCtx.map?.removeControl(control); | ||
}; | ||
}); | ||
</script> | ||
|
||
{#if !givenControl} | ||
<div bind:this={el} class={`maplibregl-ctrl ${className}`} class:maplibregl-ctrl-group={group}> | ||
{@render children?.()} | ||
</div> | ||
{/if} |
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