geojs 1.9.3 → 1.10.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geojs",
3
- "version": "1.9.3",
3
+ "version": "1.10.1",
4
4
  "description": "JavaScript Geo Visualization and Analysis Library",
5
5
  "homepage": "https://github.com/OpenGeoscience/geojs",
6
6
  "license": "Apache-2.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
 
@@ -184,6 +184,15 @@ var annotationLayer = function (arg) {
184
184
  }
185
185
  }
186
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;
187
196
  default:
188
197
  update = m_this.currentAnnotation.processAction(evt);
189
198
  break;
@@ -261,7 +270,7 @@ var annotationLayer = function (arg) {
261
270
  * @param {geo.event} evt The mouse move or click event.
262
271
  */
263
272
  this._handleMouseMoveModifiers = function (evt) {
264
- 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)) {
265
274
  if (evt.modifiers) {
266
275
  const mod = (evt.modifiers.shift ? 's' : '') + (evt.modifiers.ctrl ? 'c' : '') + (evt.modifiers.meta || evt.modifiers.alt ? 'a' : '');
267
276
  if (m_this._currentBooleanClass === m_this._booleanClasses[mod]) {
@@ -392,6 +401,13 @@ var annotationLayer = function (arg) {
392
401
  update = m_this.currentAnnotation.mouseClick(evt);
393
402
  m_this._updateFromEvent(update);
394
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
+ }
395
411
  } else if (!m_this.mode() && !m_this.currentAnnotation && m_this.options('clickToEdit')) {
396
412
  var highlighted = m_this.annotations().filter(function (ann) {
397
413
  return ann.state() === geo_annotation.state.highlight;
@@ -481,6 +497,9 @@ var annotationLayer = function (arg) {
481
497
  this.addAnnotation = function (annotation, gcs, update) {
482
498
  var pos = $.inArray(annotation, m_annotations);
483
499
  if (pos < 0) {
500
+ while (m_this.annotationById(annotation.id())) {
501
+ annotation.newId();
502
+ }
484
503
  m_this.geoTrigger(geo_event.annotation.add_before, {
485
504
  annotation: annotation
486
505
  });
@@ -588,7 +607,8 @@ var annotationLayer = function (arg) {
588
607
 
589
608
  /* A list of special modes */
590
609
  this.modes = {
591
- edit: 'edit'
610
+ edit: 'edit',
611
+ cursor: 'cursor'
592
612
  };
593
613
 
594
614
  /* Keys are short-hand for preferred event modifiers. Values are classes to
@@ -605,11 +625,13 @@ var annotationLayer = function (arg) {
605
625
  *
606
626
  * @param {string|null} [arg] `undefined` to get the current mode, `null` to
607
627
  * stop creating/editing, `this.modes.edit` (`'edit'`) plus an annotation
608
- * to switch to edit mode, or the name of the type of annotation to
609
- * 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
610
631
  * {@link geo.listAnnotations}.
611
- * @param {geo.annotation} [editAnnotation] If `arg === this.modes.edit`,
612
- * 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.
613
635
  * @param {object} [options] Additional options to pass when creating an
614
636
  * annotation.
615
637
  * @returns {string|null|this} The current mode or the layer.
@@ -619,11 +641,14 @@ var annotationLayer = function (arg) {
619
641
  if (arg === undefined) {
620
642
  return m_mode;
621
643
  }
622
- 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
+ ) {
623
648
  var createAnnotation, actions,
624
649
  mapNode = m_this.map().node(), oldMode = m_mode;
625
650
  m_mode = arg;
626
- 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));
627
652
  if (!m_mode || m_mode === m_this.modes.edit) {
628
653
  Object.values(m_this._booleanClasses).forEach((c) => mapNode.toggleClass(c, false));
629
654
  m_this._currentBooleanClass = undefined;
@@ -646,6 +671,12 @@ var annotationLayer = function (arg) {
646
671
  m_this.modified();
647
672
  m_this.draw();
648
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;
649
680
  }
650
681
  m_this.currentAnnotation = null;
651
682
  }
@@ -653,6 +684,12 @@ var annotationLayer = function (arg) {
653
684
  m_this.currentAnnotation = editAnnotation;
654
685
  m_this.currentAnnotation.state(geo_annotation.state.edit);
655
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);
656
693
  } else if (registry.registries.annotations[m_mode]) {
657
694
  createAnnotation = registry.registries.annotations[m_mode].func;
658
695
  }
@@ -666,13 +703,15 @@ var annotationLayer = function (arg) {
666
703
  m_this.currentAnnotation = createAnnotation(options);
667
704
  m_this.addAnnotation(m_this.currentAnnotation, null);
668
705
  actions = m_this.currentAnnotation.actions(geo_annotation.state.create);
706
+ }
707
+ if (actions) {
669
708
  $.each(actions, function (idx, action) {
670
709
  m_this.map().interactor().addAction(action);
671
710
  });
672
711
  }
673
712
  m_this.geoTrigger(geo_event.annotation.mode, {
674
713
  mode: m_mode, oldMode: oldMode});
675
- if (oldMode === m_this.modes.edit) {
714
+ if (oldMode === m_this.modes.edit || oldMode === m_this.modes.cursor) {
676
715
  m_this.modified();
677
716
  }
678
717
  }
@@ -1258,11 +1297,15 @@ var annotationLayer = function (arg) {
1258
1297
  this.toPolygonList = function (opts) {
1259
1298
  const poly = [];
1260
1299
  opts = opts || {};
1261
- opts.annotationIndices = [];
1300
+ const indices = [];
1301
+ if (!opts.annotationIndices) {
1302
+ opts.annotationIndices = {};
1303
+ }
1304
+ opts.annotationIndices[m_this.id()] = indices;
1262
1305
  m_annotations.forEach((annotation, idx) => {
1263
1306
  if (annotation.toPolygonList) {
1264
1307
  annotation.toPolygonList(opts).forEach((p) => poly.push(p));
1265
- opts.annotationIndices.push(idx);
1308
+ indices.push(idx);
1266
1309
  }
1267
1310
  });
1268
1311
  return poly;
@@ -1285,14 +1328,15 @@ var annotationLayer = function (arg) {
1285
1328
  const keepIds = {};
1286
1329
  const reusedIds = {};
1287
1330
  let correspond, exact, annot;
1288
- 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) {
1289
1333
  correspond = opts.correspond.poly1;
1290
1334
  exact = opts.correspond.exact1;
1291
1335
  annot = m_this.annotations();
1292
1336
  }
1293
- if (keep !== 'all' && keep !== 'none') {
1337
+ if (keep !== 'all' && keep !== 'none' && annot) {
1294
1338
  annot.forEach((oldAnnot, idx) => {
1295
- if (opts.annotationIndices.indexOf(idx) < 0) {
1339
+ if (indices.indexOf(idx) < 0) {
1296
1340
  keepIds[oldAnnot.id()] = true;
1297
1341
  }
1298
1342
  });
@@ -1306,7 +1350,7 @@ var annotationLayer = function (arg) {
1306
1350
  if (correspond) {
1307
1351
  for (let i = 0; i < correspond.length; i += 1) {
1308
1352
  if (correspond[i] && correspond[i].indexOf(idx) >= 0) {
1309
- const orig = annot[opts.annotationIndices[i]];
1353
+ const orig = annot[indices[i]];
1310
1354
  if (keep !== 'all' && keep !== 'none' && exact && exact[i] && exact[i].indexOf(idx) >= 0) {
1311
1355
  keepIds[orig.id()] = true;
1312
1356
  return;
@@ -1343,7 +1387,7 @@ var annotationLayer = function (arg) {
1343
1387
  }
1344
1388
  // add new annotations
1345
1389
  polyAnnot.forEach((p) => {
1346
- m_this.addAnnotation(registry.createAnnotation('polygon', p), m_this.gcs(), false);
1390
+ m_this.addAnnotation(registry.createAnnotation('polygon', p), m_this.map().gcs(), false);
1347
1391
  update = true;
1348
1392
  });
1349
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/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/map.js CHANGED
@@ -407,18 +407,22 @@ var map = function (arg) {
407
407
  * center.
408
408
  * @param {boolean} [ignoreDiscreteZoom] If `true`, ignore the discreteZoom
409
409
  * option when determining the new view.
410
+ * @param {boolean} [ignoreClampBounds] If `true`, ignore the clampBounds
411
+ * option when determining the new view.
410
412
  * @returns {number|this}
411
413
  * @fires geo.event.zoom
412
414
  * @fires geo.event.pan
413
415
  */
414
- this.zoom = function (val, origin, ignoreDiscreteZoom) {
416
+ this.zoom = function (val, origin, ignoreDiscreteZoom, ignoreClampBounds) {
415
417
  if (val === undefined) {
416
418
  return m_zoom;
417
419
  }
418
420
  var evt, bounds;
419
421
  /* If we are zooming around a point, ignore the clamp bounds */
420
422
  var aroundPoint = (origin && (origin.mapgcs || origin.geo) && origin.map);
421
- var ignoreClampBounds = aroundPoint;
423
+ if (aroundPoint) {
424
+ ignoreClampBounds = true;
425
+ }
422
426
 
423
427
  /* The ignoreDiscreteZoom flag is intended to allow non-integer zoom values
424
428
  * during animation. */
@@ -446,7 +450,7 @@ var map = function (arg) {
446
450
  m_this.pan({x: origin.map.x - shifted.x, y: origin.map.y - shifted.y},
447
451
  ignoreDiscreteZoom, true);
448
452
  } else {
449
- m_this.pan({x: 0, y: 0}, ignoreDiscreteZoom);
453
+ m_this.pan({x: 0, y: 0}, ignoreDiscreteZoom, ignoreClampBounds);
450
454
  }
451
455
  return m_this;
452
456
  };
@@ -1101,6 +1105,8 @@ var map = function (arg) {
1101
1105
  * a value based on what canceled a transition, `transition`: the current
1102
1106
  * transition that just completed, `next`: a boolean if another transition
1103
1107
  * follows immediately.
1108
+ * @param {boolean} [opts.endClamp=true] If `false`, the last center change
1109
+ * will not clamp to the bounds and zoom values.
1104
1110
  * @param {string|geo.transform|null} [gcs] Input gcs. `undefined` to use
1105
1111
  * the interface gcs, `null` to use the map gcs, or any other transform.
1106
1112
  * Applies only to `opts.center` and to converting zoom values to height,
@@ -1205,7 +1211,8 @@ var map = function (arg) {
1205
1211
  zCoord: opts.zCoord,
1206
1212
  done: opts.done,
1207
1213
  duration: opts.duration,
1208
- zoomOrigin: opts.zoomOrigin
1214
+ zoomOrigin: opts.zoomOrigin,
1215
+ endClamp: opts.endClamp
1209
1216
  };
1210
1217
 
1211
1218
  m_transition.interp = opts.interp([
@@ -1260,9 +1267,10 @@ var map = function (arg) {
1260
1267
  if (!next) {
1261
1268
  if (m_transition.end.center) {
1262
1269
  var needZoom = m_zoom !== m_this._fix_zoom(m_transition.end.zoom);
1263
- m_this.center(m_transition.end.center, null, needZoom, needZoom);
1270
+ var noEndClamp = needZoom || opts.endClamp === false;
1271
+ m_this.center(m_transition.end.center, null, noEndClamp, noEndClamp);
1264
1272
  }
1265
- m_this.zoom(m_transition.end.zoom, m_transition.zoomOrigin);
1273
+ m_this.zoom(m_transition.end.zoom, m_transition.zoomOrigin, opts.endClamp === false, opts.endClamp === false);
1266
1274
  m_this.rotation(fix_rotation(m_transition.end.rotation));
1267
1275
  }
1268
1276
 
@@ -1297,7 +1305,7 @@ var map = function (arg) {
1297
1305
  }, null, true, true);
1298
1306
  } else {
1299
1307
  m_center = m_this.gcsToWorld({x: p[0], y: p[1]}, null);
1300
- m_this.zoom(p[2], m_transition.zoomOrigin, true);
1308
+ m_this.zoom(p[2], m_transition.zoomOrigin, true, true);
1301
1309
  }
1302
1310
  m_this.rotation(p[3], undefined, true);
1303
1311
 
@@ -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
 
@@ -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
  }