ol-layer-control 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/package.json +60 -0
- package/readme.md +239 -0
- package/src/ol-layer-control.css +408 -0
- package/src/ol-layer-control.js +1132 -0
- package/types/ol-layer-control.d.ts +451 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
/* ol-layer-control
|
|
2
|
+
*
|
|
3
|
+
* Theme it by overriding these custom properties on any ancestor of the
|
|
4
|
+
* panel (e.g. :root or body):
|
|
5
|
+
*
|
|
6
|
+
* --ol-layer-control-bg panel background
|
|
7
|
+
* --ol-layer-control-fg panel text colour
|
|
8
|
+
* --ol-layer-control-border panel and header border colour
|
|
9
|
+
* --ol-layer-control-hover hover background of icon buttons
|
|
10
|
+
* --ol-layer-control-accent checkbox / radio / resize handle colour
|
|
11
|
+
* --ol-layer-control-font panel font shorthand
|
|
12
|
+
* --ol-layer-control-indent indentation of nested groups
|
|
13
|
+
* --ol-layer-control-shadow panel drop shadow
|
|
14
|
+
* --ol-layer-control-edge distance of the map button from the map edge
|
|
15
|
+
* --ol-layer-control-gap space between the map button and the
|
|
16
|
+
* OpenLayers control it makes room for
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/* --- map button (inside the map, styled by ol.css as an .ol-control) --- */
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* Five positions, set by the `buttonPosition` option. Offsets are derived
|
|
23
|
+
* from ol.css: controls sit 0.5em from the map edge, and a control button
|
|
24
|
+
* is 1.375em high with a 1px margin on each side.
|
|
25
|
+
*/
|
|
26
|
+
.ol-layer-control {
|
|
27
|
+
--ol-layer-control-button-size: calc(1.375em + 2px);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Below the two Zoom buttons. */
|
|
31
|
+
.ol-layer-control--top-left {
|
|
32
|
+
top: calc(var(--ol-layer-control-edge, 0.5em) + 2 * var(--ol-layer-control-button-size) + var(--ol-layer-control-gap, 0.5em));
|
|
33
|
+
left: var(--ol-layer-control-edge, 0.5em);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.ol-layer-control--bottom-left {
|
|
37
|
+
bottom: var(--ol-layer-control-edge, 0.5em);
|
|
38
|
+
left: var(--ol-layer-control-edge, 0.5em);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/* Same spot as the Rotate button, which only shows when the map is rotated. */
|
|
42
|
+
.ol-layer-control--top-right {
|
|
43
|
+
top: var(--ol-layer-control-edge, 0.5em);
|
|
44
|
+
right: var(--ol-layer-control-edge, 0.5em);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Below the Rotate button. */
|
|
48
|
+
.ol-layer-control--right {
|
|
49
|
+
top: calc(var(--ol-layer-control-edge, 0.5em) + var(--ol-layer-control-button-size) + var(--ol-layer-control-gap, 0.5em));
|
|
50
|
+
right: var(--ol-layer-control-edge, 0.5em);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Above the Attribution button. */
|
|
54
|
+
.ol-layer-control--bottom-right {
|
|
55
|
+
bottom: calc(var(--ol-layer-control-edge, 0.5em) + var(--ol-layer-control-button-size) + var(--ol-layer-control-gap, 0.5em));
|
|
56
|
+
right: var(--ol-layer-control-edge, 0.5em);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.ol-layer-control button svg {
|
|
60
|
+
width: 1em;
|
|
61
|
+
height: 1em;
|
|
62
|
+
vertical-align: middle;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* --- panel (a sibling of the map element, docked to one side) --------- */
|
|
66
|
+
|
|
67
|
+
.ol-layer-control-panel {
|
|
68
|
+
position: absolute;
|
|
69
|
+
top: 0;
|
|
70
|
+
bottom: 0;
|
|
71
|
+
right: 0;
|
|
72
|
+
z-index: 1;
|
|
73
|
+
box-sizing: border-box;
|
|
74
|
+
display: none;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
width: 320px;
|
|
77
|
+
background: var(--ol-layer-control-bg, #ffffff);
|
|
78
|
+
color: var(--ol-layer-control-fg, #222222);
|
|
79
|
+
font: var(--ol-layer-control-font, 14px/1.4 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
|
|
80
|
+
border-left: 1px solid var(--ol-layer-control-border, #d0d4d9);
|
|
81
|
+
box-shadow: var(--ol-layer-control-shadow, 0 0 8px rgba(0, 0, 0, 0.12));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.ol-layer-control-panel--left {
|
|
85
|
+
right: auto;
|
|
86
|
+
left: 0;
|
|
87
|
+
border-left: 0;
|
|
88
|
+
border-right: 1px solid var(--ol-layer-control-border, #d0d4d9);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.ol-layer-control-panel--open {
|
|
92
|
+
display: flex;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.ol-layer-control-panel--resizing {
|
|
96
|
+
cursor: ew-resize;
|
|
97
|
+
user-select: none;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* --- resize handle on the panel's inner edge ---------------------------- */
|
|
101
|
+
|
|
102
|
+
.ol-layer-control-resizer {
|
|
103
|
+
position: absolute;
|
|
104
|
+
top: 0;
|
|
105
|
+
bottom: 0;
|
|
106
|
+
left: -4px;
|
|
107
|
+
width: 8px;
|
|
108
|
+
z-index: 2;
|
|
109
|
+
cursor: ew-resize;
|
|
110
|
+
touch-action: none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.ol-layer-control-panel--left .ol-layer-control-resizer {
|
|
114
|
+
left: auto;
|
|
115
|
+
right: -4px;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.ol-layer-control-resizer::after {
|
|
119
|
+
content: "";
|
|
120
|
+
position: absolute;
|
|
121
|
+
top: 0;
|
|
122
|
+
bottom: 0;
|
|
123
|
+
left: 3px;
|
|
124
|
+
width: 2px;
|
|
125
|
+
background: var(--ol-layer-control-accent, #3d7ecc);
|
|
126
|
+
opacity: 0;
|
|
127
|
+
transition: opacity 0.15s;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.ol-layer-control-resizer:hover::after,
|
|
131
|
+
.ol-layer-control-panel--resizing .ol-layer-control-resizer::after {
|
|
132
|
+
opacity: 1;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* --- header ------------------------------------------------------------- */
|
|
136
|
+
|
|
137
|
+
.ol-layer-control-header {
|
|
138
|
+
display: flex;
|
|
139
|
+
align-items: center;
|
|
140
|
+
gap: 0.5em;
|
|
141
|
+
padding: 0.6em 0.75em;
|
|
142
|
+
border-bottom: 1px solid var(--ol-layer-control-border, #d0d4d9);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.ol-layer-control-title {
|
|
146
|
+
flex: 1;
|
|
147
|
+
appearance: none;
|
|
148
|
+
margin: 0;
|
|
149
|
+
padding: 0.15em 0.3em;
|
|
150
|
+
border: 0;
|
|
151
|
+
border-radius: 4px;
|
|
152
|
+
background: transparent;
|
|
153
|
+
color: inherit;
|
|
154
|
+
font: inherit;
|
|
155
|
+
font-weight: 600;
|
|
156
|
+
font-size: 1.05em;
|
|
157
|
+
text-align: left;
|
|
158
|
+
cursor: pointer;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.ol-layer-control-title:hover {
|
|
162
|
+
background: var(--ol-layer-control-hover, rgba(0, 0, 0, 0.06));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.ol-layer-control-title:focus-visible {
|
|
166
|
+
outline: 2px solid var(--ol-layer-control-accent, #3d7ecc);
|
|
167
|
+
outline-offset: 1px;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* --- search box (shown via the panel title or the `search` option) ------ */
|
|
171
|
+
|
|
172
|
+
.ol-layer-control-search {
|
|
173
|
+
display: none;
|
|
174
|
+
align-items: center;
|
|
175
|
+
gap: 0.4em;
|
|
176
|
+
padding: 0.5em 0.75em;
|
|
177
|
+
border-bottom: 1px solid var(--ol-layer-control-border, #d0d4d9);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.ol-layer-control-panel--search .ol-layer-control-search {
|
|
181
|
+
display: flex;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.ol-layer-control-search > svg {
|
|
185
|
+
flex: none;
|
|
186
|
+
width: 1.1em;
|
|
187
|
+
height: 1.1em;
|
|
188
|
+
opacity: 0.6;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.ol-layer-control-search input {
|
|
192
|
+
flex: 1;
|
|
193
|
+
min-width: 0;
|
|
194
|
+
box-sizing: border-box;
|
|
195
|
+
margin: 0;
|
|
196
|
+
padding: 0.35em 0.5em;
|
|
197
|
+
border: 1px solid var(--ol-layer-control-border, #d0d4d9);
|
|
198
|
+
border-radius: 4px;
|
|
199
|
+
background: var(--ol-layer-control-bg, #ffffff);
|
|
200
|
+
color: inherit;
|
|
201
|
+
font: inherit;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.ol-layer-control-search input:focus-visible {
|
|
205
|
+
outline: 2px solid var(--ol-layer-control-accent, #3d7ecc);
|
|
206
|
+
outline-offset: 1px;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.ol-layer-control-search input::-webkit-search-cancel-button {
|
|
210
|
+
display: none;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.ol-layer-control-search-clear {
|
|
214
|
+
flex: none;
|
|
215
|
+
width: 1.4em;
|
|
216
|
+
height: 1.4em;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.ol-layer-control-item--hidden {
|
|
220
|
+
display: none;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* While filtering, folded groups are opened so matches are visible. */
|
|
224
|
+
.ol-layer-control-panel--filtering .ol-layer-control-group--folded > .ol-layer-control-list {
|
|
225
|
+
display: block;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.ol-layer-control-no-results {
|
|
229
|
+
margin: 0.5em 0;
|
|
230
|
+
opacity: 0.7;
|
|
231
|
+
font-style: italic;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.ol-layer-control-close,
|
|
235
|
+
.ol-layer-control-fold,
|
|
236
|
+
.ol-layer-control-opacity-toggle,
|
|
237
|
+
.ol-layer-control-search-clear {
|
|
238
|
+
appearance: none;
|
|
239
|
+
display: inline-flex;
|
|
240
|
+
align-items: center;
|
|
241
|
+
justify-content: center;
|
|
242
|
+
padding: 0.15em;
|
|
243
|
+
margin: 0;
|
|
244
|
+
border: 0;
|
|
245
|
+
border-radius: 4px;
|
|
246
|
+
background: transparent;
|
|
247
|
+
color: inherit;
|
|
248
|
+
cursor: pointer;
|
|
249
|
+
line-height: 0;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.ol-layer-control-close:hover,
|
|
253
|
+
.ol-layer-control-fold:hover,
|
|
254
|
+
.ol-layer-control-opacity-toggle:hover,
|
|
255
|
+
.ol-layer-control-search-clear:hover {
|
|
256
|
+
background: var(--ol-layer-control-hover, rgba(0, 0, 0, 0.06));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.ol-layer-control-close:focus-visible,
|
|
260
|
+
.ol-layer-control-fold:focus-visible,
|
|
261
|
+
.ol-layer-control-opacity-toggle:focus-visible,
|
|
262
|
+
.ol-layer-control-search-clear:focus-visible,
|
|
263
|
+
.ol-layer-control-row input:focus-visible,
|
|
264
|
+
.ol-layer-control-opacity input:focus-visible {
|
|
265
|
+
outline: 2px solid var(--ol-layer-control-accent, #3d7ecc);
|
|
266
|
+
outline-offset: 1px;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.ol-layer-control-close svg,
|
|
270
|
+
.ol-layer-control-fold svg,
|
|
271
|
+
.ol-layer-control-opacity-toggle svg,
|
|
272
|
+
.ol-layer-control-search-clear svg {
|
|
273
|
+
width: 1.1em;
|
|
274
|
+
height: 1.1em;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/* --- layer tree --------------------------------------------------------- */
|
|
278
|
+
|
|
279
|
+
.ol-layer-control-body {
|
|
280
|
+
flex: 1;
|
|
281
|
+
overflow: auto;
|
|
282
|
+
padding: 0.5em 0.75em 0.75em;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.ol-layer-control-list {
|
|
286
|
+
list-style: none;
|
|
287
|
+
margin: 0;
|
|
288
|
+
padding: 0;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
.ol-layer-control-list .ol-layer-control-list {
|
|
292
|
+
padding-left: var(--ol-layer-control-indent, 1.4em);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.ol-layer-control-row {
|
|
296
|
+
display: flex;
|
|
297
|
+
align-items: center;
|
|
298
|
+
gap: 0.4em;
|
|
299
|
+
min-height: 1.9em;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* Keeps a leaf's checkbox aligned with a group's checkbox (which sits after the fold button). */
|
|
303
|
+
.ol-layer-control-spacer {
|
|
304
|
+
flex: none;
|
|
305
|
+
width: 1.4em;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.ol-layer-control-fold {
|
|
309
|
+
flex: none;
|
|
310
|
+
width: 1.4em;
|
|
311
|
+
height: 1.4em;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.ol-layer-control-fold svg {
|
|
315
|
+
transition: transform 0.15s;
|
|
316
|
+
transform: rotate(90deg);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.ol-layer-control-group--folded > .ol-layer-control-row .ol-layer-control-fold svg {
|
|
320
|
+
transform: rotate(0deg);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.ol-layer-control-group--folded > .ol-layer-control-list {
|
|
324
|
+
display: none;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.ol-layer-control-group--inactive > .ol-layer-control-list {
|
|
328
|
+
opacity: 0.5;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.ol-layer-control-row input {
|
|
332
|
+
flex: none;
|
|
333
|
+
margin: 0;
|
|
334
|
+
accent-color: var(--ol-layer-control-accent, #3d7ecc);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.ol-layer-control-label {
|
|
338
|
+
flex: 1;
|
|
339
|
+
cursor: pointer;
|
|
340
|
+
overflow-wrap: anywhere;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
span.ol-layer-control-label {
|
|
344
|
+
cursor: default;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.ol-layer-control-group > .ol-layer-control-row .ol-layer-control-label {
|
|
348
|
+
font-weight: 600;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* Group titles that can be right-clicked to toggle exclusive/non-exclusive. */
|
|
352
|
+
.ol-layer-control-label--toggle {
|
|
353
|
+
cursor: context-menu;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/* Layers outside their min/max resolution or zoom at the current view:
|
|
357
|
+
greyed out like the contents of an unchecked group. */
|
|
358
|
+
.ol-layer-control-item--out-of-range > .ol-layer-control-row,
|
|
359
|
+
.ol-layer-control-item--out-of-range > .ol-layer-control-list {
|
|
360
|
+
opacity: 0.5;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* --- opacity slider (revealed per layer by its button) ------------------ */
|
|
364
|
+
|
|
365
|
+
.ol-layer-control-opacity-toggle {
|
|
366
|
+
flex: none;
|
|
367
|
+
width: 1.4em;
|
|
368
|
+
height: 1.4em;
|
|
369
|
+
opacity: 0.5;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.ol-layer-control-opacity-toggle:hover,
|
|
373
|
+
.ol-layer-control-opacity-toggle:focus-visible,
|
|
374
|
+
.ol-layer-control-layer--opacity-open > .ol-layer-control-row .ol-layer-control-opacity-toggle {
|
|
375
|
+
opacity: 1;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.ol-layer-control-layer--opacity-open > .ol-layer-control-row .ol-layer-control-opacity-toggle {
|
|
379
|
+
color: var(--ol-layer-control-accent, #3d7ecc);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.ol-layer-control-opacity {
|
|
383
|
+
display: none;
|
|
384
|
+
align-items: center;
|
|
385
|
+
gap: 0.5em;
|
|
386
|
+
/* Align with the label: spacer + gap + input + gap. */
|
|
387
|
+
padding: 0 0.2em 0.4em calc(1.4em + 0.8em + 13px);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.ol-layer-control-layer--opacity-open > .ol-layer-control-opacity {
|
|
391
|
+
display: flex;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.ol-layer-control-opacity input[type="range"] {
|
|
395
|
+
flex: 1;
|
|
396
|
+
min-width: 0;
|
|
397
|
+
margin: 0;
|
|
398
|
+
accent-color: var(--ol-layer-control-accent, #3d7ecc);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.ol-layer-control-opacity-value {
|
|
402
|
+
flex: none;
|
|
403
|
+
width: 3em;
|
|
404
|
+
text-align: right;
|
|
405
|
+
font-size: 0.9em;
|
|
406
|
+
font-variant-numeric: tabular-nums;
|
|
407
|
+
opacity: 0.8;
|
|
408
|
+
}
|