@abi-software/flatmap-viewer 2.2.9 → 2.2.10-devel
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/package.json +1 -1
- package/src/controls.js +186 -7
- package/src/flatmap-viewer.js +25 -9
- package/src/interactions.js +26 -14
- package/src/layers.js +163 -143
- package/src/main.js +24 -17
- package/src/search.js +4 -1
- package/src/styling.js +5 -5
- package/static/flatmap-viewer.css +31 -1
package/package.json
CHANGED
package/src/controls.js
CHANGED
|
@@ -26,6 +26,20 @@ import * as pathways from './pathways.js';
|
|
|
26
26
|
|
|
27
27
|
//==============================================================================
|
|
28
28
|
|
|
29
|
+
// Make sure colour string is in `#rrggbb` form.
|
|
30
|
+
// Based on https://stackoverflow.com/a/47355187
|
|
31
|
+
|
|
32
|
+
function standardise_color(str){
|
|
33
|
+
const canvas = document.createElement("canvas");
|
|
34
|
+
const ctx = canvas.getContext("2d");
|
|
35
|
+
ctx.fillStyle = str;
|
|
36
|
+
const colour = ctx.fillStyle;
|
|
37
|
+
canvas.remove()
|
|
38
|
+
return colour;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//==============================================================================
|
|
42
|
+
|
|
29
43
|
export class NavigationControl
|
|
30
44
|
{
|
|
31
45
|
constructor(flatmap)
|
|
@@ -102,9 +116,9 @@ export class PathControl
|
|
|
102
116
|
this._legend.className = 'flatmap-nerve-grid';
|
|
103
117
|
|
|
104
118
|
const innerHTML = [];
|
|
105
|
-
innerHTML.push(`<label for="path-all-paths">ALL PATHS:</label><input id="path-all-paths" type="checkbox" checked
|
|
119
|
+
innerHTML.push(`<label for="path-all-paths">ALL PATHS:</label><div class="nerve-line"></div><input id="path-all-paths" type="checkbox" checked/>`);
|
|
106
120
|
for (const path of pathways.PATH_TYPES) {
|
|
107
|
-
innerHTML.push(`<label for="path-${path.type}">${path.label}</label><input id="path-${path.type}" type="checkbox" checked
|
|
121
|
+
innerHTML.push(`<label for="path-${path.type}">${path.label}</label><div class="nerve-line nerve-${path.type}"></div><input id="path-${path.type}" type="checkbox" checked/>`);
|
|
108
122
|
}
|
|
109
123
|
this._legend.innerHTML = innerHTML.join('\n');
|
|
110
124
|
this.__checkedCount = pathways.PATH_TYPES.length;
|
|
@@ -112,10 +126,10 @@ export class PathControl
|
|
|
112
126
|
|
|
113
127
|
this._button = document.createElement('button');
|
|
114
128
|
this._button.id = 'nerve-key-button';
|
|
115
|
-
this._button.className = 'control-button';
|
|
129
|
+
this._button.className = 'control-button text-button';
|
|
116
130
|
this._button.setAttribute('type', 'button');
|
|
117
131
|
this._button.setAttribute('aria-label', 'Nerve paths legend');
|
|
118
|
-
this._button.setAttribute('
|
|
132
|
+
this._button.setAttribute('control-visible', 'false');
|
|
119
133
|
this._button.textContent = 'PATHS';
|
|
120
134
|
this._button.title = 'Show/hide neuron paths';
|
|
121
135
|
this._container.appendChild(this._button);
|
|
@@ -135,13 +149,13 @@ export class PathControl
|
|
|
135
149
|
//=============
|
|
136
150
|
{
|
|
137
151
|
if (event.target.id === 'nerve-key-button') {
|
|
138
|
-
if (this._button.getAttribute('
|
|
152
|
+
if (this._button.getAttribute('control-visible') === 'false') {
|
|
139
153
|
this._container.appendChild(this._legend);
|
|
140
|
-
this._button.setAttribute('
|
|
154
|
+
this._button.setAttribute('control-visible', 'true');
|
|
141
155
|
this._legend.focus();
|
|
142
156
|
} else {
|
|
143
157
|
this._legend = this._container.removeChild(this._legend);
|
|
144
|
-
this._button.setAttribute('
|
|
158
|
+
this._button.setAttribute('control-visible', 'false');
|
|
145
159
|
}
|
|
146
160
|
} else if (event.target.tagName === 'INPUT') {
|
|
147
161
|
if (event.target.id === 'path-all-paths') {
|
|
@@ -186,3 +200,168 @@ export class PathControl
|
|
|
186
200
|
}
|
|
187
201
|
|
|
188
202
|
//==============================================================================
|
|
203
|
+
|
|
204
|
+
export class LayerControl
|
|
205
|
+
{
|
|
206
|
+
constructor(flatmap, layerManager)
|
|
207
|
+
{
|
|
208
|
+
this.__flatmap = flatmap;
|
|
209
|
+
this.__manager = layerManager;
|
|
210
|
+
this.__map = undefined;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
getDefaultPosition()
|
|
214
|
+
//==================
|
|
215
|
+
{
|
|
216
|
+
return 'top-right';
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
onAdd(map)
|
|
220
|
+
//========
|
|
221
|
+
{
|
|
222
|
+
this.__map = map;
|
|
223
|
+
this.__container = document.createElement('div');
|
|
224
|
+
this.__container.className = 'maplibregl-ctrl';
|
|
225
|
+
this.__container.id = 'flatmap-layer-control';
|
|
226
|
+
|
|
227
|
+
this.__layers = document.createElement('div');
|
|
228
|
+
this.__layers.id = 'layer-control-text';
|
|
229
|
+
this.__layers.className = 'flatmap-layer-grid';
|
|
230
|
+
|
|
231
|
+
const innerHTML = [];
|
|
232
|
+
innerHTML.push(`<label for="layer-all-layers">ALL LAYERS:</label><input id="layer-all-layers" type="checkbox" checked/>`);
|
|
233
|
+
for (const layer of this.__manager.layers) {
|
|
234
|
+
innerHTML.push(`<label for="layer-${layer.id}">${layer.description}</label><input id="layer-${layer.id}" type="checkbox" checked/>`);
|
|
235
|
+
}
|
|
236
|
+
this.__layers.innerHTML = innerHTML.join('\n');
|
|
237
|
+
|
|
238
|
+
this.__layersCount = this.__manager.layers.length;
|
|
239
|
+
this.__checkedCount = this.__layersCount;
|
|
240
|
+
this.__halfCount = Math.trunc(this.__checkedCount/2);
|
|
241
|
+
|
|
242
|
+
this.__button = document.createElement('button');
|
|
243
|
+
this.__button.id = 'map-layers-button';
|
|
244
|
+
this.__button.className = 'control-button text-button';
|
|
245
|
+
this.__button.setAttribute('type', 'button');
|
|
246
|
+
this.__button.setAttribute('aria-label', 'Show/hide map layers');
|
|
247
|
+
this.__button.setAttribute('control-visible', 'false');
|
|
248
|
+
this.__button.textContent = 'LAYERS';
|
|
249
|
+
this.__button.title = 'Show/hide map layers';
|
|
250
|
+
this.__container.appendChild(this.__button);
|
|
251
|
+
|
|
252
|
+
this.__container.addEventListener('click', this.onClick_.bind(this));
|
|
253
|
+
return this.__container;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
onRemove()
|
|
257
|
+
//========
|
|
258
|
+
{
|
|
259
|
+
this.__container.parentNode.removeChild(this.__container);
|
|
260
|
+
this.__map = undefined;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
onClick_(event)
|
|
264
|
+
//=============
|
|
265
|
+
{
|
|
266
|
+
if (event.target.id === 'map-layers-button') {
|
|
267
|
+
if (this.__button.getAttribute('control-visible') === 'false') {
|
|
268
|
+
this.__container.appendChild(this.__layers);
|
|
269
|
+
this.__button.setAttribute('control-visible', 'true');
|
|
270
|
+
this.__layers.focus();
|
|
271
|
+
} else {
|
|
272
|
+
this.__layers = this.__container.removeChild(this.__layers);
|
|
273
|
+
this.__button.setAttribute('control-visible', 'false');
|
|
274
|
+
}
|
|
275
|
+
} else if (event.target.tagName === 'INPUT') {
|
|
276
|
+
if (event.target.id === 'layer-all-layers') {
|
|
277
|
+
if (event.target.indeterminate) {
|
|
278
|
+
event.target.checked = (this.__checkedCount >= this.__halfCount);
|
|
279
|
+
event.target.indeterminate = false;
|
|
280
|
+
}
|
|
281
|
+
if (event.target.checked) {
|
|
282
|
+
this.__checkedCount = this.__layersCount;
|
|
283
|
+
} else {
|
|
284
|
+
this.__checkedCount = 0;
|
|
285
|
+
}
|
|
286
|
+
for (const layer of this.__manager.layers) {
|
|
287
|
+
const layerCheckbox = document.getElementById(`layer-${layer.id}`);
|
|
288
|
+
if (layerCheckbox) {
|
|
289
|
+
layerCheckbox.checked = event.target.checked;
|
|
290
|
+
this.__manager.activate(layer.id, event.target.checked);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
} else if (event.target.id.startsWith('layer-')) {
|
|
294
|
+
const layerId = event.target.id.substring(6);
|
|
295
|
+
this.__manager.activate(layerId, event.target.checked);
|
|
296
|
+
if (event.target.checked) {
|
|
297
|
+
this.__checkedCount += 1;
|
|
298
|
+
} else {
|
|
299
|
+
this.__checkedCount -= 1;
|
|
300
|
+
}
|
|
301
|
+
const allLayersCheckbox = document.getElementById('layer-all-layers');
|
|
302
|
+
if (this.__checkedCount === 0) {
|
|
303
|
+
allLayersCheckbox.checked = false;
|
|
304
|
+
allLayersCheckbox.indeterminate = false;
|
|
305
|
+
} else if (this.__checkedCount === this.__layersCount) {
|
|
306
|
+
allLayersCheckbox.checked = true;
|
|
307
|
+
allLayersCheckbox.indeterminate = false;
|
|
308
|
+
} else {
|
|
309
|
+
allLayersCheckbox.indeterminate = true;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
event.stopPropagation();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
//==============================================================================
|
|
318
|
+
|
|
319
|
+
export class BackgroundControl
|
|
320
|
+
{
|
|
321
|
+
constructor(flatmap)
|
|
322
|
+
{
|
|
323
|
+
this.__flatmap = flatmap;
|
|
324
|
+
this.__map = undefined;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
getDefaultPosition()
|
|
328
|
+
//==================
|
|
329
|
+
{
|
|
330
|
+
return 'top-right';
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
onAdd(map)
|
|
334
|
+
//========
|
|
335
|
+
{
|
|
336
|
+
this.__map = map;
|
|
337
|
+
this.__container = document.createElement('div');
|
|
338
|
+
this.__container.className = 'maplibregl-ctrl';
|
|
339
|
+
this.__colourDiv = document.createElement('div');
|
|
340
|
+
this.__colourDiv.setAttribute('aria-label', 'Change background colour');
|
|
341
|
+
this.__colourDiv.title = 'Change background colour';
|
|
342
|
+
const background = standardise_color(this.__flatmap.getBackgroundColour());
|
|
343
|
+
this.__colourDiv.innerHTML = `<input type="color" id="colourPicker" value="${background}">`;
|
|
344
|
+
this.__container.appendChild(this.__colourDiv);
|
|
345
|
+
this.__colourDiv.addEventListener('input', this.__updateColour.bind(this), false);
|
|
346
|
+
this.__colourDiv.addEventListener('change', this.__updateColour.bind(this), false);
|
|
347
|
+
return this.__container;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
onRemove()
|
|
351
|
+
//========
|
|
352
|
+
{
|
|
353
|
+
this.__container.parentNode.removeChild(this.__container);
|
|
354
|
+
this.__map = undefined;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
__updateColour(event)
|
|
358
|
+
//===================
|
|
359
|
+
{
|
|
360
|
+
const colour = event.target.value;
|
|
361
|
+
this.__flatmap.setBackgroundColour(colour);
|
|
362
|
+
this.__flatmap.controlEvent('change', 'background', colour)
|
|
363
|
+
event.stopPropagation();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
//==============================================================================
|
package/src/flatmap-viewer.js
CHANGED
|
@@ -621,12 +621,6 @@ class FlatMap
|
|
|
621
621
|
this._map.resize();
|
|
622
622
|
}
|
|
623
623
|
|
|
624
|
-
mapLayerId(name)
|
|
625
|
-
//==============
|
|
626
|
-
{
|
|
627
|
-
return `${this.uniqueId}/${name}`;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
624
|
getIdentifier()
|
|
631
625
|
//=============
|
|
632
626
|
{
|
|
@@ -872,6 +866,23 @@ class FlatMap
|
|
|
872
866
|
});
|
|
873
867
|
}
|
|
874
868
|
|
|
869
|
+
/**
|
|
870
|
+
* Generate a callback as a result of some event in a control.
|
|
871
|
+
*
|
|
872
|
+
* @param {string} eventType The event type
|
|
873
|
+
* @param {string} control The name of the control
|
|
874
|
+
* @param {string} value The value of the control
|
|
875
|
+
*/
|
|
876
|
+
controlEvent(eventType, control, value)
|
|
877
|
+
//=====================================
|
|
878
|
+
{
|
|
879
|
+
this.callback(eventType, {
|
|
880
|
+
type: 'control',
|
|
881
|
+
control: control,
|
|
882
|
+
value: value
|
|
883
|
+
});
|
|
884
|
+
}
|
|
885
|
+
|
|
875
886
|
/**
|
|
876
887
|
* Generate callbacks as a result of panning/zooming the map.
|
|
877
888
|
*
|
|
@@ -1211,6 +1222,12 @@ export class MapManager
|
|
|
1211
1222
|
mapOptions['pathControls'] = true;
|
|
1212
1223
|
}
|
|
1213
1224
|
|
|
1225
|
+
// Default is to show layer controls
|
|
1226
|
+
|
|
1227
|
+
if (!('layerControl' in mapOptions)) {
|
|
1228
|
+
mapOptions['layerControl'] = true;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1214
1231
|
// Mapmaker's changed the name of the field to indicate that indicates if
|
|
1215
1232
|
// there are raster layers
|
|
1216
1233
|
if (!('image-layers' in mapIndex) && ('image_layer' in mapIndex)) {
|
|
@@ -1285,9 +1302,8 @@ export class MapManager
|
|
|
1285
1302
|
outline: true
|
|
1286
1303
|
};
|
|
1287
1304
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
} else if ('style' in mapIndex) {
|
|
1305
|
+
mapOptions.layerOptions.authoring = ('authoring' in mapIndex) ? mapIndex.authoring : false;
|
|
1306
|
+
if ('style' in mapIndex) {
|
|
1291
1307
|
mapOptions.layerOptions.style = mapIndex.style;
|
|
1292
1308
|
} else {
|
|
1293
1309
|
mapOptions.layerOptions.style = 'flatmap';
|
package/src/interactions.js
CHANGED
|
@@ -38,7 +38,7 @@ import {displayedProperties} from './info.js';
|
|
|
38
38
|
import {InfoControl} from './info.js';
|
|
39
39
|
import {LayerManager} from './layers.js';
|
|
40
40
|
import {PATHWAYS_LAYER, Pathways} from './pathways.js';
|
|
41
|
-
import {PathControl} from './controls.js';
|
|
41
|
+
import {BackgroundControl, LayerControl, PathControl} from './controls.js';
|
|
42
42
|
import {SearchControl} from './search.js';
|
|
43
43
|
import {VECTOR_TILES_SOURCE} from './styling.js';
|
|
44
44
|
|
|
@@ -145,20 +145,32 @@ export class UserInteractions
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
// Add and manage our layers
|
|
149
|
+
|
|
150
|
+
this._layerManager = new LayerManager(flatmap);
|
|
151
|
+
|
|
152
|
+
// Control background colour (NB. this depends on having map layers created)
|
|
153
|
+
|
|
154
|
+
if (flatmap.options.backgroundControl) {
|
|
155
|
+
this._map.addControl(new BackgroundControl(flatmap));
|
|
156
|
+
}
|
|
157
|
+
|
|
148
158
|
// Neural pathways which are either controlled externally
|
|
149
159
|
// or by our local controls
|
|
150
160
|
|
|
151
161
|
this._pathways = new Pathways(flatmap);
|
|
152
162
|
|
|
153
|
-
|
|
154
|
-
// Add controls to manage our pathways
|
|
163
|
+
// Add a control to manage our pathways
|
|
155
164
|
|
|
165
|
+
if (flatmap.options.pathControls) {
|
|
156
166
|
this._map.addControl(new PathControl(flatmap));
|
|
157
167
|
}
|
|
158
168
|
|
|
159
|
-
//
|
|
169
|
+
// Add a control to manage our layers
|
|
160
170
|
|
|
161
|
-
|
|
171
|
+
if (flatmap.options.layerControl) {
|
|
172
|
+
this._map.addControl(new LayerControl(flatmap, this._layerManager));
|
|
173
|
+
}
|
|
162
174
|
|
|
163
175
|
// Flag features that have annotations
|
|
164
176
|
// Also flag those features that are models of something
|
|
@@ -650,17 +662,17 @@ export class UserInteractions
|
|
|
650
662
|
if (('label' in properties || 'hyperlink' in properties)
|
|
651
663
|
&& (forceLabel || !('tooltip' in properties) || properties.tooltip)
|
|
652
664
|
&& !('labelled' in properties)) {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
tooltip = (label.substr(0, 1).toUpperCase() + label.substr(1)).replaceAll("\n", "<br/>");
|
|
657
|
-
} else {
|
|
658
|
-
tooltip = properties.hyperlink
|
|
659
|
-
}
|
|
665
|
+
const label = ('label' in properties) ? (properties.label.substr(0, 1).toUpperCase()
|
|
666
|
+
+ properties.label.substr(1)).replaceAll("\n", "<br/>")
|
|
667
|
+
: '';
|
|
660
668
|
if ('hyperlink' in properties) {
|
|
661
|
-
|
|
669
|
+
if (label === '') {
|
|
670
|
+
return `<div class='flatmap-feature-label'><a href='{properties.hyperlink}'>${properties.hyperlink}</a></div>`;
|
|
671
|
+
} else {
|
|
672
|
+
return `<div class='flatmap-feature-label'><a href='{properties.hyperlink}'>${properties.hyperlink}</a><br/>${label}</div>`;
|
|
673
|
+
}
|
|
662
674
|
} else {
|
|
663
|
-
return `<div class='flatmap-feature-label'>${
|
|
675
|
+
return `<div class='flatmap-feature-label'>${label}</div>`;
|
|
664
676
|
}
|
|
665
677
|
}
|
|
666
678
|
return '';
|
package/src/layers.js
CHANGED
|
@@ -28,113 +28,174 @@ import * as style from './styling.js';
|
|
|
28
28
|
import * as utils from './utils.js';
|
|
29
29
|
|
|
30
30
|
const FEATURES_LAYER = 'features'
|
|
31
|
+
const RASTER_LAYERS_NAME = 'Background image layer'
|
|
31
32
|
|
|
32
33
|
//==============================================================================
|
|
33
34
|
|
|
34
|
-
class
|
|
35
|
+
class MapStylingLayers
|
|
35
36
|
{
|
|
36
|
-
constructor(flatmap,
|
|
37
|
+
constructor(flatmap, layerId)
|
|
37
38
|
{
|
|
38
39
|
this.__map = flatmap.map;
|
|
40
|
+
this.__id = layerId;
|
|
41
|
+
this.__layers = [];
|
|
42
|
+
this.__active = true;
|
|
43
|
+
this.__layerOptions = flatmap.options.layerOptions;
|
|
39
44
|
this.__separateLayers = flatmap.options.separateLayers;
|
|
40
|
-
|
|
41
|
-
this.__rasterLayers = [];
|
|
42
|
-
this.__styleLayers = [];
|
|
45
|
+
}
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
get id()
|
|
48
|
+
//======
|
|
49
|
+
{
|
|
50
|
+
return this.__id;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get active()
|
|
54
|
+
//==========
|
|
55
|
+
{
|
|
56
|
+
return this.__active;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
addLayer(styleLayer, options)
|
|
60
|
+
//==========================
|
|
61
|
+
{
|
|
62
|
+
this.__map.addLayer(styleLayer.style(options));
|
|
63
|
+
this.__layers.push(styleLayer);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
__showLayer(layer, visible=true)
|
|
67
|
+
//===============================
|
|
68
|
+
{
|
|
69
|
+
this.__map.setLayoutProperty(layer.id, 'visibility', visible ? 'visible' : 'none');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
activate(enable=true)
|
|
73
|
+
//===================
|
|
74
|
+
{
|
|
75
|
+
for (const layer of this.__layers) {
|
|
76
|
+
this.__showLayer(layer, enable);
|
|
77
|
+
}
|
|
78
|
+
this.__active = enable;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
vectorSourceId(sourceLayer)
|
|
82
|
+
//=========================
|
|
83
|
+
{
|
|
84
|
+
return this.__separateLayers ? `${this.__id}_${sourceLayer}`
|
|
85
|
+
: sourceLayer;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//==============================================================================
|
|
90
|
+
|
|
91
|
+
class MapFeatureLayers extends MapStylingLayers
|
|
92
|
+
{
|
|
93
|
+
constructor(flatmap, layer)
|
|
94
|
+
{
|
|
95
|
+
super(flatmap, layer.id);
|
|
45
96
|
const vectorTileSource = this.__map.getSource('vector-tiles');
|
|
46
97
|
const haveVectorLayers = (typeof vectorTileSource !== 'undefined');
|
|
47
|
-
|
|
48
|
-
? `${this.__id}_${FEATURES_LAYER}`
|
|
49
|
-
: FEATURES_LAYER;
|
|
50
|
-
const vectorFeatures = haveVectorLayers
|
|
51
|
-
&& vectorTileSource.vectorLayerIds.indexOf(featuresVectorLayerId) >= 0;
|
|
52
|
-
if (background_layers) {
|
|
53
|
-
if (vectorFeatures) {
|
|
54
|
-
this.__addStyleLayer(style.BodyLayer, layerOptions);
|
|
55
|
-
}
|
|
56
|
-
if (flatmap.details['image-layers']) {
|
|
57
|
-
for (const raster_layer_id of layer['image-layers']) {
|
|
58
|
-
this.__addRasterLayer(raster_layer_id, layerOptions);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
98
|
+
|
|
62
99
|
// if no image layers then make feature borders (and lines?) more visible...??
|
|
63
100
|
if (haveVectorLayers) {
|
|
101
|
+
const featuresVectorSource = this.vectorSourceId(FEATURES_LAYER);
|
|
102
|
+
const vectorFeatures = vectorTileSource.vectorLayerIds
|
|
103
|
+
.indexOf(featuresVectorSource) >= 0;
|
|
64
104
|
if (vectorFeatures) {
|
|
65
|
-
this.__addStyleLayer(style.FeatureFillLayer
|
|
66
|
-
this.__addStyleLayer(style.FeatureDashLineLayer
|
|
67
|
-
this.__addStyleLayer(style.FeatureLineLayer
|
|
68
|
-
this.__addStyleLayer(style.FeatureBorderLayer
|
|
105
|
+
this.__addStyleLayer(style.FeatureFillLayer);
|
|
106
|
+
this.__addStyleLayer(style.FeatureDashLineLayer);
|
|
107
|
+
this.__addStyleLayer(style.FeatureLineLayer);
|
|
108
|
+
this.__addStyleLayer(style.FeatureBorderLayer);
|
|
69
109
|
}
|
|
70
|
-
this.__addPathwayStyleLayers(
|
|
110
|
+
this.__addPathwayStyleLayers(this.__layerOptions);
|
|
71
111
|
if (vectorFeatures) {
|
|
72
|
-
this.__addStyleLayer(style.FeatureLargeSymbolLayer
|
|
112
|
+
this.__addStyleLayer(style.FeatureLargeSymbolLayer);
|
|
73
113
|
if (!flatmap.options.tooltips) {
|
|
74
|
-
this.__addStyleLayer(style.FeatureSmallSymbolLayer
|
|
114
|
+
this.__addStyleLayer(style.FeatureSmallSymbolLayer);
|
|
75
115
|
}
|
|
76
116
|
}
|
|
77
117
|
}
|
|
78
118
|
|
|
79
119
|
// Make sure our colour options are set properly, in particular raster layer visibility
|
|
80
120
|
|
|
81
|
-
this.setColour(
|
|
121
|
+
this.setColour(this.__layerOptions);
|
|
82
122
|
}
|
|
83
123
|
|
|
84
|
-
|
|
85
|
-
|
|
124
|
+
__addStyleLayer(styleClass, sourceLayer=FEATURES_LAYER)
|
|
125
|
+
//=====================================================
|
|
86
126
|
{
|
|
87
|
-
|
|
127
|
+
const styleLayer = new styleClass(`${this.__id}_${sourceLayer}`,
|
|
128
|
+
this.vectorSourceId(sourceLayer));
|
|
129
|
+
this.__map.addLayer(styleLayer.style(this.__layerOptions));
|
|
130
|
+
this.__layers.push(styleLayer);
|
|
88
131
|
}
|
|
89
132
|
|
|
90
|
-
|
|
91
|
-
|
|
133
|
+
__addPathwayStyleLayers()
|
|
134
|
+
//=======================
|
|
92
135
|
{
|
|
93
|
-
const
|
|
94
|
-
this.__map.
|
|
95
|
-
|
|
136
|
+
const pathwaysVectorSource = this.vectorSourceId(PATHWAYS_LAYER);
|
|
137
|
+
if (this.__map.getSource('vector-tiles')
|
|
138
|
+
.vectorLayerIds
|
|
139
|
+
.indexOf(pathwaysVectorSource) >= 0) {
|
|
140
|
+
this.__addStyleLayer(style.PathLineLayer, PATHWAYS_LAYER);
|
|
141
|
+
this.__addStyleLayer(style.PathDashlineLayer, PATHWAYS_LAYER);
|
|
142
|
+
this.__addStyleLayer(style.NervePolygonBorder, PATHWAYS_LAYER);
|
|
143
|
+
this.__addStyleLayer(style.NervePolygonFill, PATHWAYS_LAYER);
|
|
144
|
+
this.__addStyleLayer(style.FeatureNerveLayer, PATHWAYS_LAYER);
|
|
145
|
+
}
|
|
96
146
|
}
|
|
97
147
|
|
|
98
|
-
|
|
99
|
-
|
|
148
|
+
setColour(options)
|
|
149
|
+
//================
|
|
100
150
|
{
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
.indexOf(pathwaysVectorLayerId) >= 0) {
|
|
107
|
-
this.__addStyleLayer(style.PathLineLayer, options, PATHWAYS_LAYER);
|
|
108
|
-
this.__addStyleLayer(style.PathDashlineLayer, options, PATHWAYS_LAYER);
|
|
109
|
-
this.__addStyleLayer(style.NervePolygonBorder, options, PATHWAYS_LAYER);
|
|
110
|
-
this.__addStyleLayer(style.NervePolygonFill, options, PATHWAYS_LAYER);
|
|
111
|
-
this.__addStyleLayer(style.FeatureNerveLayer, options, PATHWAYS_LAYER);
|
|
151
|
+
for (const layer of this.__layers) {
|
|
152
|
+
const paintStyle = layer.paintStyle(options, true);
|
|
153
|
+
for (const [property, value] of Object.entries(paintStyle)) {
|
|
154
|
+
this.__map.setPaintProperty(layer.id, property, value, {validate: false});
|
|
155
|
+
}
|
|
112
156
|
}
|
|
113
157
|
}
|
|
158
|
+
}
|
|
114
159
|
|
|
115
|
-
|
|
116
|
-
|
|
160
|
+
//==============================================================================
|
|
161
|
+
|
|
162
|
+
class MapRasterLayers extends MapStylingLayers
|
|
163
|
+
{
|
|
164
|
+
constructor(flatmap, bodyLayerId=null)
|
|
117
165
|
{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
166
|
+
super(flatmap, 'background-image-layer');
|
|
167
|
+
if (bodyLayerId !== null) {
|
|
168
|
+
const layerId = `${bodyLayerId}_${FEATURES_LAYER}`;
|
|
169
|
+
const source = flatmap.options.separateLayers ? layerId : FEATURES_LAYER;
|
|
170
|
+
const styleLayer = new style.BodyLayer(layerId, source);
|
|
171
|
+
this.__map.addLayer(styleLayer.style(this.__layerOptions));
|
|
172
|
+
this.__layers.push(styleLayer);
|
|
173
|
+
}
|
|
174
|
+
// Make sure our colour options are set properly, in particular raster layer visibility
|
|
175
|
+
this.setColour(this.__layerOptions);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
addLayer(layer)
|
|
179
|
+
//=============
|
|
180
|
+
{
|
|
181
|
+
for (const layer_id of layer['image-layers']) {
|
|
182
|
+
const rasterLayer = new style.RasterLayer(layer_id);
|
|
183
|
+
this.__map.addLayer(rasterLayer.style(this.__layerOptions));
|
|
184
|
+
this.__layers.push(rasterLayer);
|
|
185
|
+
}
|
|
186
|
+
// Make sure our colour options are set properly, in particular raster layer visibility
|
|
187
|
+
this.setColour(this.__layerOptions);
|
|
123
188
|
}
|
|
124
189
|
|
|
125
190
|
setColour(options)
|
|
126
191
|
//================
|
|
127
192
|
{
|
|
128
193
|
const coloured = !('colour' in options) || options.colour;
|
|
129
|
-
for (const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const paintStyle = styleLayer.paintStyle(options, true);
|
|
135
|
-
for (const [property, value] of Object.entries(paintStyle)) {
|
|
136
|
-
this.__map.setPaintProperty(styleLayer.id, property, value, {validate: false});
|
|
137
|
-
}
|
|
194
|
+
for (const layer of this.__layers) {
|
|
195
|
+
// Check active status when resetting to visible....
|
|
196
|
+
this.__map.setLayoutProperty(layer.id, 'visibility',
|
|
197
|
+
(coloured && this.active) ? 'visible' : 'none',
|
|
198
|
+
{validate: false});
|
|
138
199
|
}
|
|
139
200
|
}
|
|
140
201
|
}
|
|
@@ -143,89 +204,73 @@ class MapFeatureLayer
|
|
|
143
204
|
|
|
144
205
|
export class LayerManager
|
|
145
206
|
{
|
|
146
|
-
constructor(flatmap
|
|
207
|
+
constructor(flatmap)
|
|
147
208
|
{
|
|
148
209
|
this.__flatmap = flatmap;
|
|
149
210
|
this.__map = flatmap.map;
|
|
150
211
|
this.__layers = new Map;
|
|
151
212
|
this.__mapLayers = new Map;
|
|
152
|
-
this.__activeLayers = [];
|
|
153
|
-
this.__activeLayerNames = [];
|
|
154
|
-
this.__rasterLayers = [];
|
|
155
213
|
const layerOptions = flatmap.options.layerOptions;
|
|
156
|
-
const fcDiagram = ('style' in layerOptions && layerOptions.style == 'fcdiagram');
|
|
157
214
|
const backgroundLayer = new style.BackgroundLayer();
|
|
158
|
-
if (
|
|
159
|
-
this.__map.addLayer(backgroundLayer.style('black', 1));
|
|
160
|
-
}
|
|
161
|
-
else if ('background' in flatmap.options) {
|
|
215
|
+
if ('background' in flatmap.options) {
|
|
162
216
|
this.__map.addLayer(backgroundLayer.style(flatmap.options.background));
|
|
163
217
|
} else {
|
|
164
218
|
this.__map.addLayer(backgroundLayer.style('white'));
|
|
165
219
|
}
|
|
220
|
+
|
|
166
221
|
// Add the map's layers
|
|
167
|
-
if (
|
|
222
|
+
if (flatmap.details['image-layers']) {
|
|
223
|
+
// Image layers are below all feature layers
|
|
224
|
+
|
|
225
|
+
const bodyLayer = flatmap.layers[0];
|
|
226
|
+
|
|
227
|
+
const rasterLayers = new MapRasterLayers(this.__flatmap, bodyLayer.id); // body layer if not FC??
|
|
228
|
+
|
|
168
229
|
for (const layer of flatmap.layers) {
|
|
169
|
-
|
|
170
|
-
const rasterLayer = new style.RasterLayer(raster_layer_id);
|
|
171
|
-
this.__map.addLayer(rasterLayer.style(layerOptions));
|
|
172
|
-
this.__rasterLayers.push(rasterLayer);
|
|
173
|
-
}
|
|
230
|
+
rasterLayers.addLayer(layer);
|
|
174
231
|
}
|
|
232
|
+
this.__layers.set(RASTER_LAYERS_NAME, {
|
|
233
|
+
id: RASTER_LAYERS_NAME,
|
|
234
|
+
description: RASTER_LAYERS_NAME
|
|
235
|
+
});
|
|
236
|
+
this.__mapLayers.set(RASTER_LAYERS_NAME, rasterLayers);
|
|
175
237
|
}
|
|
176
238
|
for (const layer of flatmap.layers) {
|
|
177
|
-
|
|
239
|
+
this.__addFeatureLayer(layer);
|
|
178
240
|
}
|
|
179
241
|
}
|
|
180
242
|
|
|
181
243
|
get activeLayerNames()
|
|
182
244
|
//====================
|
|
183
245
|
{
|
|
184
|
-
|
|
246
|
+
const activeNames = [];
|
|
247
|
+
for (const mapLayer of this.__mapLayers.values()) {
|
|
248
|
+
if (mapLayer.active) {
|
|
249
|
+
activeNames.push(mapLayer.id);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return activeNames;
|
|
185
253
|
}
|
|
186
254
|
|
|
187
|
-
|
|
188
|
-
|
|
255
|
+
__addFeatureLayer(layer)
|
|
256
|
+
//======================
|
|
189
257
|
{
|
|
190
|
-
this.
|
|
191
|
-
|
|
192
|
-
const layers = new MapFeatureLayer(this.__flatmap, layer, background_layers);
|
|
193
|
-
const layerId = this.__flatmap.mapLayerId(layer.id);
|
|
194
|
-
this.__layers.set(layerId, layers);
|
|
258
|
+
this.__layers.set(layer.id, layer);
|
|
259
|
+
this.__mapLayers.set(layer.id, new MapFeatureLayers(this.__flatmap, layer));
|
|
195
260
|
}
|
|
196
261
|
|
|
197
262
|
get layers()
|
|
198
263
|
//==========
|
|
199
264
|
{
|
|
200
|
-
return this.__layers;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
activate(layerId)
|
|
204
|
-
//===============
|
|
205
|
-
{
|
|
206
|
-
const layer = this.__layers.get(layerId);
|
|
207
|
-
if (layer !== undefined) {
|
|
208
|
-
layer.activate();
|
|
209
|
-
if (this.__activeLayers.indexOf(layer) < 0) {
|
|
210
|
-
this.__activeLayers.push(layer);
|
|
211
|
-
this.__activeLayerNames.push(layer.id);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
265
|
+
return Array.from(this.__layers.values());
|
|
214
266
|
}
|
|
215
267
|
|
|
216
|
-
|
|
217
|
-
|
|
268
|
+
activate(layerId, enable=true)
|
|
269
|
+
//============================
|
|
218
270
|
{
|
|
219
|
-
const
|
|
220
|
-
if (
|
|
221
|
-
|
|
222
|
-
const index = this.__activeLayers.indexOf(layer);
|
|
223
|
-
if (index >= 0) {
|
|
224
|
-
delete this.__activeLayers[index];
|
|
225
|
-
this.__activeLayers.splice(index, 1);
|
|
226
|
-
delete this.__activeLayerNames[index];
|
|
227
|
-
this.__activeLayerNames.splice(index, 1);
|
|
228
|
-
}
|
|
271
|
+
const mapLayer = this.__mapLayers.get(layerId);
|
|
272
|
+
if (mapLayer !== undefined) {
|
|
273
|
+
mapLayer.activate(enable);
|
|
229
274
|
}
|
|
230
275
|
}
|
|
231
276
|
|
|
@@ -233,35 +278,10 @@ export class LayerManager
|
|
|
233
278
|
//=====================
|
|
234
279
|
{
|
|
235
280
|
options = utils.setDefaultOptions(options, {colour: true, outline: true});
|
|
236
|
-
for (const
|
|
237
|
-
|
|
281
|
+
for (const mapLayer of this.__mapLayers.values()) {
|
|
282
|
+
mapLayer.setColour(options)
|
|
238
283
|
}
|
|
239
284
|
}
|
|
240
|
-
|
|
241
|
-
makeUppermost(layerId)
|
|
242
|
-
//====================
|
|
243
|
-
{
|
|
244
|
-
// position before top layer
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
makeLowest(layerId)
|
|
248
|
-
//=================
|
|
249
|
-
{
|
|
250
|
-
// position after bottom layer (before == undefined)
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
lower(layerId)
|
|
255
|
-
//============
|
|
256
|
-
{
|
|
257
|
-
// position before second layer underneath...
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
raise(layerId)
|
|
261
|
-
//============
|
|
262
|
-
{
|
|
263
|
-
// position before layer above...
|
|
264
|
-
}
|
|
265
285
|
}
|
|
266
286
|
|
|
267
287
|
//==============================================================================
|
package/src/main.js
CHANGED
|
@@ -27,7 +27,7 @@ export { MapManager };
|
|
|
27
27
|
|
|
28
28
|
//==============================================================================
|
|
29
29
|
|
|
30
|
-
export async function standaloneViewer(map_endpoint=null,
|
|
30
|
+
export async function standaloneViewer(map_endpoint=null, options={})
|
|
31
31
|
{
|
|
32
32
|
const requestUrl = new URL(window.location.href);
|
|
33
33
|
if (map_endpoint == null) {
|
|
@@ -52,6 +52,18 @@ export async function standaloneViewer(map_endpoint=null, map_options={})
|
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
let currentMap = null;
|
|
55
|
+
let defaultBackground = 'black';
|
|
56
|
+
|
|
57
|
+
const mapOptions = Object.assign({
|
|
58
|
+
tooltips: true,
|
|
59
|
+
background: defaultBackground,
|
|
60
|
+
backgroundControl: true,
|
|
61
|
+
debug: false,
|
|
62
|
+
minimap: false,
|
|
63
|
+
searchable: true,
|
|
64
|
+
featureInfo: true,
|
|
65
|
+
showPosition: false
|
|
66
|
+
}, options);
|
|
55
67
|
|
|
56
68
|
function loadMap(id, taxon, sex)
|
|
57
69
|
//==============================
|
|
@@ -71,20 +83,15 @@ export async function standaloneViewer(map_endpoint=null, map_options={})
|
|
|
71
83
|
}
|
|
72
84
|
requestUrl.searchParams.delete('id');
|
|
73
85
|
}
|
|
86
|
+
|
|
87
|
+
// Update address bar URL to current map
|
|
74
88
|
window.history.pushState('data', document.title, requestUrl);
|
|
75
89
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
navigationControl: 'top-right',
|
|
82
|
-
searchable: true,
|
|
83
|
-
featureInfo: true,
|
|
84
|
-
showPosition: false
|
|
85
|
-
}, map_options);
|
|
86
|
-
|
|
87
|
-
mapManager.loadMap(id, 'map-canvas', (...args) => console.log(...args), options)
|
|
90
|
+
mapManager.loadMap(id, 'map-canvas', (eventType, ...args) => {
|
|
91
|
+
if (args[0].type === 'control' && args[0].control === 'background') {
|
|
92
|
+
mapOptions.background = args[0].value;
|
|
93
|
+
}
|
|
94
|
+
}, mapOptions)
|
|
88
95
|
.then(map => {
|
|
89
96
|
map.addMarker('UBERON:0000948'); // Heart
|
|
90
97
|
map.addMarker('UBERON:0002048'); // Lung
|
|
@@ -129,7 +136,7 @@ export async function standaloneViewer(map_endpoint=null, map_options={})
|
|
|
129
136
|
let mapId = null;
|
|
130
137
|
let mapTaxon = null;
|
|
131
138
|
let mapSex = null;
|
|
132
|
-
const
|
|
139
|
+
const mapList = [];
|
|
133
140
|
for (const [name, map] of sortedMaps.entries()) {
|
|
134
141
|
const text = [ name, map.created ];
|
|
135
142
|
let selected = '';
|
|
@@ -145,12 +152,12 @@ export async function standaloneViewer(map_endpoint=null, map_options={})
|
|
|
145
152
|
mapSex = viewMapSex;
|
|
146
153
|
selected = 'selected';
|
|
147
154
|
}
|
|
148
|
-
|
|
155
|
+
mapList.push(`<option value="${id}" ${selected}>${text.join(' -- ')}</option>`);
|
|
149
156
|
}
|
|
150
|
-
|
|
157
|
+
mapList.splice(0, 0, '<option value="">Select flatmap...</option>');
|
|
151
158
|
|
|
152
159
|
const selector = document.getElementById('map-selector');
|
|
153
|
-
selector.innerHTML =
|
|
160
|
+
selector.innerHTML = mapList.join('');
|
|
154
161
|
selector.onchange = (e) => {
|
|
155
162
|
if (e.target.value !== '') {
|
|
156
163
|
loadMap(e.target.value);
|
package/src/search.js
CHANGED
|
@@ -158,7 +158,10 @@ export class SearchIndex
|
|
|
158
158
|
|
|
159
159
|
addTerm_(featureId, text)
|
|
160
160
|
//=======================
|
|
161
|
-
{
|
|
161
|
+
{
|
|
162
|
+
text = text.replace(new RegExp('<br/>', 'g'), ' ')
|
|
163
|
+
.replace('\n', ' ');
|
|
164
|
+
if (text) {
|
|
162
165
|
this._searchEngine.add({
|
|
163
166
|
id: this._featureIds.length,
|
|
164
167
|
text: text
|
package/src/styling.js
CHANGED
|
@@ -226,8 +226,7 @@ export class FeatureBorderLayer extends VectorStyleLayer
|
|
|
226
226
|
'type': 'line',
|
|
227
227
|
'filter': [
|
|
228
228
|
'all',
|
|
229
|
-
['==', '$type', 'Polygon']
|
|
230
|
-
['has', 'id']
|
|
229
|
+
['==', '$type', 'Polygon']
|
|
231
230
|
],
|
|
232
231
|
'paint': this.paintStyle(options)
|
|
233
232
|
};
|
|
@@ -268,7 +267,7 @@ export class FeatureLineLayer extends VectorStyleLayer
|
|
|
268
267
|
['boolean', ['feature-state', 'active'], false], coloured ? '#888' : '#CCC',
|
|
269
268
|
['==', ['get', 'type'], 'network'], '#AFA202',
|
|
270
269
|
['has', 'centreline'], '#888',
|
|
271
|
-
|
|
270
|
+
options.authoring ? '#C44' : '#444'
|
|
272
271
|
],
|
|
273
272
|
'line-opacity': [
|
|
274
273
|
'case',
|
|
@@ -284,7 +283,7 @@ export class FeatureLineLayer extends VectorStyleLayer
|
|
|
284
283
|
['==', ['get', 'type'], 'network'], 1.2,
|
|
285
284
|
['boolean', ['feature-state', 'selected'], false], 1.2,
|
|
286
285
|
['boolean', ['feature-state', 'active'], false], 1.2,
|
|
287
|
-
|
|
286
|
+
options.authoring ? 0.7 : 0.5
|
|
288
287
|
], [
|
|
289
288
|
'interpolate',
|
|
290
289
|
['exponential', 2],
|
|
@@ -357,6 +356,7 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
357
356
|
const paintStyle = {
|
|
358
357
|
'line-color': [
|
|
359
358
|
'case',
|
|
359
|
+
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
360
360
|
['boolean', ['feature-state', 'hidden'], false], '#CCC',
|
|
361
361
|
['==', ['get', 'type'], 'bezier'], 'red',
|
|
362
362
|
['==', ['get', 'kind'], 'error'], '#FFFE0E',
|
|
@@ -683,7 +683,7 @@ export class BackgroundLayer
|
|
|
683
683
|
return this.__id;
|
|
684
684
|
}
|
|
685
685
|
|
|
686
|
-
style(backgroundColour, opacity=0
|
|
686
|
+
style(backgroundColour, opacity=1.0)
|
|
687
687
|
{
|
|
688
688
|
return {
|
|
689
689
|
'id': this.__id,
|
|
@@ -51,6 +51,10 @@ li.flatmap-contextmenu-item:hover {
|
|
|
51
51
|
margin-top: 2px;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
.text-button {
|
|
55
|
+
width: 64px;
|
|
56
|
+
}
|
|
57
|
+
|
|
54
58
|
/* Search box */
|
|
55
59
|
|
|
56
60
|
#search-control-input {
|
|
@@ -176,7 +180,7 @@ li.flatmap-contextmenu-item:hover {
|
|
|
176
180
|
.flatmap-nerve-grid {
|
|
177
181
|
margin-top: 10px;
|
|
178
182
|
display: grid;
|
|
179
|
-
grid-template-columns: 3fr 0.
|
|
183
|
+
grid-template-columns: 3fr 0.8fr 0.2fr;
|
|
180
184
|
column-gap: 10px;
|
|
181
185
|
row-gap: 0.2em;
|
|
182
186
|
width: 300px;
|
|
@@ -226,6 +230,32 @@ label[for=path-all-paths] {
|
|
|
226
230
|
background: repeating-linear-gradient(to right,#EA3423 0,#EA3423 6px,transparent 6px,transparent 9px)
|
|
227
231
|
}
|
|
228
232
|
|
|
233
|
+
/* Layer control */
|
|
234
|
+
|
|
235
|
+
#flatmap-layer-control {
|
|
236
|
+
text-align: right;
|
|
237
|
+
}
|
|
238
|
+
.flatmap-layer-grid {
|
|
239
|
+
margin-top: 10px;
|
|
240
|
+
display: grid;
|
|
241
|
+
grid-template-columns: 3.8fr 0.2fr;
|
|
242
|
+
column-gap: 10px;
|
|
243
|
+
row-gap: 0.2em;
|
|
244
|
+
width: 300px;
|
|
245
|
+
font-size: 10pt;
|
|
246
|
+
cursor: pointer;
|
|
247
|
+
text-align: left;
|
|
248
|
+
background: white;
|
|
249
|
+
border: 1px solid gray;
|
|
250
|
+
padding: 4px;
|
|
251
|
+
opacity: 0.8;
|
|
252
|
+
}
|
|
253
|
+
.flatmap-layer-grid input {
|
|
254
|
+
height: 1.1em;
|
|
255
|
+
}
|
|
256
|
+
label[for=layer-all-layers] {
|
|
257
|
+
font-weight: bold;
|
|
258
|
+
}
|
|
229
259
|
|
|
230
260
|
/* Markers */
|
|
231
261
|
|