Skip to content

Commit

Permalink
feat(ol-search-control): add search control (#309)
Browse files Browse the repository at this point in the history
closes #306
  • Loading branch information
d-koppenhagen authored Mar 7, 2024
1 parent 3b3464d commit 4f529f7
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 0 deletions.
4 changes: 4 additions & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,10 @@ export default defineConfig({
text: "ol-rotate-control",
link: "/componentsguide/mapcontrols/rotate/",
},
{
text: "ol-search-control",
link: "/componentsguide/mapcontrols/search/",
},
{
text: "ol-scaleline-control",
link: "/componentsguide/mapcontrols/scaleline/",
Expand Down
61 changes: 61 additions & 0 deletions docs/componentsguide/mapcontrols/search/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# ol-search-control

> A Search control for OpenLayers.
<script setup>
import SearchControlDemo from "@demos/SearchControlDemo.vue"
</script>
<ClientOnly>
<SearchControlDemo />
</ClientOnly>

## Usage

::: code-group

<<< ../../../../src/demos/SearchControlDemo.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](https://viglino.github.io/ol-ext/examples/search/map.control.search.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

### select

Emits when selecting an item from the list of search results.

- **Type**: `SearchEvent`

```vue
<template>
<ol-map ref="map" style="height: 400px">
<!-- ... -->
<ol-search-control :autocomplete="autocomplete" @select="select"/>
</ol-map>
</template>
<script setup lang="ts">
// ...
function select(e: SearchEvent) {
const map: Map = e.target.getMap();
map.getView().animate({
center: e.search.pos,
zoom: e.search.zoom,
easing: easeOut,
});
}
</script>
```
24 changes: 24 additions & 0 deletions src/components/mapControls/OlSearchControl.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<template>
<div v-if="false"></div>
</template>
<script setup lang="ts">
import Search, { type Options } from "ol-ext/control/Search";
import { useAttrs } from "vue";
import useControl from "@/composables/useControl";
import usePropsAsObjectProperties from "@/composables/usePropsAsObjectProperties";
const emit = defineEmits(["select"]);
const props = withDefaults(defineProps<Options>(), {
className: "ol-search",
});
const attrs = useAttrs();
const { properties } = usePropsAsObjectProperties(props);
const { control } = useControl(Search, properties, attrs);
control.value.on("select", (event) => emit("select", event));
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 @@ -11,6 +11,7 @@ import OlOverviewMapControl from "./OlOverviewMapControl.vue";
import OlPrintDialogControl from "./OlPrintDialogControl.vue";
import OlRotateControl from "./OlRotateControl.vue";
import OlScaleLineControl from "./OlScaleLineControl.vue";
import OlSearchControl from "./OlSearchControl.vue";
import OlSwipeControl from "./OlSwipeControl.vue";
import OlToggleControl from "./OlToggleControl.vue";
import OlVideoRecorderControl from "./OlVideoRecorderControl.vue";
Expand All @@ -30,6 +31,7 @@ function install(app: App) {
app.component("ol-zoomtoextent-control", OlZoomToExtentControl);
app.component("ol-rotate-control", OlRotateControl);
app.component("ol-context-menu-control", OlContextMenuControl);
app.component("ol-search-control", OlSearchControl);
app.component("ol-swipe-control", OlSwipeControl);
app.component("ol-control-bar", OlControlBar);
app.component("ol-toggle-control", OlToggleControl);
Expand Down Expand Up @@ -57,6 +59,7 @@ export {
OlPrintDialogControl,
OlRotateControl,
OlScaleLineControl,
OlSearchControl,
OlSwipeControl,
OlToggleControl,
OlVideoRecorderControl,
Expand Down
4 changes: 4 additions & 0 deletions src/composables/useControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import type { Options as LayerSwitcherOptions } from "ol-ext/control/LayerSwitch
import type LayerSwitcherImage from "ol-ext/control/LayerSwitcherImage";
import type Rotate from "ol/control/Rotate";
import type { Options as RotateOptions } from "ol/control/Rotate";
import type Search from "ol-ext/control/Search";
import type { Options as SearchOptions } from "ol-ext/control/Search";
import type Swipe from "ol-ext/control/Swipe";
import type { Options as SwipeOptions } from "ol-ext/control/Swipe";
import type Zone from "ol-ext/control/MapZone";
Expand Down Expand Up @@ -55,6 +57,7 @@ type InnerControlType = (
| MousePosition
| OverviewMap
| Rotate
| Search
| ScaleLine
| Swipe
| Zone
Expand All @@ -73,6 +76,7 @@ type InnerControlProperties =
| ToggleOptions
| VideoRecorderOptions
| LayerSwitcherOptions
| SearchOptions
| RotateOptions
| SwipeOptions
| MapZoneOptions
Expand Down
106 changes: 106 additions & 0 deletions src/demos/SearchControlDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<template>
<ol-map ref="map" style="height: 400px" :controls="[]">
<ol-view
ref="view"
:center="center"
:zoom="zoom"
:projection="projection"
/>
<ol-tile-layer title="OSM">
<ol-source-osm />
</ol-tile-layer>

<ol-search-control
:autocomplete="autocomplete"
:getTitle="getTitle"
:collapsed="true"
:maxHistory="10"
@select="select"
/>
</ol-map>
</template>

<script setup lang="ts">
import type { Coordinate } from "ol/coordinate";
import { type SearchEvent } from "ol-ext/control/Search";
import { easeOut } from "ol/easing";
import { ref } from "vue";
import type { Map } from "ol";
type City = {
name: string;
pos: Coordinate;
zoom: number;
};
const center = ref([40, 40]);
const projection = ref("EPSG:4326");
const zoom = ref(8);
const positions: City[] = [
{
name: "Paris",
pos: [2.351828, 48.856578],
zoom: 11,
},
{
name: "London",
pos: [-0.1275, 51.507222],
zoom: 11,
},
{
name: "Geneve",
pos: [6.149985, 46.200013],
zoom: 13,
},
{
name: "Bruxelles",
pos: [4.35, 50.83],
zoom: 12,
},
{
name: "Berlin",
pos: [13.383333, 52.516667],
zoom: 12,
},
{
name: "Madrid",
pos: [-3.683333, 40.433333],
zoom: 12,
},
{
name: "Roma",
pos: [12.48657, 41.888732],
zoom: 12,
},
];
function getTitle(f: City) {
return f.name;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function autocomplete(s: string, callback: (result: City[]) => void) {
const result = [];
for (let i = 0; i < positions.length; i++) {
if (new RegExp(s.replace("*", "") || ".*", "i").test(positions[i].name)) {
result.push(positions[i]);
}
}
/* Return result directly... */
return result;
/* ...or use the callback function
callback(result);
return false;
*/
}
function select(e: SearchEvent) {
const map: Map = e.target.getMap();
map.getView().animate({
center: e.search.pos,
zoom: e.search.zoom,
easing: easeOut,
});
}
</script>
1 change: 1 addition & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export default defineConfig({
"ol-ext/control/PrintDialog": "PrintDialog",
"ol/control/Rotate": "Rotate$1",
"ol-ext/control/Swipe": "Swipe",
"ol-ext/control/Search": "Search",
"ol-ext/control/Toggle": "Toggle",
"ol-ext/control/VideoRecorder": "VideoRecorder",
"ol-ext/control/MapZone": "MapZone",
Expand Down

0 comments on commit 4f529f7

Please # to comment.