From 467b263fc0d82673c2907eb3ccbd664f6b18c0fb Mon Sep 17 00:00:00 2001 From: David Manthey Date: Tue, 2 Jan 2018 08:43:30 -0500 Subject: [PATCH 1/5] Use the average perimeter as the center of a polygon or line. When a polygon has many points near each other in one area and few along the opposite part of the perimeter, this produces a nicer center. --- src/annotation.js | 37 +++++++++++++++++++++++++++---------- tests/cases/annotation.js | 4 +++- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/annotation.js b/src/annotation.js index 0cf9e0b16c..bc2a923d24 100644 --- a/src/annotation.js +++ b/src/annotation.js @@ -131,26 +131,43 @@ var annotation = function (type, args) { }; /** - * Return the coordinate associated with the label. + * Return the coordinate associated with the center of the annotation. * - * @returns {geo.geoPosition|undefined} The map gcs position for the label, + * @returns {geo.geoPosition|undefined} The map gcs position for the center, * or `undefined` if no such position exists. */ - this._labelPosition = function () { - var coor = this._coordinates(), position = {x: 0, y: 0}, i; + this._centerPosition = function () { + var coor = this._coordinates(), position, p0, p1, w, sumw, i; if (!coor || !coor.length) { return undefined; } if (coor.length === 1) { return coor[0]; } + position = {x: 0, y: 0}; + sumw = 0; + p0 = coor[coor.length - 1]; for (i = 0; i < coor.length; i += 1) { - position.x += coor[i].x; - position.y += coor[i].y; - } - position.x /= coor.length; - position.y /= coor.length; - return position; + p1 = p0; + p0 = coor[i]; + w = Math.sqrt(Math.pow(p1.x - p0.x, 2) + Math.pow(p1.y - p0.y, 2)); + position.x += (p0.x + p1.x) * w; + position.y += (p0.y + p1.y) * w; + sumw += 2 * w; + } + position.x /= sumw; + position.y /= sumw; + return sumw ? position : p0; // return p0 if all points are the same + }; + + /** + * Return the coordinate associated with the label. + * + * @returns {geo.geoPosition|undefined} The map gcs position for the label, + * or `undefined` if no such position exists. + */ + this._labelPosition = function () { + return this._centerPosition(); }; /** diff --git a/tests/cases/annotation.js b/tests/cases/annotation.js index 18751b2b5c..f4f983debe 100644 --- a/tests/cases/annotation.js +++ b/tests/cases/annotation.js @@ -257,7 +257,9 @@ describe('geo.annotation', function () { ann._coordinates = function () { return [{x: 1, y: 2}, {x: 3, y: 5}, {x: 8, y: 11}]; }; - expect(ann._labelPosition()).toEqual({x: 4, y: 6}); + var pos = ann._labelPosition(); + expect(pos.x).toBeCloseTo(4.447); + expect(pos.y).toBeCloseTo(6.539); }); it('labelRecord', function () { var ann = geo.annotation.annotation('test', { From bff9e1aa980758436c7643aaf6f0058610e3bec6 Mon Sep 17 00:00:00 2001 From: David Manthey Date: Tue, 16 Jan 2018 16:33:44 -0500 Subject: [PATCH 2/5] Move and rename function to util.centerFromPerimeter. Add more tests. --- src/annotation.js | 32 +------------------------------- src/util/index.js | 33 +++++++++++++++++++++++++++++++++ tests/cases/util.js | 13 +++++++++++++ 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/annotation.js b/src/annotation.js index bc2a923d24..2ead4bbcb1 100644 --- a/src/annotation.js +++ b/src/annotation.js @@ -130,36 +130,6 @@ var annotation = function (type, args) { return this; }; - /** - * Return the coordinate associated with the center of the annotation. - * - * @returns {geo.geoPosition|undefined} The map gcs position for the center, - * or `undefined` if no such position exists. - */ - this._centerPosition = function () { - var coor = this._coordinates(), position, p0, p1, w, sumw, i; - if (!coor || !coor.length) { - return undefined; - } - if (coor.length === 1) { - return coor[0]; - } - position = {x: 0, y: 0}; - sumw = 0; - p0 = coor[coor.length - 1]; - for (i = 0; i < coor.length; i += 1) { - p1 = p0; - p0 = coor[i]; - w = Math.sqrt(Math.pow(p1.x - p0.x, 2) + Math.pow(p1.y - p0.y, 2)); - position.x += (p0.x + p1.x) * w; - position.y += (p0.y + p1.y) * w; - sumw += 2 * w; - } - position.x /= sumw; - position.y /= sumw; - return sumw ? position : p0; // return p0 if all points are the same - }; - /** * Return the coordinate associated with the label. * @@ -167,7 +137,7 @@ var annotation = function (type, args) { * or `undefined` if no such position exists. */ this._labelPosition = function () { - return this._centerPosition(); + return util.centerFromPerimeter(this._coordinates()); }; /** diff --git a/src/util/index.js b/src/util/index.js index 6138ffe350..7ddeec75fa 100644 --- a/src/util/index.js +++ b/src/util/index.js @@ -745,6 +745,39 @@ var util = module.exports = { return {map: mapParams, layer: layerParams}; }, + /** + * Return the coordinate associated with the center of the perimeter formed + * from a list of points. + * + * @param {geo.geoPosition[]} coor An array of coordinates. + * @returns {geo.geoPosition|undefined} The position for the center, or + * `undefined` if no such position exists. + */ + centerFromPerimeter: function (coor) { + var position, p0, p1, w, sumw, i; + if (!coor || !coor.length) { + return; + } + if (coor.length === 1) { + return {x: coor[0].x, y: coor[0].y}; + } + position = {x: 0, y: 0}; + sumw = 0; + p0 = coor[coor.length - 1]; + for (i = 0; i < coor.length; i += 1) { + p1 = p0; + p0 = coor[i]; + w = Math.sqrt(Math.pow(p1.x - p0.x, 2) + Math.pow(p1.y - p0.y, 2)); + position.x += (p0.x + p1.x) * w; + position.y += (p0.y + p1.y) * w; + sumw += 2 * w; + } + position.x /= sumw; + position.y /= sumw; + // return a copy of p0 if all points are the same + return sumw ? position : {x: p0.x, y: p0.y}; + }, + /** * Escape any character in a string that has a code point >= 127. * diff --git a/tests/cases/util.js b/tests/cases/util.js index e860526eff..20cda76e5b 100644 --- a/tests/cases/util.js +++ b/tests/cases/util.js @@ -32,4 +32,17 @@ describe('geo.util', function () { expect(({}) instanceof iframeWindow.Object).toBe(false); iframe.remove(); }); + + it('centerFromPerimter', function () { + expect(util.centerFromPerimeter()).toBe(undefined); + expect(util.centerFromPerimeter([])).toBe(undefined); + expect(util.centerFromPerimeter([{x: 1, y: 1}])).toEqual({x: 1, y: 1}); + expect(util.centerFromPerimeter([{x: 1, y: 1}, {x: 1, y: 1}])).toEqual({x: 1, y: 1}); + expect(util.centerFromPerimeter([ + {x: 1, y: 1}, {x: 3, y: 1}, {x: 3, y: 3}, {x: 1, y: 3} + ])).toEqual({x: 2, y: 2}); + expect(util.centerFromPerimeter([ + {x: 1, y: 1}, {x: 3, y: 1}, {x: 5, y: 1}, {x: 5, y: 3}, {x: 1, y: 3} + ])).toEqual({x: 3, y: 2}); + }); }); From 9171e60d5fa6963b48616efd249ccd4c102eed78 Mon Sep 17 00:00:00 2001 From: David Manthey Date: Fri, 19 Jan 2018 16:50:43 -0500 Subject: [PATCH 3/5] Shift many references of this to m_this. This removes the burden on binding events to the class instance. --- src/annotation.js | 253 +++++++++++++++++++++-------------------- src/annotationLayer.js | 89 +++++++-------- 2 files changed, 174 insertions(+), 168 deletions(-) diff --git a/src/annotation.js b/src/annotation.js index 2ead4bbcb1..f1585696c0 100644 --- a/src/annotation.js +++ b/src/annotation.js @@ -45,7 +45,8 @@ var annotation = function (type, args) { return new annotation(type, args); } - var m_options = $.extend({}, {showLabel: true}, args || {}), + var m_this = this, + m_options = $.extend({}, {showLabel: true}, args || {}), m_id = m_options.annotationId; delete m_options.annotationId; if (m_id === undefined || (m_options.layer && m_options.layer.annotationById(m_id))) { @@ -104,10 +105,10 @@ var annotation = function (type, args) { arg = ('' + arg).trim(); if (arg !== m_name) { m_name = arg; - this.modified(); + m_this.modified(); } } - return this; + return m_this; }; /** @@ -125,9 +126,9 @@ var annotation = function (type, args) { } if (arg !== m_label) { m_label = arg; - this.modified(); + m_this.modified(); } - return this; + return m_this; }; /** @@ -137,7 +138,7 @@ var annotation = function (type, args) { * or `undefined` if no such position exists. */ this._labelPosition = function () { - return util.centerFromPerimeter(this._coordinates()); + return util.centerFromPerimeter(m_this._coordinates()); }; /** @@ -148,19 +149,19 @@ var annotation = function (type, args) { * `undefined` if it should not be shown. */ this.labelRecord = function () { - var show = this.options('showLabel'); + var show = m_this.options('showLabel'); if (!show) { return; } - var state = this.state(); + var state = m_this.state(); if ((show === true && state === annotationState.create) || (show !== true && show.indexOf(state) < 0)) { return; } - var style = this.options('labelStyle'); + var style = m_this.options('labelStyle'); var labelRecord = { - text: this.label(), - position: this._labelPosition() + text: m_this.label(), + position: m_this._labelPosition() }; if (!labelRecord.position) { return; @@ -184,9 +185,9 @@ var annotation = function (type, args) { } if (arg !== m_description) { m_description = arg; - this.modified(); + m_this.modified(); } - return this; + return m_this; }; /** @@ -201,7 +202,7 @@ var annotation = function (type, args) { return m_layer; } m_layer = arg; - return this; + return m_this; }; /** @@ -218,13 +219,13 @@ var annotation = function (type, args) { } if (m_state !== arg) { m_state = arg; - if (this.layer()) { - this.layer().geoTrigger(geo_event.annotation.state, { + if (m_this.layer()) { + m_this.layer().geoTrigger(geo_event.annotation.state, { annotation: this }); } } - return this; + return m_this; }; /** @@ -284,24 +285,24 @@ var annotation = function (type, args) { if (m_options.coordinates) { var coor = m_options.coordinates; delete m_options.coordinates; - this._coordinates(coor); + m_this._coordinates(coor); } if (m_options.name !== undefined) { var name = m_options.name; delete m_options.name; - this.name(name); + m_this.name(name); } if (m_options.label !== undefined) { var label = m_options.label; delete m_options.label; - this.label(label); + m_this.label(label); } if (m_options.description !== undefined) { var description = m_options.description; delete m_options.description; - this.description(description); + m_this.description(description); } - this.modified(); + m_this.modified(); return this; }; @@ -329,8 +330,8 @@ var annotation = function (type, args) { } else { m_options.style[arg1] = arg2; } - this.modified(); - return this; + m_this.modified(); + return m_this; }; /** @@ -357,8 +358,8 @@ var annotation = function (type, args) { } else { m_options.editStyle[arg1] = arg2; } - this.modified(); - return this; + m_this.modified(); + return m_this; }; /** @@ -428,9 +429,9 @@ var annotation = function (type, args) { * @returns {geo.geoPosition[]} An array of coordinates. */ this.coordinates = function (gcs) { - var coord = this._coordinates() || []; - if (this.layer()) { - var map = this.layer().map(); + var coord = m_this._coordinates() || []; + if (m_this.layer()) { + var map = m_this.layer().map(); gcs = (gcs === null ? map.gcs() : ( gcs === undefined ? map.ingcs() : gcs)); if (gcs !== map.gcs()) { @@ -447,10 +448,10 @@ var annotation = function (type, args) { * @returns {this} The annotation. */ this.modified = function () { - if (this.layer()) { - this.layer().modified(); + if (m_this.layer()) { + m_this.layer().modified(); } - return this; + return m_this; }; /** @@ -459,11 +460,11 @@ var annotation = function (type, args) { * @returns {this} The annotation. */ this.draw = function () { - if (this.layer()) { - this.layer()._update(); - this.layer().draw(); + if (m_this.layer()) { + m_this.layer()._update(); + m_this.layer().draw(); } - return this; + return m_this; }; /** @@ -510,11 +511,11 @@ var annotation = function (type, args) { * should not be represented (for instance, while it is being created). */ this.geojson = function (gcs, includeCrs) { - var coor = this._geojsonCoordinates(gcs), - geotype = this._geojsonGeometryType(), - styles = this._geojsonStyles(), - objStyle = this.options('style') || {}, - objLabelStyle = this.options('labelStyle') || {}, + var coor = m_this._geojsonCoordinates(gcs), + geotype = m_this._geojsonGeometryType(), + styles = m_this._geojsonStyles(), + objStyle = m_this.options('style') || {}, + objLabelStyle = m_this.options('labelStyle') || {}, i, key, value; if (!coor || !coor.length || !geotype) { return; @@ -527,8 +528,8 @@ var annotation = function (type, args) { }, properties: { annotationType: m_type, - name: this.name(), - annotationId: this.id() + name: m_this.name(), + annotationId: m_this.id() } }; if (m_label) { @@ -537,8 +538,8 @@ var annotation = function (type, args) { if (m_description) { obj.properties.description = m_description; } - if (this.options('showLabel') === false) { - obj.properties.showLabel = this.options('showLabel'); + if (m_this.options('showLabel') === false) { + obj.properties.showLabel = m_this.options('showLabel'); } for (i = 0; i < styles.length; i += 1) { key = styles[i]; @@ -561,7 +562,7 @@ var annotation = function (type, args) { } } if (includeCrs) { - var map = this.layer().map(); + var map = m_this.layer().map(); gcs = (gcs === null ? map.gcs() : ( gcs === undefined ? map.ingcs() : gcs)); obj.crs = { @@ -643,6 +644,9 @@ var rectangleAnnotation = function (args) { delete args.coordinates; annotation.call(this, 'rectangle', args); + var m_this = this, + s_actions = this.actions; + /** * Return actions needed for the specified state of this annotation. * @@ -652,7 +656,7 @@ var rectangleAnnotation = function (args) { */ this.actions = function (state) { if (!state) { - state = this.state(); + state = m_this.state(); } switch (state) { case annotationState.create: @@ -665,7 +669,7 @@ var rectangleAnnotation = function (args) { selectionRectangle: true }]; default: - return []; + return s_actions.apply(this, arguments); } }; @@ -679,21 +683,22 @@ var rectangleAnnotation = function (args) { * anything. */ this.processAction = function (evt) { - var layer = this.layer(); - if (this.state() !== annotationState.create || !layer || + var layer = m_this.layer(); + if (m_this.state() !== annotationState.create || !layer || evt.event !== geo_event.actionselection || evt.state.action !== geo_action.annotation_rectangle) { return; } - var map = layer.map(); - this.options('corners', [ - /* Keep in map gcs, not interface gcs to avoid wrapping issues */ - map.displayToGcs({x: evt.lowerLeft.x, y: evt.lowerLeft.y}, null), - map.displayToGcs({x: evt.lowerLeft.x, y: evt.upperRight.y}, null), - map.displayToGcs({x: evt.upperRight.x, y: evt.upperRight.y}, null), - map.displayToGcs({x: evt.upperRight.x, y: evt.lowerLeft.y}, null) - ]); - this.state(annotationState.done); + var map = layer.map(), + corners = [ + /* Keep in map gcs, not interface gcs to avoid wrapping issues */ + map.displayToGcs({x: evt.lowerLeft.x, y: evt.lowerLeft.y}, null), + map.displayToGcs({x: evt.lowerLeft.x, y: evt.upperRight.y}, null), + map.displayToGcs({x: evt.upperRight.x, y: evt.upperRight.y}, null), + map.displayToGcs({x: evt.upperRight.x, y: evt.lowerLeft.y}, null) + ]; + m_this.options('corners', corners); + m_this.state(annotationState.done); return 'done'; }; @@ -703,8 +708,8 @@ var rectangleAnnotation = function (args) { * @returns {array} An array of features. */ this.features = function () { - var opt = this.options(), - state = this.state(), + var opt = m_this.options(), + state = m_this.state(), features; switch (state) { case annotationState.create: @@ -740,11 +745,11 @@ var rectangleAnnotation = function (args) { */ this._coordinates = function (coordinates) { if (coordinates && coordinates.length >= 4) { - this.options('corners', coordinates.slice(0, 4)); + m_this.options('corners', coordinates.slice(0, 4)); /* Should we ensure that the four points form a rectangle in the current * projection, though this might not be rectangular in another gcs? */ } - return this.options('corners'); + return m_this.options('corners'); }; /** @@ -756,8 +761,8 @@ var rectangleAnnotation = function (args) { * coordinate system. `undefined` if this annotation is incomplete. */ this._geojsonCoordinates = function (gcs) { - var src = this.coordinates(gcs); - if (!src || this.state() === annotationState.create || src.length < 4) { + var src = m_this.coordinates(gcs); + if (!src || m_this.state() === annotationState.create || src.length < 4) { return; } var coor = []; @@ -796,7 +801,7 @@ var rectangleAnnotation = function (args) { * @param {geo.event} evt The mouse move event. */ this._setCornersFromMouse = function (corners, evt) { - var map = this.layer().map(), + var map = m_this.layer().map(), c0 = map.gcsToDisplay({x: corners[0].x, y: corners[0].y}, null), c2 = map.gcsToDisplay(evt.mapgcs, null), c1 = {x: c2.x, y: c0.y}, @@ -814,12 +819,12 @@ var rectangleAnnotation = function (args) { * update anything. */ this.mouseMove = function (evt) { - if (this.state() !== annotationState.create) { + if (m_this.state() !== annotationState.create) { return; } - var corners = this.options('corners'); + var corners = m_this.options('corners'); if (corners.length) { - this._setCornersFromMouse(corners, evt); + m_this._setCornersFromMouse(corners, evt); return true; } }; @@ -835,21 +840,21 @@ var rectangleAnnotation = function (args) { * anything. */ this.mouseClick = function (evt) { - var layer = this.layer(); - if (this.state() !== annotationState.create || !layer) { + var layer = m_this.layer(); + if (m_this.state() !== annotationState.create || !layer) { return; } if (!evt.buttonsDown.left && !evt.buttonsDown.right) { return; } - var corners = this.options('corners'); + var corners = m_this.options('corners'); if (evt.buttonsDown.right && !corners.length) { return; } evt.handled = true; if (corners.length) { - this._setCornersFromMouse(corners, evt); - this.state(annotationState.done); + m_this._setCornersFromMouse(corners, evt); + m_this.state(annotationState.done); return 'done'; } if (evt.buttonsDown.left) { @@ -906,8 +911,6 @@ var polygonAnnotation = function (args) { return new polygonAnnotation(args); } - var m_this = this; - args = $.extend(true, {}, { style: { fill: true, @@ -946,6 +949,8 @@ var polygonAnnotation = function (args) { delete args.coordinates; annotation.call(this, 'polygon', args); + var m_this = this; + /** * Get a list of renderable features for this annotation. When the polygon * is done, this is just a single polygon. During creation this can be a @@ -954,8 +959,8 @@ var polygonAnnotation = function (args) { * @returns {array} An array of features. */ this.features = function () { - var opt = this.options(), - state = this.state(), + var opt = m_this.options(), + state = m_this.state(), features; switch (state) { case annotationState.create: @@ -999,9 +1004,9 @@ var polygonAnnotation = function (args) { */ this._coordinates = function (coordinates) { if (coordinates) { - this.options('vertices', coordinates); + m_this.options('vertices', coordinates); } - return this.options('vertices'); + return m_this.options('vertices'); }; /** @@ -1012,10 +1017,10 @@ var polygonAnnotation = function (args) { * update anything. */ this.mouseMove = function (evt) { - if (this.state() !== annotationState.create) { + if (m_this.state() !== annotationState.create) { return; } - var vertices = this.options('vertices'); + var vertices = m_this.options('vertices'); if (vertices.length) { vertices[vertices.length - 1] = evt.mapgcs; return true; @@ -1033,15 +1038,15 @@ var polygonAnnotation = function (args) { * anything. */ this.mouseClick = function (evt) { - var layer = this.layer(); - if (this.state() !== annotationState.create || !layer) { + var layer = m_this.layer(); + if (m_this.state() !== annotationState.create || !layer) { return; } var end = !!evt.buttonsDown.right, skip; if (!evt.buttonsDown.left && !evt.buttonsDown.right) { return; } - var vertices = this.options('vertices'); + var vertices = m_this.options('vertices'); if (evt.buttonsDown.right && !vertices.length) { return; } @@ -1076,7 +1081,7 @@ var polygonAnnotation = function (args) { return 'remove'; } vertices.pop(); - this.state(annotationState.done); + m_this.state(annotationState.done); return 'done'; } return (end || !skip); @@ -1091,8 +1096,8 @@ var polygonAnnotation = function (args) { * coordinate system. `undefined` if this annotation is incomplete. */ this._geojsonCoordinates = function (gcs) { - var src = this.coordinates(gcs); - if (!src || src.length < 3 || this.state() === annotationState.create) { + var src = m_this.coordinates(gcs); + if (!src || src.length < 3 || m_this.state() === annotationState.create) { return; } var coor = []; @@ -1164,8 +1169,6 @@ var lineAnnotation = function (args) { return new lineAnnotation(args); } - var m_this = this; - args = $.extend(true, {}, { style: { line: function (d) { @@ -1206,14 +1209,17 @@ var lineAnnotation = function (args) { delete args.coordinates; annotation.call(this, 'line', args); + var m_this = this, + s_actions = this.actions; + /** * Get a list of renderable features for this annotation. * * @returns {array} An array of features. */ this.features = function () { - var opt = this.options(), - state = this.state(), + var opt = m_this.options(), + state = m_this.state(), features; switch (state) { case annotationState.create: @@ -1246,9 +1252,9 @@ var lineAnnotation = function (args) { */ this._coordinates = function (coordinates) { if (coordinates) { - this.options('vertices', coordinates); + m_this.options('vertices', coordinates); } - return this.options('vertices'); + return m_this.options('vertices'); }; /** @@ -1259,10 +1265,10 @@ var lineAnnotation = function (args) { * update anything. */ this.mouseMove = function (evt) { - if (this.state() !== annotationState.create) { + if (m_this.state() !== annotationState.create) { return; } - var vertices = this.options('vertices'); + var vertices = m_this.options('vertices'); if (vertices.length) { vertices[vertices.length - 1] = evt.mapgcs; return true; @@ -1280,15 +1286,15 @@ var lineAnnotation = function (args) { * anything. */ this.mouseClick = function (evt) { - var layer = this.layer(); - if (this.state() !== annotationState.create || !layer) { + var layer = m_this.layer(); + if (m_this.state() !== annotationState.create || !layer) { return; } var end = !!evt.buttonsDown.right, skip; if (!evt.buttonsDown.left && !evt.buttonsDown.right) { return; } - var vertices = this.options('vertices'); + var vertices = m_this.options('vertices'); if (evt.buttonsDown.right && !vertices.length) { return; } @@ -1324,8 +1330,8 @@ var lineAnnotation = function (args) { return 'remove'; } vertices.pop(); - this.options('style').closed = end === 'close'; - this.state(annotationState.done); + m_this.options('style').closed = end === 'close'; + m_this.state(annotationState.done); return 'done'; } return (end || !skip); @@ -1340,7 +1346,7 @@ var lineAnnotation = function (args) { */ this.actions = function (state) { if (!state) { - state = this.state(); + state = m_this.state(); } switch (state) { case annotationState.create: @@ -1357,7 +1363,7 @@ var lineAnnotation = function (args) { input: 'pan' }]; default: - return []; + return s_actions.apply(this, arguments); } }; @@ -1371,15 +1377,15 @@ var lineAnnotation = function (args) { * anything. */ this.processAction = function (evt) { - var layer = this.layer(); - if (this.state() !== annotationState.create || !layer || + var layer = m_this.layer(); + if (m_this.state() !== annotationState.create || !layer || evt.state.action !== geo_action.annotation_line) { return; } var cpp = layer.options('continuousPointProximity'); var cpc = layer.options('continuousPointColinearity'); if (cpp || cpp === 0) { - var vertices = this.options('vertices'); + var vertices = m_this.options('vertices'); if (!vertices.length) { vertices.push(evt.mouse.mapgcs); vertices.push(evt.mouse.mapgcs); @@ -1415,8 +1421,8 @@ var lineAnnotation = function (args) { * coordinate system. `undefined` if this annotation is incomplete. */ this._geojsonCoordinates = function (gcs) { - var src = this.coordinates(gcs); - if (!src || src.length < 2 || this.state() === annotationState.create) { + var src = m_this.coordinates(gcs); + if (!src || src.length < 2 || m_this.state() === annotationState.create) { return; } var coor = []; @@ -1479,15 +1485,14 @@ registerAnnotation('line', lineAnnotation, lineRequiredFeatures); * zoom level. If it is `true`, the radius is based on the zoom level at * first instantiation. Otherwise, if it is a number, the radius is used * at that zoom level. - * @param {object} [args.editStyle] The style to apply to a line in edit - * mode. This uses styles for lines. + * @param {object} [args.editStyle] The style to apply to a point in edit + * mode. */ var pointAnnotation = function (args) { 'use strict'; if (!(this instanceof pointAnnotation)) { return new pointAnnotation(args); } - var m_this = this; args = $.extend(true, {}, { style: { @@ -1506,14 +1511,16 @@ var pointAnnotation = function (args) { delete args.coordinates; annotation.call(this, 'point', args); + var m_this = this; + /** * Get a list of renderable features for this annotation. * * @returns {array} An array of features. */ this.features = function () { - var opt = this.options(), - state = this.state(), + var opt = m_this.options(), + state = m_this.state(), features, style, scaleOnZoom; switch (state) { case annotationState.create: @@ -1523,14 +1530,14 @@ var pointAnnotation = function (args) { style = opt.style; if (opt.style.scaled || opt.style.scaled === 0) { if (opt.style.scaled === true) { - opt.style.scaled = this.layer().map().zoom(); + opt.style.scaled = m_this.layer().map().zoom(); } style = $.extend({}, style, { radius: function () { var radius = opt.style.radius, zoom = m_this.layer().map().zoom(); if (util.isFunction(radius)) { - radius = radius.apply(this, arguments); + radius = radius.apply(m_this, arguments); } radius *= Math.pow(2, zoom - opt.style.scaled); return radius; @@ -1561,12 +1568,12 @@ var pointAnnotation = function (args) { */ this._coordinates = function (coordinates) { if (coordinates && coordinates.length >= 1) { - this.options('position', coordinates[0]); + m_this.options('position', coordinates[0]); } - if (this.state() === annotationState.create) { + if (m_this.state() === annotationState.create) { return []; } - return [this.options('position')]; + return [m_this.options('position')]; }; /** @@ -1580,15 +1587,15 @@ var pointAnnotation = function (args) { * anything. */ this.mouseClick = function (evt) { - if (this.state() !== annotationState.create) { + if (m_this.state() !== annotationState.create) { return; } if (!evt.buttonsDown.left) { return; } evt.handled = true; - this.options('position', evt.mapgcs); - this.state(annotationState.done); + m_this.options('position', evt.mapgcs); + m_this.state(annotationState.done); return 'done'; }; @@ -1613,8 +1620,8 @@ var pointAnnotation = function (args) { * coordinate system. `undefined` if this annotation is incomplete. */ this._geojsonCoordinates = function (gcs) { - var src = this.coordinates(gcs); - if (!src || this.state() === annotationState.create || src.length < 1 || src[0] === undefined) { + var src = m_this.coordinates(gcs); + if (!src || m_this.state() === annotationState.create || src.length < 1 || src[0] === undefined) { return; } return [src[0].x, src[0].y]; diff --git a/src/annotationLayer.js b/src/annotationLayer.js index 7f340ac8ab..d1d4672799 100644 --- a/src/annotationLayer.js +++ b/src/annotationLayer.js @@ -126,10 +126,10 @@ var annotationLayer = function (args) { var update; if (evt.state && evt.state.actionRecord && evt.state.actionRecord.owner === geo_annotation.actionOwner && - this.currentAnnotation) { - update = this.currentAnnotation.processAction(evt); + m_this.currentAnnotation) { + update = m_this.currentAnnotation.processAction(evt); } - this._updateFromEvent(update); + m_this._updateFromEvent(update); }; /** @@ -163,8 +163,8 @@ var annotationLayer = function (args) { * @param {geo.event} evt The mouse move event. */ this._handleMouseMove = function (evt) { - if (this.mode() && this.currentAnnotation) { - var update = this.currentAnnotation.mouseMove(evt); + if (m_this.mode() && m_this.currentAnnotation) { + var update = m_this.currentAnnotation.mouseMove(evt); if (update) { m_this.modified(); m_this.draw(); @@ -179,9 +179,9 @@ var annotationLayer = function (args) { * @param {geo.event} evt The mouse click event. */ this._handleMouseClick = function (evt) { - if (this.mode() && this.currentAnnotation) { - var update = this.currentAnnotation.mouseClick(evt); - this._updateFromEvent(update); + if (m_this.mode() && m_this.currentAnnotation) { + var update = m_this.currentAnnotation.mouseClick(evt); + m_this._updateFromEvent(update); } }; @@ -208,8 +208,8 @@ var annotationLayer = function (args) { } else { m_options[arg1] = arg2; } - this.modified(); - return this; + m_this.modified(); + return m_this; }; /** @@ -217,16 +217,16 @@ var annotationLayer = function (args) { * * @param {geo.geoPosition|geo.screenPosition} coord1 The first coordinates. * @param {string|geo.transform|null} gcs1 `undefined` to use the interface - * gcs, `null` to use the map gcs, `'display`' if the coordinates are + * gcs, `null` to use the map gcs, `'display'` if the coordinates are * already in display coordinates, or any other transform. * @param {geo.geoPosition|geo.screenPosition} coord2 the second coordinates. * @param {string|geo.transform|null} [gcs2] `undefined` to use the interface - * gcs, `null` to use the map gcs, `'display`' if the coordinates are + * gcs, `null` to use the map gcs, `'display'` if the coordinates are * already in display coordinates, or any other transform. * @returns {number} the Euclidian distance between the two coordinates. */ this.displayDistance = function (coord1, gcs1, coord2, gcs2) { - var map = this.map(); + var map = m_this.map(); if (gcs1 !== 'display') { gcs1 = (gcs1 === null ? map.gcs() : ( gcs1 === undefined ? map.ingcs() : gcs1)); @@ -257,21 +257,21 @@ var annotationLayer = function (args) { annotation: annotation }); m_annotations.push(annotation); - annotation.layer(this); - var map = this.map(); + annotation.layer(m_this); + var map = m_this.map(); gcs = (gcs === null ? map.gcs() : ( gcs === undefined ? map.ingcs() : gcs)); if (gcs !== map.gcs()) { annotation._coordinates(transform.transformCoordinates( gcs, map.gcs(), annotation._coordinates())); } - this.modified(); - this.draw(); + m_this.modified(); + m_this.draw(); m_this.geoTrigger(geo_event.annotation.add, { annotation: annotation }); } - return this; + return m_this; }; /** @@ -285,14 +285,14 @@ var annotationLayer = function (args) { this.removeAnnotation = function (annotation, update) { var pos = $.inArray(annotation, m_annotations); if (pos >= 0) { - if (annotation === this.currentAnnotation) { - this.currentAnnotation = null; + if (annotation === m_this.currentAnnotation) { + m_this.currentAnnotation = null; } annotation._exit(); m_annotations.splice(pos, 1); if (update !== false) { - this.modified(); - this.draw(); + m_this.modified(); + m_this.draw(); } m_this.geoTrigger(geo_event.annotation.remove, { annotation: annotation @@ -318,12 +318,12 @@ var annotationLayer = function (args) { pos += 1; continue; } - this.removeAnnotation(annotation, false); + m_this.removeAnnotation(annotation, false); removed += 1; } if (removed && update !== false) { - this.modified(); - this.draw(); + m_this.modified(); + m_this.draw(); } return removed; }; @@ -357,11 +357,10 @@ var annotationLayer = function (args) { }; /** - * Get or set the current mode. The mode is either `null` for nothing being - * created, or the name of the type of annotation that is being created. + * Get or set the current mode. * - * @param {string|null} [arg] The new mode or `undefined` to get the current - * mode. + * @param {string|null} [arg] `undefined` to get the current mode, `null` to + * stop creating/editing, or the name of the type of annotation to create. * @returns {string|null|this} The current mode or the layer. */ this.mode = function (arg) { @@ -378,13 +377,13 @@ var annotationLayer = function (args) { } else { Mousetrap(mapNode[0]).unbind('esc'); } - if (this.currentAnnotation) { - switch (this.currentAnnotation.state()) { + if (m_this.currentAnnotation) { + switch (m_this.currentAnnotation.state()) { case geo_annotation.state.create: - this.removeAnnotation(this.currentAnnotation); + m_this.removeAnnotation(m_this.currentAnnotation); break; } - this.currentAnnotation = null; + m_this.currentAnnotation = null; } switch (m_mode) { case 'line': @@ -403,12 +402,12 @@ var annotationLayer = function (args) { m_this.map().interactor().removeAction( undefined, undefined, geo_annotation.actionOwner); if (createAnnotation) { - this.currentAnnotation = createAnnotation({ + m_this.currentAnnotation = createAnnotation({ state: geo_annotation.state.create, layer: this }); - this.addAnnotation(m_this.currentAnnotation, null); - actions = this.currentAnnotation.actions(geo_annotation.state.create); + m_this.addAnnotation(m_this.currentAnnotation, null); + actions = m_this.currentAnnotation.actions(geo_annotation.state.create); $.each(actions, function (idx, action) { m_this.map().interactor().addAction(action); }); @@ -416,7 +415,7 @@ var annotationLayer = function (args) { m_this.geoTrigger(geo_event.annotation.mode, { mode: m_mode, oldMode: oldMode}); } - return this; + return m_this; }; /** @@ -443,15 +442,15 @@ var annotationLayer = function (args) { */ this.geojson = function (geojson, clear, gcs, includeCrs) { if (geojson !== undefined) { - var reader = registry.createFileReader('jsonReader', {layer: this}); + var reader = registry.createFileReader('jsonReader', {layer: m_this}); if (!reader.canRead(geojson)) { return; } if (clear === true) { - this.removeAllAnnotations(true, false); + m_this.removeAllAnnotations(true, false); } if (clear === 'update') { - $.each(this.annotations(), function (idx, annotation) { + $.each(m_this.annotations(), function (idx, annotation) { annotation.options('updated', false); }); } @@ -462,15 +461,15 @@ var annotationLayer = function (args) { }); }); if (clear === 'update') { - $.each(this.annotations(), function (idx, annotation) { + $.each(m_this.annotations(), function (idx, annotation) { if (annotation.options('updated') === false && annotation.state() === geo_annotation.state.done) { m_this.removeAnnotation(annotation, false); } }); } - this.modified(); - this.draw(); + m_this.modified(); + m_this.draw(); return m_annotations.length; } geojson = null; @@ -736,7 +735,7 @@ var annotationLayer = function (args) { */ this._update = function () { if (m_this.getMTime() > m_buildTime.getMTime()) { - var labels = this.options('showLabels') ? [] : null; + var labels = m_this.options('showLabels') ? [] : null; /* Interally, we have a set of feature levels (to provide z-index * support), each of which can have data from multiple annotations. We * clear the data on each of these features, then build it up from each @@ -834,7 +833,7 @@ var annotationLayer = function (args) { m_buildTime.modified(); } s_update.call(m_this, arguments); - return this; + return m_this; }; /** From 6aab984b0488c1a5de670835d17522e6568cd5bd Mon Sep 17 00:00:00 2001 From: David Manthey Date: Mon, 5 Feb 2018 08:34:32 -0500 Subject: [PATCH 4/5] Add a longer explanation of what is being done. --- src/util/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/util/index.js b/src/util/index.js index 7ddeec75fa..0188e4f1b6 100644 --- a/src/util/index.js +++ b/src/util/index.js @@ -747,7 +747,10 @@ var util = module.exports = { /** * Return the coordinate associated with the center of the perimeter formed - * from a list of points. + * from a list of points. This averages all of the vertices in the perimeter + * weighted by the line length on either side of each point. Functionally, + * this is the same as the average of all the points of the lines of the + * perimeter. * * @param {geo.geoPosition[]} coor An array of coordinates. * @returns {geo.geoPosition|undefined} The position for the center, or From e65944f2e93ad5f998142112ae365960cb78a9bd Mon Sep 17 00:00:00 2001 From: David Manthey Date: Mon, 5 Feb 2018 08:36:27 -0500 Subject: [PATCH 5/5] Convert a few more `this` to `m_this`. --- src/annotation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/annotation.js b/src/annotation.js index f1585696c0..a82e4c6d47 100644 --- a/src/annotation.js +++ b/src/annotation.js @@ -669,7 +669,7 @@ var rectangleAnnotation = function (args) { selectionRectangle: true }]; default: - return s_actions.apply(this, arguments); + return s_actions.apply(m_this, arguments); } }; @@ -1363,7 +1363,7 @@ var lineAnnotation = function (args) { input: 'pan' }]; default: - return s_actions.apply(this, arguments); + return s_actions.apply(m_this, arguments); } };