@abi-software/flatmap-viewer 2.3.0-a.1 → 2.3.0-a.3

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/src/layers.js CHANGED
@@ -27,113 +27,163 @@ import {PATHWAYS_LAYER} from './pathways.js';
27
27
  import * as style from './styling.js';
28
28
  import * as utils from './utils.js';
29
29
 
30
- const FEATURES_LAYER = 'features'
30
+ const FEATURES_LAYER = 'features';
31
+ const RASTER_LAYERS_NAME = 'Background image layer';
32
+ const RASTER_LAYERS_ID = 'background-image-layer';
31
33
 
32
34
  //==============================================================================
33
35
 
34
- class MapFeatureLayer
36
+ class MapStylingLayers
35
37
  {
36
- constructor(flatmap, layer, background_layers=true)
38
+ constructor(flatmap, layer, options)
37
39
  {
38
40
  this.__map = flatmap.map;
39
- this.__separateLayers = flatmap.options.separateLayers;
40
41
  this.__id = layer.id;
41
- this.__rasterLayers = [];
42
- this.__styleLayers = [];
42
+ this.__description = layer.description;
43
+ this.__active = true;
44
+ this.__layers = [];
45
+ this.__layerOptions = options;
46
+ this.__separateLayers = flatmap.options.separateLayers;
47
+ }
48
+
49
+ get id()
50
+ //======
51
+ {
52
+ return this.__id;
53
+ }
54
+
55
+ get description()
56
+ //===============
57
+ {
58
+ return this.__description;
59
+ }
60
+
61
+ get active()
62
+ //==========
63
+ {
64
+ return this.__active;
65
+ }
66
+
67
+ addLayer(styleLayer, options)
68
+ //===========================
69
+ {
70
+ this.__map.addLayer(styleLayer.style(options));
71
+ this.__layers.push(styleLayer);
72
+ }
73
+
74
+ __showLayer(layer, visible=true)
75
+ //===============================
76
+ {
77
+ this.__map.setLayoutProperty(layer.id, 'visibility', visible ? 'visible' : 'none');
78
+ }
79
+
80
+ activate(enable=true)
81
+ //===================
82
+ {
83
+ for (const layer of this.__layers) {
84
+ this.__showLayer(layer, enable);
85
+ }
86
+ this.__active = enable;
87
+ }
43
88
 
44
- const layerOptions = flatmap.options.layerOptions;
89
+ vectorSourceId(sourceLayer)
90
+ //=========================
91
+ {
92
+ return (this.__separateLayers ? `${this.__id}_${sourceLayer}`
93
+ : sourceLayer).replaceAll('/', '_');
94
+ }
95
+
96
+ setPaint(options)
97
+ {
98
+ }
99
+
100
+ setFilter(options)
101
+ {
102
+ }
103
+ }
104
+
105
+ //==============================================================================
106
+
107
+ class MapFeatureLayers extends MapStylingLayers
108
+ {
109
+ constructor(flatmap, layer, options)
110
+ {
111
+ super(flatmap, layer, options);
45
112
  const vectorTileSource = this.__map.getSource('vector-tiles');
46
113
  const haveVectorLayers = (typeof vectorTileSource !== 'undefined');
47
- const featuresVectorLayerId = this.__separateLayers
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
- }
114
+
62
115
  // if no image layers then make feature borders (and lines?) more visible...??
63
116
  if (haveVectorLayers) {
117
+ const featuresVectorSource = this.vectorSourceId(FEATURES_LAYER);
118
+ const vectorFeatures = vectorTileSource.vectorLayerIds
119
+ .indexOf(featuresVectorSource) >= 0;
64
120
  if (vectorFeatures) {
65
- this.__addStyleLayer(style.FeatureFillLayer, layerOptions);
66
- this.__addStyleLayer(style.FeatureDashLineLayer, layerOptions);
67
- this.__addStyleLayer(style.FeatureLineLayer, layerOptions);
68
- this.__addStyleLayer(style.FeatureBorderLayer, layerOptions);
121
+ this.__addStyleLayer(style.FeatureFillLayer);
122
+ this.__addStyleLayer(style.FeatureDashLineLayer);
123
+ this.__addStyleLayer(style.FeatureLineLayer);
124
+ this.__addStyleLayer(style.FeatureBorderLayer);
125
+ this.__addStyleLayer(style.CentrelineNodeFillLayer);
126
+ this.__addStyleLayer(style.CentrelineNodeBorderLayer);
69
127
  }
70
- this.__addPathwayStyleLayers(layerOptions);
128
+ this.__addPathwayStyleLayers();
71
129
  if (vectorFeatures) {
72
- this.__addStyleLayer(style.FeatureLargeSymbolLayer, layerOptions);
130
+ this.__addStyleLayer(style.FeatureLargeSymbolLayer);
73
131
  if (!flatmap.options.tooltips) {
74
- this.__addStyleLayer(style.FeatureSmallSymbolLayer, layerOptions);
132
+ this.__addStyleLayer(style.FeatureSmallSymbolLayer);
75
133
  }
76
134
  }
77
135
  }
78
136
 
79
- // Make sure our colour options are set properly, in particular raster layer visibility
80
-
81
- this.setColour(layerOptions);
82
- }
137
+ // Make sure our paint options are set properly, in particular raster layer visibility
83
138
 
84
- get id()
85
- //======
86
- {
87
- return this.__id;
139
+ this.setPaint(this.__layerOptions);
88
140
  }
89
141
 
90
- __addRasterLayer(raster_layer_id, options)
91
- //========================================
142
+ __addStyleLayer(styleClass, sourceLayer=FEATURES_LAYER)
143
+ //=====================================================
92
144
  {
93
- const rasterLayer = new style.RasterLayer(raster_layer_id);
94
- this.__map.addLayer(rasterLayer.style(options));
95
- this.__rasterLayers.push(rasterLayer);
145
+ const styleLayer = new styleClass(`${this.__id}_${sourceLayer}`,
146
+ this.vectorSourceId(sourceLayer));
147
+ this.addLayer(styleLayer, this.__layerOptions);
96
148
  }
97
149
 
98
- __addPathwayStyleLayers(options)
99
- //==============================
150
+ __addPathwayStyleLayers()
151
+ //=======================
100
152
  {
101
- const pathwaysVectorLayerId = this.__separateLayers
102
- ? `${this.__id}_${PATHWAYS_LAYER}`
103
- : PATHWAYS_LAYER;
153
+ const pathwaysVectorSource = this.vectorSourceId(PATHWAYS_LAYER);
104
154
  if (this.__map.getSource('vector-tiles')
105
155
  .vectorLayerIds
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);
156
+ .indexOf(pathwaysVectorSource) >= 0) {
157
+ this.__addStyleLayer(style.CentrelineEdgeLayer, PATHWAYS_LAYER);
158
+ this.__addStyleLayer(style.CentrelineTrackLayer, PATHWAYS_LAYER);
159
+
160
+ this.__addStyleLayer(style.PathLineLayer, PATHWAYS_LAYER);
161
+ this.__addStyleLayer(style.PathDashlineLayer, PATHWAYS_LAYER);
162
+
163
+ this.__addStyleLayer(style.NervePolygonBorder, PATHWAYS_LAYER);
164
+ this.__addStyleLayer(style.NervePolygonFill, PATHWAYS_LAYER);
165
+ this.__addStyleLayer(style.FeatureNerveLayer, PATHWAYS_LAYER);
112
166
  }
113
167
  }
114
168
 
115
- __addStyleLayer(styleClass, options, sourceLayer=FEATURES_LAYER)
116
- //==============================================================
169
+ setPaint(options)
170
+ //===============
117
171
  {
118
- const layerId = `${this.__id}_${sourceLayer}`;
119
- const source = this.__separateLayers ? layerId : sourceLayer;
120
- const styleLayer = new styleClass(layerId, source);
121
- this.__map.addLayer(styleLayer.style(options));
122
- this.__styleLayers.push(styleLayer);
172
+ for (const layer of this.__layers) {
173
+ const paintStyle = layer.paintStyle(options, true);
174
+ for (const [property, value] of Object.entries(paintStyle)) {
175
+ this.__map.setPaintProperty(layer.id, property, value, {validate: false});
176
+ }
177
+ }
123
178
  }
124
179
 
125
- setColour(options)
180
+ setFilter(options)
126
181
  //================
127
182
  {
128
- const coloured = !('colour' in options) || options.colour;
129
- for (const rasterLayer of this.__rasterLayers) {
130
- this.__map.setLayoutProperty(rasterLayer.id, 'visibility', coloured ? 'visible' : 'none',
131
- {validate: false});
132
- }
133
- for (const styleLayer of this.__styleLayers) {
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});
183
+ for (const layer of this.__layers) {
184
+ const filter = layer.makeFilter(options);
185
+ if (filter !== null) {
186
+ this.__map.setFilter(layer.id, filter, {validate: true});
137
187
  }
138
188
  }
139
189
  }
@@ -141,126 +191,167 @@ class MapFeatureLayer
141
191
 
142
192
  //==============================================================================
143
193
 
194
+ class MapRasterLayers extends MapStylingLayers
195
+ {
196
+ constructor(flatmap, options, bodyLayerId=null)
197
+ {
198
+ const rasterLayer = {
199
+ id: RASTER_LAYERS_ID,
200
+ description: RASTER_LAYERS_NAME
201
+ };
202
+ super(flatmap, rasterLayer, options);
203
+ if (bodyLayerId !== null) {
204
+ const layerId = `${bodyLayerId}_${FEATURES_LAYER}`;
205
+ const source = flatmap.options.separateLayers ? layerId : FEATURES_LAYER;
206
+ const styleLayer = new style.BodyLayer(layerId, source);
207
+ this.__map.addLayer(styleLayer.style(this.__layerOptions));
208
+ this.__layers.push(styleLayer);
209
+ }
210
+ // Make sure our paint options are set properly, in particular raster layer visibility
211
+ this.setPaint(this.__layerOptions);
212
+ }
213
+
214
+ addLayer(layer)
215
+ //=============
216
+ {
217
+ for (const layer_id of layer['image-layers']) {
218
+ const rasterLayer = new style.RasterLayer(layer_id);
219
+ this.__map.addLayer(rasterLayer.style(this.__layerOptions));
220
+ this.__layers.push(rasterLayer);
221
+ }
222
+ // Make sure our paint options are set properly, in particular raster layer visibility
223
+ this.setPaint(this.__layerOptions);
224
+ }
225
+
226
+ setPaint(options)
227
+ //===============
228
+ {
229
+ const coloured = !('colour' in options) || options.colour;
230
+ for (const layer of this.__layers) {
231
+ // Check active status when resetting to visible....
232
+ this.__map.setLayoutProperty(layer.id, 'visibility',
233
+ (coloured && this.active) ? 'visible' : 'none',
234
+ {validate: false});
235
+ }
236
+ }
237
+ }
238
+
239
+ //==============================================================================
240
+
144
241
  export class LayerManager
145
242
  {
146
- constructor(flatmap, switcher=false)
243
+ constructor(flatmap)
147
244
  {
148
245
  this.__flatmap = flatmap;
149
246
  this.__map = flatmap.map;
150
- this.__layers = new Map;
151
247
  this.__mapLayers = new Map;
152
- this.__activeLayers = [];
153
- this.__activeLayerNames = [];
154
- this.__rasterLayers = [];
155
- const layerOptions = flatmap.options.layerOptions;
156
- const fcDiagram = ('style' in layerOptions && layerOptions.style == 'fcdiagram');
248
+ this.__layerOptions = utils.setDefaults(flatmap.options.layerOptions, {
249
+ colour: true,
250
+ outline: true,
251
+ sckan: 'valid'
252
+ });
157
253
  const backgroundLayer = new style.BackgroundLayer();
158
- if (fcDiagram) {
159
- this.__map.addLayer(backgroundLayer.style('black', 1));
160
- }
161
- else if ('background' in flatmap.options) {
254
+ if ('background' in flatmap.options) {
162
255
  this.__map.addLayer(backgroundLayer.style(flatmap.options.background));
163
256
  } else {
164
257
  this.__map.addLayer(backgroundLayer.style('white'));
165
258
  }
259
+
166
260
  // Add the map's layers
167
- if (fcDiagram && flatmap.details['image-layers']) {
261
+ if (flatmap.details['image-layers']) {
262
+ this.__layerOptions.activeRasterLayer = true;
263
+
264
+ // Image layers are below all feature layers
265
+ const bodyLayer = flatmap.layers[0];
266
+ const rasterLayers = new MapRasterLayers(this.__flatmap,
267
+ this.__layerOptions,
268
+ bodyLayer.id); // body layer if not FC??
168
269
  for (const layer of flatmap.layers) {
169
- for (const raster_layer_id of layer['image-layers']) {
170
- const rasterLayer = new style.RasterLayer(raster_layer_id);
171
- this.__map.addLayer(rasterLayer.style(layerOptions));
172
- this.__rasterLayers.push(rasterLayer);
173
- }
270
+ rasterLayers.addLayer(layer);
174
271
  }
272
+ this.__mapLayers.set(RASTER_LAYERS_ID, rasterLayers);
273
+ } else {
274
+ this.__layerOptions.activeRasterLayer = false;
175
275
  }
176
276
  for (const layer of flatmap.layers) {
177
- this.addLayer(layer, !fcDiagram);
277
+ this.__mapLayers.set(layer.id, new MapFeatureLayers(this.__flatmap,
278
+ layer,
279
+ this.__layerOptions));
178
280
  }
179
281
  }
180
282
 
181
- get activeLayerNames()
182
- //====================
183
- {
184
- return this.__activeLayerNames;
185
- }
186
-
187
- addLayer(layer, background_layers=true)
188
- //=====================================
189
- {
190
- this.__mapLayers.set(layer.id, layer);
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);
195
- }
196
-
197
283
  get layers()
198
284
  //==========
199
285
  {
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
- }
286
+ const layers = [];
287
+ for (const mapLayer of this.__mapLayers.values()) {
288
+ layers.push({
289
+ id: mapLayer.id,
290
+ description: mapLayer.description,
291
+ enabled: mapLayer.active
292
+ });
213
293
  }
294
+ return layers;
214
295
  }
215
296
 
216
- deactivate(layerId)
217
- //=================
297
+ activate(layerId, enable=true)
298
+ //============================
218
299
  {
219
- const layer = this.__layers.get(layerId);
300
+ const layer = this.__mapLayers.get(layerId);
220
301
  if (layer !== undefined) {
221
- layer.deactivate();
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);
302
+ layer.activate(enable);
303
+ if (layer.id === RASTER_LAYERS_ID) {
304
+ this.__layerOptions.activeRasterLayer = enable;
305
+ for (const mapLayer of this.__mapLayers.values()) {
306
+ if (mapLayer.id !== RASTER_LAYERS_ID) {
307
+ mapLayer.setPaint(this.__layerOptions);
308
+ }
309
+ }
228
310
  }
229
311
  }
230
312
  }
231
313
 
232
- setColour(options=null)
233
- //=====================
314
+ setPaint(options={})
315
+ //==================
234
316
  {
235
- options = utils.setDefaultOptions(options, {colour: true, outline: true});
236
- for (const layer of this.__layers.values()) {
237
- layer.setColour(options)
317
+ this.__layerOptions = utils.setDefaults(options, this.__layerOptions);
318
+ for (const mapLayer of this.__mapLayers.values()) {
319
+ mapLayer.setPaint(this.__layerOptions);
238
320
  }
239
321
  }
240
322
 
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
- //============
323
+ setFilter(options={})
324
+ //===================
256
325
  {
257
- // position before second layer underneath...
326
+ this.__layerOptions = utils.setDefaults(options, this.__layerOptions);
327
+ for (const mapLayer of this.__mapLayers.values()) {
328
+ mapLayer.setFilter(this.__layerOptions);
329
+ }
258
330
  }
259
331
 
260
- raise(layerId)
261
- //============
332
+ enableSckanPath(sckanState, enable=true)
333
+ //======================================
262
334
  {
263
- // position before layer above...
335
+ const currentState = this.__layerOptions.sckan;
336
+ const validEnabled = ['valid', 'all'].indexOf(currentState) >= 0;
337
+ const invalidEnabled = ['invalid', 'all'].indexOf(currentState) >= 0;
338
+ let newState = sckanState.toLowerCase();
339
+ if (newState === 'valid') {
340
+ if (enable && !validEnabled) {
341
+ newState = invalidEnabled ? 'all' : 'valid';
342
+ } else if (!enable && validEnabled) {
343
+ newState = invalidEnabled ? 'invalid' : 'none';
344
+ }
345
+ } else if (newState === 'invalid') {
346
+ if (enable && !invalidEnabled) {
347
+ newState = validEnabled ? 'all' : 'invalid';
348
+ } else if (!enable && invalidEnabled) {
349
+ newState = validEnabled ? 'valid' : 'none';
350
+ }
351
+ }
352
+ if (newState !== this.__layerOptions.sckan) {
353
+ this.setFilter({sckan: newState});
354
+ }
264
355
  }
265
356
  }
266
357
 
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, map_options={})
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,16 @@ export async function standaloneViewer(map_endpoint=null, map_options={})
52
52
  });
53
53
 
54
54
  let currentMap = null;
55
+ let defaultBackground = localStorage.getItem('flatmap-background-colour') || 'black';
56
+
57
+ const mapOptions = Object.assign({
58
+ tooltips: true,
59
+ background: defaultBackground,
60
+ debug: false,
61
+ minimap: false,
62
+ showPosition: false,
63
+ standalone: true
64
+ }, options);
55
65
 
56
66
  function loadMap(id, taxon, sex)
57
67
  //==============================
@@ -71,20 +81,15 @@ export async function standaloneViewer(map_endpoint=null, map_options={})
71
81
  }
72
82
  requestUrl.searchParams.delete('id');
73
83
  }
84
+
85
+ // Update address bar URL to current map
74
86
  window.history.pushState('data', document.title, requestUrl);
75
87
 
76
- const options = Object.assign({
77
- tooltips: true,
78
- background: '#EEF',
79
- debug: false,
80
- minimap: false,
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)
88
+ mapManager.loadMap(id, 'map-canvas', (eventType, ...args) => {
89
+ if (args[0].type === 'control' && args[0].control === 'background') {
90
+ mapOptions.background = args[0].value;
91
+ }
92
+ }, mapOptions)
88
93
  .then(map => {
89
94
  map.addMarker('UBERON:0000948'); // Heart
90
95
  map.addMarker('UBERON:0002048'); // Lung
@@ -129,7 +134,7 @@ export async function standaloneViewer(map_endpoint=null, map_options={})
129
134
  let mapId = null;
130
135
  let mapTaxon = null;
131
136
  let mapSex = null;
132
- const options = [];
137
+ const mapList = [];
133
138
  for (const [name, map] of sortedMaps.entries()) {
134
139
  const text = [ name, map.created ];
135
140
  let selected = '';
@@ -145,12 +150,12 @@ export async function standaloneViewer(map_endpoint=null, map_options={})
145
150
  mapSex = viewMapSex;
146
151
  selected = 'selected';
147
152
  }
148
- options.push(`<option value="${id}" ${selected}>${text.join(' -- ')}</option>`);
153
+ mapList.push(`<option value="${id}" ${selected}>${text.join(' -- ')}</option>`);
149
154
  }
150
- options.splice(0, 0, '<option value="">Select flatmap...</option>');
155
+ mapList.splice(0, 0, '<option value="">Select flatmap...</option>');
151
156
 
152
157
  const selector = document.getElementById('map-selector');
153
- selector.innerHTML = options.join('');
158
+ selector.innerHTML = mapList.join('');
154
159
  selector.onchange = (e) => {
155
160
  if (e.target.value !== '') {
156
161
  loadMap(e.target.value);