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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geojs",
3
- "version": "1.9.2",
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": "^1.7.0",
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.57.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
- annotation_line: 'geo_annotation_line',
21
- annotation_polygon: 'geo_annotation_polygon',
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`, or
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='highlightHandleStyle'`.
574
- * @function highlightHandleStyle
629
+ * Calls {@link geo.annotation#style} with `styleType='highlightStyle'`.
630
+ * @function highlightStyle
575
631
  * @memberof geo.annotation
576
632
  * @instance
577
633
  */
578
- ['createStyle', 'editStyle', 'editHandleStyle', 'labelStyle', 'highlightStyle'
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
 
@@ -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, or the name of the type of annotation to
598
- * create. Available annotations can listed via
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 edited.
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 || (arg === m_this.modes.edit && editAnnotation !== m_this.editAnnotation) || (arg !== m_this.modes.edit && arg && !m_this.currentAnnotation)) {
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
- opts.annotationIndices = [];
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
- opts.annotationIndices.push(idx);
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.spec} [opts] This contains annotationIndices and
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
- if (opts.annotationIndices && opts.correspond && opts.correspond.poly1 && opts.annotationIndices.length === opts.correspond.poly1.length) {
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 (opts.annotationIndices.indexOf(idx) < 0) {
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[opts.annotationIndices[i]];
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;
@@ -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 if each
50
- * line has a uniform style (uniform stroke color, opacity, and width). Can
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 ""
@@ -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 distance
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
 
@@ -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
  );
@@ -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
  }