geojs 1.8.4 → 1.8.7
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/CHANGELOG.md +18 -0
- package/geo.js +1316 -1084
- package/geo.lean.js +1316 -1084
- package/geo.lean.min.js +2 -2
- package/geo.min.js +2 -2
- package/package.json +1 -1
- package/src/{annotation.js → annotation/annotation.js} +38 -1374
- package/src/annotation/circleAnnotation.js +33 -0
- package/src/annotation/ellipseAnnotation.js +80 -0
- package/src/annotation/index.js +21 -0
- package/src/annotation/lineAnnotation.js +344 -0
- package/src/annotation/pointAnnotation.js +208 -0
- package/src/annotation/polygonAnnotation.js +313 -0
- package/src/annotation/rectangleAnnotation.js +402 -0
- package/src/annotation/squareAnnotation.js +33 -0
- package/src/fetchQueue.js +25 -11
- package/src/index.js +1 -1
- package/src/transform.js +15 -0
- package/src/typedef.js +9 -0
- package/src/webgl/lineFeature.js +7 -3
- package/src/webgl/polygonFeature.js +11 -8
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const $ = require('jquery');
|
|
2
|
+
const inherit = require('../inherit');
|
|
3
|
+
const registerAnnotation = require('../registry').registerAnnotation;
|
|
4
|
+
const markerFeature = require('../markerFeature');
|
|
5
|
+
|
|
6
|
+
const ellipseAnnotation = require('./ellipseAnnotation');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Circle annotation class.
|
|
10
|
+
*
|
|
11
|
+
* Circles are a subset of rectangles with a fixed aspect ratio.
|
|
12
|
+
*
|
|
13
|
+
* @class
|
|
14
|
+
* @alias geo.circleAnnotation
|
|
15
|
+
* @extends geo.annotation
|
|
16
|
+
*
|
|
17
|
+
* @param {geo.circleAnnotation.spec?} [args] Options for the annotation.
|
|
18
|
+
* @param {string} [annotationName='circle'] Override the annotation name.
|
|
19
|
+
*/
|
|
20
|
+
var circleAnnotation = function (args, annotationName) {
|
|
21
|
+
'use strict';
|
|
22
|
+
args = $.extend({}, args, {constraint: 1});
|
|
23
|
+
if (!(this instanceof circleAnnotation)) {
|
|
24
|
+
return new circleAnnotation(args, annotationName);
|
|
25
|
+
}
|
|
26
|
+
ellipseAnnotation.call(this, args, annotationName || 'circle');
|
|
27
|
+
};
|
|
28
|
+
inherit(circleAnnotation, ellipseAnnotation);
|
|
29
|
+
var circleRequiredFeatures = {};
|
|
30
|
+
circleRequiredFeatures[markerFeature.capabilities.feature] = true;
|
|
31
|
+
registerAnnotation('circle', circleAnnotation, circleRequiredFeatures);
|
|
32
|
+
|
|
33
|
+
module.exports = circleAnnotation;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const $ = require('jquery');
|
|
2
|
+
const inherit = require('../inherit');
|
|
3
|
+
const registerAnnotation = require('../registry').registerAnnotation;
|
|
4
|
+
const markerFeature = require('../markerFeature');
|
|
5
|
+
|
|
6
|
+
const annotationState = require('./annotation').state;
|
|
7
|
+
const rectangleAnnotation = require('./rectangleAnnotation');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Ellipse annotation class.
|
|
11
|
+
*
|
|
12
|
+
* Ellipses are always rendered as markers.
|
|
13
|
+
*
|
|
14
|
+
* @class
|
|
15
|
+
* @alias geo.ellipseAnnotation
|
|
16
|
+
* @extends geo.annotation
|
|
17
|
+
*
|
|
18
|
+
* @param {geo.ellipseAnnotation.spec?} [args] Options for the annotation.
|
|
19
|
+
* @param {string} [annotationName='ellipse'] Override the annotation name.
|
|
20
|
+
*/
|
|
21
|
+
var ellipseAnnotation = function (args, annotationName) {
|
|
22
|
+
'use strict';
|
|
23
|
+
if (!(this instanceof ellipseAnnotation)) {
|
|
24
|
+
return new ellipseAnnotation(args, annotationName);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
rectangleAnnotation.call(this, args, annotationName || 'ellipse');
|
|
28
|
+
|
|
29
|
+
var m_this = this;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Get a list of renderable features for this annotation.
|
|
33
|
+
*
|
|
34
|
+
* @returns {array} An array of features.
|
|
35
|
+
*/
|
|
36
|
+
this.features = function () {
|
|
37
|
+
var opt = m_this.options(),
|
|
38
|
+
state = m_this.state(),
|
|
39
|
+
features;
|
|
40
|
+
features = [];
|
|
41
|
+
if (opt.corners && opt.corners.length >= 4) {
|
|
42
|
+
const style = m_this.styleForState(state);
|
|
43
|
+
const w = ((opt.corners[0].x - opt.corners[1].x) ** 2 + (opt.corners[0].y - opt.corners[1].y) ** 2) ** 0.5;
|
|
44
|
+
const h = ((opt.corners[0].x - opt.corners[3].x) ** 2 + (opt.corners[0].y - opt.corners[3].y) ** 2) ** 0.5;
|
|
45
|
+
const radius = Math.max(w, h) / 2 / m_this.layer().map().unitsPerPixel(0);
|
|
46
|
+
const aspect = w ? h / w : 1e20;
|
|
47
|
+
const rotation = -Math.atan2(opt.corners[1].y - opt.corners[0].y, opt.corners[1].x - opt.corners[0].x);
|
|
48
|
+
features = [{
|
|
49
|
+
marker: {
|
|
50
|
+
x: (opt.corners[0].x + opt.corners[1].x + opt.corners[2].x + opt.corners[3].x) / 4,
|
|
51
|
+
y: (opt.corners[0].y + opt.corners[1].y + opt.corners[2].y + opt.corners[3].y) / 4,
|
|
52
|
+
style: $.extend(
|
|
53
|
+
{}, style,
|
|
54
|
+
{
|
|
55
|
+
radius: radius,
|
|
56
|
+
symbolValue: aspect,
|
|
57
|
+
rotation: rotation,
|
|
58
|
+
strokeOffset: 0,
|
|
59
|
+
radiusIncludesStroke: false,
|
|
60
|
+
scaleWithZoom: markerFeature.scaleMode.fill,
|
|
61
|
+
rotateWithMap: true,
|
|
62
|
+
strokeOpacity: style.stroke === false ? 0 : style.strokeOpacity,
|
|
63
|
+
fillOpacity: style.fill === false ? 0 : style.fillOpacity
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
}];
|
|
67
|
+
}
|
|
68
|
+
if (state === annotationState.edit) {
|
|
69
|
+
m_this._addEditHandles(features, opt.corners);
|
|
70
|
+
}
|
|
71
|
+
return features;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
inherit(ellipseAnnotation, rectangleAnnotation);
|
|
75
|
+
|
|
76
|
+
var ellipseRequiredFeatures = {};
|
|
77
|
+
ellipseRequiredFeatures[markerFeature.capabilities.feature] = true;
|
|
78
|
+
registerAnnotation('ellipse', ellipseAnnotation, ellipseRequiredFeatures);
|
|
79
|
+
|
|
80
|
+
module.exports = ellipseAnnotation;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const annotation = require('./annotation');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @namespace geo.annotation
|
|
5
|
+
*/
|
|
6
|
+
module.exports = {
|
|
7
|
+
state: annotation.state,
|
|
8
|
+
actionOwner: annotation.actionOwner,
|
|
9
|
+
annotation: annotation.annotation,
|
|
10
|
+
_editHandleFeatureLevel: annotation._editHandleFeatureLevel,
|
|
11
|
+
defaultEditHandleStyle: annotation.defaultEditHandleStyle,
|
|
12
|
+
constrainAspectRatio: annotation.constrainAspectRatio,
|
|
13
|
+
baseAnnotation: annotation,
|
|
14
|
+
circleAnnotation: require('./circleAnnotation'),
|
|
15
|
+
ellipseAnnotation: require('./ellipseAnnotation'),
|
|
16
|
+
lineAnnotation: require('./lineAnnotation'),
|
|
17
|
+
pointAnnotation: require('./pointAnnotation'),
|
|
18
|
+
polygonAnnotation: require('./polygonAnnotation'),
|
|
19
|
+
rectangleAnnotation: require('./rectangleAnnotation'),
|
|
20
|
+
squareAnnotation: require('./squareAnnotation')
|
|
21
|
+
};
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
const $ = require('jquery');
|
|
2
|
+
const inherit = require('../inherit');
|
|
3
|
+
const registerAnnotation = require('../registry').registerAnnotation;
|
|
4
|
+
const lineFeature = require('../lineFeature');
|
|
5
|
+
|
|
6
|
+
const annotation = require('./annotation').annotation;
|
|
7
|
+
const annotationState = require('./annotation').state;
|
|
8
|
+
const continuousVerticesActions = require('./annotation').continuousVerticesActions;
|
|
9
|
+
const continuousVerticesProcessAction = require('./annotation').continuousVerticesProcessAction;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Line annotation specification. Extends {@link geo.annotation.spec}.
|
|
13
|
+
*
|
|
14
|
+
* @typedef {object} geo.lineAnnotation.spec
|
|
15
|
+
* @extends geo.annotation.spec
|
|
16
|
+
* @property {geo.geoPosition[]} [vertices] A list of vertices in map gcs
|
|
17
|
+
* coordinates.
|
|
18
|
+
* @property {geo.geoPosition[]} [coordinates] An alternate name for
|
|
19
|
+
* `vertices`.
|
|
20
|
+
* @property {geo.lineFeature.styleSpec} [style] The style to apply to a
|
|
21
|
+
* finished line. This uses styles for {@link geo.lineFeature}.
|
|
22
|
+
* @property {geo.lineFeature.styleSpec} [editStyle] The style to apply to a
|
|
23
|
+
* line in edit mode.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Line annotation class.
|
|
28
|
+
*
|
|
29
|
+
* @class
|
|
30
|
+
* @alias geo.lineAnnotation
|
|
31
|
+
* @extends geo.annotation
|
|
32
|
+
*
|
|
33
|
+
* @param {geo.lineAnnotation.spec?} [args] Options for the annotation.
|
|
34
|
+
*/
|
|
35
|
+
var lineAnnotation = function (args) {
|
|
36
|
+
'use strict';
|
|
37
|
+
if (!(this instanceof lineAnnotation)) {
|
|
38
|
+
return new lineAnnotation(args);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
args = $.extend(true, {}, {
|
|
42
|
+
style: {
|
|
43
|
+
line: function (d) {
|
|
44
|
+
/* Return an array that has the same number of items as we have
|
|
45
|
+
* vertices. */
|
|
46
|
+
return Array.apply(null, Array(m_this.options('vertices').length)).map(
|
|
47
|
+
function () { return d; });
|
|
48
|
+
},
|
|
49
|
+
position: function (d, i) {
|
|
50
|
+
return m_this.options('vertices')[i];
|
|
51
|
+
},
|
|
52
|
+
strokeColor: {r: 0, g: 0, b: 0},
|
|
53
|
+
strokeOpacity: 1,
|
|
54
|
+
strokeWidth: 3,
|
|
55
|
+
closed: false,
|
|
56
|
+
lineCap: 'butt',
|
|
57
|
+
lineJoin: 'miter'
|
|
58
|
+
},
|
|
59
|
+
highlightStyle: {
|
|
60
|
+
strokeWidth: 5
|
|
61
|
+
},
|
|
62
|
+
createStyle: {
|
|
63
|
+
line: function (d) {
|
|
64
|
+
/* Return an array that has the same number of items as we have
|
|
65
|
+
* vertices. */
|
|
66
|
+
return Array.apply(null, Array(m_this.options('vertices').length)).map(
|
|
67
|
+
function () { return d; });
|
|
68
|
+
},
|
|
69
|
+
position: function (d, i) {
|
|
70
|
+
return m_this.options('vertices')[i];
|
|
71
|
+
},
|
|
72
|
+
strokeColor: {r: 0, g: 0, b: 1},
|
|
73
|
+
strokeOpacity: 1,
|
|
74
|
+
strokeWidth: 3,
|
|
75
|
+
closed: false,
|
|
76
|
+
lineCap: 'butt',
|
|
77
|
+
lineJoin: 'miter'
|
|
78
|
+
}
|
|
79
|
+
}, args || {});
|
|
80
|
+
args.vertices = args.vertices || args.coordinates || [];
|
|
81
|
+
delete args.coordinates;
|
|
82
|
+
annotation.call(this, 'line', args);
|
|
83
|
+
|
|
84
|
+
var m_this = this,
|
|
85
|
+
s_actions = this.actions,
|
|
86
|
+
s_processEditAction = this.processEditAction;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Get a list of renderable features for this annotation.
|
|
90
|
+
*
|
|
91
|
+
* @returns {array} An array of features.
|
|
92
|
+
*/
|
|
93
|
+
this.features = function () {
|
|
94
|
+
var opt = m_this.options(),
|
|
95
|
+
state = m_this.state(),
|
|
96
|
+
features;
|
|
97
|
+
switch (state) {
|
|
98
|
+
case annotationState.create:
|
|
99
|
+
features = [{
|
|
100
|
+
line: {
|
|
101
|
+
line: opt.vertices,
|
|
102
|
+
style: m_this.styleForState(state)
|
|
103
|
+
}
|
|
104
|
+
}];
|
|
105
|
+
break;
|
|
106
|
+
default:
|
|
107
|
+
features = [{
|
|
108
|
+
line: {
|
|
109
|
+
line: opt.vertices,
|
|
110
|
+
style: m_this.styleForState(state)
|
|
111
|
+
}
|
|
112
|
+
}];
|
|
113
|
+
if (state === annotationState.edit) {
|
|
114
|
+
m_this._addEditHandles(features, opt.vertices, undefined, !m_this.style('closed'));
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
return features;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Get and optionally set coordinates associated with this annotation in the
|
|
123
|
+
* map gcs coordinate system.
|
|
124
|
+
*
|
|
125
|
+
* @param {geo.geoPosition[]} [coordinates] An optional array of coordinates
|
|
126
|
+
* to set.
|
|
127
|
+
* @returns {geo.geoPosition[]} The current array of coordinates.
|
|
128
|
+
*/
|
|
129
|
+
this._coordinates = function (coordinates) {
|
|
130
|
+
if (coordinates) {
|
|
131
|
+
m_this.options('vertices', coordinates);
|
|
132
|
+
}
|
|
133
|
+
return m_this.options('vertices');
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Handle a mouse move on this annotation.
|
|
138
|
+
*
|
|
139
|
+
* @param {geo.event} evt The mouse move event.
|
|
140
|
+
* @returns {boolean} Truthy to update the annotation, falsy to not
|
|
141
|
+
* update anything.
|
|
142
|
+
*/
|
|
143
|
+
this.mouseMove = function (evt) {
|
|
144
|
+
if (m_this.state() !== annotationState.create) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
var vertices = m_this.options('vertices');
|
|
148
|
+
if (vertices.length) {
|
|
149
|
+
vertices[vertices.length - 1] = evt.mapgcs;
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Handle a mouse click on this annotation. If the event is processed,
|
|
156
|
+
* evt.handled should be set to `true` to prevent further processing.
|
|
157
|
+
*
|
|
158
|
+
* @param {geo.event} evt The mouse click event.
|
|
159
|
+
* @returns {boolean|string} `true` to update the annotation, `'done'` if
|
|
160
|
+
* the annotation was completed (changed from create to done state),
|
|
161
|
+
* `'remove'` if the annotation should be removed, falsy to not update
|
|
162
|
+
* anything.
|
|
163
|
+
*/
|
|
164
|
+
this.mouseClick = function (evt) {
|
|
165
|
+
var layer = m_this.layer();
|
|
166
|
+
if (m_this.state() !== annotationState.create || !layer) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
var end = !!evt.buttonsDown.right, skip;
|
|
170
|
+
if (!evt.buttonsDown.left && !evt.buttonsDown.right) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
var vertices = m_this.options('vertices');
|
|
174
|
+
if (evt.buttonsDown.right && !vertices.length) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
evt.handled = true;
|
|
178
|
+
if (evt.buttonsDown.left) {
|
|
179
|
+
if (vertices.length) {
|
|
180
|
+
if (vertices.length >= 2 && layer.displayDistance(
|
|
181
|
+
vertices[vertices.length - 2], null, evt.map, 'display') <=
|
|
182
|
+
layer.options('adjacentPointProximity')) {
|
|
183
|
+
skip = true;
|
|
184
|
+
if (m_this._lastClick &&
|
|
185
|
+
evt.time - m_this._lastClick < layer.options('dblClickTime')) {
|
|
186
|
+
end = true;
|
|
187
|
+
}
|
|
188
|
+
} else if (vertices.length >= 2 && layer.displayDistance(
|
|
189
|
+
vertices[0], null, evt.map, 'display') <=
|
|
190
|
+
layer.options('finalPointProximity')) {
|
|
191
|
+
end = 'close';
|
|
192
|
+
} else {
|
|
193
|
+
vertices[vertices.length - 1] = evt.mapgcs;
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
vertices.push(evt.mapgcs);
|
|
197
|
+
}
|
|
198
|
+
if (!end && !skip) {
|
|
199
|
+
vertices.push(evt.mapgcs);
|
|
200
|
+
}
|
|
201
|
+
m_this._lastClick = evt.time;
|
|
202
|
+
m_this._lastClickVertexCount = vertices.length;
|
|
203
|
+
}
|
|
204
|
+
if (end) {
|
|
205
|
+
if (vertices.length < 3) {
|
|
206
|
+
return 'remove';
|
|
207
|
+
}
|
|
208
|
+
vertices.pop();
|
|
209
|
+
m_this.options('style').closed = end === 'close';
|
|
210
|
+
m_this.state(annotationState.done);
|
|
211
|
+
return 'done';
|
|
212
|
+
}
|
|
213
|
+
return !skip;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Return actions needed for the specified state of this annotation.
|
|
218
|
+
*
|
|
219
|
+
* @param {string} [state] The state to return actions for. Defaults to
|
|
220
|
+
* the current state.
|
|
221
|
+
* @returns {geo.actionRecord[]} A list of actions.
|
|
222
|
+
*/
|
|
223
|
+
this.actions = function (state) {
|
|
224
|
+
return continuousVerticesActions(m_this, s_actions, state, 'line', arguments);
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Process any actions for this annotation.
|
|
229
|
+
*
|
|
230
|
+
* @param {geo.event} evt The action event.
|
|
231
|
+
* @returns {boolean|string} `true` to update the annotation, `'done'` if the
|
|
232
|
+
* annotation was completed (changed from create to done state),
|
|
233
|
+
* `'remove'` if the annotation should be removed, falsy to not update
|
|
234
|
+
* anything.
|
|
235
|
+
*/
|
|
236
|
+
this.processAction = function (evt) {
|
|
237
|
+
return continuousVerticesProcessAction(m_this, evt, 'line');
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Return the coordinates to be stored in a geojson geometry object.
|
|
242
|
+
*
|
|
243
|
+
* @param {string|geo.transform|null} [gcs] `undefined` to use the interface
|
|
244
|
+
* gcs, `null` to use the map gcs, or any other transform.
|
|
245
|
+
* @returns {array} An array of flattened coordinates in the interface gcs
|
|
246
|
+
* coordinate system. `undefined` if this annotation is incomplete.
|
|
247
|
+
*/
|
|
248
|
+
this._geojsonCoordinates = function (gcs) {
|
|
249
|
+
var src = m_this.coordinates(gcs);
|
|
250
|
+
if (!src || src.length < 2 || m_this.state() === annotationState.create) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
var coord = [];
|
|
254
|
+
for (var i = 0; i < src.length; i += 1) {
|
|
255
|
+
coord.push([src[i].x, src[i].y]);
|
|
256
|
+
}
|
|
257
|
+
return coord;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Return the geometry type that is used to store this annotation in geojson.
|
|
262
|
+
*
|
|
263
|
+
* @returns {string} A geojson geometry type.
|
|
264
|
+
*/
|
|
265
|
+
this._geojsonGeometryType = function () {
|
|
266
|
+
return 'LineString';
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Return a list of styles that should be preserved in a geojson
|
|
271
|
+
* representation of the annotation.
|
|
272
|
+
*
|
|
273
|
+
* @returns {string[]} A list of style names to store.
|
|
274
|
+
*/
|
|
275
|
+
this._geojsonStyles = function () {
|
|
276
|
+
return [
|
|
277
|
+
'closed', 'lineCap', 'lineJoin', 'strokeColor', 'strokeOffset',
|
|
278
|
+
'strokeOpacity', 'strokeWidth'];
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Process any edit actions for this annotation.
|
|
283
|
+
*
|
|
284
|
+
* @param {geo.event} evt The action event.
|
|
285
|
+
* @returns {boolean|string} `true` to update the annotation, falsy to not
|
|
286
|
+
* update anything.
|
|
287
|
+
*/
|
|
288
|
+
this.processEditAction = function (evt) {
|
|
289
|
+
switch (m_this._editHandle.handle.type) {
|
|
290
|
+
case 'vertex':
|
|
291
|
+
return m_this._processEditActionVertex(evt, true);
|
|
292
|
+
}
|
|
293
|
+
return s_processEditAction.apply(m_this, arguments);
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Handle a mouse click on this annotation when in edit mode. If the event
|
|
298
|
+
* is processed, evt.handled should be set to `true` to prevent further
|
|
299
|
+
* processing.
|
|
300
|
+
*
|
|
301
|
+
* @param {geo.event} evt The mouse click event.
|
|
302
|
+
* @returns {boolean|string} `true` to update the annotation, `'done'` if
|
|
303
|
+
* the annotation was completed (changed from create to done state),
|
|
304
|
+
* `'remove'` if the annotation should be removed, falsy to not update
|
|
305
|
+
* anything.
|
|
306
|
+
*/
|
|
307
|
+
this.mouseClickEdit = function (evt) {
|
|
308
|
+
// if we get a left double click on an edge on a closed line, break the
|
|
309
|
+
// line at that edge
|
|
310
|
+
var layer = m_this.layer(),
|
|
311
|
+
handle = m_this._editHandle,
|
|
312
|
+
split;
|
|
313
|
+
// ensure we are in edit mode and this is a left click
|
|
314
|
+
if (m_this.state() !== annotationState.edit || !layer || !evt.buttonsDown.left) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
// ensure this is an edge on a closed line
|
|
318
|
+
if (!handle || !handle.handle.selected || handle.handle.type !== 'edge' || !m_this.options('style').closed) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
evt.handled = true;
|
|
322
|
+
if (m_this._lastClick && evt.time - m_this._lastClick < layer.options('dblClickTime')) {
|
|
323
|
+
split = true;
|
|
324
|
+
}
|
|
325
|
+
m_this._lastClick = evt.time;
|
|
326
|
+
if (split) {
|
|
327
|
+
var index = handle.handle.index,
|
|
328
|
+
curPts = m_this._coordinates(),
|
|
329
|
+
pts = curPts.slice(index + 1).concat(curPts.slice(0, index + 1));
|
|
330
|
+
m_this._coordinates(pts);
|
|
331
|
+
m_this.options('style').closed = false;
|
|
332
|
+
handle.handle.index = undefined;
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
};
|
|
338
|
+
inherit(lineAnnotation, annotation);
|
|
339
|
+
|
|
340
|
+
var lineRequiredFeatures = {};
|
|
341
|
+
lineRequiredFeatures[lineFeature.capabilities.basic] = [annotationState.create];
|
|
342
|
+
registerAnnotation('line', lineAnnotation, lineRequiredFeatures);
|
|
343
|
+
|
|
344
|
+
module.exports = lineAnnotation;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
const $ = require('jquery');
|
|
2
|
+
const inherit = require('../inherit');
|
|
3
|
+
const util = require('../util');
|
|
4
|
+
const registerAnnotation = require('../registry').registerAnnotation;
|
|
5
|
+
const pointFeature = require('../pointFeature');
|
|
6
|
+
|
|
7
|
+
const annotation = require('./annotation').annotation;
|
|
8
|
+
const annotationState = require('./annotation').state;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Point annotation specification. Extends {@link geo.annotation.spec}.
|
|
12
|
+
*
|
|
13
|
+
* @typedef {object} geo.pointAnnotation.spec
|
|
14
|
+
* @extends geo.annotation.spec
|
|
15
|
+
* @property {geo.geoPosition} [position] A coordinate in map gcs coordinates.
|
|
16
|
+
* @property {geo.geoPosition[]} [coordinates] An array with one coordinate to
|
|
17
|
+
* use in place of `position`.
|
|
18
|
+
* @property {geo.pointFeature.styleSpec} [style] The style to apply to a
|
|
19
|
+
* finished point. This uses styles for {@link geo.pointFeature}.
|
|
20
|
+
* @property {boolean|number} [style.scaled=false] If `false`, the point is not
|
|
21
|
+
* scaled with zoom level. If `true`, the radius is based on the zoom level
|
|
22
|
+
* at first instantiation. If a number, the radius is used at the `scaled`
|
|
23
|
+
* zoom level.
|
|
24
|
+
* @property {geo.pointFeature.styleSpec} [editStyle] The style to apply to a
|
|
25
|
+
* point in edit mode.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Point annotation class.
|
|
30
|
+
*
|
|
31
|
+
* @class
|
|
32
|
+
* @alias geo.pointAnnotation
|
|
33
|
+
* @extends geo.annotation
|
|
34
|
+
*
|
|
35
|
+
* @param {geo.pointAnnotation.spec?} [args] Options for the annotation.
|
|
36
|
+
*/
|
|
37
|
+
var pointAnnotation = function (args) {
|
|
38
|
+
'use strict';
|
|
39
|
+
if (!(this instanceof pointAnnotation)) {
|
|
40
|
+
return new pointAnnotation(args);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
args = $.extend(true, {}, {
|
|
44
|
+
style: {
|
|
45
|
+
fill: true,
|
|
46
|
+
fillColor: {r: 0, g: 1, b: 0},
|
|
47
|
+
fillOpacity: 0.25,
|
|
48
|
+
radius: 10,
|
|
49
|
+
scaled: false,
|
|
50
|
+
stroke: true,
|
|
51
|
+
strokeColor: {r: 0, g: 0, b: 0},
|
|
52
|
+
strokeOpacity: 1,
|
|
53
|
+
strokeWidth: 3
|
|
54
|
+
},
|
|
55
|
+
createStyle: {
|
|
56
|
+
fillColor: {r: 0.3, g: 0.3, b: 0.3},
|
|
57
|
+
fillOpacity: 0.25,
|
|
58
|
+
strokeColor: {r: 0, g: 0, b: 1}
|
|
59
|
+
},
|
|
60
|
+
highlightStyle: {
|
|
61
|
+
fillColor: {r: 0, g: 1, b: 1},
|
|
62
|
+
fillOpacity: 0.5,
|
|
63
|
+
strokeWidth: 5
|
|
64
|
+
}
|
|
65
|
+
}, args || {});
|
|
66
|
+
args.position = args.position || (args.coordinates ? args.coordinates[0] : undefined);
|
|
67
|
+
delete args.coordinates;
|
|
68
|
+
annotation.call(this, 'point', args);
|
|
69
|
+
|
|
70
|
+
var m_this = this;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get a list of renderable features for this annotation.
|
|
74
|
+
*
|
|
75
|
+
* @returns {array} An array of features.
|
|
76
|
+
*/
|
|
77
|
+
this.features = function () {
|
|
78
|
+
var opt = m_this.options(),
|
|
79
|
+
state = m_this.state(),
|
|
80
|
+
features, style, scaleOnZoom;
|
|
81
|
+
switch (state) {
|
|
82
|
+
case annotationState.create:
|
|
83
|
+
features = [];
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
style = m_this.styleForState(state);
|
|
87
|
+
if (opt.style.scaled || opt.style.scaled === 0) {
|
|
88
|
+
if (opt.style.scaled === true) {
|
|
89
|
+
opt.style.scaled = m_this.layer().map().zoom();
|
|
90
|
+
}
|
|
91
|
+
style = $.extend({}, style, {
|
|
92
|
+
radius: function () {
|
|
93
|
+
var radius = opt.style.radius,
|
|
94
|
+
zoom = m_this.layer().map().zoom();
|
|
95
|
+
if (util.isFunction(radius)) {
|
|
96
|
+
radius = radius.apply(m_this, arguments);
|
|
97
|
+
}
|
|
98
|
+
radius *= Math.pow(2, zoom - opt.style.scaled);
|
|
99
|
+
return radius;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
scaleOnZoom = true;
|
|
103
|
+
}
|
|
104
|
+
features = [{
|
|
105
|
+
point: {
|
|
106
|
+
x: opt.position.x,
|
|
107
|
+
y: opt.position.y,
|
|
108
|
+
style: style,
|
|
109
|
+
scaleOnZoom: scaleOnZoom
|
|
110
|
+
}
|
|
111
|
+
}];
|
|
112
|
+
if (state === annotationState.edit) {
|
|
113
|
+
m_this._addEditHandles(
|
|
114
|
+
features, [opt.position],
|
|
115
|
+
{edge: false, center: false, resize: false, rotate: false});
|
|
116
|
+
}
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
return features;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get and optionally set coordinates associated with this annotation in the
|
|
124
|
+
* map gcs coordinate system.
|
|
125
|
+
*
|
|
126
|
+
* @param {geo.geoPosition[]} [coordinates] An optional array of coordinates
|
|
127
|
+
* to set.
|
|
128
|
+
* @returns {geo.geoPosition[]} The current array of coordinates.
|
|
129
|
+
*/
|
|
130
|
+
this._coordinates = function (coordinates) {
|
|
131
|
+
if (coordinates && coordinates.length >= 1) {
|
|
132
|
+
m_this.options('position', coordinates[0]);
|
|
133
|
+
}
|
|
134
|
+
if (m_this.state() === annotationState.create) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
return [m_this.options('position')];
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
this._coordinateOption = 'position';
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Handle a mouse click on this annotation. If the event is processed,
|
|
144
|
+
* evt.handled should be set to `true` to prevent further processing.
|
|
145
|
+
*
|
|
146
|
+
* @param {geo.event} evt The mouse click event.
|
|
147
|
+
* @returns {boolean|string} `true` to update the annotation, `'done'` if
|
|
148
|
+
* the annotation was completed (changed from create to done state),
|
|
149
|
+
* `'remove'` if the annotation should be removed, falsy to not update
|
|
150
|
+
* anything.
|
|
151
|
+
*/
|
|
152
|
+
this.mouseClick = function (evt) {
|
|
153
|
+
if (m_this.state() !== annotationState.create) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (!evt.buttonsDown.left) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
evt.handled = true;
|
|
160
|
+
m_this.options('position', evt.mapgcs);
|
|
161
|
+
m_this.state(annotationState.done);
|
|
162
|
+
return 'done';
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Return a list of styles that should be preserved in a geojson
|
|
167
|
+
* representation of the annotation.
|
|
168
|
+
*
|
|
169
|
+
* @returns {string[]} A list of style names to store.
|
|
170
|
+
*/
|
|
171
|
+
this._geojsonStyles = function () {
|
|
172
|
+
return [
|
|
173
|
+
'fill', 'fillColor', 'fillOpacity', 'radius', 'scaled', 'stroke',
|
|
174
|
+
'strokeColor', 'strokeOpacity', 'strokeWidth'];
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Return the coordinates to be stored in a geojson geometry object.
|
|
179
|
+
*
|
|
180
|
+
* @param {string|geo.transform|null} [gcs] `undefined` to use the interface
|
|
181
|
+
* gcs, `null` to use the map gcs, or any other transform.
|
|
182
|
+
* @returns {array} An array of flattened coordinates in the interface gcs
|
|
183
|
+
* coordinate system. `undefined` if this annotation is incomplete.
|
|
184
|
+
*/
|
|
185
|
+
this._geojsonCoordinates = function (gcs) {
|
|
186
|
+
var src = m_this.coordinates(gcs);
|
|
187
|
+
if (!src || m_this.state() === annotationState.create || src.length < 1 || src[0] === undefined) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
return [src[0].x, src[0].y];
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Return the geometry type that is used to store this annotation in geojson.
|
|
195
|
+
*
|
|
196
|
+
* @returns {string} A geojson geometry type.
|
|
197
|
+
*/
|
|
198
|
+
this._geojsonGeometryType = function () {
|
|
199
|
+
return 'Point';
|
|
200
|
+
};
|
|
201
|
+
};
|
|
202
|
+
inherit(pointAnnotation, annotation);
|
|
203
|
+
|
|
204
|
+
var pointRequiredFeatures = {};
|
|
205
|
+
pointRequiredFeatures[pointFeature.capabilities.feature] = true;
|
|
206
|
+
registerAnnotation('point', pointAnnotation, pointRequiredFeatures);
|
|
207
|
+
|
|
208
|
+
module.exports = pointAnnotation;
|