geojs 1.9.2 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/main.yml +1 -1
- package/CHANGELOG.md +38 -0
- package/geo.js +315 -42
- package/geo.lean.js +314 -41
- package/geo.lean.min.js +2 -2
- package/geo.min.js +7 -7
- package/package.json +3 -3
- package/src/action.js +3 -5
- package/src/annotation/annotation.js +73 -7
- package/src/annotation/polygonAnnotation.js +11 -0
- package/src/annotationLayer.js +73 -18
- package/src/event.js +28 -0
- package/src/lineFeature.js +6 -3
- package/src/main.styl +11 -0
- package/src/mapInteractor.js +49 -3
- package/src/registry.js +3 -0
- package/src/trackFeature.js +3 -1
- package/src/util/polyops.js +4 -1
- package/src/webgl/lineFeature.js +14 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "geojs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "JavaScript Geo Visualization and Analysis Library",
|
|
5
5
|
"homepage": "https://github.com/OpenGeoscience/geojs",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"karma-coverage": "^2.1.1",
|
|
68
68
|
"karma-firefox-launcher": "^2.1.2",
|
|
69
69
|
"karma-jasmine": "^5.0.0",
|
|
70
|
-
"karma-jasmine-html-reporter": "^
|
|
70
|
+
"karma-jasmine-html-reporter": "^2.0.0",
|
|
71
71
|
"karma-sinon": "^1.0.5",
|
|
72
72
|
"karma-sourcemap-loader": "^0.3.8",
|
|
73
73
|
"karma-spec-reporter": "^0.0.34",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"shader-loader": "^1.3.1",
|
|
86
86
|
"sinon": "^14.0.0",
|
|
87
87
|
"style-loader": "^3.3.1",
|
|
88
|
-
"stylus": "^0.
|
|
88
|
+
"stylus": "^0.58.1",
|
|
89
89
|
"stylus-loader": "^7.0.0",
|
|
90
90
|
"terser-webpack-plugin": "^5.3.1",
|
|
91
91
|
"touch-emulator": "^1.0.0",
|
package/src/action.js
CHANGED
|
@@ -16,11 +16,9 @@ var geo_action = {
|
|
|
16
16
|
zoomrotate: 'geo_action_zoom_rotate',
|
|
17
17
|
zoomselect: 'geo_action_zoomselect',
|
|
18
18
|
|
|
19
|
-
// annotation actions
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
annotation_rectangle: 'geo_annotation_rectangle',
|
|
23
|
-
annotation_edit_handle: 'geo_annotation_edit_handle'
|
|
19
|
+
// annotation actions -- some are also added by the registry
|
|
20
|
+
annotation_edit_handle: 'geo_annotation_edit_handle',
|
|
21
|
+
annotation_cursor: 'geo_annotation_cursor'
|
|
24
22
|
};
|
|
25
23
|
|
|
26
24
|
module.exports = geo_action;
|
|
@@ -15,7 +15,8 @@ var annotationState = {
|
|
|
15
15
|
create: 'create',
|
|
16
16
|
done: 'done',
|
|
17
17
|
highlight: 'highlight',
|
|
18
|
-
edit: 'edit'
|
|
18
|
+
edit: 'edit',
|
|
19
|
+
cursor: 'cursor'
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
var annotationActionOwner = 'annotationAction';
|
|
@@ -151,6 +152,17 @@ var annotation = function (type, args) {
|
|
|
151
152
|
return m_id;
|
|
152
153
|
};
|
|
153
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Assign a new id to this annotation.
|
|
157
|
+
*
|
|
158
|
+
* @returns {this}
|
|
159
|
+
*/
|
|
160
|
+
this.newId = function () {
|
|
161
|
+
annotationId += 1;
|
|
162
|
+
m_id = annotationId;
|
|
163
|
+
return m_this;
|
|
164
|
+
};
|
|
165
|
+
|
|
154
166
|
/**
|
|
155
167
|
* Get or set the name of this annotation.
|
|
156
168
|
*
|
|
@@ -300,6 +312,27 @@ var annotation = function (type, args) {
|
|
|
300
312
|
return m_this;
|
|
301
313
|
};
|
|
302
314
|
|
|
315
|
+
this._cursorHandleMousemove = function (evt) {
|
|
316
|
+
m_this.layer()._handleMouseMoveModifiers(evt);
|
|
317
|
+
const center = m_this._cursorCenter;
|
|
318
|
+
const delta = {
|
|
319
|
+
x: evt.mapgcs.x - center.x,
|
|
320
|
+
y: evt.mapgcs.y - center.y
|
|
321
|
+
};
|
|
322
|
+
if (delta.x || delta.y) {
|
|
323
|
+
const curPts = m_this._coordinates();
|
|
324
|
+
var pts = m_this._coordinatesMapFunc(curPts, function (elem) {
|
|
325
|
+
return {x: elem.x + delta.x, y: elem.y + delta.y};
|
|
326
|
+
});
|
|
327
|
+
m_this._coordinates(pts);
|
|
328
|
+
m_this._cursorCenter = evt.mapgcs;
|
|
329
|
+
m_this.modified();
|
|
330
|
+
m_this.draw();
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
return false;
|
|
334
|
+
};
|
|
335
|
+
|
|
303
336
|
/**
|
|
304
337
|
* Get or set the state of this annotation.
|
|
305
338
|
*
|
|
@@ -320,6 +353,17 @@ var annotation = function (type, args) {
|
|
|
320
353
|
annotation: m_this
|
|
321
354
|
});
|
|
322
355
|
}
|
|
356
|
+
if (m_this.layer()) {
|
|
357
|
+
m_this.layer().geoOff(geo_event.mousemove, m_this._cursorHandleMousemove);
|
|
358
|
+
}
|
|
359
|
+
switch (m_state) {
|
|
360
|
+
case annotationState.cursor:
|
|
361
|
+
m_this._cursorCenter = util.centerFromPerimeter(m_this._coordinates());
|
|
362
|
+
if (m_this.layer()) {
|
|
363
|
+
m_this.layer().geoOn(geo_event.mousemove, m_this._cursorHandleMousemove);
|
|
364
|
+
}
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
323
367
|
}
|
|
324
368
|
return m_this;
|
|
325
369
|
};
|
|
@@ -348,6 +392,18 @@ var annotation = function (type, args) {
|
|
|
348
392
|
owner: annotationActionOwner,
|
|
349
393
|
input: 'pan'
|
|
350
394
|
}];
|
|
395
|
+
case annotationState.cursor:
|
|
396
|
+
return [{
|
|
397
|
+
action: geo_action.annotation_cursor,
|
|
398
|
+
name: 'annotation cursor',
|
|
399
|
+
owner: annotationActionOwner,
|
|
400
|
+
input: 'pan'
|
|
401
|
+
}, {
|
|
402
|
+
action: geo_action.annotation_cursor,
|
|
403
|
+
name: 'annotation cursor',
|
|
404
|
+
owner: annotationActionOwner,
|
|
405
|
+
input: 'left'
|
|
406
|
+
}];
|
|
351
407
|
default:
|
|
352
408
|
return [];
|
|
353
409
|
}
|
|
@@ -471,7 +527,7 @@ var annotation = function (type, args) {
|
|
|
471
527
|
/* For style objects, re-extend them without recursion. This allows
|
|
472
528
|
* setting colors without an opacity field, for instance. */
|
|
473
529
|
['style', 'createStyle', 'editStyle', 'editHandleStyle', 'labelStyle',
|
|
474
|
-
'highlightStyle'
|
|
530
|
+
'highlightStyle', 'cursorStyle'
|
|
475
531
|
].forEach(function (key) {
|
|
476
532
|
if (arg1[key] !== undefined) {
|
|
477
533
|
$.extend(m_options[key], arg1[key]);
|
|
@@ -520,8 +576,8 @@ var annotation = function (type, args) {
|
|
|
520
576
|
* current style with the values in the specified object.
|
|
521
577
|
* @param {*} [arg2] If `arg1` is a string, the new value for that style.
|
|
522
578
|
* @param {string} [styleType='style'] The name of the style type, such as
|
|
523
|
-
* `createStyle`, `editStyle`, `editHandleStyle`, `labelStyle`,
|
|
524
|
-
* `highlightStyle`.
|
|
579
|
+
* `createStyle`, `editStyle`, `editHandleStyle`, `labelStyle`,
|
|
580
|
+
* `highlightStyle`, or `cursorStyle`.
|
|
525
581
|
* @returns {object|this} Either the entire style object, the value of a
|
|
526
582
|
* specific style, or the current class instance.
|
|
527
583
|
*/
|
|
@@ -570,12 +626,18 @@ var annotation = function (type, args) {
|
|
|
570
626
|
* @instance
|
|
571
627
|
*/
|
|
572
628
|
/**
|
|
573
|
-
* Calls {@link geo.annotation#style} with `styleType='
|
|
574
|
-
* @function
|
|
629
|
+
* Calls {@link geo.annotation#style} with `styleType='highlightStyle'`.
|
|
630
|
+
* @function highlightStyle
|
|
575
631
|
* @memberof geo.annotation
|
|
576
632
|
* @instance
|
|
577
633
|
*/
|
|
578
|
-
|
|
634
|
+
/**
|
|
635
|
+
* Calls {@link geo.annotation#style} with `styleType='cursorStyle'`.
|
|
636
|
+
* @function cursorStyle
|
|
637
|
+
* @memberof geo.annotation
|
|
638
|
+
* @instance
|
|
639
|
+
*/
|
|
640
|
+
['createStyle', 'editStyle', 'editHandleStyle', 'labelStyle', 'highlightStyle', 'cursorStyle'
|
|
579
641
|
].forEach(function (styleType) {
|
|
580
642
|
m_this[styleType] = function (arg1, arg2) {
|
|
581
643
|
return m_this.style(arg1, arg2, styleType);
|
|
@@ -600,6 +662,10 @@ var annotation = function (type, args) {
|
|
|
600
662
|
return $.extend({}, m_options.style, m_options.editStyle,
|
|
601
663
|
m_options[state + 'Style']);
|
|
602
664
|
}
|
|
665
|
+
if (state === annotationState.cursor) {
|
|
666
|
+
return $.extend({}, m_options.style, m_options.editStyle,
|
|
667
|
+
m_options.createStyle, m_options[state + 'Style']);
|
|
668
|
+
}
|
|
603
669
|
return m_options[state + 'Style'] || m_options.style || {};
|
|
604
670
|
};
|
|
605
671
|
|
|
@@ -3,6 +3,7 @@ const inherit = require('../inherit');
|
|
|
3
3
|
const registerAnnotation = require('../registry').registerAnnotation;
|
|
4
4
|
const lineFeature = require('../lineFeature');
|
|
5
5
|
const polygonFeature = require('../polygonFeature');
|
|
6
|
+
const util = require('../util');
|
|
6
7
|
|
|
7
8
|
const annotation = require('./annotation').annotation;
|
|
8
9
|
const annotationState = require('./annotation').state;
|
|
@@ -61,6 +62,9 @@ var polygonAnnotation = function (args) {
|
|
|
61
62
|
}
|
|
62
63
|
return m_this.options('vertices')[i];
|
|
63
64
|
}
|
|
65
|
+
},
|
|
66
|
+
cursorStyle: {
|
|
67
|
+
position: util.identityFunction
|
|
64
68
|
}
|
|
65
69
|
}, args);
|
|
66
70
|
args.vertices = args.vertices || args.coordinates || [];
|
|
@@ -332,6 +336,13 @@ polygonAnnotation.defaults = $.extend({}, annotation.defaults, {
|
|
|
332
336
|
stroke: false,
|
|
333
337
|
strokeColor: {r: 0, g: 0, b: 1}
|
|
334
338
|
},
|
|
339
|
+
cursorStyle: {
|
|
340
|
+
closed: true,
|
|
341
|
+
fillColor: {r: 0.3, g: 0.3, b: 0.3},
|
|
342
|
+
fillOpacity: 0.25,
|
|
343
|
+
stroke: true,
|
|
344
|
+
strokeColor: {r: 0, g: 0, b: 1}
|
|
345
|
+
},
|
|
335
346
|
allowBooleanOperations: true
|
|
336
347
|
});
|
|
337
348
|
|
package/src/annotationLayer.js
CHANGED
|
@@ -49,6 +49,17 @@ var textFeature = require('./textFeature');
|
|
|
49
49
|
* style object.
|
|
50
50
|
*/
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* @typedef {geo.util.polyop.spec} geo.util.polyop.annotationLayerSpec
|
|
54
|
+
* @extends {geo.util.polyop.spec}
|
|
55
|
+
* @property {string} [keepAnnotations='exact'] Determine which annotations are
|
|
56
|
+
* present after a boolean operation. `'exact'` replaces modified
|
|
57
|
+
* annotations with the results; unmodified annotations are left as is.
|
|
58
|
+
* `'all'` replaces all annotations, so unchanged annotations may be
|
|
59
|
+
* converted to polygonAnnotations. `'none'` discards all existing
|
|
60
|
+
* annotations and only keeps modified results.
|
|
61
|
+
*/
|
|
62
|
+
|
|
52
63
|
/**
|
|
53
64
|
* Layer to handle direct interactions with different features. Annotations
|
|
54
65
|
* (features) can be created by calling mode(<name of feature>) or cancelled
|
|
@@ -173,6 +184,15 @@ var annotationLayer = function (arg) {
|
|
|
173
184
|
}
|
|
174
185
|
}
|
|
175
186
|
break;
|
|
187
|
+
case m_this.modes.cursor:
|
|
188
|
+
m_this.currentAnnotation._cursorHandleMousemove(evt.mouse);
|
|
189
|
+
update = m_this.currentAnnotation.processAction(evt);
|
|
190
|
+
m_this.geoTrigger(geo_event.annotation.cursor_action, {
|
|
191
|
+
annotation: m_this.currentAnnotation,
|
|
192
|
+
operation: m_this.currentBooleanOperation(),
|
|
193
|
+
evt: evt
|
|
194
|
+
});
|
|
195
|
+
break;
|
|
176
196
|
default:
|
|
177
197
|
update = m_this.currentAnnotation.processAction(evt);
|
|
178
198
|
break;
|
|
@@ -250,7 +270,7 @@ var annotationLayer = function (arg) {
|
|
|
250
270
|
* @param {geo.event} evt The mouse move or click event.
|
|
251
271
|
*/
|
|
252
272
|
this._handleMouseMoveModifiers = function (evt) {
|
|
253
|
-
if (m_this.mode() !== m_this.modes.edit && m_this.currentAnnotation.options('allowBooleanOperations') && m_this.currentAnnotation._coordinates().length < 2) {
|
|
273
|
+
if (m_this.mode() !== m_this.modes.edit && m_this.currentAnnotation.options('allowBooleanOperations') && (m_this.currentAnnotation._coordinates().length < 2 || m_this.mode() === m_this.modes.cursor)) {
|
|
254
274
|
if (evt.modifiers) {
|
|
255
275
|
const mod = (evt.modifiers.shift ? 's' : '') + (evt.modifiers.ctrl ? 'c' : '') + (evt.modifiers.meta || evt.modifiers.alt ? 'a' : '');
|
|
256
276
|
if (m_this._currentBooleanClass === m_this._booleanClasses[mod]) {
|
|
@@ -381,6 +401,13 @@ var annotationLayer = function (arg) {
|
|
|
381
401
|
update = m_this.currentAnnotation.mouseClick(evt);
|
|
382
402
|
m_this._updateFromEvent(update);
|
|
383
403
|
retrigger = !m_this.mode();
|
|
404
|
+
if (m_this.mode() === m_this.modes.cursor) {
|
|
405
|
+
m_this.geoTrigger(geo_event.annotation.cursor_click, {
|
|
406
|
+
annotation: m_this.currentAnnotation,
|
|
407
|
+
operation: m_this.currentBooleanOperation(),
|
|
408
|
+
evt: evt
|
|
409
|
+
});
|
|
410
|
+
}
|
|
384
411
|
} else if (!m_this.mode() && !m_this.currentAnnotation && m_this.options('clickToEdit')) {
|
|
385
412
|
var highlighted = m_this.annotations().filter(function (ann) {
|
|
386
413
|
return ann.state() === geo_annotation.state.highlight;
|
|
@@ -470,6 +497,9 @@ var annotationLayer = function (arg) {
|
|
|
470
497
|
this.addAnnotation = function (annotation, gcs, update) {
|
|
471
498
|
var pos = $.inArray(annotation, m_annotations);
|
|
472
499
|
if (pos < 0) {
|
|
500
|
+
while (m_this.annotationById(annotation.id())) {
|
|
501
|
+
annotation.newId();
|
|
502
|
+
}
|
|
473
503
|
m_this.geoTrigger(geo_event.annotation.add_before, {
|
|
474
504
|
annotation: annotation
|
|
475
505
|
});
|
|
@@ -577,7 +607,8 @@ var annotationLayer = function (arg) {
|
|
|
577
607
|
|
|
578
608
|
/* A list of special modes */
|
|
579
609
|
this.modes = {
|
|
580
|
-
edit: 'edit'
|
|
610
|
+
edit: 'edit',
|
|
611
|
+
cursor: 'cursor'
|
|
581
612
|
};
|
|
582
613
|
|
|
583
614
|
/* Keys are short-hand for preferred event modifiers. Values are classes to
|
|
@@ -594,11 +625,13 @@ var annotationLayer = function (arg) {
|
|
|
594
625
|
*
|
|
595
626
|
* @param {string|null} [arg] `undefined` to get the current mode, `null` to
|
|
596
627
|
* stop creating/editing, `this.modes.edit` (`'edit'`) plus an annotation
|
|
597
|
-
* to switch to edit mode,
|
|
598
|
-
*
|
|
628
|
+
* to switch to edit mode, `this.modes.cursor` plus an annotation to
|
|
629
|
+
* switch to using the annotation as a cursor, or the name of the type of
|
|
630
|
+
* annotation to create. Available annotations can listed via
|
|
599
631
|
* {@link geo.listAnnotations}.
|
|
600
|
-
* @param {geo.annotation} [editAnnotation] If `arg === this.modes.edit
|
|
601
|
-
* this is the annotation that should be
|
|
632
|
+
* @param {geo.annotation} [editAnnotation] If `arg === this.modes.edit` or
|
|
633
|
+
* `arg === this.modes.cursor`, this is the annotation that should be
|
|
634
|
+
* edited or used.
|
|
602
635
|
* @param {object} [options] Additional options to pass when creating an
|
|
603
636
|
* annotation.
|
|
604
637
|
* @returns {string|null|this} The current mode or the layer.
|
|
@@ -608,11 +641,14 @@ var annotationLayer = function (arg) {
|
|
|
608
641
|
if (arg === undefined) {
|
|
609
642
|
return m_mode;
|
|
610
643
|
}
|
|
611
|
-
if (arg !== m_mode ||
|
|
644
|
+
if (arg !== m_mode ||
|
|
645
|
+
((arg === m_this.modes.edit || arg === m_this.modes.cursor) && editAnnotation !== m_this.editAnnotation) ||
|
|
646
|
+
(arg !== m_this.modes.edit && arg !== m_this.modes.cursor && arg && !m_this.currentAnnotation)
|
|
647
|
+
) {
|
|
612
648
|
var createAnnotation, actions,
|
|
613
649
|
mapNode = m_this.map().node(), oldMode = m_mode;
|
|
614
650
|
m_mode = arg;
|
|
615
|
-
mapNode.toggleClass('annotation-input', !!(m_mode && m_mode !== m_this.modes.edit));
|
|
651
|
+
mapNode.toggleClass('annotation-input', !!(m_mode && m_mode !== m_this.modes.edit && m_mode !== m_this.modes.cursor));
|
|
616
652
|
if (!m_mode || m_mode === m_this.modes.edit) {
|
|
617
653
|
Object.values(m_this._booleanClasses).forEach((c) => mapNode.toggleClass(c, false));
|
|
618
654
|
m_this._currentBooleanClass = undefined;
|
|
@@ -635,6 +671,12 @@ var annotationLayer = function (arg) {
|
|
|
635
671
|
m_this.modified();
|
|
636
672
|
m_this.draw();
|
|
637
673
|
break;
|
|
674
|
+
case geo_annotation.state.cursor:
|
|
675
|
+
m_this.currentAnnotation.state(geo_annotation.state.done);
|
|
676
|
+
m_this.modified();
|
|
677
|
+
m_this.draw();
|
|
678
|
+
m_this.map().node().toggleClass('annotation-cursor', false);
|
|
679
|
+
break;
|
|
638
680
|
}
|
|
639
681
|
m_this.currentAnnotation = null;
|
|
640
682
|
}
|
|
@@ -642,6 +684,12 @@ var annotationLayer = function (arg) {
|
|
|
642
684
|
m_this.currentAnnotation = editAnnotation;
|
|
643
685
|
m_this.currentAnnotation.state(geo_annotation.state.edit);
|
|
644
686
|
m_this.modified();
|
|
687
|
+
} else if (m_mode === m_this.modes.cursor) {
|
|
688
|
+
m_this.currentAnnotation = editAnnotation;
|
|
689
|
+
m_this.currentAnnotation.state(geo_annotation.state.cursor);
|
|
690
|
+
m_this.modified();
|
|
691
|
+
m_this.map().node().toggleClass('annotation-cursor', true);
|
|
692
|
+
actions = m_this.currentAnnotation.actions(geo_annotation.state.cursor);
|
|
645
693
|
} else if (registry.registries.annotations[m_mode]) {
|
|
646
694
|
createAnnotation = registry.registries.annotations[m_mode].func;
|
|
647
695
|
}
|
|
@@ -655,13 +703,15 @@ var annotationLayer = function (arg) {
|
|
|
655
703
|
m_this.currentAnnotation = createAnnotation(options);
|
|
656
704
|
m_this.addAnnotation(m_this.currentAnnotation, null);
|
|
657
705
|
actions = m_this.currentAnnotation.actions(geo_annotation.state.create);
|
|
706
|
+
}
|
|
707
|
+
if (actions) {
|
|
658
708
|
$.each(actions, function (idx, action) {
|
|
659
709
|
m_this.map().interactor().addAction(action);
|
|
660
710
|
});
|
|
661
711
|
}
|
|
662
712
|
m_this.geoTrigger(geo_event.annotation.mode, {
|
|
663
713
|
mode: m_mode, oldMode: oldMode});
|
|
664
|
-
if (oldMode === m_this.modes.edit) {
|
|
714
|
+
if (oldMode === m_this.modes.edit || oldMode === m_this.modes.cursor) {
|
|
665
715
|
m_this.modified();
|
|
666
716
|
}
|
|
667
717
|
}
|
|
@@ -1247,11 +1297,15 @@ var annotationLayer = function (arg) {
|
|
|
1247
1297
|
this.toPolygonList = function (opts) {
|
|
1248
1298
|
const poly = [];
|
|
1249
1299
|
opts = opts || {};
|
|
1250
|
-
|
|
1300
|
+
const indices = [];
|
|
1301
|
+
if (!opts.annotationIndices) {
|
|
1302
|
+
opts.annotationIndices = {};
|
|
1303
|
+
}
|
|
1304
|
+
opts.annotationIndices[m_this.id()] = indices;
|
|
1251
1305
|
m_annotations.forEach((annotation, idx) => {
|
|
1252
1306
|
if (annotation.toPolygonList) {
|
|
1253
1307
|
annotation.toPolygonList(opts).forEach((p) => poly.push(p));
|
|
1254
|
-
|
|
1308
|
+
indices.push(idx);
|
|
1255
1309
|
}
|
|
1256
1310
|
});
|
|
1257
1311
|
return poly;
|
|
@@ -1261,8 +1315,8 @@ var annotationLayer = function (arg) {
|
|
|
1261
1315
|
* Replace appropriate annotations with a list of polygons.
|
|
1262
1316
|
*
|
|
1263
1317
|
* @param {geo.polygonList} poly A list of polygons.
|
|
1264
|
-
* @param {geo.util.polyop.
|
|
1265
|
-
* correspondence used to track annotations.
|
|
1318
|
+
* @param {geo.util.polyop.annotationLayerSpec} [opts] This contains
|
|
1319
|
+
* annotationIndices and correspondence used to track annotations.
|
|
1266
1320
|
* @returns {this}
|
|
1267
1321
|
*/
|
|
1268
1322
|
this.fromPolygonList = function (poly, opts) {
|
|
@@ -1274,14 +1328,15 @@ var annotationLayer = function (arg) {
|
|
|
1274
1328
|
const keepIds = {};
|
|
1275
1329
|
const reusedIds = {};
|
|
1276
1330
|
let correspond, exact, annot;
|
|
1277
|
-
|
|
1331
|
+
const indices = (opts.annotationIndices || {})[m_this.id()];
|
|
1332
|
+
if (indices && opts.correspond && opts.correspond.poly1 && indices.length === opts.correspond.poly1.length) {
|
|
1278
1333
|
correspond = opts.correspond.poly1;
|
|
1279
1334
|
exact = opts.correspond.exact1;
|
|
1280
1335
|
annot = m_this.annotations();
|
|
1281
1336
|
}
|
|
1282
|
-
if (keep !== 'all' && keep !== 'none') {
|
|
1337
|
+
if (keep !== 'all' && keep !== 'none' && annot) {
|
|
1283
1338
|
annot.forEach((oldAnnot, idx) => {
|
|
1284
|
-
if (
|
|
1339
|
+
if (indices.indexOf(idx) < 0) {
|
|
1285
1340
|
keepIds[oldAnnot.id()] = true;
|
|
1286
1341
|
}
|
|
1287
1342
|
});
|
|
@@ -1295,7 +1350,7 @@ var annotationLayer = function (arg) {
|
|
|
1295
1350
|
if (correspond) {
|
|
1296
1351
|
for (let i = 0; i < correspond.length; i += 1) {
|
|
1297
1352
|
if (correspond[i] && correspond[i].indexOf(idx) >= 0) {
|
|
1298
|
-
const orig = annot[
|
|
1353
|
+
const orig = annot[indices[i]];
|
|
1299
1354
|
if (keep !== 'all' && keep !== 'none' && exact && exact[i] && exact[i].indexOf(idx) >= 0) {
|
|
1300
1355
|
keepIds[orig.id()] = true;
|
|
1301
1356
|
return;
|
|
@@ -1332,7 +1387,7 @@ var annotationLayer = function (arg) {
|
|
|
1332
1387
|
}
|
|
1333
1388
|
// add new annotations
|
|
1334
1389
|
polyAnnot.forEach((p) => {
|
|
1335
|
-
m_this.addAnnotation(registry.createAnnotation('polygon', p), m_this.gcs(), false);
|
|
1390
|
+
m_this.addAnnotation(registry.createAnnotation('polygon', p), m_this.map().gcs(), false);
|
|
1336
1391
|
update = true;
|
|
1337
1392
|
});
|
|
1338
1393
|
if (update) {
|
package/src/event.js
CHANGED
|
@@ -706,4 +706,32 @@ geo_event.annotation.mode = 'geo_annotation_mode';
|
|
|
706
706
|
*/
|
|
707
707
|
geo_event.annotation.boolean = 'geo_annotation_boolean';
|
|
708
708
|
|
|
709
|
+
/**
|
|
710
|
+
* Triggered when an annotation is in cursor mode and the mouse is clicked.
|
|
711
|
+
*
|
|
712
|
+
* @event geo.event.annotation.cursor_click
|
|
713
|
+
* @type {geo.event.base}
|
|
714
|
+
* @property {geo.annotation} annotation The annotation that is being operated
|
|
715
|
+
* on.
|
|
716
|
+
* @property {string} operation The operation being performed.
|
|
717
|
+
* @property {boolean} [cancel] If the handle sets this to false, don't apply
|
|
718
|
+
* the operation to the annotation layer.
|
|
719
|
+
* @property {object} event The triggering event.
|
|
720
|
+
*/
|
|
721
|
+
geo_event.annotation.cursor_click = 'geo_annotation_cursor_click';
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Triggered when an annotation is in cursor mode and an action occurs.
|
|
725
|
+
*
|
|
726
|
+
* @event geo.event.annotation.cursor_action
|
|
727
|
+
* @type {geo.event.base}
|
|
728
|
+
* @property {geo.annotation} annotation The annotation that is being operated
|
|
729
|
+
* on.
|
|
730
|
+
* @property {string} operation The operation being performed.
|
|
731
|
+
* @property {boolean} [cancel] If the handle sets this to false, don't apply
|
|
732
|
+
* the operation to the annotation layer.
|
|
733
|
+
* @property {object} event The triggering event.
|
|
734
|
+
*/
|
|
735
|
+
geo_event.annotation.cursor_action = 'geo_annotation_cursor_action';
|
|
736
|
+
|
|
709
737
|
module.exports = geo_event;
|
package/src/lineFeature.js
CHANGED
|
@@ -46,9 +46,12 @@ var util = require('./util');
|
|
|
46
46
|
* divided by the sine of half the angle between segments, then a bevel join
|
|
47
47
|
* is used instead. This is a single value that applies to all lines. If a
|
|
48
48
|
* function, it is called with `(data)`.
|
|
49
|
-
* @property {boolean|function} [uniformLine=false] Boolean indicating
|
|
50
|
-
* line has a uniform style (uniform stroke color, opacity, and
|
|
51
|
-
* vary by line.
|
|
49
|
+
* @property {boolean|string|function} [uniformLine=false] Boolean indicating
|
|
50
|
+
* if each line has a uniform style (uniform stroke color, opacity, and
|
|
51
|
+
* width). Can vary by line. A value of `'drop'` will modify rendered
|
|
52
|
+
* vertex order by dropping duplicates and setting later values to zero
|
|
53
|
+
* opacity. This can be faster but makes it so updating the style array
|
|
54
|
+
* can no longer be used.
|
|
52
55
|
* @property {number|function} [antialiasing] Antialiasing distance in pixels.
|
|
53
56
|
* Values must be non-negative. A value greater than 1 will produce a
|
|
54
57
|
* visible gradient. This is a single value that applies to all lines.
|
package/src/main.styl
CHANGED
|
@@ -58,6 +58,17 @@
|
|
|
58
58
|
&.annotation-xor
|
|
59
59
|
cursor embedurl("./css/cursor-crosshair-xor.svg") 12 12,crosshair
|
|
60
60
|
|
|
61
|
+
&.annotation-cursor
|
|
62
|
+
cursor crosshair
|
|
63
|
+
&.annotation-intersect
|
|
64
|
+
cursor embedurl("./css/cursor-crosshair-intersect.svg") 12 12,crosshair
|
|
65
|
+
&.annotation-difference
|
|
66
|
+
cursor embedurl("./css/cursor-crosshair-difference.svg") 12 12,crosshair
|
|
67
|
+
&.annotation-union
|
|
68
|
+
cursor embedurl("./css/cursor-crosshair-union.svg") 12 12,crosshair
|
|
69
|
+
&.annotation-xor
|
|
70
|
+
cursor embedurl("./css/cursor-crosshair-xor.svg") 12 12,crosshair
|
|
71
|
+
|
|
61
72
|
&.highlight-focus
|
|
62
73
|
&:after
|
|
63
74
|
content ""
|
package/src/mapInteractor.js
CHANGED
|
@@ -25,8 +25,8 @@ var Mousetrap = require('mousetrap');
|
|
|
25
25
|
* event must occur within this time in milliseconds of the mouse down
|
|
26
26
|
* event for it to be considered a click.
|
|
27
27
|
* @property {boolean|number} [click.cancelOnMove=true] If true, don't generate
|
|
28
|
-
* click events if the mouse moved at all. If a positive number, the
|
|
29
|
-
* at which to cancel click events when the mouse moves.
|
|
28
|
+
* click events if the mouse moved at all. If a positive number, the
|
|
29
|
+
* distance at which to cancel click events when the mouse moves.
|
|
30
30
|
* @property {object} [keyboard] An object describing which keyboard events are
|
|
31
31
|
* handled.
|
|
32
32
|
* @property {object} [keyboard.actions] An object with different actions that
|
|
@@ -39,6 +39,9 @@ var Mousetrap = require('mousetrap');
|
|
|
39
39
|
* an object with keys of the meta keys that are required to be down or
|
|
40
40
|
* up for that scale action to trigger. If the value of the meta key is
|
|
41
41
|
* truthy, it must be down. If `false`, it must be up.
|
|
42
|
+
* @property {string[]} [keyboard.metakeyMouseEvents] A list of meta keys
|
|
43
|
+
* * that, when typed singly, trigger a repeat of the last mousemove or
|
|
44
|
+
* actionmove event so that listeners can update metakey information.
|
|
42
45
|
* @property {boolean} [keyboard.focusHighlight=true] If truthy, when the map
|
|
43
46
|
* gains focus, a highlight style is shown around it. This gives an
|
|
44
47
|
* indicator that keyboard events will affect the map, but may not be
|
|
@@ -131,6 +134,7 @@ var mapInteractor = function (args) {
|
|
|
131
134
|
m_boundKeys,
|
|
132
135
|
m_touchHandler,
|
|
133
136
|
m_state,
|
|
137
|
+
m_nextStateId = 0,
|
|
134
138
|
m_queue,
|
|
135
139
|
$node,
|
|
136
140
|
m_selectionLayer = null,
|
|
@@ -294,6 +298,10 @@ var mapInteractor = function (args) {
|
|
|
294
298
|
1: {shift: true, ctrl: true},
|
|
295
299
|
2: {shift: true, ctrl: false}
|
|
296
300
|
},
|
|
301
|
+
/* This is a list of meta keys that when typed singly trigger a repeat
|
|
302
|
+
* of the last mousemove or actionmove event so that listeners can
|
|
303
|
+
* update metakey information. */
|
|
304
|
+
metakeyMouseEvents: ['shift', 'ctrl', 'shift+ctrl', 'shift+alt', 'shift+meta'],
|
|
297
305
|
/* if focusHighlight is truthy, then a class is added to the map such
|
|
298
306
|
* that when the map gets focus, it is indicated inside the border of
|
|
299
307
|
* the map -- browsers usually show focus on the outside, which isn't
|
|
@@ -648,6 +656,35 @@ var mapInteractor = function (args) {
|
|
|
648
656
|
}
|
|
649
657
|
};
|
|
650
658
|
|
|
659
|
+
/**
|
|
660
|
+
* Repeat a mousemove or actionmove event with new metakey information.
|
|
661
|
+
*
|
|
662
|
+
* @param {event} [evt] A Mousetrap event with the key change.
|
|
663
|
+
* @fires geo.event.mousemove
|
|
664
|
+
* @fires geo.event.actionmove
|
|
665
|
+
*/
|
|
666
|
+
this._repeatMouseMoveEvent = function (evt) {
|
|
667
|
+
if (!m_mouse || !m_mouse.modifiers) {
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
const old = {
|
|
671
|
+
alt: m_mouse.modifiers.alt,
|
|
672
|
+
ctrl: m_mouse.modifiers.ctrl,
|
|
673
|
+
meta: m_mouse.modifiers.meta,
|
|
674
|
+
shift: m_mouse.modifiers.shift
|
|
675
|
+
};
|
|
676
|
+
m_this._getMouseModifiers(evt);
|
|
677
|
+
if (m_mouse.modifiers.alt === old.alt && m_mouse.modifiers.ctrl === old.ctrl && m_mouse.modifiers.meta === old.meta && m_mouse.modifiers.shift === old.shift) {
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
if (m_state.boundDocumentHandlers) {
|
|
681
|
+
m_this.map().geoTrigger(geo_event.actionmove, {
|
|
682
|
+
state: m_this.state(), mouse: m_this.mouse(), event: evt});
|
|
683
|
+
} else {
|
|
684
|
+
m_this.map().geoTrigger(geo_event.mousemove, m_this.mouse());
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
|
|
651
688
|
/**
|
|
652
689
|
* Retrigger a mouse movement with the current mouse state.
|
|
653
690
|
* @fires geo.event.mousemove
|
|
@@ -711,6 +748,13 @@ var mapInteractor = function (args) {
|
|
|
711
748
|
bound = bound.concat(m_options.keyboard.actions[keyAction]);
|
|
712
749
|
}
|
|
713
750
|
}
|
|
751
|
+
if (m_options.keyboard.metakeyMouseEvents) {
|
|
752
|
+
m_options.keyboard.metakeyMouseEvents.forEach((meta) => {
|
|
753
|
+
m_keyHandler.bind(meta, m_this._repeatMouseMoveEvent, 'keydown');
|
|
754
|
+
m_keyHandler.bind(meta, m_this._repeatMouseMoveEvent, 'keyup');
|
|
755
|
+
bound.push(meta);
|
|
756
|
+
});
|
|
757
|
+
}
|
|
714
758
|
m_boundKeys = bound;
|
|
715
759
|
}
|
|
716
760
|
$node.toggleClass(
|
|
@@ -1074,6 +1118,7 @@ var mapInteractor = function (args) {
|
|
|
1074
1118
|
};
|
|
1075
1119
|
|
|
1076
1120
|
// store the state object
|
|
1121
|
+
m_nextStateId += 1;
|
|
1077
1122
|
m_state = {
|
|
1078
1123
|
action: action,
|
|
1079
1124
|
actionRecord: actionRecord,
|
|
@@ -1081,6 +1126,7 @@ var mapInteractor = function (args) {
|
|
|
1081
1126
|
initialZoom: map.zoom(),
|
|
1082
1127
|
initialRotation: map.rotation(),
|
|
1083
1128
|
initialEventRotation: evt.rotation,
|
|
1129
|
+
stateId: m_nextStateId,
|
|
1084
1130
|
delta: {x: 0, y: 0}
|
|
1085
1131
|
};
|
|
1086
1132
|
|
|
@@ -2095,7 +2141,7 @@ var mapInteractor = function (args) {
|
|
|
2095
2141
|
preventDefault: function () {},
|
|
2096
2142
|
simulated: true
|
|
2097
2143
|
};
|
|
2098
|
-
m_keyHandler.trigger(keys);
|
|
2144
|
+
m_keyHandler.trigger(keys, options.event);
|
|
2099
2145
|
return;
|
|
2100
2146
|
}
|
|
2101
2147
|
|
package/src/registry.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
var $ = require('jquery');
|
|
2
|
+
var geo_action = require('./action');
|
|
3
|
+
|
|
2
4
|
var widgets = {
|
|
3
5
|
dom: {}
|
|
4
6
|
};
|
|
@@ -398,6 +400,7 @@ util.registerAnnotation = function (name, func, features) {
|
|
|
398
400
|
console.warn('The ' + name + ' annotation is already registered');
|
|
399
401
|
}
|
|
400
402
|
annotations[name] = {func: func, features: features || {}};
|
|
403
|
+
geo_action['annotation_' + name] = 'geo_annotation_' + name;
|
|
401
404
|
return old;
|
|
402
405
|
};
|
|
403
406
|
|
package/src/trackFeature.js
CHANGED
|
@@ -816,7 +816,9 @@ var trackFeature = function (arg) {
|
|
|
816
816
|
{
|
|
817
817
|
track: util.identityFunction,
|
|
818
818
|
position: util.identityFunction,
|
|
819
|
-
time: (d, i) => (d.t !== undefined ? d.t : i)
|
|
819
|
+
time: (d, i) => (d.t !== undefined ? d.t : i),
|
|
820
|
+
uniformLine: 'drop',
|
|
821
|
+
closed: false
|
|
820
822
|
},
|
|
821
823
|
arg.style === undefined ? {} : arg.style
|
|
822
824
|
);
|
package/src/util/polyops.js
CHANGED
|
@@ -327,16 +327,19 @@ function generateCorrespondence(poly1, poly2, newpoly, results) {
|
|
|
327
327
|
results[ekey] = Array(poly.length);
|
|
328
328
|
poly.forEach((p, idx) => {
|
|
329
329
|
const found = {};
|
|
330
|
+
let missed = 0;
|
|
330
331
|
p.forEach((h) => h.forEach((pt) => {
|
|
331
332
|
const key = '_' + pt[0] + '_' + pt[1];
|
|
332
333
|
if (pts[key]) {
|
|
333
334
|
pts[key].forEach((val) => {
|
|
334
335
|
found[val] = (found[val] || 0) + 1;
|
|
335
336
|
});
|
|
337
|
+
} else {
|
|
338
|
+
missed += 1;
|
|
336
339
|
}
|
|
337
340
|
}));
|
|
338
341
|
Object.keys(found).forEach((nidx) => {
|
|
339
|
-
if (found[nidx] === counts[+nidx]) {
|
|
342
|
+
if (found[nidx] === counts[+nidx] && !missed && p.length === newpoly[+nidx].length) {
|
|
340
343
|
if (!results[ekey][idx]) {
|
|
341
344
|
results[ekey][idx] = [];
|
|
342
345
|
}
|