Skip to content

feat(ol-profile-control): add control for ol-ext/controls/Profile #318

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

Merged
merged 2 commits into from
Mar 22, 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
4 changes: 4 additions & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,10 @@ export const config: UserConfig = {
text: "ol-printdialog-control",
link: "/componentsguide/mapcontrols/printdialog/",
},
{
text: "ol-profile-control",
link: "/componentsguide/mapcontrols/profile/",
},
{
text: "ol-rotate-control",
link: "/componentsguide/mapcontrols/rotate/",
Expand Down
69 changes: 69 additions & 0 deletions docs/componentsguide/mapcontrols/profile/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# ol-profile-control

> A profile control.

<script setup>
import ProfileControlDemo from "@demos/ProfileControlDemo.vue"
</script>
<ClientOnly>
<ProfileControlDemo />
</ClientOnly>

## Usage

::: code-group

<<< ../../../../src/demos/ProfileControlDemo.vue

:::

## Properties

### Props from OpenLayers

Properties are passed-trough from `ol-ext` directly.
Their types and default values can be checked-out [in the official OpenLayers docs: `ol-ext/control/Profile`](https://viglino.github.io/ol-ext/doc/doc-pages/ol.control.Profile.html).
Only some properties deviate caused by reserved keywords from Vue / HTML.
This deviating props are described in the section below.

### Deviating Properties

None.

## Events

You have access to all Events from the underlying `ol-ext` Profile Control API (without the `event:` prefix).
Check out [the official OpenLayers docs](https://viglino.github.io/ol-ext/doc/doc-pages/ol.control.Profile.html) to see the available events tht will be fired.

For example:

```html
<ol-profile-control @over="handleOver" @out="handleOut" />
```

## Methods

You have access to all Methods from the underlying `ol-ext` Profile Control API.
Check out [the official OpenLayers docs](https://viglino.github.io/ol-ext/doc/doc-pages/ol.control.Profile.html) to see the available methods.

To access the source, you can use a `ref()` as shown below:

```vue
<template>
<!-- ... -->
<ol-profile-control ref="profileControlRef" />
<!-- ... -->
</template>

<script setup lang="ts">
import { ref, onMounted } from "vue";
import type Profile from "ol-ext/controls/Profile";

const profileControlRef = ref<{ control: Profile }>(null);

onMounted(() => {
const profile: Profile = profileControlRef.value?.control;
// call your method on `profile`
});
</script>
```
35 changes: 35 additions & 0 deletions src/components/mapControls/OlProfileControl.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<template>
<div v-if="false"></div>
</template>
<script setup lang="ts">
import Profile, { type Options } from "ol-ext/control/Profile";
import { useAttrs } from "vue";
import useControl from "@/composables/useControl";
import usePropsAsObjectProperties from "@/composables/usePropsAsObjectProperties";
import { useOpenLayersEvents } from "@/composables/useOpenLayersEvents";

// prevent warnings caused by event pass-through via useOpenLayersEvents composable
defineOptions({
inheritAttrs: false,
});

const props = withDefaults(defineProps<Options>(), {});

const attrs = useAttrs();
const { properties } = usePropsAsObjectProperties(props);
const { control } = useControl(Profile, properties, attrs);

useOpenLayersEvents(control, [
"over",
"out",
"show",
"dragstart",
"dragging",
"dragend",
"dragcancel",
]);

defineExpose({
control,
});
</script>
3 changes: 3 additions & 0 deletions src/components/mapControls/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import OlLayerSwitcherImageControl from "./OlLayerSwitcherImageControl.vue";
import OlMousePositionControl from "./OlMousePositionControl.vue";
import OlOverviewMapControl from "./OlOverviewMapControl.vue";
import OlPrintDialogControl from "./OlPrintDialogControl.vue";
import OlProfileControl from "./OlProfileControl.vue";
import OlRotateControl from "./OlRotateControl.vue";
import OlScaleLineControl from "./OlScaleLineControl.vue";
import OlSearchControl from "./OlSearchControl.vue";
Expand Down Expand Up @@ -37,6 +38,7 @@ function install(app: App) {
app.component("ol-toggle-control", OlToggleControl);
app.component("ol-button-control", OlButtonControl);
app.component("ol-printdialog-control", OlPrintDialogControl);
app.component("ol-profile-control", OlProfileControl);
app.component("ol-videorecorder-control", OlVideoRecorderControl);
app.component("ol-layerswitcher-control", OlLayerSwitcherControl);
app.component("ol-layerswitcherimage-control", OlLayerSwitcherImageControl);
Expand All @@ -57,6 +59,7 @@ export {
OlMousePositionControl,
OlOverviewMapControl,
OlPrintDialogControl,
OlProfileControl,
OlRotateControl,
OlScaleLineControl,
OlSearchControl,
Expand Down
4 changes: 4 additions & 0 deletions src/composables/useControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import type Button from "ol-ext/control/Button";
import type { Options as ButtonOptions } from "ol-ext/control/Button";
import type PrintDialog from "ol-ext/control/PrintDialog";
import type { Options as PrintDialogOptions } from "ol-ext/control/PrintDialog";
import type Profile from "ol-ext/control/Profile";
import type { Options as ProfileOptions } from "ol-ext/control/Profile";
import type Toggle from "ol-ext/control/Toggle";
import type { Options as ToggleOptions } from "ol-ext/control/Toggle";
import type VideoRecorder from "ol-ext/control/VideoRecorder";
Expand Down Expand Up @@ -49,6 +51,7 @@ type InnerControlType = (
| Bar
| Button
| PrintDialog
| Profile
| Toggle
| VideoRecorder
| FullScreen
Expand All @@ -73,6 +76,7 @@ type InnerControlProperties =
| BarOptions
| ButtonOptions
| PrintDialogOptions
| ProfileOptions
| ToggleOptions
| VideoRecorderOptions
| LayerSwitcherOptions
Expand Down
26 changes: 23 additions & 3 deletions src/demos/LineString.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

<ol-vector-layer>
<ol-source-vector>
<ol-feature>
<ol-feature ref="profileFeatureRef">
<ol-geom-line-string
:coordinates="[
[116.544921, 40.451633],
Expand Down Expand Up @@ -47,15 +47,35 @@
</ol-feature>
</ol-source-vector>
</ol-vector-layer>

<ol-profile-control
v-if="profileFeatureRef?.feature"
:feature="profileFeatureRef.feature"
@over="over"
@out="out"
></ol-profile-control>
</ol-map>
</template>

<script setup>
import { ref } from "vue";
<script setup lang="ts">
import { ref, onMounted } from "vue";

const center = ref([116.54875, 40.45064]);
const projection = ref("EPSG:4326");
const zoom = ref(17);
const strokeWidth = ref(10);
const strokeColor = ref("red");
const profileFeatureRef = ref(null);

function over(event) {
console.log(event);
}

function out(event) {
console.log(event);
}

onMounted(() => {
console.log(profileFeatureRef.value);
});
</script>
121 changes: 121 additions & 0 deletions src/demos/ProfileControlDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<template>
<ol-map
:loadTilesWhileAnimating="true"
:loadTilesWhileInteracting="true"
style="height: 400px"
>
<ol-view ref="view" :center="center" :zoom="zoom" />

<ol-tile-layer>
<ol-source-osm />
</ol-tile-layer>

<!-- vector data path -->
<ol-vector-layer>
<ol-source-vector
url="https://raw.githubusercontent.com/Viglino/ol-ext/master/examples/data/2009-09-04_rando.gpx"
:format="gpx"
@featuresloadend="handleFeaturesloadend"
>
<ol-style>
<ol-style-stroke color="red" :width="3"></ol-style-stroke>
</ol-style>
</ol-source-vector>
</ol-vector-layer>

<!-- Hover handling -->
<ol-interaction-select
@select="featureSelected"
:condition="selectCondition"
:hitTolerance="10"
>
<ol-style>
<ol-style-stroke color="red" :width="3"></ol-style-stroke>
</ol-style>
</ol-interaction-select>

<!-- point -->
<ol-vector-layer>
<ol-source-vector>
<ol-feature>
<ol-geom-point v-if="point" :coordinates="point"></ol-geom-point>
<ol-style>
<ol-style-circle :radius="3">
<ol-style-fill color="green"></ol-style-fill>
<ol-style-stroke color="green" :width="10"></ol-style-stroke>
</ol-style-circle>
</ol-style>
</ol-feature>
</ol-source-vector>
</ol-vector-layer>

<ol-profile-control
@over="over"
@out="out"
ref="profileControl"
></ol-profile-control>
</ol-map>
</template>

<script setup lang="ts">
import type { Feature } from "ol";
import type Profile from "ol-ext/control/Profile";
import type { Coordinate } from "ol/coordinate";
import type { Point } from "ol/geom";
import type { SelectEvent } from "ol/interaction/Select";
import type { VectorSourceEvent } from "ol/source/Vector";
import { ref, inject } from "vue";

const center = ref([650000, 5407500]);
const zoom = ref(13);
const profileFeature = ref(null);
const profileControl = ref<{ control: Profile } | null>(null);
const point = ref<Coordinate | null>(null);

const selectConditions = inject("ol-selectconditions");
const format = inject("ol-format");

const gpx = new format.GPX();
const selectCondition = selectConditions.pointerMove;

function handleFeaturesloadend(event: VectorSourceEvent) {
profileFeature.value = event.target.getFeatures()[0];
if (profileFeature.value) {
profileControl.value?.control?.setGeometry(profileFeature.value);
}
}

function featureSelected(event: SelectEvent) {
const selected = event.selected[0] as Feature<Point>;
if (selected) {
const p = selected
.getGeometry()
?.getClosestPoint(event.mapBrowserEvent.coordinate);
if (p) {
drawPoint("over", p);
}
}
}

function over(event: { type: "over" | "out"; coord: Coordinate }) {
drawPoint("over", event.coord);
}

function out(event: { type: "over" | "out"; coord: Coordinate }) {
drawPoint(event.type, event.coord);
}

function drawPoint(type: "over" | "out", coord: Coordinate) {
const profile = profileControl.value?.control;
if (!profile) return;
if (coord) {
point.value = coord;
const position = profile.showAt(coord);
profile.popup(`${position[2]} m`);
} else {
point.value = null;
profile.showAt([]);
profile.popup("");
}
}
</script>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions tests/controls.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,18 @@ test.describe("ol-printdialog-control", () => {
});
});

test.describe("ol-profile-control", () => {
test("should render", async ({ page }) => {
const map = new MapPage(page);
await map.goto("/componentsguide/mapcontrols/profile/");
await map.waitUntilReady();
await map.waitUntilCanvasLoaded();
await map.page.locator(".ol-control").getByTitle("Profile").click();
await map.hoverOnCanvas([104, 192]);
await map.checkCanvasScreenshot();
});
});

test.describe("ol-rotate-control", () => {
test("should render", async ({ page }) => {
const map = new MapPage(page);
Expand Down
1 change: 1 addition & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export default defineConfig({
"ol-ext/control/Toggle": "Toggle",
"ol-ext/control/VideoRecorder": "VideoRecorder",
"ol-ext/control/MapZone": "MapZone",
"ol-ext/control/Profile": "Profile",
"ol/control/Zoom": "Zoom",
"ol/control/ZoomSlider": "ZoomSlider",
"ol/control/ZoomToExtent": "ZoomToExtent",
Expand Down