@abi-software/flatmap-viewer 2.2.1-alpha.1 → 2.2.1-beta.10
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/README.rst +2 -2
- package/package.json +2 -1
- package/src/flatmap-viewer.js +29 -3
- package/src/interactions.js +108 -72
- package/src/layers.js +66 -25
- package/src/styling.js +109 -71
package/README.rst
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Flatmap Viewer
|
|
3
3
|
==============
|
|
4
4
|
|
|
5
|
-
A viewer for anatomical flatmaps generated by `flatmap-maker <https://github.com/
|
|
5
|
+
A viewer for anatomical flatmaps generated by `flatmap-maker <https://github.com/AnatomicMaps/flatmap-maker>`_. The viewer is intended to be a component of a larger Javascript web application, although may be used standalone for local flatmap development and testing. Flatmap content is obtained from a `flatmap-server <https://github.com/AnatomicMaps/flatmap-server>`_.
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
Standalone Use
|
|
@@ -38,7 +38,7 @@ The map server endpoint is specified as ``MAP_ENDPOINT`` in ``src/main.js``. It
|
|
|
38
38
|
Package Installation
|
|
39
39
|
====================
|
|
40
40
|
|
|
41
|
-
* ``npm install @abi-software/flatmap-viewer``
|
|
41
|
+
* ``npm install @abi-software/flatmap-viewer@2.2.1-beta.10``
|
|
42
42
|
|
|
43
43
|
Documentation
|
|
44
44
|
-------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abi-software/flatmap-viewer",
|
|
3
|
-
"version": "2.2.1-
|
|
3
|
+
"version": "2.2.1-beta.10",
|
|
4
4
|
"description": "Flatmap viewer using Maplibre GL",
|
|
5
5
|
"repository": "https://github.com/AnatomicMaps/flatmap-viewer.git",
|
|
6
6
|
"main": "src/main.js",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"@turf/area": "^6.0.1",
|
|
22
22
|
"@turf/bbox": "^6.0.1",
|
|
23
23
|
"@turf/helpers": "^6.1.4",
|
|
24
|
+
"bezier-js": "^6.1.0",
|
|
24
25
|
"maplibre-gl": ">=1.15.3",
|
|
25
26
|
"minisearch": "^2.2.1",
|
|
26
27
|
"polylabel": "^1.1.0"
|
package/src/flatmap-viewer.js
CHANGED
|
@@ -45,6 +45,10 @@ import * as utils from './utils.js';
|
|
|
45
45
|
|
|
46
46
|
//==============================================================================
|
|
47
47
|
|
|
48
|
+
const MAP_MAKER_SEPARATE_LAYERS_VERSION = 1.4;
|
|
49
|
+
|
|
50
|
+
//==============================================================================
|
|
51
|
+
|
|
48
52
|
/**
|
|
49
53
|
* Maps are not created directly but instead are created and loaded by
|
|
50
54
|
* :meth:`LoadMap` of :class:`MapManager`.
|
|
@@ -1001,9 +1005,15 @@ export class MapManager
|
|
|
1001
1005
|
{
|
|
1002
1006
|
return await this._initialisingMutex.dispatch(async () => {
|
|
1003
1007
|
if (!this._initialised) {
|
|
1004
|
-
this._mapList =
|
|
1008
|
+
this._mapList = [];
|
|
1009
|
+
const maps = await this._mapServer.loadJSON('');
|
|
1005
1010
|
// Check map schema version (set by mapmaker) and
|
|
1006
1011
|
// remove maps we can't view (giving a console warning...)
|
|
1012
|
+
for (const map of maps) {
|
|
1013
|
+
// Are features in separate vector tile source layers?
|
|
1014
|
+
map.separateLayers = ('version' in map && map.version >= MAP_MAKER_SEPARATE_LAYERS_VERSION);
|
|
1015
|
+
this._mapList.push(map);
|
|
1016
|
+
}
|
|
1007
1017
|
this._initialised = true;
|
|
1008
1018
|
}
|
|
1009
1019
|
});
|
|
@@ -1157,7 +1167,7 @@ export class MapManager
|
|
|
1157
1167
|
try {
|
|
1158
1168
|
const map = await this.findMap_(identifier);
|
|
1159
1169
|
if (map === null) {
|
|
1160
|
-
reject(`Unknown map
|
|
1170
|
+
reject(`Unknown map: ${JSON.stringify(identifier)}`);
|
|
1161
1171
|
};
|
|
1162
1172
|
|
|
1163
1173
|
// Load the maps index file
|
|
@@ -1181,6 +1191,12 @@ export class MapManager
|
|
|
1181
1191
|
mapOptions['pathControls'] = true;
|
|
1182
1192
|
}
|
|
1183
1193
|
|
|
1194
|
+
// Mapmaker's changed the name of the field to indicate that indicates if
|
|
1195
|
+
// there are raster layers
|
|
1196
|
+
if (!('image-layers' in mapIndex) && ('image_layer' in mapIndex)) {
|
|
1197
|
+
mapIndex['image-layers'] = mapIndex['image_layer'];
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1184
1200
|
// Get details about the map's layers
|
|
1185
1201
|
|
|
1186
1202
|
let mapLayers = [];
|
|
@@ -1249,7 +1265,17 @@ export class MapManager
|
|
|
1249
1265
|
outline: true
|
|
1250
1266
|
};
|
|
1251
1267
|
}
|
|
1252
|
-
|
|
1268
|
+
if ('authoring' in mapIndex) {
|
|
1269
|
+
mapOptions.layerOptions.style == 'authoring'
|
|
1270
|
+
} else if ('style' in mapIndex) {
|
|
1271
|
+
mapOptions.layerOptions.style = mapIndex.style;
|
|
1272
|
+
} else {
|
|
1273
|
+
mapOptions.layerOptions.style = 'flatmap';
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
// Are features in separate vector tile source layers?
|
|
1277
|
+
|
|
1278
|
+
mapOptions.separateLayers = map.separateLayers;
|
|
1253
1279
|
|
|
1254
1280
|
// Display the map
|
|
1255
1281
|
|
package/src/interactions.js
CHANGED
|
@@ -162,34 +162,6 @@ export class UserInteractions
|
|
|
162
162
|
|
|
163
163
|
this._layerManager = new LayerManager(flatmap);
|
|
164
164
|
|
|
165
|
-
// Add the map's layers
|
|
166
|
-
|
|
167
|
-
// Layers have an id, either layer-N or an assigned name
|
|
168
|
-
// Some layers might have a description. These are the selectable layers,
|
|
169
|
-
// unless they are flagged as `no-select`
|
|
170
|
-
// Selectable layers have opacity 0 unless active, in which case they have opacity 1.
|
|
171
|
-
// `no-select` layers have opacity 0.5
|
|
172
|
-
// Background layer has opacity 0.2
|
|
173
|
-
|
|
174
|
-
const layersById = new Map();
|
|
175
|
-
const layerBackgroundIds = [];
|
|
176
|
-
for (const layer of flatmap.layers) {
|
|
177
|
-
layer.backgroundLayers = [];
|
|
178
|
-
layersById.set(layer.id, layer);
|
|
179
|
-
}
|
|
180
|
-
for (const layer of flatmap.layers) {
|
|
181
|
-
if (layer.background_for) {
|
|
182
|
-
const l = layersById.get(layer.background_for);
|
|
183
|
-
l.backgroundLayers.push(layer);
|
|
184
|
-
layerBackgroundIds.push(layer.id);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
for (const layer of flatmap.layers) {
|
|
188
|
-
if (layerBackgroundIds.indexOf(layer.id) < 0) {
|
|
189
|
-
this._layerManager.addLayer(layer, flatmap.options.layerOptions);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
165
|
// Flag features that have annotations
|
|
194
166
|
// Also flag those features that are models of something
|
|
195
167
|
|
|
@@ -205,7 +177,7 @@ export class UserInteractions
|
|
|
205
177
|
// Display a context menu on right-click
|
|
206
178
|
|
|
207
179
|
this._lastContextTime = 0;
|
|
208
|
-
this._contextMenu = new ContextMenu(flatmap, this.
|
|
180
|
+
this._contextMenu = new ContextMenu(flatmap, this.__clearModal.bind(this));
|
|
209
181
|
this._map.on('contextmenu', this.contextMenuEvent_.bind(this));
|
|
210
182
|
|
|
211
183
|
// Display a context menu with a touch longer than 0.5 second
|
|
@@ -285,7 +257,9 @@ export class UserInteractions
|
|
|
285
257
|
return {
|
|
286
258
|
id: featureId,
|
|
287
259
|
source: VECTOR_TILES_SOURCE,
|
|
288
|
-
sourceLayer:
|
|
260
|
+
sourceLayer: this._flatmap.options.separateLayers
|
|
261
|
+
? `${ann['layer']}_${ann['tile-layer']}`
|
|
262
|
+
: ann['tile-layer']
|
|
289
263
|
};
|
|
290
264
|
}
|
|
291
265
|
|
|
@@ -330,8 +304,8 @@ export class UserInteractions
|
|
|
330
304
|
}
|
|
331
305
|
}
|
|
332
306
|
|
|
333
|
-
|
|
334
|
-
|
|
307
|
+
__unselectFeatures()
|
|
308
|
+
//==================
|
|
335
309
|
{
|
|
336
310
|
for (const featureId of this._selectedFeatureIds.keys()) {
|
|
337
311
|
const feature = this.mapFeature_(featureId);
|
|
@@ -447,8 +421,8 @@ export class UserInteractions
|
|
|
447
421
|
this._modal = true;
|
|
448
422
|
}
|
|
449
423
|
|
|
450
|
-
|
|
451
|
-
|
|
424
|
+
__clearModal(event)
|
|
425
|
+
//=================
|
|
452
426
|
{
|
|
453
427
|
this._modal = false;
|
|
454
428
|
}
|
|
@@ -459,7 +433,7 @@ export class UserInteractions
|
|
|
459
433
|
this._contextMenu.hide();
|
|
460
434
|
const nodeId = event.target.getAttribute('featureId');
|
|
461
435
|
this.enablePathFeatures_(enable, this._pathways.pathFeatureIds(nodeId));
|
|
462
|
-
this.
|
|
436
|
+
this.__clearModal();
|
|
463
437
|
}
|
|
464
438
|
|
|
465
439
|
enablePathFeatures_(enable, featureIds)
|
|
@@ -490,9 +464,9 @@ export class UserInteractions
|
|
|
490
464
|
reset()
|
|
491
465
|
//=====
|
|
492
466
|
{
|
|
493
|
-
this.
|
|
467
|
+
this.__clearModal();
|
|
494
468
|
this.clearActiveMarker_();
|
|
495
|
-
this.
|
|
469
|
+
this.__unselectFeatures();
|
|
496
470
|
this.enablePathFeatures_(true, this._pathways.allFeatureIds());
|
|
497
471
|
this._disabledPathFeatures = false;
|
|
498
472
|
}
|
|
@@ -500,7 +474,7 @@ export class UserInteractions
|
|
|
500
474
|
clearSearchResults(reset=true)
|
|
501
475
|
//============================
|
|
502
476
|
{
|
|
503
|
-
this.
|
|
477
|
+
this.__unselectFeatures();
|
|
504
478
|
}
|
|
505
479
|
|
|
506
480
|
/**
|
|
@@ -536,7 +510,7 @@ export class UserInteractions
|
|
|
536
510
|
//========================
|
|
537
511
|
{
|
|
538
512
|
if (featureIds.length) {
|
|
539
|
-
this.
|
|
513
|
+
this.__unselectFeatures();
|
|
540
514
|
for (const featureId of featureIds) {
|
|
541
515
|
const annotation = this._flatmap.annotation(featureId);
|
|
542
516
|
if (annotation) {
|
|
@@ -569,7 +543,7 @@ export class UserInteractions
|
|
|
569
543
|
const padding = options.padding || 100;
|
|
570
544
|
if (featureIds.length) {
|
|
571
545
|
this.unhighlightFeatures_();
|
|
572
|
-
if (select) this.
|
|
546
|
+
if (select) this.__unselectFeatures();
|
|
573
547
|
let bbox = null;
|
|
574
548
|
for (const featureId of featureIds) {
|
|
575
549
|
const annotation = this._flatmap.annotation(featureId);
|
|
@@ -616,7 +590,7 @@ export class UserInteractions
|
|
|
616
590
|
|
|
617
591
|
// Highlight the feature
|
|
618
592
|
|
|
619
|
-
this.
|
|
593
|
+
this.__unselectFeatures();
|
|
620
594
|
this.selectFeature_(featureId);
|
|
621
595
|
|
|
622
596
|
// Find the pop-up's postion
|
|
@@ -638,7 +612,7 @@ export class UserInteractions
|
|
|
638
612
|
}
|
|
639
613
|
this.setModal_();
|
|
640
614
|
this._currentPopup = new maplibre.Popup(options).addTo(this._map);
|
|
641
|
-
this._currentPopup.on('close', this.
|
|
615
|
+
this._currentPopup.on('close', this.__clearPopup.bind(this));
|
|
642
616
|
this._currentPopup.setLngLat(location);
|
|
643
617
|
if (typeof content === 'object') {
|
|
644
618
|
this._currentPopup.setDOMContent(content);
|
|
@@ -648,6 +622,13 @@ export class UserInteractions
|
|
|
648
622
|
}
|
|
649
623
|
}
|
|
650
624
|
|
|
625
|
+
__clearPopup()
|
|
626
|
+
//============
|
|
627
|
+
{
|
|
628
|
+
this.__clearModal();
|
|
629
|
+
this.__unselectFeatures();
|
|
630
|
+
}
|
|
631
|
+
|
|
651
632
|
removeTooltip_()
|
|
652
633
|
//==============
|
|
653
634
|
{
|
|
@@ -657,15 +638,47 @@ export class UserInteractions
|
|
|
657
638
|
}
|
|
658
639
|
}
|
|
659
640
|
|
|
641
|
+
lineTooltip_(lineFeatures)
|
|
642
|
+
//========================
|
|
643
|
+
{
|
|
644
|
+
const tooltips = [];
|
|
645
|
+
for (const lineFeature of lineFeatures) {
|
|
646
|
+
const properties = lineFeature.properties;
|
|
647
|
+
if ('label' in properties
|
|
648
|
+
&& (!('tooltip' in properties) || properties.tooltip)
|
|
649
|
+
&& !('labelled' in properties)) {
|
|
650
|
+
let tooltip = '';
|
|
651
|
+
const label = properties.label;
|
|
652
|
+
const cleanLabel = (label.substr(0, 1).toUpperCase() + label.substr(1)).replaceAll("\n", "<br/>");
|
|
653
|
+
if (!tooltips.includes(cleanLabel)) {
|
|
654
|
+
tooltips.push(cleanLabel);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (tooltips.length === 0) {
|
|
659
|
+
return '';
|
|
660
|
+
}
|
|
661
|
+
return `<div class='flatmap-feature-label'>${tooltips.join('<hr/>')}</div>`;
|
|
662
|
+
}
|
|
663
|
+
|
|
660
664
|
tooltipHtml_(properties, forceLabel=false)
|
|
661
665
|
//========================================
|
|
662
666
|
{
|
|
663
|
-
if ('label' in properties
|
|
667
|
+
if (('label' in properties || 'hyperlink' in properties)
|
|
664
668
|
&& (forceLabel || !('tooltip' in properties) || properties.tooltip)
|
|
665
669
|
&& !('labelled' in properties)) {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
670
|
+
let tooltip = '';
|
|
671
|
+
if ('label' in properties) {
|
|
672
|
+
const label = properties.label;
|
|
673
|
+
tooltip = (label.substr(0, 1).toUpperCase() + label.substr(1)).replaceAll("\n", "<br/>");
|
|
674
|
+
} else {
|
|
675
|
+
tooltip = properties.hyperlink
|
|
676
|
+
}
|
|
677
|
+
if ('hyperlink' in properties) {
|
|
678
|
+
return `<div class='flatmap-feature-label'><a href='{properties.hyperlink}'>${tooltip}</a></div>`;
|
|
679
|
+
} else {
|
|
680
|
+
return `<div class='flatmap-feature-label'>${tooltip}</div>`;
|
|
681
|
+
}
|
|
669
682
|
}
|
|
670
683
|
return '';
|
|
671
684
|
}
|
|
@@ -681,36 +694,37 @@ export class UserInteractions
|
|
|
681
694
|
return false;
|
|
682
695
|
}
|
|
683
696
|
|
|
684
|
-
|
|
685
|
-
|
|
697
|
+
__resetFeatureDisplay()
|
|
698
|
+
//=====================
|
|
686
699
|
{
|
|
687
|
-
// No tooltip when context menu is open
|
|
688
|
-
|
|
689
|
-
if (this._modal) {
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
700
|
// Remove any existing tooltip
|
|
694
|
-
|
|
695
701
|
this.removeTooltip_();
|
|
696
702
|
|
|
697
703
|
// Reset cursor
|
|
698
|
-
|
|
699
704
|
this._map.getCanvas().style.cursor = 'default';
|
|
700
705
|
|
|
701
706
|
// Reset any active features
|
|
702
|
-
|
|
703
707
|
this.resetActiveFeatures_();
|
|
708
|
+
}
|
|
704
709
|
|
|
705
|
-
|
|
710
|
+
mouseMoveEvent_(event)
|
|
711
|
+
//====================
|
|
712
|
+
{
|
|
713
|
+
// No tooltip when context menu is open
|
|
714
|
+
if (this._modal) {
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
706
717
|
|
|
718
|
+
// Remove tooltip, reset active features, etc
|
|
719
|
+
this.__resetFeatureDisplay();
|
|
720
|
+
|
|
721
|
+
// Reset any info display
|
|
707
722
|
const displayInfo = (this._infoControl && this._infoControl.active);
|
|
708
723
|
if (displayInfo) {
|
|
709
724
|
this._infoControl.reset()
|
|
710
725
|
}
|
|
711
726
|
|
|
712
727
|
// Get all the features at the current point
|
|
713
|
-
|
|
714
728
|
const features = this._map.queryRenderedFeatures(event.point);
|
|
715
729
|
if (features.length === 0) {
|
|
716
730
|
this._lastFeatureMouseEntered = null;
|
|
@@ -748,18 +762,20 @@ export class UserInteractions
|
|
|
748
762
|
&& feature.properties.type.startsWith('line'))
|
|
749
763
|
|| 'centreline' in feature.properties));
|
|
750
764
|
if (lineFeatures.length > 0) {
|
|
751
|
-
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
765
|
+
tooltip = this.lineTooltip_(lineFeatures);
|
|
766
|
+
for (const lineFeature of lineFeatures) {
|
|
767
|
+
const lineFeatureId = +lineFeature.properties.featureId; // Ensure numeric
|
|
768
|
+
this.activateFeature_(lineFeature);
|
|
769
|
+
const lineIds = new Set(lineFeatures.map(f => f.properties.featureId));
|
|
770
|
+
for (const featureId of this._pathways.lineFeatureIds(lineIds)) {
|
|
771
|
+
if (+featureId !== lineFeatureId) {
|
|
772
|
+
this.activateFeature_(this.mapFeature_(featureId));
|
|
773
|
+
}
|
|
759
774
|
}
|
|
760
775
|
}
|
|
761
776
|
} else {
|
|
762
|
-
let labelledFeatures = features.filter(feature => (('
|
|
777
|
+
let labelledFeatures = features.filter(feature => (('hyperlink' in feature.properties
|
|
778
|
+
|| 'label' in feature.properties
|
|
763
779
|
|| 'node' in feature.properties)
|
|
764
780
|
&& (!('tooltip' in feature.properties)
|
|
765
781
|
|| feature.properties.tooltip)))
|
|
@@ -801,11 +817,20 @@ export class UserInteractions
|
|
|
801
817
|
}
|
|
802
818
|
info = `<div id="info-control-info">${htmlList.join('\n')}</div>`;
|
|
803
819
|
}
|
|
804
|
-
this.activateFeature_(feature);
|
|
805
820
|
if ('nerveId' in feature.properties) {
|
|
821
|
+
if (feature.properties.active) {
|
|
822
|
+
this.activateFeature_(feature);
|
|
823
|
+
} else {
|
|
824
|
+
tooltip = '';
|
|
825
|
+
}
|
|
806
826
|
if (feature.properties.nerveId !== feature.properties.featureId) {
|
|
807
827
|
this.activateNerveFeatures_(feature.properties.nerveId);
|
|
808
828
|
}
|
|
829
|
+
} else {
|
|
830
|
+
this.activateFeature_(feature);
|
|
831
|
+
}
|
|
832
|
+
if ('hyperlink' in feature.properties) {
|
|
833
|
+
this._map.getCanvas().style.cursor = 'pointer';
|
|
809
834
|
}
|
|
810
835
|
}
|
|
811
836
|
}
|
|
@@ -839,7 +864,7 @@ export class UserInteractions
|
|
|
839
864
|
{
|
|
840
865
|
const multipleSelect = event.ctrlKey || event.metaKey;
|
|
841
866
|
if (!multipleSelect) {
|
|
842
|
-
this.
|
|
867
|
+
this.__unselectFeatures();
|
|
843
868
|
}
|
|
844
869
|
if (feature !== undefined) {
|
|
845
870
|
const featureId = feature.id;
|
|
@@ -872,8 +897,17 @@ export class UserInteractions
|
|
|
872
897
|
this.clearActiveMarker_();
|
|
873
898
|
const feature = this._activeFeatures[0]
|
|
874
899
|
this.selectionEvent_(event.originalEvent, feature);
|
|
875
|
-
if (
|
|
900
|
+
if (this._modal) {
|
|
901
|
+
// Remove tooltip, reset active features, etc
|
|
902
|
+
this.__resetFeatureDisplay();
|
|
903
|
+
this.__unselectFeatures();
|
|
904
|
+
this.__clearModal();
|
|
905
|
+
} else if (feature !== undefined) {
|
|
906
|
+
this.__lastClickLngLat = event.lngLat;
|
|
876
907
|
this.__featureEvent('click', feature);
|
|
908
|
+
if ('hyperlink' in feature.properties) {
|
|
909
|
+
window.open(feature.properties.hyperlink, '_blank');
|
|
910
|
+
}
|
|
877
911
|
}
|
|
878
912
|
}
|
|
879
913
|
|
|
@@ -930,7 +964,9 @@ export class UserInteractions
|
|
|
930
964
|
}
|
|
931
965
|
let position = annotation.centroid;
|
|
932
966
|
const features = this._map.querySourceFeatures(VECTOR_TILES_SOURCE, {
|
|
933
|
-
'sourceLayer':
|
|
967
|
+
'sourceLayer': this._flatmap.options.separateLayers
|
|
968
|
+
? `${annotation['layer']}_${annotation['tile-layer']}`
|
|
969
|
+
: annotation['tile-layer'],
|
|
934
970
|
'filter': [
|
|
935
971
|
'all',
|
|
936
972
|
[ '==', ['id'], parseInt(featureId) ],
|
package/src/layers.js
CHANGED
|
@@ -27,41 +27,58 @@ 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'
|
|
31
|
+
|
|
30
32
|
//==============================================================================
|
|
31
33
|
|
|
32
34
|
class MapFeatureLayer
|
|
33
35
|
{
|
|
34
|
-
constructor(flatmap, layer,
|
|
36
|
+
constructor(flatmap, layer, background_layers=true)
|
|
35
37
|
{
|
|
36
38
|
this.__map = flatmap.map;
|
|
39
|
+
this.__separateLayers = flatmap.options.separateLayers;
|
|
37
40
|
this.__id = layer.id;
|
|
38
41
|
this.__rasterLayers = [];
|
|
39
42
|
this.__styleLayers = [];
|
|
40
43
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
const layerOptions = flatmap.options.layerOptions;
|
|
45
|
+
const vectorTileSource = this.__map.getSource('vector-tiles');
|
|
46
|
+
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
|
+
}
|
|
48
60
|
}
|
|
49
61
|
}
|
|
50
62
|
// if no image layers then make feature borders (and lines?) more visible...??
|
|
51
63
|
if (haveVectorLayers) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
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);
|
|
69
|
+
}
|
|
70
|
+
this.__addPathwayStyleLayers(layerOptions);
|
|
71
|
+
if (vectorFeatures) {
|
|
72
|
+
this.__addStyleLayer(style.FeatureLargeSymbolLayer, layerOptions);
|
|
73
|
+
if (!flatmap.options.tooltips) {
|
|
74
|
+
this.__addStyleLayer(style.FeatureSmallSymbolLayer, layerOptions);
|
|
75
|
+
}
|
|
59
76
|
}
|
|
60
77
|
}
|
|
61
78
|
|
|
62
|
-
// Make sure our
|
|
79
|
+
// Make sure our colour options are set properly, in particular raster layer visibility
|
|
63
80
|
|
|
64
|
-
this.setColour(
|
|
81
|
+
this.setColour(layerOptions);
|
|
65
82
|
}
|
|
66
83
|
|
|
67
84
|
get id()
|
|
@@ -81,9 +98,12 @@ class MapFeatureLayer
|
|
|
81
98
|
__addPathwayStyleLayers(options)
|
|
82
99
|
//==============================
|
|
83
100
|
{
|
|
101
|
+
const pathwaysVectorLayerId = this.__separateLayers
|
|
102
|
+
? `${this.__id}_${PATHWAYS_LAYER}`
|
|
103
|
+
: PATHWAYS_LAYER;
|
|
84
104
|
if (this.__map.getSource('vector-tiles')
|
|
85
105
|
.vectorLayerIds
|
|
86
|
-
.indexOf(
|
|
106
|
+
.indexOf(pathwaysVectorLayerId) >= 0) {
|
|
87
107
|
this.__addStyleLayer(style.PathLineLayer, options, PATHWAYS_LAYER);
|
|
88
108
|
this.__addStyleLayer(style.PathDashlineLayer, options, PATHWAYS_LAYER);
|
|
89
109
|
this.__addStyleLayer(style.NervePolygonBorder, options, PATHWAYS_LAYER);
|
|
@@ -92,10 +112,12 @@ class MapFeatureLayer
|
|
|
92
112
|
}
|
|
93
113
|
}
|
|
94
114
|
|
|
95
|
-
__addStyleLayer(styleClass, options, sourceLayer=
|
|
96
|
-
|
|
115
|
+
__addStyleLayer(styleClass, options, sourceLayer=FEATURES_LAYER)
|
|
116
|
+
//==============================================================
|
|
97
117
|
{
|
|
98
|
-
const
|
|
118
|
+
const layerId = `${this.__id}_${sourceLayer}`;
|
|
119
|
+
const source = this.__separateLayers ? layerId : sourceLayer;
|
|
120
|
+
const styleLayer = new styleClass(layerId, source);
|
|
99
121
|
this.__map.addLayer(styleLayer.style(options));
|
|
100
122
|
this.__styleLayers.push(styleLayer);
|
|
101
123
|
}
|
|
@@ -129,12 +151,31 @@ export class LayerManager
|
|
|
129
151
|
this.__mapLayers = new Map;
|
|
130
152
|
this.__activeLayers = [];
|
|
131
153
|
this.__activeLayerNames = [];
|
|
154
|
+
this.__rasterLayers = [];
|
|
155
|
+
const layerOptions = flatmap.options.layerOptions;
|
|
156
|
+
const fcDiagram = ('style' in layerOptions && layerOptions.style == 'fcdiagram');
|
|
132
157
|
const backgroundLayer = new style.BackgroundLayer();
|
|
133
|
-
if (
|
|
158
|
+
if (fcDiagram) {
|
|
159
|
+
this.__map.addLayer(backgroundLayer.style('black', 1));
|
|
160
|
+
}
|
|
161
|
+
else if ('background' in flatmap.options) {
|
|
134
162
|
this.__map.addLayer(backgroundLayer.style(flatmap.options.background));
|
|
135
163
|
} else {
|
|
136
164
|
this.__map.addLayer(backgroundLayer.style('white'));
|
|
137
165
|
}
|
|
166
|
+
// Add the map's layers
|
|
167
|
+
if (fcDiagram && flatmap.details['image-layers']) {
|
|
168
|
+
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
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
for (const layer of flatmap.layers) {
|
|
177
|
+
this.addLayer(layer, !fcDiagram);
|
|
178
|
+
}
|
|
138
179
|
}
|
|
139
180
|
|
|
140
181
|
get activeLayerNames()
|
|
@@ -143,12 +184,12 @@ export class LayerManager
|
|
|
143
184
|
return this.__activeLayerNames;
|
|
144
185
|
}
|
|
145
186
|
|
|
146
|
-
addLayer(layer,
|
|
147
|
-
|
|
187
|
+
addLayer(layer, background_layers=true)
|
|
188
|
+
//=====================================
|
|
148
189
|
{
|
|
149
190
|
this.__mapLayers.set(layer.id, layer);
|
|
150
191
|
|
|
151
|
-
const layers = new MapFeatureLayer(this.__flatmap, layer,
|
|
192
|
+
const layers = new MapFeatureLayer(this.__flatmap, layer, background_layers);
|
|
152
193
|
const layerId = this.__flatmap.mapLayerId(layer.id);
|
|
153
194
|
this.__layers.set(layerId, layers);
|
|
154
195
|
}
|
package/src/styling.js
CHANGED
|
@@ -28,9 +28,9 @@ export const VECTOR_TILES_SOURCE = 'vector-tiles';
|
|
|
28
28
|
|
|
29
29
|
class VectorStyleLayer
|
|
30
30
|
{
|
|
31
|
-
constructor(
|
|
31
|
+
constructor(id, suffix, sourceLayer)
|
|
32
32
|
{
|
|
33
|
-
this.__id = `${
|
|
33
|
+
this.__id = `${id}_${suffix}`;
|
|
34
34
|
this.__sourceLayer = sourceLayer;
|
|
35
35
|
this.__lastPaintStyle = {};
|
|
36
36
|
}
|
|
@@ -78,9 +78,9 @@ class VectorStyleLayer
|
|
|
78
78
|
|
|
79
79
|
export class BodyLayer extends VectorStyleLayer
|
|
80
80
|
{
|
|
81
|
-
constructor(
|
|
81
|
+
constructor(id, sourceLayer)
|
|
82
82
|
{
|
|
83
|
-
super(
|
|
83
|
+
super(id, 'body', sourceLayer);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
style(options)
|
|
@@ -105,9 +105,9 @@ export class BodyLayer extends VectorStyleLayer
|
|
|
105
105
|
|
|
106
106
|
export class FeatureFillLayer extends VectorStyleLayer
|
|
107
107
|
{
|
|
108
|
-
constructor(
|
|
108
|
+
constructor(id, sourceLayer)
|
|
109
109
|
{
|
|
110
|
-
super(
|
|
110
|
+
super(id, 'fill', sourceLayer);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
paintStyle(options, changes=false)
|
|
@@ -117,12 +117,12 @@ export class FeatureFillLayer extends VectorStyleLayer
|
|
|
117
117
|
const paintStyle = {
|
|
118
118
|
'fill-color': [
|
|
119
119
|
'case',
|
|
120
|
-
['boolean', ['feature-state', 'active'], false], coloured ? '#D88' : '#CCC',
|
|
121
120
|
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
121
|
+
['has', 'colour'], ['get', 'colour'],
|
|
122
|
+
['boolean', ['feature-state', 'active'], false], coloured ? '#D88' : '#CCC',
|
|
122
123
|
['any',
|
|
123
124
|
['==', ['get', 'kind'], 'scaffold']
|
|
124
125
|
], 'white',
|
|
125
|
-
['has', 'colour'], ['get', 'colour'],
|
|
126
126
|
['has', 'node'], '#AFA202',
|
|
127
127
|
'white' // background colour? body colour ??
|
|
128
128
|
],
|
|
@@ -133,10 +133,10 @@ export class FeatureFillLayer extends VectorStyleLayer
|
|
|
133
133
|
['==', ['get', 'kind'], 'tissue'],
|
|
134
134
|
['==', ['get', 'kind'], 'cell-type'],
|
|
135
135
|
], 0.1,
|
|
136
|
-
['has', 'colour'], 0.008,
|
|
137
136
|
['has', 'node'], 0.3,
|
|
138
137
|
['boolean', ['feature-state', 'selected'], false], 1.0,
|
|
139
138
|
['boolean', ['feature-state', 'active'], false], 0.8,
|
|
139
|
+
['has', 'colour'], 0.008,
|
|
140
140
|
(coloured && !dimmed) ? 0.01 : 0.5
|
|
141
141
|
]
|
|
142
142
|
};
|
|
@@ -165,9 +165,9 @@ export class FeatureFillLayer extends VectorStyleLayer
|
|
|
165
165
|
|
|
166
166
|
export class FeatureBorderLayer extends VectorStyleLayer
|
|
167
167
|
{
|
|
168
|
-
constructor(
|
|
168
|
+
constructor(id, sourceLayer)
|
|
169
169
|
{
|
|
170
|
-
super(
|
|
170
|
+
super(id, 'border', sourceLayer);
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
paintStyle(options, changes=false)
|
|
@@ -236,68 +236,105 @@ export class FeatureBorderLayer extends VectorStyleLayer
|
|
|
236
236
|
|
|
237
237
|
export class FeatureLineLayer extends VectorStyleLayer
|
|
238
238
|
{
|
|
239
|
-
constructor(
|
|
239
|
+
constructor(id, sourceLayer, dashed=false)
|
|
240
240
|
{
|
|
241
|
-
|
|
241
|
+
const filterType = dashed ? 'line-dash' : 'line';
|
|
242
|
+
super(id, `feature-${filterType}`, sourceLayer);
|
|
243
|
+
this.__filter = dashed ?
|
|
244
|
+
[
|
|
245
|
+
'any',
|
|
246
|
+
['==', 'type', `line-dash`]
|
|
247
|
+
]
|
|
248
|
+
:
|
|
249
|
+
[
|
|
250
|
+
'any',
|
|
251
|
+
['has', 'centreline'],
|
|
252
|
+
['==', 'type', 'bezier'],
|
|
253
|
+
['==', 'type', `line`]
|
|
254
|
+
];
|
|
255
|
+
this.__dashed = dashed;
|
|
242
256
|
}
|
|
243
257
|
|
|
244
|
-
|
|
258
|
+
paintStyle(options)
|
|
245
259
|
{
|
|
246
260
|
const coloured = !('colour' in options) || options.colour;
|
|
261
|
+
const paintStyle = {
|
|
262
|
+
'line-color': [
|
|
263
|
+
'case',
|
|
264
|
+
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
265
|
+
['has', 'colour'], ['get', 'colour'],
|
|
266
|
+
['boolean', ['feature-state', 'active'], false], coloured ? '#888' : '#CCC',
|
|
267
|
+
['==', ['get', 'type'], 'network'], '#AFA202',
|
|
268
|
+
['has', 'centreline'], '#888',
|
|
269
|
+
('style' in options && options.style === 'authoring') ? '#C44' : '#444'
|
|
270
|
+
],
|
|
271
|
+
'line-opacity': [
|
|
272
|
+
'case',
|
|
273
|
+
['boolean', ['feature-state', 'selected'], false], 1.0,
|
|
274
|
+
['boolean', ['feature-state', 'active'], false], 1.0,
|
|
275
|
+
0.3
|
|
276
|
+
],
|
|
277
|
+
'line-width': [
|
|
278
|
+
'let',
|
|
279
|
+
'width', [
|
|
280
|
+
'case',
|
|
281
|
+
['has', 'centreline'], 1.2,
|
|
282
|
+
['==', ['get', 'type'], 'network'], 1.2,
|
|
283
|
+
['boolean', ['feature-state', 'selected'], false], 1.2,
|
|
284
|
+
['boolean', ['feature-state', 'active'], false], 1.2,
|
|
285
|
+
('style' in options && options.style === 'authoring') ? 0.7 : 0.5
|
|
286
|
+
], [
|
|
287
|
+
'interpolate',
|
|
288
|
+
['exponential', 2],
|
|
289
|
+
['zoom'],
|
|
290
|
+
2, ["*", ['var', 'width'], ["^", 2, -0.5]],
|
|
291
|
+
7, ["*", ['var', 'width'], ["^", 2, 2.5]],
|
|
292
|
+
9, ["*", ['var', 'width'], ["^", 2, 4.0]]
|
|
293
|
+
]
|
|
294
|
+
]
|
|
295
|
+
// Need to vary width based on zoom??
|
|
296
|
+
// Or opacity??
|
|
297
|
+
};
|
|
298
|
+
if (this.__dashed) {
|
|
299
|
+
paintStyle['line-dasharray'] = [3, 2];
|
|
300
|
+
}
|
|
301
|
+
return paintStyle;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
style(options)
|
|
305
|
+
{
|
|
247
306
|
return {
|
|
248
307
|
...super.style(),
|
|
249
308
|
'type': 'line',
|
|
250
309
|
'filter': [
|
|
251
|
-
|
|
252
|
-
|
|
310
|
+
'all',
|
|
311
|
+
['==', '$type', 'LineString'],
|
|
312
|
+
this.__filter
|
|
253
313
|
// not for paths...
|
|
254
314
|
],
|
|
255
|
-
'paint':
|
|
256
|
-
'line-color': [
|
|
257
|
-
'case',
|
|
258
|
-
['boolean', ['feature-state', 'active'], false], coloured ? '#D88' : '#CCC',
|
|
259
|
-
['boolean', ['feature-state', 'selected'], false], '#0F0',
|
|
260
|
-
['==', ['get', 'type'], 'network'], '#AFA202',
|
|
261
|
-
['has', 'centreline'], '#888',
|
|
262
|
-
('authoring' in options && options.authoring) ? '#C44' : '#444'
|
|
263
|
-
],
|
|
264
|
-
'line-opacity': [
|
|
265
|
-
'case',
|
|
266
|
-
['boolean', ['feature-state', 'active'], false], 1.0,
|
|
267
|
-
0.3
|
|
268
|
-
],
|
|
269
|
-
'line-width': [
|
|
270
|
-
'let',
|
|
271
|
-
'width', [
|
|
272
|
-
'case',
|
|
273
|
-
['has', 'centreline'], 1.2,
|
|
274
|
-
['==', ['get', 'type'], 'network'], 1.2,
|
|
275
|
-
['boolean', ['feature-state', 'active'], false], 1.2,
|
|
276
|
-
('authoring' in options && options.authoring) ? 0.7 : 0.1
|
|
277
|
-
], [
|
|
278
|
-
'interpolate',
|
|
279
|
-
['exponential', 2],
|
|
280
|
-
['zoom'],
|
|
281
|
-
2, ["*", ['var', 'width'], ["^", 2, -0.5]],
|
|
282
|
-
7, ["*", ['var', 'width'], ["^", 2, 2.5]],
|
|
283
|
-
9, ["*", ['var', 'width'], ["^", 2, 4.0]]
|
|
284
|
-
]
|
|
285
|
-
]
|
|
286
|
-
// Need to vary width based on zoom??
|
|
287
|
-
// Or opacity??
|
|
288
|
-
}
|
|
315
|
+
'paint': this.paintStyle(options)
|
|
289
316
|
};
|
|
290
317
|
}
|
|
291
318
|
}
|
|
292
319
|
|
|
293
320
|
//==============================================================================
|
|
294
321
|
|
|
322
|
+
export class FeatureDashLineLayer extends FeatureLineLayer
|
|
323
|
+
{
|
|
324
|
+
constructor(id, sourceLayer)
|
|
325
|
+
{
|
|
326
|
+
super(id, sourceLayer, true);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
//==============================================================================
|
|
331
|
+
|
|
295
332
|
export class PathLineLayer extends VectorStyleLayer
|
|
296
333
|
{
|
|
297
|
-
constructor(
|
|
334
|
+
constructor(id, sourceLayer, dashed=false)
|
|
298
335
|
{
|
|
299
336
|
const filterType = dashed ? 'line-dash' : 'line';
|
|
300
|
-
super(
|
|
337
|
+
super(id, `path-${filterType}`, sourceLayer);
|
|
301
338
|
this.__filter = dashed ?
|
|
302
339
|
[
|
|
303
340
|
'any',
|
|
@@ -386,9 +423,9 @@ export class PathLineLayer extends VectorStyleLayer
|
|
|
386
423
|
|
|
387
424
|
export class PathDashlineLayer extends PathLineLayer
|
|
388
425
|
{
|
|
389
|
-
constructor(
|
|
426
|
+
constructor(id, sourceLayer)
|
|
390
427
|
{
|
|
391
|
-
super(
|
|
428
|
+
super(id, sourceLayer, true);
|
|
392
429
|
}
|
|
393
430
|
}
|
|
394
431
|
|
|
@@ -396,9 +433,9 @@ export class PathDashlineLayer extends PathLineLayer
|
|
|
396
433
|
|
|
397
434
|
export class FeatureNerveLayer extends VectorStyleLayer
|
|
398
435
|
{
|
|
399
|
-
constructor(
|
|
436
|
+
constructor(id, sourceLayer)
|
|
400
437
|
{
|
|
401
|
-
super(
|
|
438
|
+
super(id, 'nerve-path', sourceLayer);
|
|
402
439
|
}
|
|
403
440
|
|
|
404
441
|
style(options)
|
|
@@ -417,7 +454,8 @@ export class FeatureNerveLayer extends VectorStyleLayer
|
|
|
417
454
|
['boolean', ['feature-state', 'active'], false], '#222',
|
|
418
455
|
['boolean', ['feature-state', 'selected'], false], 'red',
|
|
419
456
|
['boolean', ['feature-state', 'hidden'], false], '#CCC',
|
|
420
|
-
'#888'
|
|
457
|
+
['boolean', ['get', 'active'], false], '#888',
|
|
458
|
+
'#FFF'
|
|
421
459
|
],
|
|
422
460
|
'line-opacity': [
|
|
423
461
|
'case',
|
|
@@ -449,9 +487,9 @@ export class FeatureNerveLayer extends VectorStyleLayer
|
|
|
449
487
|
|
|
450
488
|
export class NervePolygonBorder extends VectorStyleLayer
|
|
451
489
|
{
|
|
452
|
-
constructor(
|
|
490
|
+
constructor(id, sourceLayer)
|
|
453
491
|
{
|
|
454
|
-
super(
|
|
492
|
+
super(id, 'nerve-border', sourceLayer);
|
|
455
493
|
}
|
|
456
494
|
|
|
457
495
|
style(options)
|
|
@@ -493,9 +531,9 @@ export class NervePolygonBorder extends VectorStyleLayer
|
|
|
493
531
|
|
|
494
532
|
export class NervePolygonFill extends VectorStyleLayer
|
|
495
533
|
{
|
|
496
|
-
constructor(
|
|
534
|
+
constructor(id, sourceLayer)
|
|
497
535
|
{
|
|
498
|
-
super(
|
|
536
|
+
super(id, 'nerve-fill', sourceLayer);
|
|
499
537
|
}
|
|
500
538
|
|
|
501
539
|
style(options)
|
|
@@ -543,9 +581,9 @@ export class NervePolygonFill extends VectorStyleLayer
|
|
|
543
581
|
|
|
544
582
|
export class FeatureLargeSymbolLayer extends VectorStyleLayer
|
|
545
583
|
{
|
|
546
|
-
constructor(
|
|
584
|
+
constructor(id, sourceLayer)
|
|
547
585
|
{
|
|
548
|
-
super(
|
|
586
|
+
super(id, 'large-symbol', sourceLayer);
|
|
549
587
|
}
|
|
550
588
|
|
|
551
589
|
style(options)
|
|
@@ -587,9 +625,9 @@ export class FeatureLargeSymbolLayer extends VectorStyleLayer
|
|
|
587
625
|
|
|
588
626
|
export class FeatureSmallSymbolLayer extends VectorStyleLayer
|
|
589
627
|
{
|
|
590
|
-
constructor(
|
|
628
|
+
constructor(id, sourceLayer)
|
|
591
629
|
{
|
|
592
|
-
super(
|
|
630
|
+
super(id, 'small-symbol', sourceLayer);
|
|
593
631
|
}
|
|
594
632
|
|
|
595
633
|
style(options)
|
|
@@ -630,7 +668,7 @@ export class FeatureSmallSymbolLayer extends VectorStyleLayer
|
|
|
630
668
|
|
|
631
669
|
export class BackgroundLayer
|
|
632
670
|
{
|
|
633
|
-
constructor(
|
|
671
|
+
constructor()
|
|
634
672
|
{
|
|
635
673
|
this.__id = 'background';
|
|
636
674
|
}
|
|
@@ -640,14 +678,14 @@ export class BackgroundLayer
|
|
|
640
678
|
return this.__id;
|
|
641
679
|
}
|
|
642
680
|
|
|
643
|
-
style(backgroundColour)
|
|
681
|
+
style(backgroundColour, opacity=0.1)
|
|
644
682
|
{
|
|
645
683
|
return {
|
|
646
|
-
'id':
|
|
684
|
+
'id': this.__id,
|
|
647
685
|
'type': 'background',
|
|
648
686
|
'paint': {
|
|
649
687
|
'background-color': backgroundColour,
|
|
650
|
-
'background-opacity':
|
|
688
|
+
'background-opacity': opacity
|
|
651
689
|
}
|
|
652
690
|
};
|
|
653
691
|
}
|
|
@@ -657,9 +695,9 @@ export class BackgroundLayer
|
|
|
657
695
|
|
|
658
696
|
export class RasterLayer
|
|
659
697
|
{
|
|
660
|
-
constructor(
|
|
698
|
+
constructor(id)
|
|
661
699
|
{
|
|
662
|
-
this.__id =
|
|
700
|
+
this.__id = id;
|
|
663
701
|
}
|
|
664
702
|
|
|
665
703
|
get id()
|