perf: Uncross polygon annotations.
MODIFY
CHANGELOG.md
CHANGELOG.md
# GeoJS Change Log
+## Version 1.10.6
+
+### Improvements
+
+- Uncross polygon annotations ([#1236](../../pull/1236))
+
## Version 1.10.5
### Improvements

MODIFY
src/annotation/polygonAnnotation.js
src/annotation/polygonAnnotation.js
@@ -72,7 +72,8 @@ var polygonAnnotation = function (args) {
annotation.call(this, 'polygon', args);
var m_this = this,
- s_actions = this.actions;
+ s_actions = this.actions,
+ s_state = this.state;
/**
* Get a list of renderable features for this annotation. When the polygon
@@ -245,6 +246,46 @@ var polygonAnnotation = function (args) {
return continuousVerticesActions(m_this, s_actions, state, 'polygon', arguments);
};
+ /**
+ * Get or set the state of this annotation.
+ *
+ * @param {string|undefined} [arg] If `undefined`, return the state,
+ * otherwise change it. This should be one of the
+ * {@link geo.annotation.state} values.
+ * @returns {this|string} The current state or this annotation.
+ * @fires geo.event.annotation.state
+ */
+ this.state = function (arg) {
+ const oldState = s_state();
+ if (arg && arg !== oldState && ((oldState === annotationState.create || oldState === annotationState.edit) && arg === annotationState.done)) {
+ /* Uncross polygons when they are complete. */
+ const opts = {style: 'object-listlist-outer-list'};
+ const polys = util.polyops.union(m_this.options('vertices'), [], opts);
+ let merged = true;
+ while (polys.length > 1 && merged) {
+ merged = false;
+ for (let i = 0; !merged && i < polys[0].outer.length; i += 1) {
+ const pt1 = polys[0].outer[i];
+ for (let p = 1; !merged && p < polys.length; p += 1) {
+ for (let j = 0; !merged && j < polys[p].outer.length; j += 1) {
+ const pt2 = polys[p].outer[j];
+ if (pt1.x === pt2.x && pt1.y === pt2.y) {
+ polys[0].inner = polys[0].inner.concat(polys[p].inner);
+ polys[0].outer = polys[0].outer.slice(0, i).concat(polys[p].outer.slice(j)).concat(polys[p].outer.slice(0, j)).concat(polys[0].outer.slice(i));
+ polys.splice(p, 1);
+ merged = true;
+ }
+ }
+ }
+ }
+ }
+ if (polys.length === 1) {
+ m_this.options('vertices', polys[0].inner.length ? polys[0] : polys[0].outer);
+ }
+ }
+ return s_state(arg);
+ };
+
/**
* Process any actions for this annotation.
*

MODIFY
tests/cases/annotation.js
tests/cases/annotation.js
@@ -1062,6 +1062,58 @@ describe('geo.annotation', function () {
expect(ann.options('vertices').length).toBe(3);
expect(ann.state()).toBe(geo.annotation.state.done);
});
+ it('crossed polygon', function () {
+ var map = createMap();
+ var layer = map.createLayer('annotation', {
+ annotations: ['polygon']
+ });
+ var ann = geo.annotation.polygonAnnotation({layer: layer});
+ var time = Date.now();
+ ann.state(geo.annotation.state.create);
+ ann.mouseClick({
+ buttonsDown: {left: true},
+ time: time,
+ map: {x: 10, y: 20},
+ mapgcs: map.displayToGcs({x: 10, y: 20}, null)
+ });
+ expect(ann.options('vertices').length).toBe(2);
+ ann.mouseClick({
+ buttonsDown: {left: true},
+ time: time,
+ map: {x: 50, y: 20},
+ mapgcs: map.displayToGcs({x: 50, y: 20}, null)
+ });
+ expect(ann.options('vertices').length).toBe(3);
+ ann.mouseClick({
+ buttonsDown: {left: true},
+ time: time,
+ map: {x: 40, y: 30},
+ mapgcs: map.displayToGcs({x: 40, y: 30}, null)
+ });
+ expect(ann.options('vertices').length).toBe(4);
+ ann.mouseClick({
+ buttonsDown: {left: true},
+ time: time,
+ map: {x: 30, y: 10},
+ mapgcs: map.displayToGcs({x: 30, y: 10}, null)
+ });
+ expect(ann.options('vertices').length).toBe(5);
+ ann.mouseClick({
+ buttonsDown: {left: true},
+ time: time,
+ map: {x: 20, y: 30},
+ mapgcs: map.displayToGcs({x: 20, y: 30}, null)
+ });
+ expect(ann.options('vertices').length).toBe(6);
+ ann.mouseClick({
+ buttonsDown: {left: true},
+ time: time,
+ map: {x: 10, y: 20},
+ mapgcs: map.displayToGcs({x: 10, y: 20}, null)
+ });
+ expect(ann.options('vertices').length).toBe(9);
+ expect(ann.state()).toBe(geo.annotation.state.done);
+ });
});
describe('geo.annotation.polygonAnnotation with holes', function () {

perf: Uncross polygon annotations.