@abi-software/flatmap-viewer 2.5.9 → 2.6.0-a.1

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 CHANGED
@@ -26,7 +26,7 @@ Running
26
26
 
27
27
  ::
28
28
 
29
- $ npm start
29
+ $ npm run dev
30
30
 
31
31
  Maps can then be viewed at http://localhost:3000
32
32
 
package/package.json CHANGED
@@ -1,26 +1,27 @@
1
1
  {
2
2
  "name": "@abi-software/flatmap-viewer",
3
- "version": "2.5.9",
3
+ "version": "2.6.0-a.1",
4
4
  "description": "Flatmap viewer using Maplibre GL",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/AnatomicMaps/flatmap-viewer.git"
8
8
  },
9
9
  "main": "src/main.js",
10
+ "type": "module",
10
11
  "files": [
11
12
  "src",
12
13
  "static"
13
14
  ],
14
15
  "scripts": {
15
16
  "test": "echo \"Error: no test specified\" && exit 1",
16
- "start": "node app",
17
- "build": "webpack --mode production",
17
+ "dev": "vite serve app --port 3000",
18
+ "build": "tsc && vite build",
19
+ "preview": "vite preview",
18
20
  "docs": "cd docs; poetry run make html"
19
21
  },
20
22
  "author": "David Brooks",
21
23
  "license": "MIT",
22
24
  "dependencies": {
23
- "@babel/runtime": "^7.10.4",
24
25
  "@deck.gl/core": "^8.9.33",
25
26
  "@deck.gl/layers": "^8.9.33",
26
27
  "@deck.gl/mapbox": "^8.9.33",
@@ -38,22 +39,8 @@
38
39
  "polylabel": "^1.1.0"
39
40
  },
40
41
  "devDependencies": {
41
- "@babel/core": "^7.5.5",
42
- "@babel/plugin-transform-runtime": "^7.5.5",
43
- "@babel/preset-env": "^7.10.4",
44
- "babel-loader": "^8.1.0",
45
- "browser-sync": "^2.26.7",
46
- "bs-fullscreen-message": "^1.1.0",
47
- "clean-webpack-plugin": "^3.0.0",
48
- "css-loader": "^6.7.3",
49
42
  "eslint": "^8.7.0",
50
- "express": "^4.17.1",
51
- "html-webpack-plugin": "^4.5.2",
52
- "strip-ansi": "^7.0.1",
53
- "style-loader": "^3.3.2",
54
- "webpack": "^5.16.0",
55
- "webpack-cli": "^4.4.0",
56
- "webpack-dev-middleware": "^4.1.0",
57
- "webpack-node-externals": "^1.7.2"
43
+ "typescript": "^5.2.2",
44
+ "vite": "^5.1.4"
58
45
  }
59
46
  }
@@ -41,10 +41,9 @@ limitations under the License.
41
41
 
42
42
  //==============================================================================
43
43
 
44
- import MapboxDraw from "@mapbox/mapbox-gl-draw"
44
+ import MapboxDraw from "@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw-unminified.js"
45
45
  import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css'
46
46
 
47
-
48
47
  //==============================================================================
49
48
 
50
49
  const drawStyleIds = MapboxDraw.lib.theme.map(s => s.id)
@@ -222,6 +221,8 @@ export class AnnotationDrawControl
222
221
  this.__committedFeatures.set(feature.id, feature)
223
222
  }
224
223
  this.__uncommittedFeatureIds.delete(feature.id)
224
+ this.__flatmap.showPopup(feature.id, '<div>committed</div>')
225
+
225
226
  }
226
227
 
227
228
  abortEvent(event)
@@ -269,10 +270,15 @@ export class AnnotationDrawControl
269
270
  this.__uncommittedFeatureIds.delete(ids[0])
270
271
  }
271
272
 
272
- refreshGeometry(feature)
273
+ getFeature(featureId)
274
+ //===================
275
+ {
276
+ return this.__draw.get(featureId) || null
277
+ }
278
+
279
+ selectFeature(featureId)
273
280
  //======================
274
281
  {
275
- return this.__draw.get(feature.id) || null
276
282
  }
277
283
  }
278
284
 
@@ -102,6 +102,8 @@ function labelPosition(feature)
102
102
  if (feature.geometry.type === 'Point') {
103
103
  return feature.geometry.coordinates
104
104
  }
105
+ // LineString?
106
+ // Multi geometries??
105
107
  const polygon = feature.geometry.coordinates;
106
108
  // Rough heuristic. Area is in km^2; below appears to be good enough.
107
109
  const precision = ('area' in feature.properties)
@@ -266,7 +268,6 @@ export class UserInteractions
266
268
  this._map.addControl(this.#annotationDrawControl)
267
269
 
268
270
  // Handle mouse events
269
-
270
271
  this._map.on('click', this.clickEvent_.bind(this));
271
272
  this._map.on('touchend', this.clickEvent_.bind(this));
272
273
  this._map.on('mousemove', this.mouseMoveEvent_.bind(this));
@@ -385,7 +386,7 @@ export class UserInteractions
385
386
  //=======================================
386
387
  {
387
388
  if (this.#annotationDrawControl) {
388
- return this.#annotationDrawControl.refreshGeometry(feature)
389
+ return this.#annotationDrawControl.getFeature(feature.id)
389
390
  }
390
391
  }
391
392
 
@@ -465,21 +466,37 @@ export class UserInteractions
465
466
  this.__systemsManager.enable(systemId, enable);
466
467
  }
467
468
 
469
+ #getAnnotationProperties(featureId)
470
+ //=================================
471
+ {
472
+ const properties = this._flatmap.annotation(featureId)
473
+ if (properties) {
474
+ return properties
475
+ } else if (this.#annotationDrawControl) {
476
+ const drawnFeature = this.#annotationDrawControl.getFeature(featureId)
477
+ if (drawnFeature) {
478
+ drawnFeature.properties.user_drawn = true
479
+ return drawnFeature.properties
480
+ }
481
+ }
482
+ return null
483
+ }
484
+
468
485
  mapFeature(featureId)
469
486
  //===================
470
487
  {
471
- const ann = this._flatmap.annotation(featureId);
472
- if (ann !== undefined) {
488
+ const properties = this.#getAnnotationProperties(featureId);
489
+ if (properties && !properties.user_drawn) {
473
490
  return {
474
491
  id: featureId,
475
492
  source: VECTOR_TILES_SOURCE,
476
493
  sourceLayer: (this._flatmap.options.separateLayers
477
- ? `${ann['layer']}_${ann['tile-layer']}`
478
- : ann['tile-layer']).replaceAll('/', '_'),
479
- children: ann.children || []
494
+ ? `${properties['layer']}_${properties['tile-layer']}`
495
+ : properties['tile-layer']).replaceAll('/', '_'),
496
+ children: properties.children || []
480
497
  };
481
498
  }
482
- return undefined;
499
+ return null;
483
500
  }
484
501
 
485
502
  #getFeatureState(feature)
@@ -509,7 +526,7 @@ export class UserInteractions
509
526
  enableMapFeature(feature, enable=true)
510
527
  //====================================
511
528
  {
512
- if (feature !== undefined) {
529
+ if (feature) {
513
530
  const state = this.#getFeatureState(feature);
514
531
  if ('hidden' in state) {
515
532
  if (enable) {
@@ -542,7 +559,7 @@ export class UserInteractions
542
559
  //============================================================
543
560
  {
544
561
  const feature = this.mapFeature(featureId);
545
- if (feature !== undefined) {
562
+ if (feature) {
546
563
  this.enableFeature(featureId, enable, force);
547
564
  for (const childFeatureId of feature.children) {
548
565
  this.enableFeatureWithChildren(childFeatureId, enable, force);
@@ -554,7 +571,7 @@ export class UserInteractions
554
571
  //===========================================
555
572
  {
556
573
  const markerId = this.__markerIdByFeatureId.get(+featureId);
557
- if (markerId !== undefined) {
574
+ if (markerId) {
558
575
  const markerDiv = document.getElementById(`marker-${markerId}`);
559
576
  if (markerDiv) {
560
577
  markerDiv.style.visibility = enable ? 'visible' : 'hidden';
@@ -567,7 +584,7 @@ export class UserInteractions
567
584
  {
568
585
  if (feature.id) {
569
586
  const state = this.#getFeatureState(feature);
570
- return (state !== undefined
587
+ return (state
571
588
  && (!('hidden' in state) || !state.hidden));
572
589
  }
573
590
  return DRAW_ANNOTATION_LAYERS.includes(feature.layer.id)
@@ -582,12 +599,12 @@ export class UserInteractions
582
599
  selectFeature(featureId, dim=true)
583
600
  //================================
584
601
  {
585
- const ann = this._flatmap.annotation(featureId);
586
- if (ann && 'sckan' in ann) {
602
+ const properties = this.#getAnnotationProperties(featureId);
603
+ if (properties && 'sckan' in properties) {
587
604
  const sckanState = this._layerManager.sckanState;
588
605
  if (sckanState === 'none'
589
- || sckanState === 'valid' && !ann.sckan
590
- || sckanState === 'invalid' && ann.sckan) {
606
+ || sckanState === 'valid' && !properties.sckan
607
+ || sckanState === 'invalid' && properties.sckan) {
591
608
  return false;
592
609
  }
593
610
  }
@@ -597,11 +614,15 @@ export class UserInteractions
597
614
  if (this._selectedFeatureIds.has(featureId)) {
598
615
  this._selectedFeatureIds.set(featureId, this._selectedFeatureIds.get(featureId) + 1);
599
616
  result = true;
617
+ } else if (properties.user_drawn) {
618
+ if (this.#annotationDrawControl) {
619
+ this.#annotationDrawControl.selectFeature(featureId, true)
620
+ }
600
621
  } else {
601
622
  const feature = this.mapFeature(featureId);
602
- if (feature !== undefined) {
623
+ if (feature) {
603
624
  const state = this.#getFeatureState(feature);
604
- if (state !== undefined && (!('hidden' in state) || !state.hidden)) {
625
+ if (state && (!('hidden' in state) || !state.hidden)) {
605
626
  this.#setFeatureState(feature, { selected: true });
606
627
  this._selectedFeatureIds.set(featureId, 1);
607
628
  result = true;
@@ -624,7 +645,7 @@ export class UserInteractions
624
645
  this._selectedFeatureIds.set(featureId, references - 1);
625
646
  } else {
626
647
  const feature = this.mapFeature(featureId);
627
- if (feature !== undefined) {
648
+ if (feature) {
628
649
  this.#removeFeatureState(feature, 'selected');
629
650
  this._selectedFeatureIds.delete(+featureId);
630
651
  }
@@ -640,7 +661,7 @@ export class UserInteractions
640
661
  {
641
662
  for (const featureId of this._selectedFeatureIds.keys()) {
642
663
  const feature = this.mapFeature(featureId);
643
- if (feature !== undefined) {
664
+ if (feature) {
644
665
  this.#removeFeatureState(feature, 'selected');
645
666
  }
646
667
  }
@@ -651,7 +672,7 @@ export class UserInteractions
651
672
  activateFeature(feature)
652
673
  //======================
653
674
  {
654
- if (feature !== undefined) {
675
+ if (feature) {
655
676
  this.#setFeatureState(feature, { active: true });
656
677
  this._activeFeatures.add(feature);
657
678
  }
@@ -737,7 +758,7 @@ export class UserInteractions
737
758
  if (featureIds.length) {
738
759
  this.unselectFeatures();
739
760
  for (const featureId of featureIds) {
740
- const annotation = this._flatmap.annotation(featureId);
761
+ const annotation = this.#getAnnotationProperties(featureId);
741
762
  if (annotation) {
742
763
  if (this.selectFeature(featureId)) {
743
764
  if ('type' in annotation && annotation.type.startsWith('line')) {
@@ -785,14 +806,14 @@ export class UserInteractions
785
806
  padding.lng -= bbox[0];
786
807
  padding.lat = bbox[3] - padding.lat;
787
808
  for (const featureId of featureIds) {
788
- const annotation = this._flatmap.annotation(featureId);
809
+ const annotation = this.#getAnnotationProperties(featureId);
789
810
  if (annotation) {
790
811
  if (this.selectFeature(featureId)) {
791
812
  bbox = expandBounds(bbox, annotation.bounds, padding);
792
813
  if ('type' in annotation && annotation.type.startsWith('line')) {
793
814
  for (const pathFeatureId of this.__pathManager.lineFeatureIds([featureId])) {
794
815
  if (this.selectFeature(pathFeatureId)) {
795
- const pathAnnotation = this._flatmap.annotation(pathFeatureId)
816
+ const pathAnnotation = this.#getAnnotationProperties(pathFeatureId)
796
817
  bbox = expandBounds(bbox, pathAnnotation.bounds, padding);
797
818
  }
798
819
  }
@@ -812,12 +833,11 @@ export class UserInteractions
812
833
  showPopup(featureId, content, options={})
813
834
  //=======================================
814
835
  {
815
- const ann = this._flatmap.annotation(featureId);
836
+ const properties = this.#getAnnotationProperties(featureId);
816
837
  const drawn = options && options.annotationFeatureGeometry;
817
- if (ann || drawn) { // The feature exists or it is a drawn annotation
838
+ if (properties || drawn) { // The feature exists or it is a drawn annotation
818
839
 
819
840
  // Remove any existing popup
820
-
821
841
  if (this._currentPopup) {
822
842
  if (options && options.preserveSelection) {
823
843
  this._currentPopup.options.preserveSelection = options.preserveSelection;
@@ -826,7 +846,6 @@ export class UserInteractions
826
846
  }
827
847
 
828
848
  // Clear selection if we are not preserving it
829
-
830
849
  if (options && options.preserveSelection) {
831
850
  delete options.preserveSelection; // Don't pass to onClose()
832
851
  } else { // via the popup's options
@@ -834,10 +853,9 @@ export class UserInteractions
834
853
  }
835
854
 
836
855
  // Select the feature
837
-
838
856
  this.selectFeature(featureId);
839
857
 
840
- // Find the pop-up's postion
858
+ // Find the pop-up's position
841
859
 
842
860
  let location = null;
843
861
  if ('positionAtLastClick' in options
@@ -850,7 +868,7 @@ export class UserInteractions
850
868
  location = options.annotationFeatureGeometry;
851
869
  } else {
852
870
  // Position popup at the feature's 'centre'
853
- location = this.__markerPosition(featureId, ann);
871
+ location = this.__markerPosition(featureId, properties);
854
872
  }
855
873
 
856
874
  // Make sure the feature is on screen
@@ -866,10 +884,11 @@ export class UserInteractions
866
884
  }
867
885
  this._currentPopup.setLngLat(location);
868
886
  if (typeof content === 'object') {
869
- this._currentPopup.setDOMContent(content);
887
+ this._currentPopup.setDOMContent(content)
870
888
  } else {
871
- this._currentPopup.setText(content);
889
+ this._currentPopup.setText(content)
872
890
  }
891
+ this._currentPopup.addTo(this._map)
873
892
  }
874
893
  }
875
894
 
@@ -1147,7 +1166,7 @@ export class UserInteractions
1147
1166
  selectionEvent_(event, feature)
1148
1167
  //=============================
1149
1168
  {
1150
- if (feature !== undefined) {
1169
+ if (feature) {
1151
1170
  const clickedFeatureId = +feature.id;
1152
1171
  const dim = !('properties' in feature
1153
1172
  && 'kind' in feature.properties
@@ -1305,26 +1324,33 @@ export class UserInteractions
1305
1324
 
1306
1325
  // Marker handling
1307
1326
 
1308
- __markerPosition(featureId, annotation)
1327
+ __markerPosition(featureId, properties)
1309
1328
  {
1310
1329
  if (this.__markerPositions.has(featureId)) {
1311
1330
  return this.__markerPositions.get(featureId);
1312
1331
  }
1313
- let position = annotation.markerPosition || annotation.centroid;
1314
- if (position === null || position == undefined) {
1332
+ let position = properties.markerPosition || properties.centroid || null;
1333
+ if (!position) {
1315
1334
  // Find where to place a label or popup on a feature
1316
- const features = this._map.querySourceFeatures(VECTOR_TILES_SOURCE, {
1317
- 'sourceLayer': this._flatmap.options.separateLayers
1318
- ? `${annotation['layer']}_${annotation['tile-layer']}`
1319
- : annotation['tile-layer'],
1320
- 'filter': [
1321
- 'all',
1322
- [ '==', ['id'], parseInt(featureId) ],
1323
- [ '==', ['geometry-type'], 'Polygon' ]
1324
- ]
1325
- });
1326
- if (features.length > 0) {
1327
- position = labelPosition(features[0]);
1335
+ if (properties.user_drawn) {
1336
+ if (this.#annotationDrawControl) {
1337
+ const feature = this.#annotationDrawControl.getFeature(featureId)
1338
+ position = labelPosition(feature);
1339
+ }
1340
+ } else {
1341
+ const features = this._map.querySourceFeatures(VECTOR_TILES_SOURCE, {
1342
+ 'sourceLayer': this._flatmap.options.separateLayers
1343
+ ? `${properties['layer']}_${properties['tile-layer']}`
1344
+ : properties['tile-layer'],
1345
+ 'filter': [
1346
+ 'all',
1347
+ [ '==', ['id'], parseInt(featureId) ],
1348
+ [ '==', ['geometry-type'], 'Polygon' ]
1349
+ ]
1350
+ });
1351
+ if (features.length > 0) {
1352
+ position = labelPosition(features[0]);
1353
+ }
1328
1354
  }
1329
1355
  }
1330
1356
  this.__markerPositions.set(featureId, position);
@@ -1338,7 +1364,7 @@ export class UserInteractions
1338
1364
  let markerId = -1;
1339
1365
 
1340
1366
  for (const featureId of featureIds) {
1341
- const annotation = this._flatmap.annotation(featureId);
1367
+ const annotation = this.#getAnnotationProperties(featureId);
1342
1368
  if (!('markerPosition' in annotation) && !annotation.geometry.includes('Polygon')) {
1343
1369
  continue;
1344
1370
  }
@@ -1454,7 +1480,7 @@ export class UserInteractions
1454
1480
  const annotation = this.__annotationByMarkerId.get(markerId);
1455
1481
  // The marker's feature
1456
1482
  const feature = this.mapFeature(annotation.featureId);
1457
- if (feature !== undefined) {
1483
+ if (feature) {
1458
1484
  if (event.type === 'mouseenter') {
1459
1485
  // Highlight on mouse enter
1460
1486
  this.resetActiveFeatures_();
@@ -0,0 +1,187 @@
1
+ /******************************************************************************
2
+
3
+ Flatmap viewer and annotation tool
4
+
5
+ Copyright (c) 2019 - 2024 David Brooks
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
18
+
19
+ ******************************************************************************/
20
+
21
+ type FilterExpression = Record<string, any>
22
+
23
+ //==============================================================================
24
+
25
+ export class FeatureFilter
26
+ {
27
+ #filter: FilterExpression
28
+
29
+ constructor(filter: FilterExpression)
30
+ {
31
+ this.#filter = filter
32
+ }
33
+
34
+ makeStyleFilter()
35
+ //===============
36
+ {
37
+ return this.#makeStyleFilter(this.#filter)
38
+ }
39
+
40
+ #makeStyleFilter(filter: FilterExpression): Array<any>
41
+ //====================================================
42
+ {
43
+ // We expect an object, so check and warn...
44
+ if (!filter || filter.constructor !== Object) {
45
+ console.warn(`makeFilter: Invalid filter expression: ${filter}`)
46
+ return []
47
+ }
48
+
49
+ const styleFilter = []
50
+ for (const [key, expr] of Object.entries(filter)) {
51
+ if (key === 'AND' || key === 'OR') {
52
+ if (Array.isArray(expr) && expr.length >= 2) {
53
+ styleFilter.push((key === 'AND') ? 'all' : 'any',
54
+ ...expr.map(e => this.#makeStyleFilter(e)))
55
+ } else {
56
+ console.warn(`makeFilter: Invalid ${key} operands: ${expr}`)
57
+ }
58
+ } else if (key === 'HAS') {
59
+ styleFilter.push('has', expr)
60
+ } else if (key === 'NOT') {
61
+ const filterExpr = this.#makeStyleFilter(expr)
62
+ if (filterExpr.length === 2 && ['has', '!has'].includes(filterExpr[0])) {
63
+ if (filterExpr[0] === 'has') {
64
+ styleFilter.push('!has', filterExpr[1])
65
+ } else {
66
+ styleFilter.push('has', filterExpr[1])
67
+ }
68
+ } else if (filterExpr.length === 3 && ['==', '!='].includes(filterExpr[0])) {
69
+ if (filterExpr[0] === '==') {
70
+ styleFilter.push('!=', filterExpr[1], filterExpr[2])
71
+ } else {
72
+ styleFilter.push('==', filterExpr[1], filterExpr[2])
73
+ }
74
+ } else {
75
+ styleFilter.push('!', filterExpr)
76
+ }
77
+ } else {
78
+ if (Array.isArray(expr)) {
79
+ styleFilter.push('any', ...expr.map(e => ['==', key, e]))
80
+ } else {
81
+ styleFilter.push('==', key, expr)
82
+ }
83
+ }
84
+ }
85
+ return styleFilter
86
+ }
87
+
88
+ }
89
+
90
+ //==============================================================================
91
+
92
+ function testFilter(f: FilterExpression)
93
+ //======================================
94
+ {
95
+ const featureFilter = new FeatureFilter(f)
96
+ console.log(f, '--->', featureFilter.makeStyleFilter())
97
+ }
98
+
99
+ export function testFilters()
100
+ //===========================
101
+ {
102
+ /*
103
+ { HAS: 'prop' } ---> [ 'has', 'prop' ]
104
+ { prop: 1 } ---> [ '==', 'prop', 1 ]
105
+ { NOT: { prop: 1 } } ---> [ '!=', 'prop', 1 ]
106
+ { NOT: { prop: [ 1, 2 ] } } ---> [ '!', [ 'any', [ '==', 'prop', 1 ], [ '==', 'prop', 2 ] ] ]
107
+ { OR: [ { prop1: 10 }, { prop2: 11 } ] } ---> [ 'any', [ '==', 'prop1', 10 ], [ '==', 'prop2', 11 ] ]
108
+ { AND: [ { prop1: 10 }, { prop2: 11 } ] } ---> [ 'all', [ '==', 'prop1', 10 ], [ '==', 'prop2', 11 ] ]
109
+ { OR: [ { AND: [Array] }, { AND: [Array] } ] } ---> [
110
+ 'any',
111
+ [ 'all', [ '!=', 'prop1', 10 ], [ '==', 'prop2', 11 ] ],
112
+ [ 'all', [ '==', 'prop3', 10 ], [ '==', 'prop4', 11 ] ]
113
+ ]
114
+ { NOT: { OR: [ [Object], [Object] ] } } ---> [
115
+ '!',
116
+ [ 'any', [ 'all', [Array], [Array] ], [ 'all', [Array], [Array] ] ]
117
+ ]
118
+ */
119
+
120
+ testFilter({
121
+ "HAS": "prop"
122
+ })
123
+
124
+ testFilter({
125
+ "prop": 1
126
+ })
127
+
128
+ testFilter({
129
+ "NOT": {
130
+ "prop": 1
131
+ }
132
+ })
133
+
134
+ testFilter({
135
+ "NOT": {
136
+ "prop": [1, 2]
137
+ }
138
+ })
139
+
140
+ testFilter({
141
+ "OR": [
142
+ {"prop1": 10},
143
+ {"prop2": 11}
144
+ ]
145
+ })
146
+
147
+ testFilter({
148
+ "AND": [
149
+ {"prop1": 10},
150
+ {"prop2": 11}
151
+ ]
152
+ })
153
+
154
+ testFilter({
155
+ "OR": [{
156
+ "AND": [
157
+ { "NOT": {"prop1": 10}},
158
+ {"prop2": 11}
159
+ ]}, {
160
+ "AND": [
161
+ {"prop3": 10},
162
+ {"prop4": 11}
163
+ ]}
164
+ ]
165
+ })
166
+
167
+ testFilter({
168
+ "NOT": {
169
+ "OR": [{
170
+ "AND": [
171
+ {"prop1": 10},
172
+ {"prop2": 11}
173
+ ]}, {
174
+ "AND": [
175
+ {"prop3": 10},
176
+ {"prop4": 11}
177
+ ]}
178
+ ]
179
+ }
180
+ })
181
+ }
182
+
183
+ //==============================================================================
184
+
185
+ //testFilters()
186
+
187
+ //==============================================================================
@@ -22,6 +22,8 @@ limitations under the License.
22
22
 
23
23
  //==============================================================================
24
24
 
25
+ import {FeatureFilter} from './filter'
26
+
25
27
  import {PATHWAYS_LAYER} from '../pathways.js';
26
28
  import * as utils from '../utils.js';
27
29
 
@@ -44,6 +46,11 @@ class MapStylingLayers
44
46
  this.__layers = [];
45
47
  this.__layerOptions = options;
46
48
  this.__separateLayers = flatmap.options.separateLayers;
49
+
50
+ const f = new FeatureFilter({
51
+ "HAS": "prop"
52
+ })
53
+ console.log(f.makeStyleFilter())
47
54
  }
48
55
 
49
56
  get id()
package/src/main.js CHANGED
@@ -64,6 +64,9 @@ class DrawControl
64
64
  //================
65
65
  {
66
66
  console.log(event)
67
+
68
+ this._flatmap.showPopup(event.feature.id, '<div>event</div>')
69
+
67
70
  if (this._idField) {
68
71
  this._idField.innerText = `Annotation ${event.type}, Id: ${event.feature.id}`
69
72
  this._lastEvent = event