Skip to content

Commit 4fdd742

Browse files
committed
feat(ol-interaction-link): add interaction for sync with URL query params
1 parent e72b1f9 commit 4fdd742

File tree

11 files changed

+217
-45
lines changed

11 files changed

+217
-45
lines changed

Diff for: docs/.vitepress/config.ts

+46-42
Original file line numberDiff line numberDiff line change
@@ -259,48 +259,6 @@ export const config: UserConfig = {
259259
},
260260
],
261261
},
262-
{
263-
text: "Interactions",
264-
collapsed: true,
265-
items: [
266-
{
267-
text: "ol-interaction-clusterselect",
268-
link: "/componentsguide/interactions/clusterselect/",
269-
},
270-
{
271-
text: "ol-interaction-draw",
272-
link: "/componentsguide/interactions/draw/",
273-
},
274-
{
275-
text: "ol-interaction-dragbox",
276-
link: "/componentsguide/interactions/dragbox/",
277-
},
278-
{
279-
text: "ol-interaction-dragrotate",
280-
link: "/componentsguide/interactions/dragrotate/",
281-
},
282-
{
283-
text: "ol-interaction-dragrotatezoom",
284-
link: "/componentsguide/interactions/dragrotatezoom/",
285-
},
286-
{
287-
text: "ol-interaction-modify",
288-
link: "/componentsguide/interactions/modify/",
289-
},
290-
{
291-
text: "ol-interaction-select",
292-
link: "/componentsguide/interactions/select/",
293-
},
294-
{
295-
text: "ol-interaction-snap",
296-
link: "/componentsguide/interactions/snap/",
297-
},
298-
{
299-
text: "ol-interaction-transform",
300-
link: "/componentsguide/interactions/transform/",
301-
},
302-
],
303-
},
304262
{
305263
text: "Animations",
306264
collapsed: true,
@@ -337,6 +295,52 @@ export const config: UserConfig = {
337295
},
338296
],
339297
},
298+
{
299+
text: "Interactions",
300+
collapsed: true,
301+
items: [
302+
{
303+
text: "ol-interaction-clusterselect",
304+
link: "/componentsguide/interactions/clusterselect/",
305+
},
306+
{
307+
text: "ol-interaction-draw",
308+
link: "/componentsguide/interactions/draw/",
309+
},
310+
{
311+
text: "ol-interaction-dragbox",
312+
link: "/componentsguide/interactions/dragbox/",
313+
},
314+
{
315+
text: "ol-interaction-dragrotate",
316+
link: "/componentsguide/interactions/dragrotate/",
317+
},
318+
{
319+
text: "ol-interaction-dragrotatezoom",
320+
link: "/componentsguide/interactions/dragrotatezoom/",
321+
},
322+
{
323+
text: "ol-interaction-link",
324+
link: "/componentsguide/interactions/link/",
325+
},
326+
{
327+
text: "ol-interaction-modify",
328+
link: "/componentsguide/interactions/modify/",
329+
},
330+
{
331+
text: "ol-interaction-select",
332+
link: "/componentsguide/interactions/select/",
333+
},
334+
{
335+
text: "ol-interaction-snap",
336+
link: "/componentsguide/interactions/snap/",
337+
},
338+
{
339+
text: "ol-interaction-transform",
340+
link: "/componentsguide/interactions/transform/",
341+
},
342+
],
343+
},
340344
{
341345
text: "Map Controls",
342346
collapsed: true,

Diff for: docs/componentsguide/interactions/link/index.md

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# ol-interaction-link
2+
3+
The link interaction allows you to synchronize the map state with the URL.
4+
By default the view center, zoom level, and rotation will be reflected in the URL as you navigate around the map.
5+
Layer visibility is also reflected in the URL.
6+
Reloading the page restores the map view state.
7+
8+
<script setup>
9+
import ViewDemo from "@demos/ViewDemo.vue"
10+
</script>
11+
12+
<ClientOnly>
13+
<ViewDemo/>
14+
</ClientOnly>
15+
16+
## Usage
17+
18+
::: code-group
19+
20+
<<< ../../../../src/demos/ViewDemo.vue
21+
22+
:::
23+
24+
## Properties
25+
26+
### Props from OpenLayers
27+
28+
Properties are passed-trough from OpenLayers directly.
29+
Their types and default values can be checked-out [in the official OpenLayers docs](https://openlayers.org/en/latest/apidoc/module-ol_interaction_Link-Link.html).
30+
Only some properties deviate caused by reserved keywords from Vue / HTML.
31+
This deviating props are described in the section below.
32+
33+
### Deviating Properties
34+
35+
None.
36+
37+
## Events
38+
39+
You have access to all Events from the underlying interaction.
40+
Check out [the official OpenLayers docs](https://openlayers.org/en/latest/apidoc/module-ol_interaction_Link-Link.html) to see the available events tht will be fired.
41+
42+
```html
43+
<ol-interaction-link @error="handleEvent" />
44+
```
45+
46+
## Methods
47+
48+
You have access to all Methods from the underlying interaction.
49+
Check out [the official OpenLayers docs](https://openlayers.org/en/latest/apidoc/module-ol_interaction_Link-Link.html) to see the available methods.
50+
51+
To access the source, you can use a `ref()` as shown below:
52+
53+
```vue
54+
<template>
55+
<!-- ... -->
56+
<ol-interaction-link ref="interactionRef" />
57+
<!-- ... -->
58+
</template>
59+
60+
<script setup lang="ts">
61+
import { ref, onMounted } from "vue";
62+
import type Link from "ol/interaction/Link";
63+
64+
const interactionRef = ref<{ link: Link } | null>(null);
65+
66+
onMounted(() => {
67+
const link: Link = interactionRef.value?.link;
68+
// call your method on `link`
69+
});
70+
</script>
71+
```

Diff for: src/components/interaction/OlLinktInteraction.vue

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<template>
2+
<slot></slot>
3+
</template>
4+
5+
<script setup lang="ts">
6+
import {
7+
provide,
8+
inject,
9+
watch,
10+
onMounted,
11+
onUnmounted,
12+
shallowRef,
13+
} from "vue";
14+
import Link, { type Options } from "ol/interaction/Link";
15+
import type Map from "ol/Map";
16+
import usePropsAsObjectProperties from "@/composables/usePropsAsObjectProperties";
17+
import { useOpenLayersEvents } from "@/composables/useOpenLayersEvents";
18+
19+
// prevent warnings caused by event pass-through via useOpenLayersEvents composable
20+
defineOptions({
21+
inheritAttrs: false,
22+
});
23+
24+
const props = withDefaults(defineProps<Options>(), {
25+
animate: true,
26+
params: ["x", "y", "z", "r", "l"],
27+
replace: false,
28+
prefix: "",
29+
});
30+
31+
const map = inject<Map>("map");
32+
const { properties } = usePropsAsObjectProperties(props);
33+
34+
const link = shallowRef(new Link(properties));
35+
36+
useOpenLayersEvents(link, ["change:active"]);
37+
38+
watch(link, (newVal, oldVal) => {
39+
map?.removeInteraction(oldVal);
40+
map?.addInteraction(newVal);
41+
map?.changed();
42+
});
43+
44+
onMounted(() => {
45+
map?.addInteraction(link.value);
46+
});
47+
48+
onUnmounted(() => {
49+
map?.removeInteraction(link.value);
50+
});
51+
52+
provide("stylable", link);
53+
54+
defineExpose({
55+
link,
56+
});
57+
</script>

Diff for: src/components/interaction/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import OlClusterSelectInteraction from "./OlClusterSelectInteraction.vue";
33
import OlDragBoxInteraction from "./OlDragBoxInteraction.vue";
44
import OlDragRotateInteraction from "./OlDragRotateInteraction.vue";
55
import OlDragRotateZoomInteraction from "./OlDragRotateZoomInteraction.vue";
6+
import OlLinktInteraction from "./OlLinktInteraction.vue";
67
import OlSelectInteraction from "./OlSelectInteraction.vue";
78
import OlDrawInteraction from "./OlDrawInteraction.vue";
89
import OlModifyInteraction from "./OlModifyInteraction.vue";
@@ -14,6 +15,7 @@ function install(app: App) {
1415
app.component("ol-interaction-dragbox", OlDragBoxInteraction);
1516
app.component("ol-interaction-dragrotate", OlDragRotateInteraction);
1617
app.component("ol-interaction-dragrotatezoom", OlDragRotateZoomInteraction);
18+
app.component("ol-interaction-link", OlLinktInteraction);
1719
app.component("ol-interaction-select", OlSelectInteraction);
1820
app.component("ol-interaction-draw", OlDrawInteraction);
1921
app.component("ol-interaction-modify", OlModifyInteraction);
@@ -29,6 +31,7 @@ export {
2931
OlDragBoxInteraction,
3032
OlDragRotateInteraction,
3133
OlDragRotateZoomInteraction,
34+
OlLinktInteraction,
3235
OlSelectInteraction,
3336
OlDrawInteraction,
3437
OlModifyInteraction,

Diff for: src/demos/AnimatedClusterDemo2.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ const geoJsonFeatures = computed(() => {
9494
return geoJson.readFeatures(providerFeatureCollection);
9595
});
9696
97-
const overrideStyleFunction = (feature: FeatureLike, style: any) => {
97+
const overrideStyleFunction = (feature: FeatureLike, style) => {
9898
const clusteredFeatures = feature.get("features");
9999
const size = clusteredFeatures.length;
100100

Diff for: src/demos/ViewDemo.vue

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
</ol-tile-layer>
2222

2323
<ol-rotate-control></ol-rotate-control>
24+
<ol-interaction-link />
2425
</ol-map>
2526

2627
<ul>

Diff for: src/demos/points.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,6 @@ export const arrayWith500Points = [
503503

504504
export const arrayWith50000Points = Array(100)
505505
.fill()
506-
.reduce((acc, _) => acc.concat(arrayWith500Points), []);
506+
.reduce((acc) => acc.concat(arrayWith500Points), []);
507507

508508
console.log(arrayWith50000Points);
Loading

Diff for: tests/interactions.test.ts

+36-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { test } from "@playwright/test";
1+
import { expect, test } from "@playwright/test";
22

33
import { MapPage } from "./MapPage";
44

@@ -107,6 +107,41 @@ test.describe("ol-interaction-dragrotatezoom", () => {
107107
});
108108
});
109109

110+
test.describe("ol-interaction-link", () => {
111+
test("should update the URL after loading", async ({ page }) => {
112+
const map = new MapPage(page);
113+
await map.goto("/componentsguide/interactions/link/");
114+
await map.waitUntilReady();
115+
await map.waitUntilCanvasLoaded();
116+
await map.checkCanvasScreenshot();
117+
await expect(map.page).toHaveURL(
118+
"/componentsguide/interactions/link/?x=40&y=40&z=8&r=0&l=1",
119+
);
120+
});
121+
122+
test("should load map view based on query params", async ({ page }) => {
123+
const map = new MapPage(page);
124+
await map.goto(
125+
"/componentsguide/interactions/link/?x=13.3&y=52.5&z=9&r=-0.1&l=1",
126+
);
127+
await map.waitUntilReady();
128+
await map.waitUntilCanvasLoaded();
129+
await map.checkCanvasScreenshot();
130+
});
131+
132+
test("should no override existing query params by default", async ({
133+
page,
134+
}) => {
135+
const map = new MapPage(page);
136+
await map.goto("/componentsguide/interactions/link/?existingParam=active");
137+
await map.waitUntilReady();
138+
await map.waitUntilCanvasLoaded();
139+
await expect(map.page).toHaveURL(
140+
"/componentsguide/interactions/link/?existingParam=active&x=40&y=40&z=8&r=0&l=1",
141+
);
142+
});
143+
});
144+
110145
test.describe("ol-interaction-select", () => {
111146
test("should be able to select a shape by hover", async ({ page }) => {
112147
const map = new MapPage(page);

Diff for: vite.config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ export default defineConfig({
122122
"ol/geom/Point": "Point$2",
123123
"ol/geom/Polygon": "Polygon",
124124
"ol/style/Style": "Style",
125+
"ol/interaction/Link": "Link",
125126
"ol/interaction/Draw": "Draw",
126127
"ol/interaction/DragBox": "DragBox",
127128
"ol/interaction/Modify": "Modify",

0 commit comments

Comments
 (0)