Skip to content

Commit 73920db

Browse files
committed
Add LayersControl
1 parent 2c7e260 commit 73920db

File tree

15 files changed

+360
-33
lines changed

15 files changed

+360
-33
lines changed
File renamed without changes.

src/lib/controls/DrawControl.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import GeoJSON from 'ol/format/GeoJSON';
1010
import { listen, unlistenByKey } from 'ol/events';
1111
import { useMap } from '../Map';
1212
import { drawIcon, lineIcon, pointIcon, polygonIcon, circleIcon, moveIcon} from './icons';
13-
import './style.css';
13+
import './DrawControl.css';
1414

15-
class DrawControlClass extends Control {
15+
class DrawControl extends Control {
1616
vectorSource: VectorSource;
1717
modify: Modify; // modifying vectorSource
1818
drawLayer: VectorLayer; // layer to hold vectorSource
@@ -138,12 +138,12 @@ class DrawControlClass extends Control {
138138
}
139139
}
140140

141-
export function DrawControl(props) {
141+
export default function(props) {
142142
const map: ol.Map = useMap();
143143

144144
useEffect(() => {
145145
if (!map) return;
146-
map.addControl(new DrawControlClass());
146+
map.addControl(new DrawControl());
147147
}, [map]);
148148

149149
return null;

src/lib/controls/LayersControl.css

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
.layers-control {
2+
top: 60px;
3+
right: 8px;
4+
5+
#layers {
6+
display: none;
7+
text-align: left;
8+
}
9+
10+
&.active {
11+
#toggle-btn {
12+
width: 100%;
13+
filter: invert(100%);
14+
}
15+
#layers {
16+
display: block;
17+
padding: 4px;
18+
background: #333;
19+
}
20+
}
21+
22+
#layers {
23+
display: none;
24+
text-align: left;
25+
26+
ul {
27+
list-style: none;
28+
margin: 0;
29+
padding: 0;
30+
}
31+
li {
32+
background-color: #FFF;
33+
color: #333;
34+
padding: 0 8px;
35+
&.visible {
36+
background-color: #333;
37+
color: #FFF;
38+
}
39+
> ul {
40+
margin-left: 20px;
41+
}
42+
}
43+
}
44+
}

src/lib/controls/LayersControl.tsx

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { Map as OlMap } from 'ol';
2+
import Control from 'ol/control/Control';
3+
import LayerGroup from 'ol/layer/Group';
4+
import { useEffect } from 'react';
5+
import { useMap } from '../Map';
6+
import { layersIcon } from './icons';
7+
import './LayersControl.css';
8+
9+
class LayersControl extends Control {
10+
11+
constructor(options={}) {
12+
const element = document.createElement('div');
13+
const {target} = options as any;
14+
super({element, target});
15+
const map = this.getMap();
16+
17+
element.className = 'layers-control ol-unselectable ol-control';
18+
element.insertAdjacentHTML('beforeend', `
19+
<button id="toggle-btn" title="Clik here to switch layers">
20+
${layersIcon}
21+
</button>
22+
<div id="layers">
23+
layers goes here
24+
</div>
25+
`);
26+
27+
element.querySelector('.layers-control #toggle-btn')
28+
.addEventListener('click', this.onToggleBtnClick.bind(this));
29+
}
30+
31+
onToggleBtnClick(event) {
32+
const controlEl = event.target.closest('.layers-control');
33+
controlEl.classList.toggle('active');
34+
if (!controlEl.classList.contains('active')) {
35+
return;
36+
}
37+
38+
function createUL(layer) {
39+
const ul = document.createElement('ul');
40+
41+
layer.getLayers().forEach(layer => {
42+
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) => {
46+
event.stopPropagation();
47+
li.classList.toggle('visible');
48+
layer.setVisible(li.classList.contains('visible'));
49+
});
50+
51+
if (layer instanceof LayerGroup) {
52+
li.appendChild(createUL(layer));
53+
}
54+
55+
ul.appendChild(li);
56+
});
57+
58+
return ul;
59+
}
60+
61+
const ul = createUL(this.getMap());
62+
const layersEl = controlEl.querySelector('#layers');
63+
layersEl.innerHTML = '';
64+
layersEl.appendChild(ul);
65+
}
66+
67+
}
68+
69+
export default function(props) {
70+
const map: OlMap = useMap();
71+
72+
useEffect(() => {
73+
if (!map) return;
74+
map.addControl(new LayersControl());
75+
}, [map]);
76+
77+
return null;
78+
};

src/lib/controls/icons.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,11 @@ export const moveIcon = `
3030
<polyline points="19 9 22 12 19 15" />
3131
<line x1="2" y1="12" x2="22" y2="12" />
3232
<line x1="12" y1="2" x2="12" y2="22" />
33-
</svg>`
33+
</svg>`
34+
35+
export const layersIcon = `
36+
<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">
37+
<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>
39+
<rect x="0" y="0" width="36" height="36" fill-opacity="0"/>
40+
</svg>`;

src/lib/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,20 @@ export { View } from './View';
55
export { Marker, getMarkerImage } from './Marker';
66
export { Overlay } from './Overlay';
77

8+
export { LayerGroup } from './layers/LayerGroup';
89
export { TileLayer } from './layers/TileLayer';
910
export { VectorLayer } from './layers/VectorLayer';
1011
export { GraticuleLayer } from './layers/GraticuleLayer';
1112
export { HeatmapLayer } from './layers/HeatmapLayer';
1213
export { WebGLTileLayer } from './layers/WebGLTileLayer';
1314

14-
export { DrawControl } from './controls/DrawControl';
1515
export { FullScreenControl } from './controls/FullScreenControl';
1616
export { ScaleLineControl } from './controls/ScaleLineControl';
1717
export { AttributionControl } from './controls/AttributionControl';
1818
export { MousePositionControl } from './controls/MousePositionControl';
1919
export { OverviewMapControl } from './controls/OverviewMapControl';
20+
export { default as DrawControl } from './controls/DrawControl';
21+
export { default as LayersControl } from './controls/LayersControl';
2022

2123
export { DragRotateAndZoomInteraction } from './interactions/DragRotateAndZoom';
2224
export { TranslateInteraction } from './interactions/TranslateInteraction';

src/lib/layers/GraticuleLayer.tsx

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,38 @@
1-
import { useEffect } from 'react';
1+
import { Map as OlMap } from 'ol';
2+
import { useEffect, useRef } from 'react';
23
import OlGraticuleLayer from 'ol/layer/Graticule';
34
import { useMap } from '../Map';
5+
import { useGroup } from './LayerGroup';
46

57
export function GraticuleLayer(props) {
68
const map = useMap();
9+
const group = useGroup();
10+
const layerRef = useRef(new OlGraticuleLayer(props)); // single instance
711

812
useEffect(() => {
9-
if (!map) return;
10-
const layer = new OlGraticuleLayer(props);
11-
map.addLayer(layer);
12-
}, [map]);
13+
if (!map && !group) return;
14+
15+
const layer = layerRef.current; // same instance every time
16+
const target = group || map;
17+
18+
if (target) {
19+
if (target instanceof OlMap) {
20+
target.addLayer(layer);
21+
} else {
22+
target.getLayers().push(layer);
23+
}
24+
}
25+
26+
return () => {
27+
if (target) {
28+
if (target instanceof OlMap) {
29+
target.removeLayer(layer);
30+
} else {
31+
target.getLayers().remove(layer);
32+
}
33+
}
34+
};
35+
}, [map, group]);
1336

1437
return null;
15-
};
38+
}

src/lib/layers/HeatmapLayer.tsx

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,38 @@
1-
import { useEffect } from 'react';
1+
import { useEffect, useRef } from 'react';
2+
import { Map as OlMap } from 'ol';
23
import OlHeatmapLayer from 'ol/layer/Heatmap';
34
import { useMap } from '../Map';
5+
import { useGroup } from './LayerGroup';
46

57
export function HeatmapLayer(props) {
68
const map = useMap();
9+
const group = useGroup();
10+
const layerRef = useRef(new OlHeatmapLayer(props)); // single instance
711

812
useEffect(() => {
9-
if (!map) return;
10-
const layer = new OlHeatmapLayer(props);
11-
map.addLayer(layer);
12-
}, [map]);
13+
if (!map && !group) return;
14+
15+
const layer = layerRef.current; // same instance every time
16+
const target = group || map;
17+
18+
if (target) {
19+
if (target instanceof OlMap) {
20+
target.addLayer(layer);
21+
} else {
22+
target.getLayers().push(layer);
23+
}
24+
}
25+
26+
return () => {
27+
if (target) {
28+
if (target instanceof OlMap) {
29+
target.removeLayer(layer);
30+
} else {
31+
target.getLayers().remove(layer);
32+
}
33+
}
34+
};
35+
}, [map, group]);
1336

1437
return null;
15-
};
38+
}

src/lib/layers/TileLayer.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as ol from 'ol';
1+
import { Map as OlMap} from 'ol';
22
import { useEffect, useRef } from 'react';
33
import OlTileLayer from 'ol/layer/Tile';
44
import { useMap } from '../Map';
@@ -16,7 +16,7 @@ export function TileLayer(props: any) {
1616
const target = group || map;
1717

1818
if (target) {
19-
if (target instanceof ol.Map) {
19+
if (target instanceof OlMap) {
2020
target.addLayer(layer);
2121
} else {
2222
target.getLayers().push(layer);
@@ -25,7 +25,7 @@ export function TileLayer(props: any) {
2525

2626
return () => {
2727
if (target) {
28-
if (target instanceof ol.Map) {
28+
if (target instanceof OlMap) {
2929
target.removeLayer(layer);
3030
} else {
3131
target.getLayers().remove(layer);

src/lib/layers/VectorLayer.tsx

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,38 @@
1-
import { useEffect } from 'react';
1+
import { Map as OlMap } from 'ol';
2+
import { useEffect, useRef } from 'react';
23
import OlVectorLayer from 'ol/layer/Vector';
34
import { useMap } from '../Map';
5+
import { useGroup } from './LayerGroup';
46

57
export function VectorLayer(props) {
68
const map = useMap();
9+
const group = useGroup();
10+
const layerRef = useRef(new OlVectorLayer(props)); // single instance
711

812
useEffect(() => {
9-
if (!map) return;
10-
const layer = new OlVectorLayer(props);
11-
map.addLayer(layer);
12-
}, [map]);
13+
if (!map && !group) return;
14+
15+
const layer = layerRef.current; // same instance every time
16+
const target = group || map;
17+
18+
if (target) {
19+
if (target instanceof OlMap) {
20+
target.addLayer(layer);
21+
} else {
22+
target.getLayers().push(layer);
23+
}
24+
}
25+
26+
return () => {
27+
if (target) {
28+
if (target instanceof OlMap) {
29+
target.removeLayer(layer);
30+
} else {
31+
target.getLayers().remove(layer);
32+
}
33+
}
34+
};
35+
}, [map, group]);
1336

1437
return null;
15-
};
38+
}

0 commit comments

Comments
 (0)