Skip to content

Commit 29753ce

Browse files
committed
Added LayersControl, SearchControl, Measuring tool
1 parent f86b0a0 commit 29753ce

24 files changed

+342
-43
lines changed

.storybook/preview-head.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDwE-ajIJZ9sOohSf-QFOBbVFn9_OqGRAQ&libraries=places"></script>

src/lib/Map.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ export const Map = forwardRef<OlMap | undefined, MapProps>((props, ref) => {
5151
},
5252
...props, // Override with props.view if provided
5353
};
54+
if (props.darkMode) {
55+
mapRef.current.style.filter = 'invert(1)'
56+
}
5457
const olMap = new OlMap(mapProps);
5558
setMap(olMap);
5659
mounted.current = true;

src/lib/add-marker.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import Feature from "ol/Feature";
2+
import { Point } from "ol/geom";
3+
import VectorLayer from "ol/layer/Vector";
4+
import { fromLonLat } from "ol/proj";
5+
import VectorSource from "ol/source/Vector";
6+
import Icon from "ol/style/Icon";
7+
import Style from "ol/style/Style";
8+
import { getMarkerImage } from "./Marker";
9+
10+
export function addMarker(map, lonLat, color='red', char='') {
11+
let markerLayer = map.getLayers().getArray()
12+
.find(el => el.get('key') === 'markerLayer') as VectorLayer;
13+
14+
if (!markerLayer) {
15+
const newMarkerLayer = new VectorLayer({
16+
source: new VectorSource({ features: [] }),
17+
properties: {key: 'markerLayer'},
18+
zIndex: 1,
19+
});
20+
map.addLayer(newMarkerLayer);
21+
markerLayer = newMarkerLayer;
22+
}
23+
24+
// container of markers, this can be set when marker is added, so that I can remove it here.
25+
const markerFeature = new Feature({
26+
geometry: new Point(fromLonLat(lonLat))
27+
});
28+
29+
markerFeature.setStyle(new Style({
30+
image: new Icon({
31+
scale: 1,
32+
anchor: [0.5,40],
33+
anchorXUnits: 'fraction',
34+
anchorYUnits: 'pixels',
35+
src: getMarkerImage(color, char)
36+
}),
37+
}));
38+
39+
markerLayer.getSource().addFeature(markerFeature);
40+
return markerFeature;
41+
}

src/lib/controls/DrawControl.css

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,22 @@
11
.draw-control {
2-
top: 60px;
3-
left: 8px;
2+
top: .5em;
3+
left: .5em;
4+
display: flex;
5+
flex-wrap: wrap;
6+
background-color: transparent;
7+
8+
[hidden] {
9+
display: none !important;
10+
}
11+
412
.shapes {
13+
display: flex;
14+
flex-wrap: wrap;
15+
516
> * {
617
background: #f0f0f0;
718
}
19+
820
> .active {
921
border: 2px inset;
1022
background: #ddd;

src/lib/controls/DrawControl.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@ class DrawControl extends Control {
2020
snap: Snap;
2121
keyboardListener;
2222

23-
constructor(options={}) {
23+
constructor(options={} as any) {
2424
const {target} = options as any;
2525

2626
const element = document.createElement('div');
2727
element.className = 'draw-control ol-unselectable ol-control';
28+
if (options.style) {
29+
Object.assign(element.style, options.style);
30+
}
2831
const title = 'Press shift for freehand drawing';
2932
element.insertAdjacentHTML('beforeend', `
3033
<button id="toggle-btn"
@@ -143,7 +146,7 @@ export default function(props) {
143146

144147
useEffect(() => {
145148
if (!map) return;
146-
map.addControl(new DrawControl());
149+
map.addControl(new DrawControl(props));
147150
}, [map]);
148151

149152
return null;

src/lib/controls/LayersControl.css

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
.layers-control {
2-
top: 60px;
3-
right: 8px;
2+
top: .5rem;
3+
right: .5rem;
44

5-
#layers {
6-
display: none;
7-
text-align: left;
8-
}
9-
105
&.active {
116
#toggle-btn {
127
width: 100%;
@@ -15,30 +10,20 @@
1510
#layers {
1611
display: block;
1712
padding: 4px;
18-
background: #333;
1913
}
2014
}
2115

2216
#layers {
2317
display: none;
2418
text-align: left;
25-
2619
ul {
2720
list-style: none;
2821
margin: 0;
2922
padding: 0;
3023
}
3124
li {
3225
background-color: #FFF;
33-
color: #333;
3426
padding: 0 8px;
35-
&.visible {
36-
background-color: #333;
37-
color: #FFF;
38-
}
39-
> ul {
40-
margin-left: 20px;
41-
}
4227
}
4328
}
4429
}

src/lib/controls/LayersControl.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,18 @@ class LayersControl extends Control {
4040

4141
layer.getLayers().forEach(layer => {
4242
const li = document.createElement('li');
43-
li.innerHTML = layer.get('name') || layer.constructor.name;
44-
layer.getVisible() && li.classList.add('visible');
45-
li.addEventListener('click', (event) => {
43+
const labelEl = document.createElement('label');
44+
const chkbox = document.createElement('input');
45+
chkbox.setAttribute('type', 'checkbox');
46+
chkbox.checked = layer.getVisible();
47+
chkbox.addEventListener('click', (e: any) => {
4648
event.stopPropagation();
47-
li.classList.toggle('visible');
48-
layer.setVisible(li.classList.contains('visible'));
49+
layer.setVisible(e.target.checked);
4950
});
51+
labelEl.appendChild(chkbox);
52+
const name = layer.get('name') || layer.constructor.name;
53+
labelEl.insertAdjacentText('beforeend', name);
54+
li.appendChild(labelEl);
5055

5156
if (layer instanceof LayerGroup) {
5257
li.appendChild(createUL(layer));

src/lib/controls/SearchControl.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.search-control {
2+
top: .5rem;
3+
left: .5rem;
4+
display: flex;
5+
6+
&.active {
7+
#toggle-btn {
8+
width: 100%;
9+
filter: invert(100%);
10+
}
11+
#search {
12+
display: block;
13+
padding: 4px;
14+
}
15+
}
16+
17+
#search {
18+
display: none;
19+
}
20+
}

src/lib/controls/SearchControl.tsx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Map as OlMap } from 'ol';
2+
import Control from 'ol/control/Control';
3+
import { useEffect } from 'react';
4+
import { useMap } from '../Map';
5+
import { searchIcon } from './icons';
6+
import './SearchControl.css';
7+
import { addMarker } from '../add-marker';
8+
import { fromLonLat } from 'ol/proj';
9+
10+
declare var google: any;
11+
12+
class SearchControl extends Control {
13+
14+
constructor(options={}) {
15+
const element = document.createElement('div');
16+
const {target} = options as any;
17+
super({element, target});
18+
19+
element.className = 'search-control ol-unselectable ol-control';
20+
element.insertAdjacentHTML('beforeend', `
21+
<button id="toggle-btn" title="Clik here to switch layers">${searchIcon}</button>
22+
<input id="search" title="Enter address to search" autocomplete="off" size="40" />
23+
`);
24+
25+
element.querySelector('.search-control #toggle-btn')
26+
.addEventListener('click', this.onToggleBtnClick.bind(this));
27+
28+
const inputEl = element.querySelector('input#search');
29+
var autocomplete = new google.maps.places.Autocomplete(inputEl);
30+
autocomplete.addListener("place_changed", () => {
31+
const place = autocomplete.getPlace();
32+
var latitude = place.geometry.location.lat();
33+
var longitude = place.geometry.location.lng();
34+
const map = this.getMap();
35+
addMarker(map, [longitude, latitude], 'blue');
36+
map.getView().setCenter(fromLonLat([longitude, latitude]));
37+
map.getView().setZoom(18);
38+
});
39+
}
40+
41+
onToggleBtnClick(event) {
42+
const controlEl = event.target.closest('.search-control');
43+
controlEl.classList.toggle('active');
44+
}
45+
}
46+
47+
48+
export default function(props) {
49+
const map: OlMap = useMap();
50+
51+
useEffect(() => {
52+
if (!map) return;
53+
map.addControl(new SearchControl());
54+
}, [map]);
55+
56+
return null;
57+
};

src/lib/controls/icons.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@ export const moveIcon = `
3535
export const layersIcon = `
3636
<svg fill="#000000" width="100%" height="100%" viewBox="0 0 36 36" version="1.1" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3737
<title>layers-solid</title>
38-
<path class="clr-i-solid clr-i-solid-path-1" d="M18,20.25a1,1,0,0,1-.43-.1l-15-7.09a1,1,0,0,1,0-1.81l15-7.09a1,1,0,0,1,.85,0l15,7.09a1,1,0,0,1,0,1.81l-15,7.09A1,1,0,0,1,18,20.25Z"></path><path class="clr-i-solid clr-i-solid-path-2" d="M18,26.16a1,1,0,0,1-.43-.1L2.57,19a1,1,0,1,1,.85-1.81L18,24.06l14.57-6.89A1,1,0,1,1,33.43,19l-15,7.09A1,1,0,0,1,18,26.16Z"></path><path class="clr-i-solid clr-i-solid-path-3" d="M18,32.07a1,1,0,0,1-.43-.1l-15-7.09a1,1,0,0,1,.85-1.81L18,30l14.57-6.89a1,1,0,1,1,.85,1.81L18.43,32A1,1,0,0,1,18,32.07Z"></path>
38+
<path class="clr-i-solid clr-i-solid-path-1"
39+
d="M18,20.25a1,1,0,0,1-.43-.1l-15-7.09a1,1,0,0,1,0-1.81l15-7.09a1,1,0,0,1,.85,0l15,7.09a1,1,0,0,1,0,1.81l-15,7.09A1,1,0,0,1,18,20.25Z">
40+
</path>
41+
<path class="clr-i-solid clr-i-solid-path-2"
42+
d="M18,26.16a1,1,0,0,1-.43-.1L2.57,19a1,1,0,1,1,.85-1.81L18,24.06l14.57-6.89A1,1,0,1,1,33.43,19l-15,7.09A1,1,0,0,1,18,26.16Z">
43+
</path>
44+
<path class="clr-i-solid clr-i-solid-path-3" d="M18,32.07a1,1,0,0,1-.43-.1l-15-7.09a1,1,0,0,1,.85-1.81L18,30l14.57-6.89a1,1,0,1,1,.85,1.81L18.43,32A1,1,0,0,1,18,32.07Z">
45+
</path>
3946
<rect x="0" y="0" width="36" height="36" fill-opacity="0"/>
40-
</svg>`;
47+
</svg>`;
48+
49+
export const searchIcon = `
50+
<svg width="100%" height="100%" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
51+
<path d="M10 4a6 6 0 1 0 0 12 6 6 0 0 0 0-12zm-8 6a8 8 0 1 1 14.32 4.906l5.387 5.387a1 1 0 0 1-1.414 1.414l-5.387-5.387A8 8 0 0 1 2 10z"
52+
fill="#0D0D0D"/>
53+
</svg>
54+
`

0 commit comments

Comments
 (0)