diff --git a/CHANGELOG.md b/CHANGELOG.md index a42d79e91e..4b3ca1c3ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # GeoJS Change Log +## Version 1.10.6 + +### Improvements + +- Uncross polygon annotations ([#1236](../../pull/1236)) + ## Version 1.10.5 ### Improvements diff --git a/src/annotation/polygonAnnotation.js b/src/annotation/polygonAnnotation.js index eca5c7e6c6..28513c8bc4 100644 --- a/src/annotation/polygonAnnotation.js +++ b/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. * diff --git a/tests/cases/annotation.js b/tests/cases/annotation.js index b9b23a60ea..f01beab6ed 100644 --- a/tests/cases/annotation.js +++ b/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 () {