Skip to content

Commit

Permalink
Popup events (#130)
Browse files Browse the repository at this point in the history
* add on:open and on:close to Popup

* typescript types for dispatch

* changeset
  • Loading branch information
singingwolfboy committed Mar 2, 2024
1 parent d3a923a commit d464803
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 14 deletions.
5 changes: 5 additions & 0 deletions .changeset/afraid-pumpkins-visit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-maplibre": minor
---

Add on:open and on:close events to Popup
6 changes: 5 additions & 1 deletion src/lib/DeckGlLayer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
export let type: any;
export let data: DATA[];
const dispatch = createEventDispatcher();
const dispatch = createEventDispatcher<{
click: DeckGlMouseEvent<DATA>;
mousemove: DeckGlMouseEvent<DATA>;
mouseleave: DeckGlMouseEvent<DATA>;
}>();
const context = mapContext();
const { map, minzoom: minZoomContext, maxzoom: maxZoomContext } = context;
Expand Down
8 changes: 6 additions & 2 deletions src/lib/DefaultMarker.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@
/** The opacity of the marker */
export let opacity: number = 1;
const dispatch = createEventDispatcher();
const dispatch = createEventDispatcher<{
drag: MarkerClickInfo;
dragstart: MarkerClickInfo;
dragend: MarkerClickInfo;
}>();
const { map, layerEvent, self: marker } = updatedMarkerContext();
const dragStartListener = () => sendEvent('dragstart');
Expand Down Expand Up @@ -74,7 +78,7 @@
}
}
function sendEvent(eventName: string) {
function sendEvent(eventName: Parameters<typeof dispatch>[0]) {
let loc = $marker?.getLngLat();
if (!loc) {
return;
Expand Down
9 changes: 7 additions & 2 deletions src/lib/Marker.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@
/** The opacity of the marker */
export let opacity: number = 1;
const dispatch = createEventDispatcher();
const dispatch = createEventDispatcher<{
drag: MarkerClickInfo;
dragstart: MarkerClickInfo;
dragend: MarkerClickInfo;
click: MarkerClickInfo;
}>();
const { map, layerEvent, self: marker } = updatedMarkerContext();
function addMarker(node: HTMLDivElement) {
Expand Down Expand Up @@ -115,7 +120,7 @@
}
}
function sendEvent(eventName: string) {
function sendEvent(eventName: Parameters<typeof dispatch>[0]) {
if (!interactive) {
return;
}
Expand Down
15 changes: 14 additions & 1 deletion src/lib/MarkerLayer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,22 @@
import Marker from './Marker.svelte';
import FillLayer from './FillLayer.svelte';
import type { MapLibreZoomEvent } from 'maplibre-gl';
import type { MarkerClickInfo } from './types';
interface ExtendedMarkerClickInfo extends MarkerClickInfo {
source: string | null;
feature: GeoJSON.Feature;
}
const { map, source, minzoom: minZoomContext, maxzoom: maxZoomContext } = mapContext();
const dispatch = createEventDispatcher();
const dispatch = createEventDispatcher<{
click: ExtendedMarkerClickInfo;
dblclick: ExtendedMarkerClickInfo;
contextmenu: ExtendedMarkerClickInfo;
drag: ExtendedMarkerClickInfo;
dragstart: ExtendedMarkerClickInfo;
dragend: ExtendedMarkerClickInfo;
}>();
export let applyToClusters: boolean | undefined = undefined;
export let filter: maplibregl.ExpressionSpecification | undefined = undefined;
Expand Down
23 changes: 15 additions & 8 deletions src/lib/Popup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,8 @@
type MapLayerMouseEvent,
type MapLayerTouchEvent,
} from 'maplibre-gl';
import { onDestroy, onMount, tick } from 'svelte';
import {
mapContext,
type DeckGlMouseEvent,
type LayerEvent,
isDeckGlMouseEvent,
} from './context.js';
import { onDestroy, onMount, createEventDispatcher } from 'svelte';
import { mapContext, type LayerEvent, isDeckGlMouseEvent } from './context.js';
/** Show the built-in close button. By default the close button will be shown
* only if closeOnClickOutside and closeOnClickInside are not set. */
Expand Down Expand Up @@ -45,6 +40,12 @@
/** Whether the popup is open or not. Can be set to manualy open the popup at `lngLat`. */
export let open = false;
const dispatch = createEventDispatcher<{
open: maplibregl.Popup;
close: maplibregl.Popup;
hover: maplibregl.Popup;
}>();
const { map, popupTarget, layerEvent, layer, eventTopMost } = mapContext();
const clickEvents = ['click', 'dblclick', 'contextmenu'];
Expand All @@ -70,10 +71,16 @@
popup.on('open', () => {
open = true;
setPopupClickHandler();
dispatch('open', popup);
});
popup.on('close', (e) => {
popup.on('close', () => {
open = false;
dispatch('close', popup);
});
popup.on('hover', () => {
dispatch('hover', popup);
});
}
Expand Down
1 change: 1 addition & 0 deletions src/routes/NavBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
{ href: '/examples/marker', title: `Default Markers` },
{ href: '/examples/custom_marker', title: `Custom Markers` },
{ href: '/examples/draggable_custom_marker', title: `Custom draggable Markers` },
{ href: '/examples/popup_remote', title: `Remote Popup Data` },
{ href: '/examples/geojson_polygon', title: `GeoJSON Filled Polygon` },
{ href: '/examples/geojson_line_layer', title: `Styled Line` },
{ href: '/examples/heatmap', title: `Heatmap` },
Expand Down
87 changes: 87 additions & 0 deletions src/routes/examples/popup_remote/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<script lang="ts">
import MapLibre from '$lib/MapLibre.svelte';
import DefaultMarker from '$lib/DefaultMarker.svelte';
import { mapClasses } from '../styles';
import code from './+page.svelte?raw';
import serverCode from './[id]/+server.ts?raw';
import CodeSample from '$site/CodeSample.svelte';
import Popup from '$lib/Popup.svelte';
const markers = [
{
lngLat: [-122.2993, 47.4464],
label: 'SEA',
name: 'Seattle',
},
{
lngLat: [-159.3438, 21.9788],
label: 'LIH',
name: 'Lihue',
},
{
lngLat: [2.5479, 49.0097],
label: 'CDG',
name: 'Paris Charles de Gaulle',
},
{
lngLat: [-58.5348, -34.82],
label: 'EZE',
name: 'Ministro Pistarini',
},
{
lngLat: [18.6021, -33.9715],
label: 'CPT',
name: 'Cape Town',
},
{
lngLat: [121.0165, 14.5123],
label: 'MNL',
name: 'Ninoy Aquino',
},
];
interface APIResponse {
width: number;
height: number;
}
let cache: Record<string, APIResponse> = {};
</script>

<MapLibre
style="https://basemaps.cartocdn.com/gl/positron-gl-style/style.json"
class={mapClasses}
standardControls
zoom={1}
center={[-20, 0]}
>
{#each markers as { lngLat, name }}
<!-- Unlike the custom marker example, default markers do not have mouse events,
and popups only support the default openOn="click" behavior -->
<DefaultMarker {lngLat} draggable>
<Popup
offset={[0, -10]}
on:open={async () => {
if (!(name in cache)) {
const resp = await fetch(`/examples/popup_remote/${name}`);
const result = await resp.json();
cache[name] = result;
// trigger reactivity
cache = cache;
}
}}
>
{#if name in cache}
{@const result = cache[name]}
<div class="text-lg font-bold">{name}</div>
<img alt="kitten" src={`http://placekitten.com/${result.width}/${result.height}`} />
{:else}
<div>Loading...</div>
{/if}
</Popup>
</DefaultMarker>
{/each}
</MapLibre>

<CodeSample {code} />
<CodeSample code={serverCode} language="typescript" startBoundary="" endBoundary="" />
7 changes: 7 additions & 0 deletions src/routes/examples/popup_remote/+page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { PageLoad } from './$types';

export const load: PageLoad = () => {
return {
title: 'Remote Popup Data',
};
};
18 changes: 18 additions & 0 deletions src/routes/examples/popup_remote/[id]/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { json } from '@sveltejs/kit';

const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));

/**
* This is a very contrived example.
*/
export async function GET({ params }) {
const { id } = params;
// make this request take one second
await sleep(1000);
// return some meaningless data
return json({
id,
width: 10 * id.length,
height: 12 * id.length,
});
}

0 comments on commit d464803

Please sign in to comment.