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
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
var $ = require('jquery');
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
var registerAnnotation = require('./registry').registerAnnotation;
|
|
8
|
-
var lineFeature = require('./lineFeature');
|
|
9
|
-
var markerFeature = require('./markerFeature');
|
|
10
|
-
var pointFeature = require('./pointFeature');
|
|
11
|
-
var polygonFeature = require('./polygonFeature');
|
|
12
|
-
var textFeature = require('./textFeature');
|
|
2
|
+
var geo_event = require('../event');
|
|
3
|
+
var geo_action = require('../action');
|
|
4
|
+
var transform = require('../transform');
|
|
5
|
+
var util = require('../util');
|
|
6
|
+
var textFeature = require('../textFeature');
|
|
13
7
|
|
|
14
8
|
var annotationId = 0;
|
|
15
9
|
|
|
@@ -1267,1358 +1261,17 @@ function continuousVerticesProcessAction(m_this, evt, name) {
|
|
|
1267
1261
|
}
|
|
1268
1262
|
}
|
|
1269
1263
|
|
|
1270
|
-
/**
|
|
1271
|
-
* Rectangle annotation specification. Extends {@link geo.annotation.spec}.
|
|
1272
|
-
*
|
|
1273
|
-
* @typedef {object} geo.rectangleAnnotation.spec
|
|
1274
|
-
* @extends geo.annotation.spec
|
|
1275
|
-
* @property {geo.geoPosition[]} [corners] A list of four corners in map gcs
|
|
1276
|
-
* coordinates. These must be in order around the perimeter of the
|
|
1277
|
-
* rectangle (in either direction).
|
|
1278
|
-
* @property {geo.geoPosition[]} [coordinates] An alternate name for `corners`.
|
|
1279
|
-
* @property {geo.polygonFeature.styleSpec} [style] The style to apply to a
|
|
1280
|
-
* finished rectangle. This uses styles for {@link geo.polygonFeature}.
|
|
1281
|
-
* @property {geo.polygonFeature.styleSpec} [editStyle] The style to apply to a
|
|
1282
|
-
* rectangle in edit mode.
|
|
1283
|
-
* @property {number|number[]|function} [constraint] If specified, an aspect
|
|
1284
|
-
* ratio or list of aspect ratios to constraint the rectangle to. If a
|
|
1285
|
-
* function, a selection constraint function to call to adjust the
|
|
1286
|
-
* rectangle.
|
|
1287
|
-
*/
|
|
1288
|
-
|
|
1289
|
-
/**
|
|
1290
|
-
* Rectangle annotation class.
|
|
1291
|
-
*
|
|
1292
|
-
* Rectangles are always rendered as polygons. This could be changed -- if no
|
|
1293
|
-
* stroke is specified, the quad feature would be sufficient and work on more
|
|
1294
|
-
* renderers.
|
|
1295
|
-
*
|
|
1296
|
-
* @class
|
|
1297
|
-
* @alias geo.rectangleAnnotation
|
|
1298
|
-
* @extends geo.annotation
|
|
1299
|
-
*
|
|
1300
|
-
* @param {geo.rectangleAnnotation.spec?} [args] Options for the annotation.
|
|
1301
|
-
* @param {string} [annotationName='rectangle'] Override the annotation name.
|
|
1302
|
-
*/
|
|
1303
|
-
var rectangleAnnotation = function (args, annotationName) {
|
|
1304
|
-
'use strict';
|
|
1305
|
-
if (!(this instanceof rectangleAnnotation)) {
|
|
1306
|
-
return new rectangleAnnotation(args, annotationName);
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
args = $.extend(true, {}, {
|
|
1310
|
-
style: {
|
|
1311
|
-
fill: true,
|
|
1312
|
-
fillColor: {r: 0, g: 1, b: 0},
|
|
1313
|
-
fillOpacity: 0.25,
|
|
1314
|
-
polygon: function (d) { return d.polygon; },
|
|
1315
|
-
stroke: true,
|
|
1316
|
-
strokeColor: {r: 0, g: 0, b: 0},
|
|
1317
|
-
strokeOpacity: 1,
|
|
1318
|
-
strokeWidth: 3,
|
|
1319
|
-
uniformPolygon: true
|
|
1320
|
-
},
|
|
1321
|
-
highlightStyle: {
|
|
1322
|
-
fillColor: {r: 0, g: 1, b: 1},
|
|
1323
|
-
fillOpacity: 0.5,
|
|
1324
|
-
strokeWidth: 5
|
|
1325
|
-
},
|
|
1326
|
-
createStyle: {
|
|
1327
|
-
fillColor: {r: 0.3, g: 0.3, b: 0.3},
|
|
1328
|
-
fillOpacity: 0.25,
|
|
1329
|
-
strokeColor: {r: 0, g: 0, b: 1}
|
|
1330
|
-
}
|
|
1331
|
-
}, args || {});
|
|
1332
|
-
args.corners = args.corners || args.coordinates || [];
|
|
1333
|
-
delete args.coordinates;
|
|
1334
|
-
annotation.call(this, annotationName || 'rectangle', args);
|
|
1335
|
-
|
|
1336
|
-
var m_this = this,
|
|
1337
|
-
s_actions = this.actions,
|
|
1338
|
-
s_processEditAction = this.processEditAction;
|
|
1339
|
-
|
|
1340
|
-
/**
|
|
1341
|
-
* Return actions needed for the specified state of this annotation.
|
|
1342
|
-
*
|
|
1343
|
-
* @param {string} [state] The state to return actions for. Defaults to
|
|
1344
|
-
* the current state.
|
|
1345
|
-
* @returns {geo.actionRecord[]} A list of actions.
|
|
1346
|
-
*/
|
|
1347
|
-
this.actions = function (state) {
|
|
1348
|
-
if (!state) {
|
|
1349
|
-
state = m_this.state();
|
|
1350
|
-
}
|
|
1351
|
-
switch (state) {
|
|
1352
|
-
case annotationState.create:
|
|
1353
|
-
return [{
|
|
1354
|
-
action: geo_action.annotation_rectangle,
|
|
1355
|
-
name: 'rectangle create',
|
|
1356
|
-
owner: annotationActionOwner,
|
|
1357
|
-
input: 'left',
|
|
1358
|
-
modifiers: {shift: false, ctrl: false},
|
|
1359
|
-
selectionRectangle: true,
|
|
1360
|
-
selectionConstraint: this._selectionConstraint
|
|
1361
|
-
}];
|
|
1362
|
-
default:
|
|
1363
|
-
return s_actions.apply(m_this, arguments);
|
|
1364
|
-
}
|
|
1365
|
-
};
|
|
1366
|
-
|
|
1367
|
-
/**
|
|
1368
|
-
* Process any actions for this annotation.
|
|
1369
|
-
*
|
|
1370
|
-
* @param {geo.event} evt The action event.
|
|
1371
|
-
* @returns {boolean|string} `true` to update the annotation, `'done'` if the
|
|
1372
|
-
* annotation was completed (changed from create to done state),
|
|
1373
|
-
* `'remove'` if the annotation should be removed, falsy to not update
|
|
1374
|
-
* anything.
|
|
1375
|
-
*/
|
|
1376
|
-
this.processAction = function (evt) {
|
|
1377
|
-
var layer = m_this.layer();
|
|
1378
|
-
if (m_this.state() !== annotationState.create || !layer ||
|
|
1379
|
-
evt.event !== geo_event.actionselection ||
|
|
1380
|
-
evt.state.action !== geo_action.annotation_rectangle) {
|
|
1381
|
-
return;
|
|
1382
|
-
}
|
|
1383
|
-
var map = layer.map(),
|
|
1384
|
-
corners = [
|
|
1385
|
-
/* Keep in map gcs, not interface gcs to avoid wrapping issues */
|
|
1386
|
-
map.displayToGcs({x: evt.lowerLeft.x, y: evt.lowerLeft.y}, null),
|
|
1387
|
-
map.displayToGcs({x: evt.lowerLeft.x, y: evt.upperRight.y}, null),
|
|
1388
|
-
map.displayToGcs({x: evt.upperRight.x, y: evt.upperRight.y}, null),
|
|
1389
|
-
map.displayToGcs({x: evt.upperRight.x, y: evt.lowerLeft.y}, null)
|
|
1390
|
-
];
|
|
1391
|
-
if (this._selectionConstraint && evt.mouse && evt.state.origin) {
|
|
1392
|
-
this._selectionConstraint(evt.mouse.mapgcs, evt.state.origin.mapgcs, corners);
|
|
1393
|
-
}
|
|
1394
|
-
/* Don't keep rectangles that have nearly zero area in display pixels */
|
|
1395
|
-
if (layer.displayDistance(corners[0], null, corners[1], null) *
|
|
1396
|
-
layer.displayDistance(corners[0], null, corners[3], null) < 0.01) {
|
|
1397
|
-
return 'remove';
|
|
1398
|
-
}
|
|
1399
|
-
m_this.options('corners', corners);
|
|
1400
|
-
m_this.state(annotationState.done);
|
|
1401
|
-
return 'done';
|
|
1402
|
-
};
|
|
1403
|
-
|
|
1404
|
-
/**
|
|
1405
|
-
* Get a list of renderable features for this annotation.
|
|
1406
|
-
*
|
|
1407
|
-
* @returns {array} An array of features.
|
|
1408
|
-
*/
|
|
1409
|
-
this.features = function () {
|
|
1410
|
-
var opt = m_this.options(),
|
|
1411
|
-
state = m_this.state(),
|
|
1412
|
-
features;
|
|
1413
|
-
features = [];
|
|
1414
|
-
if (opt.corners && opt.corners.length >= 4) {
|
|
1415
|
-
features = [{
|
|
1416
|
-
polygon: {
|
|
1417
|
-
polygon: opt.corners,
|
|
1418
|
-
style: m_this.styleForState(state)
|
|
1419
|
-
}
|
|
1420
|
-
}];
|
|
1421
|
-
}
|
|
1422
|
-
if (state === annotationState.edit) {
|
|
1423
|
-
m_this._addEditHandles(features, opt.corners);
|
|
1424
|
-
}
|
|
1425
|
-
return features;
|
|
1426
|
-
};
|
|
1427
|
-
|
|
1428
|
-
/**
|
|
1429
|
-
* Get and optionally set coordinates associated with this annotation in the
|
|
1430
|
-
* map gcs coordinate system.
|
|
1431
|
-
*
|
|
1432
|
-
* @param {geo.geoPosition[]} [coordinates] An optional array of coordinates
|
|
1433
|
-
* to set.
|
|
1434
|
-
* @returns {geo.geoPosition[]} The current array of coordinates.
|
|
1435
|
-
*/
|
|
1436
|
-
this._coordinates = function (coordinates) {
|
|
1437
|
-
if (coordinates && coordinates.length >= 4) {
|
|
1438
|
-
m_this.options('corners', coordinates.slice(0, 4));
|
|
1439
|
-
/* Should we ensure that the four points form a rectangle in the current
|
|
1440
|
-
* projection, though this might not be rectangular in another gcs? */
|
|
1441
|
-
}
|
|
1442
|
-
return m_this.options('corners');
|
|
1443
|
-
};
|
|
1444
|
-
|
|
1445
|
-
this._coordinateOption = 'corners';
|
|
1446
|
-
|
|
1447
|
-
/**
|
|
1448
|
-
* Return the coordinates to be stored in a geojson geometry object.
|
|
1449
|
-
*
|
|
1450
|
-
* @param {string|geo.transform|null} [gcs] `undefined` to use the interface
|
|
1451
|
-
* gcs, `null` to use the map gcs, or any other transform.
|
|
1452
|
-
* @returns {array} An array of flattened coordinates in the interface gcs
|
|
1453
|
-
* coordinate system. `undefined` if this annotation is incomplete.
|
|
1454
|
-
*/
|
|
1455
|
-
this._geojsonCoordinates = function (gcs) {
|
|
1456
|
-
var src = m_this.coordinates(gcs);
|
|
1457
|
-
if (!src || m_this.state() === annotationState.create || src.length < 4) {
|
|
1458
|
-
return;
|
|
1459
|
-
}
|
|
1460
|
-
var coord = [];
|
|
1461
|
-
for (var i = 0; i < 4; i += 1) {
|
|
1462
|
-
coord.push([src[i].x, src[i].y]);
|
|
1463
|
-
}
|
|
1464
|
-
coord.push([src[0].x, src[0].y]);
|
|
1465
|
-
return [coord];
|
|
1466
|
-
};
|
|
1467
|
-
|
|
1468
|
-
/**
|
|
1469
|
-
* Return the geometry type that is used to store this annotation in geojson.
|
|
1470
|
-
*
|
|
1471
|
-
* @returns {string} A geojson geometry type.
|
|
1472
|
-
*/
|
|
1473
|
-
this._geojsonGeometryType = function () {
|
|
1474
|
-
return 'Polygon';
|
|
1475
|
-
};
|
|
1476
|
-
|
|
1477
|
-
/**
|
|
1478
|
-
* Return a list of styles that should be preserved in a geojson
|
|
1479
|
-
* representation of the annotation.
|
|
1480
|
-
*
|
|
1481
|
-
* @returns {string[]} A list of style names to store.
|
|
1482
|
-
*/
|
|
1483
|
-
this._geojsonStyles = function () {
|
|
1484
|
-
return [
|
|
1485
|
-
'fill', 'fillColor', 'fillOpacity', 'lineCap', 'lineJoin', 'stroke',
|
|
1486
|
-
'strokeColor', 'strokeOffset', 'strokeOpacity', 'strokeWidth'];
|
|
1487
|
-
};
|
|
1488
|
-
|
|
1489
|
-
/**
|
|
1490
|
-
* Set three corners based on an initial corner and a mouse event.
|
|
1491
|
-
*
|
|
1492
|
-
* @param {geo.geoPosition} corners An array of four corners to update.
|
|
1493
|
-
* @param {geo.event} evt The mouse move event.
|
|
1494
|
-
*/
|
|
1495
|
-
this._setCornersFromMouse = function (corners, evt) {
|
|
1496
|
-
var map = m_this.layer().map(),
|
|
1497
|
-
c0 = map.gcsToDisplay({x: corners[0].x, y: corners[0].y}, null),
|
|
1498
|
-
c2 = map.gcsToDisplay(evt.mapgcs, null),
|
|
1499
|
-
c1 = {x: c2.x, y: c0.y},
|
|
1500
|
-
c3 = {x: c0.x, y: c2.y};
|
|
1501
|
-
corners[2] = $.extend({}, evt.mapgcs);
|
|
1502
|
-
corners[1] = map.displayToGcs(c1, null);
|
|
1503
|
-
corners[3] = map.displayToGcs(c3, null);
|
|
1504
|
-
if (this._selectionConstraint) {
|
|
1505
|
-
this._selectionConstraint(evt.mapgcs, corners[0], corners);
|
|
1506
|
-
}
|
|
1507
|
-
};
|
|
1508
|
-
|
|
1509
|
-
/**
|
|
1510
|
-
* Handle a mouse move on this annotation.
|
|
1511
|
-
*
|
|
1512
|
-
* @param {geo.event} evt The mouse move event.
|
|
1513
|
-
* @returns {boolean} Truthy to update the annotation, falsy to not
|
|
1514
|
-
* update anything.
|
|
1515
|
-
*/
|
|
1516
|
-
this.mouseMove = function (evt) {
|
|
1517
|
-
if (m_this.state() !== annotationState.create) {
|
|
1518
|
-
return;
|
|
1519
|
-
}
|
|
1520
|
-
var corners = m_this.options('corners');
|
|
1521
|
-
if (corners.length) {
|
|
1522
|
-
m_this._setCornersFromMouse(corners, evt);
|
|
1523
|
-
return true;
|
|
1524
|
-
}
|
|
1525
|
-
};
|
|
1526
|
-
|
|
1527
|
-
/**
|
|
1528
|
-
* Handle a mouse click on this annotation. If the event is processed,
|
|
1529
|
-
* evt.handled should be set to `true` to prevent further processing.
|
|
1530
|
-
*
|
|
1531
|
-
* @param {geo.event} evt The mouse click event.
|
|
1532
|
-
* @returns {boolean|string} `true` to update the annotation, `'done'` if
|
|
1533
|
-
* the annotation was completed (changed from create to done state),
|
|
1534
|
-
* `'remove'` if the annotation should be removed, falsy to not update
|
|
1535
|
-
* anything.
|
|
1536
|
-
*/
|
|
1537
|
-
this.mouseClick = function (evt) {
|
|
1538
|
-
var layer = m_this.layer();
|
|
1539
|
-
if (m_this.state() !== annotationState.create || !layer) {
|
|
1540
|
-
return;
|
|
1541
|
-
}
|
|
1542
|
-
if (!evt.buttonsDown.left && !evt.buttonsDown.right) {
|
|
1543
|
-
return;
|
|
1544
|
-
}
|
|
1545
|
-
var corners = m_this.options('corners');
|
|
1546
|
-
if (evt.buttonsDown.right && !corners.length) {
|
|
1547
|
-
return;
|
|
1548
|
-
}
|
|
1549
|
-
evt.handled = true;
|
|
1550
|
-
if (corners.length) {
|
|
1551
|
-
m_this._setCornersFromMouse(corners, evt);
|
|
1552
|
-
/* Don't keep rectangles that have nearly zero area in display pixels */
|
|
1553
|
-
if (layer.displayDistance(corners[0], null, corners[1], null) *
|
|
1554
|
-
layer.displayDistance(corners[0], null, corners[3], null) < 0.01) {
|
|
1555
|
-
return 'remove';
|
|
1556
|
-
}
|
|
1557
|
-
m_this.state(annotationState.done);
|
|
1558
|
-
return 'done';
|
|
1559
|
-
}
|
|
1560
|
-
if (evt.buttonsDown.left) {
|
|
1561
|
-
corners.push($.extend({}, evt.mapgcs));
|
|
1562
|
-
corners.push($.extend({}, evt.mapgcs));
|
|
1563
|
-
corners.push($.extend({}, evt.mapgcs));
|
|
1564
|
-
corners.push($.extend({}, evt.mapgcs));
|
|
1565
|
-
return true;
|
|
1566
|
-
}
|
|
1567
|
-
};
|
|
1568
|
-
|
|
1569
|
-
/**
|
|
1570
|
-
* Process any edit actions for this annotation.
|
|
1571
|
-
*
|
|
1572
|
-
* @param {geo.event} evt The action event.
|
|
1573
|
-
* @returns {boolean|string} `true` to update the annotation, falsy to not
|
|
1574
|
-
* update anything.
|
|
1575
|
-
*/
|
|
1576
|
-
this.processEditAction = function (evt) {
|
|
1577
|
-
var start = m_this._editHandle.startCoordinates,
|
|
1578
|
-
delta = {
|
|
1579
|
-
x: evt.mouse.mapgcs.x - evt.state.origin.mapgcs.x,
|
|
1580
|
-
y: evt.mouse.mapgcs.y - evt.state.origin.mapgcs.y
|
|
1581
|
-
},
|
|
1582
|
-
type = m_this._editHandle.handle.type,
|
|
1583
|
-
index = m_this._editHandle.handle.index,
|
|
1584
|
-
ang = [
|
|
1585
|
-
Math.atan2(start[1].y - start[0].y, start[1].x - start[0].x),
|
|
1586
|
-
Math.atan2(start[2].y - start[1].y, start[2].x - start[1].x),
|
|
1587
|
-
Math.atan2(start[3].y - start[2].y, start[3].x - start[2].x),
|
|
1588
|
-
Math.atan2(start[0].y - start[3].y, start[0].x - start[3].x)
|
|
1589
|
-
],
|
|
1590
|
-
corners, delta1, delta2, ang1, ang2;
|
|
1591
|
-
// an angle can be zero because it is horizontal or undefined. If opposite
|
|
1592
|
-
// angles are both zero, this is a degenerate rectangle (a line or a point)
|
|
1593
|
-
if (!ang[0] && !ang[1] && !ang[2] && !ang[3]) {
|
|
1594
|
-
ang[1] = Math.PI / 2;
|
|
1595
|
-
ang[2] = Math.PI;
|
|
1596
|
-
ang[3] = -Math.PI / 2;
|
|
1597
|
-
}
|
|
1598
|
-
if (!ang[0] && !ang[2]) {
|
|
1599
|
-
ang[0] = ang[1] - Math.PI / 2;
|
|
1600
|
-
ang[2] = ang[1] + Math.PI / 2;
|
|
1601
|
-
}
|
|
1602
|
-
if (!ang[1] && !ang[3]) {
|
|
1603
|
-
ang[1] = ang[2] - Math.PI / 2;
|
|
1604
|
-
ang[3] = ang[2] + Math.PI / 2;
|
|
1605
|
-
}
|
|
1606
|
-
switch (type) {
|
|
1607
|
-
case 'vertex':
|
|
1608
|
-
corners = start.map(function (elem) {
|
|
1609
|
-
return {x: elem.x, y: elem.y};
|
|
1610
|
-
});
|
|
1611
|
-
ang1 = ang[(index + 1) % 4];
|
|
1612
|
-
delta1 = {
|
|
1613
|
-
x: (delta.x * Math.cos(ang1) + delta.y * Math.sin(ang1)) * Math.cos(ang1),
|
|
1614
|
-
y: (delta.y * Math.sin(ang1) + delta.x * Math.cos(ang1)) * Math.sin(ang1)
|
|
1615
|
-
};
|
|
1616
|
-
ang2 = ang[index];
|
|
1617
|
-
delta2 = {
|
|
1618
|
-
x: (delta.x * Math.cos(ang2) + delta.y * Math.sin(ang2)) * Math.cos(ang2),
|
|
1619
|
-
y: (delta.y * Math.sin(ang2) + delta.x * Math.cos(ang2)) * Math.sin(ang2)
|
|
1620
|
-
};
|
|
1621
|
-
corners[index].x += delta.x;
|
|
1622
|
-
corners[index].y += delta.y;
|
|
1623
|
-
corners[(index + 1) % 4].x += delta1.x;
|
|
1624
|
-
corners[(index + 1) % 4].y += delta1.y;
|
|
1625
|
-
corners[(index + 3) % 4].x += delta2.x;
|
|
1626
|
-
corners[(index + 3) % 4].y += delta2.y;
|
|
1627
|
-
if (this._selectionConstraint) {
|
|
1628
|
-
corners = this._selectionConstraint(evt.mouse.mapgcs, evt.state.origin.mapgcs, corners, 'vertex', ang, index).corners;
|
|
1629
|
-
}
|
|
1630
|
-
m_this.options('corners', corners);
|
|
1631
|
-
return true;
|
|
1632
|
-
case 'edge':
|
|
1633
|
-
corners = start.map(function (elem) {
|
|
1634
|
-
return {x: elem.x, y: elem.y};
|
|
1635
|
-
});
|
|
1636
|
-
ang1 = ang[(index + 1) % 4];
|
|
1637
|
-
delta = {
|
|
1638
|
-
x: (delta.x * Math.cos(ang1) + delta.y * Math.sin(ang1)) * Math.cos(ang1),
|
|
1639
|
-
y: (delta.y * Math.sin(ang1) + delta.x * Math.cos(ang1)) * Math.sin(ang1)
|
|
1640
|
-
};
|
|
1641
|
-
corners[index].x += delta.x;
|
|
1642
|
-
corners[index].y += delta.y;
|
|
1643
|
-
corners[(index + 1) % 4].x += delta.x;
|
|
1644
|
-
corners[(index + 1) % 4].y += delta.y;
|
|
1645
|
-
if (this._selectionConstraint) {
|
|
1646
|
-
corners = this._selectionConstraint(evt.mouse.mapgcs, evt.state.origin.mapgcs, corners, 'edge', ang, index).corners;
|
|
1647
|
-
}
|
|
1648
|
-
m_this.options('corners', corners);
|
|
1649
|
-
return true;
|
|
1650
|
-
}
|
|
1651
|
-
return s_processEditAction.apply(m_this, arguments);
|
|
1652
|
-
};
|
|
1653
|
-
};
|
|
1654
|
-
inherit(rectangleAnnotation, annotation);
|
|
1655
|
-
|
|
1656
|
-
var rectangleRequiredFeatures = {};
|
|
1657
|
-
rectangleRequiredFeatures[polygonFeature.capabilities.feature] = true;
|
|
1658
|
-
registerAnnotation('rectangle', rectangleAnnotation, rectangleRequiredFeatures);
|
|
1659
|
-
|
|
1660
|
-
/**
|
|
1661
|
-
* Square annotation class.
|
|
1662
|
-
*
|
|
1663
|
-
* Squares are a subset of rectangles with a fixed aspect ratio.
|
|
1664
|
-
*
|
|
1665
|
-
* @class
|
|
1666
|
-
* @alias geo.squareAnnotation
|
|
1667
|
-
* @extends geo.annotation
|
|
1668
|
-
*
|
|
1669
|
-
* @param {geo.squareAnnotation.spec?} [args] Options for the annotation.
|
|
1670
|
-
* @param {string} [annotationName='square'] Override the annotation name.
|
|
1671
|
-
*/
|
|
1672
|
-
var squareAnnotation = function (args, annotationName) {
|
|
1673
|
-
'use strict';
|
|
1674
|
-
args = $.extend({}, args, {constraint: 1});
|
|
1675
|
-
if (!(this instanceof squareAnnotation)) {
|
|
1676
|
-
return new squareAnnotation(args, annotationName);
|
|
1677
|
-
}
|
|
1678
|
-
rectangleAnnotation.call(this, args, annotationName || 'square');
|
|
1679
|
-
};
|
|
1680
|
-
inherit(squareAnnotation, rectangleAnnotation);
|
|
1681
|
-
var squareRequiredFeatures = {};
|
|
1682
|
-
squareRequiredFeatures[polygonFeature.capabilities.feature] = true;
|
|
1683
|
-
registerAnnotation('square', squareAnnotation, squareRequiredFeatures);
|
|
1684
|
-
|
|
1685
|
-
/**
|
|
1686
|
-
* Ellipse annotation class.
|
|
1687
|
-
*
|
|
1688
|
-
* Ellipses are always rendered as markers.
|
|
1689
|
-
*
|
|
1690
|
-
* @class
|
|
1691
|
-
* @alias geo.ellipseAnnotation
|
|
1692
|
-
* @extends geo.annotation
|
|
1693
|
-
*
|
|
1694
|
-
* @param {geo.ellipseAnnotation.spec?} [args] Options for the annotation.
|
|
1695
|
-
* @param {string} [annotationName='ellipse'] Override the annotation name.
|
|
1696
|
-
*/
|
|
1697
|
-
var ellipseAnnotation = function (args, annotationName) {
|
|
1698
|
-
'use strict';
|
|
1699
|
-
if (!(this instanceof ellipseAnnotation)) {
|
|
1700
|
-
return new ellipseAnnotation(args, annotationName);
|
|
1701
|
-
}
|
|
1702
|
-
|
|
1703
|
-
rectangleAnnotation.call(this, args, annotationName || 'ellipse');
|
|
1704
|
-
|
|
1705
|
-
var m_this = this;
|
|
1706
|
-
|
|
1707
|
-
/**
|
|
1708
|
-
* Get a list of renderable features for this annotation.
|
|
1709
|
-
*
|
|
1710
|
-
* @returns {array} An array of features.
|
|
1711
|
-
*/
|
|
1712
|
-
this.features = function () {
|
|
1713
|
-
var opt = m_this.options(),
|
|
1714
|
-
state = m_this.state(),
|
|
1715
|
-
features;
|
|
1716
|
-
features = [];
|
|
1717
|
-
if (opt.corners && opt.corners.length >= 4) {
|
|
1718
|
-
const style = m_this.styleForState(state);
|
|
1719
|
-
const w = ((opt.corners[0].x - opt.corners[1].x) ** 2 + (opt.corners[0].y - opt.corners[1].y) ** 2) ** 0.5;
|
|
1720
|
-
const h = ((opt.corners[0].x - opt.corners[3].x) ** 2 + (opt.corners[0].y - opt.corners[3].y) ** 2) ** 0.5;
|
|
1721
|
-
const radius = Math.max(w, h) / 2 / m_this.layer().map().unitsPerPixel(0);
|
|
1722
|
-
const aspect = w ? h / w : 1e20;
|
|
1723
|
-
const rotation = -Math.atan2(opt.corners[1].y - opt.corners[0].y, opt.corners[1].x - opt.corners[0].x);
|
|
1724
|
-
features = [{
|
|
1725
|
-
marker: {
|
|
1726
|
-
x: (opt.corners[0].x + opt.corners[1].x + opt.corners[2].x + opt.corners[3].x) / 4,
|
|
1727
|
-
y: (opt.corners[0].y + opt.corners[1].y + opt.corners[2].y + opt.corners[3].y) / 4,
|
|
1728
|
-
style: $.extend(
|
|
1729
|
-
{}, style,
|
|
1730
|
-
{
|
|
1731
|
-
radius: radius,
|
|
1732
|
-
symbolValue: aspect,
|
|
1733
|
-
rotation: rotation,
|
|
1734
|
-
strokeOffset: 0,
|
|
1735
|
-
radiusIncludesStroke: false,
|
|
1736
|
-
scaleWithZoom: markerFeature.scaleMode.fill,
|
|
1737
|
-
rotateWithMap: true,
|
|
1738
|
-
strokeOpacity: style.stroke === false ? 0 : style.strokeOpacity,
|
|
1739
|
-
fillOpacity: style.fill === false ? 0 : style.fillOpacity
|
|
1740
|
-
})
|
|
1741
|
-
}
|
|
1742
|
-
}];
|
|
1743
|
-
}
|
|
1744
|
-
if (state === annotationState.edit) {
|
|
1745
|
-
m_this._addEditHandles(features, opt.corners);
|
|
1746
|
-
}
|
|
1747
|
-
return features;
|
|
1748
|
-
};
|
|
1749
|
-
};
|
|
1750
|
-
inherit(ellipseAnnotation, rectangleAnnotation);
|
|
1751
|
-
|
|
1752
|
-
var ellipseRequiredFeatures = {};
|
|
1753
|
-
ellipseRequiredFeatures[markerFeature.capabilities.feature] = true;
|
|
1754
|
-
registerAnnotation('ellipse', ellipseAnnotation, ellipseRequiredFeatures);
|
|
1755
|
-
|
|
1756
|
-
/**
|
|
1757
|
-
* Circle annotation class.
|
|
1758
|
-
*
|
|
1759
|
-
* Circles are a subset of rectangles with a fixed aspect ratio.
|
|
1760
|
-
*
|
|
1761
|
-
* @class
|
|
1762
|
-
* @alias geo.circleAnnotation
|
|
1763
|
-
* @extends geo.annotation
|
|
1764
|
-
*
|
|
1765
|
-
* @param {geo.circleAnnotation.spec?} [args] Options for the annotation.
|
|
1766
|
-
* @param {string} [annotationName='circle'] Override the annotation name.
|
|
1767
|
-
*/
|
|
1768
|
-
var circleAnnotation = function (args, annotationName) {
|
|
1769
|
-
'use strict';
|
|
1770
|
-
args = $.extend({}, args, {constraint: 1});
|
|
1771
|
-
if (!(this instanceof circleAnnotation)) {
|
|
1772
|
-
return new circleAnnotation(args, annotationName);
|
|
1773
|
-
}
|
|
1774
|
-
ellipseAnnotation.call(this, args, annotationName || 'circle');
|
|
1775
|
-
};
|
|
1776
|
-
inherit(circleAnnotation, ellipseAnnotation);
|
|
1777
|
-
var circleRequiredFeatures = {};
|
|
1778
|
-
circleRequiredFeatures[markerFeature.capabilities.feature] = true;
|
|
1779
|
-
registerAnnotation('circle', circleAnnotation, circleRequiredFeatures);
|
|
1780
|
-
|
|
1781
|
-
/**
|
|
1782
|
-
* Polygon annotation specification. Extends {@link geo.annotation.spec}.
|
|
1783
|
-
*
|
|
1784
|
-
* @typedef {object} geo.polygonAnnotation.spec
|
|
1785
|
-
* @extends geo.annotation.spec
|
|
1786
|
-
* @property {geo.geoPosition[]} [vertices] A list of vertices in map gcs
|
|
1787
|
-
* coordinates. These must be in order around the perimeter of the polygon
|
|
1788
|
-
* (in either direction).
|
|
1789
|
-
* @property {geo.geoPosition[]} [coordinates] An alternate name for
|
|
1790
|
-
* `vertices`.
|
|
1791
|
-
* @property {geo.polygonFeature.styleSpec} [style] The style to apply to a
|
|
1792
|
-
* finished polygon. This uses styles for {@link geo.polygonFeature}.
|
|
1793
|
-
* @property {geo.polygonFeature.styleSpec} [editStyle] The style to apply to ai
|
|
1794
|
-
* polygon in edit mode.
|
|
1795
|
-
*/
|
|
1796
|
-
|
|
1797
|
-
/**
|
|
1798
|
-
* Polygon annotation class
|
|
1799
|
-
*
|
|
1800
|
-
* When complete, polygons are rendered as polygons. During creation they are
|
|
1801
|
-
* rendered as lines and polygons.
|
|
1802
|
-
*
|
|
1803
|
-
* @class
|
|
1804
|
-
* @alias geo.polygonAnnotation
|
|
1805
|
-
* @extends geo.annotation
|
|
1806
|
-
*
|
|
1807
|
-
* @param {geo.polygonAnnotation.spec?} [args] Options for the annotation.
|
|
1808
|
-
*/
|
|
1809
|
-
var polygonAnnotation = function (args) {
|
|
1810
|
-
'use strict';
|
|
1811
|
-
if (!(this instanceof polygonAnnotation)) {
|
|
1812
|
-
return new polygonAnnotation(args);
|
|
1813
|
-
}
|
|
1814
|
-
|
|
1815
|
-
args = $.extend(true, {}, {
|
|
1816
|
-
style: {
|
|
1817
|
-
fill: true,
|
|
1818
|
-
fillColor: {r: 0, g: 1, b: 0},
|
|
1819
|
-
fillOpacity: 0.25,
|
|
1820
|
-
polygon: function (d) { return d.polygon; },
|
|
1821
|
-
stroke: true,
|
|
1822
|
-
strokeColor: {r: 0, g: 0, b: 0},
|
|
1823
|
-
strokeOpacity: 1,
|
|
1824
|
-
strokeWidth: 3,
|
|
1825
|
-
uniformPolygon: true
|
|
1826
|
-
},
|
|
1827
|
-
highlightStyle: {
|
|
1828
|
-
fillColor: {r: 0, g: 1, b: 1},
|
|
1829
|
-
fillOpacity: 0.5,
|
|
1830
|
-
strokeWidth: 5
|
|
1831
|
-
},
|
|
1832
|
-
createStyle: {
|
|
1833
|
-
closed: false,
|
|
1834
|
-
fillColor: {r: 0.3, g: 0.3, b: 0.3},
|
|
1835
|
-
fillOpacity: 0.25,
|
|
1836
|
-
line: function (d) {
|
|
1837
|
-
const coord = m_this._coordinates();
|
|
1838
|
-
/* Return an array that has the same number of items as we have
|
|
1839
|
-
* vertices. */
|
|
1840
|
-
return Array.apply(null, Array((coord.outer || coord).length)).map(
|
|
1841
|
-
function () { return d; });
|
|
1842
|
-
},
|
|
1843
|
-
position: function (d, i) {
|
|
1844
|
-
if (d.x !== undefined) {
|
|
1845
|
-
return d.x;
|
|
1846
|
-
}
|
|
1847
|
-
return m_this.options('vertices')[i];
|
|
1848
|
-
},
|
|
1849
|
-
stroke: false,
|
|
1850
|
-
strokeColor: {r: 0, g: 0, b: 1}
|
|
1851
|
-
}
|
|
1852
|
-
}, args || {});
|
|
1853
|
-
args.vertices = args.vertices || args.coordinates || [];
|
|
1854
|
-
delete args.coordinates;
|
|
1855
|
-
annotation.call(this, 'polygon', args);
|
|
1856
|
-
|
|
1857
|
-
var m_this = this,
|
|
1858
|
-
s_actions = this.actions;
|
|
1859
|
-
|
|
1860
|
-
/**
|
|
1861
|
-
* Get a list of renderable features for this annotation. When the polygon
|
|
1862
|
-
* is done, this is just a single polygon. During creation this can be a
|
|
1863
|
-
* polygon and line at z-levels 1 and 2.
|
|
1864
|
-
*
|
|
1865
|
-
* @returns {array} An array of features.
|
|
1866
|
-
*/
|
|
1867
|
-
this.features = function () {
|
|
1868
|
-
var opt = m_this.options(),
|
|
1869
|
-
state = m_this.state(),
|
|
1870
|
-
style = m_this.styleForState(state),
|
|
1871
|
-
features;
|
|
1872
|
-
switch (state) {
|
|
1873
|
-
case annotationState.create:
|
|
1874
|
-
features = [];
|
|
1875
|
-
if (opt.vertices && (opt.vertices.outer || opt.vertices.length >= 3)) {
|
|
1876
|
-
features[1] = {
|
|
1877
|
-
polygon: {
|
|
1878
|
-
polygon: opt.vertices,
|
|
1879
|
-
style: style
|
|
1880
|
-
}
|
|
1881
|
-
};
|
|
1882
|
-
}
|
|
1883
|
-
if (opt.vertices && opt.vertices.length >= 2) {
|
|
1884
|
-
features[2] = {
|
|
1885
|
-
line: {
|
|
1886
|
-
line: opt.vertices,
|
|
1887
|
-
style: style
|
|
1888
|
-
}
|
|
1889
|
-
};
|
|
1890
|
-
}
|
|
1891
|
-
break;
|
|
1892
|
-
default:
|
|
1893
|
-
features = [{
|
|
1894
|
-
polygon: {
|
|
1895
|
-
polygon: opt.vertices,
|
|
1896
|
-
style: style
|
|
1897
|
-
}
|
|
1898
|
-
}];
|
|
1899
|
-
if (state === annotationState.edit) {
|
|
1900
|
-
m_this._addEditHandles(features, opt.vertices);
|
|
1901
|
-
}
|
|
1902
|
-
break;
|
|
1903
|
-
}
|
|
1904
|
-
return features;
|
|
1905
|
-
};
|
|
1906
|
-
|
|
1907
|
-
/**
|
|
1908
|
-
* Get and optionally set coordinates associated with this annotation in the
|
|
1909
|
-
* map gcs coordinate system.
|
|
1910
|
-
*
|
|
1911
|
-
* @param {geo.geoPosition[]} [coordinates] An optional array of coordinates
|
|
1912
|
-
* to set.
|
|
1913
|
-
* @returns {geo.geoPosition[]} The current array of coordinates.
|
|
1914
|
-
*/
|
|
1915
|
-
this._coordinates = function (coordinates) {
|
|
1916
|
-
if (coordinates) {
|
|
1917
|
-
m_this.options('vertices', coordinates);
|
|
1918
|
-
}
|
|
1919
|
-
return m_this.options('vertices');
|
|
1920
|
-
};
|
|
1921
|
-
|
|
1922
|
-
/**
|
|
1923
|
-
* Handle a mouse move on this annotation.
|
|
1924
|
-
*
|
|
1925
|
-
* @param {geo.event} evt The mouse move event.
|
|
1926
|
-
* @returns {boolean} Truthy to update the annotation, falsy to not
|
|
1927
|
-
* update anything.
|
|
1928
|
-
*/
|
|
1929
|
-
this.mouseMove = function (evt) {
|
|
1930
|
-
if (m_this.state() !== annotationState.create) {
|
|
1931
|
-
return;
|
|
1932
|
-
}
|
|
1933
|
-
var vertices = m_this.options('vertices');
|
|
1934
|
-
if (vertices.length) {
|
|
1935
|
-
vertices[vertices.length - 1] = evt.mapgcs;
|
|
1936
|
-
return true;
|
|
1937
|
-
}
|
|
1938
|
-
};
|
|
1939
|
-
|
|
1940
|
-
/**
|
|
1941
|
-
* Handle a mouse click on this annotation. If the event is processed,
|
|
1942
|
-
* evt.handled should be set to `true` to prevent further processing.
|
|
1943
|
-
*
|
|
1944
|
-
* @param {geo.event} evt The mouse click event.
|
|
1945
|
-
* @returns {boolean|string} `true` to update the annotation, `'done'` if
|
|
1946
|
-
* the annotation was completed (changed from create to done state),
|
|
1947
|
-
* `'remove'` if the annotation should be removed, falsy to not update
|
|
1948
|
-
* anything.
|
|
1949
|
-
*/
|
|
1950
|
-
this.mouseClick = function (evt) {
|
|
1951
|
-
var layer = m_this.layer();
|
|
1952
|
-
if (m_this.state() !== annotationState.create || !layer) {
|
|
1953
|
-
return;
|
|
1954
|
-
}
|
|
1955
|
-
var end = !!evt.buttonsDown.right, skip;
|
|
1956
|
-
if (!evt.buttonsDown.left && !evt.buttonsDown.right) {
|
|
1957
|
-
return;
|
|
1958
|
-
}
|
|
1959
|
-
var vertices = m_this.options('vertices');
|
|
1960
|
-
if (evt.buttonsDown.right && !vertices.length) {
|
|
1961
|
-
return;
|
|
1962
|
-
}
|
|
1963
|
-
evt.handled = true;
|
|
1964
|
-
if (evt.buttonsDown.left) {
|
|
1965
|
-
if (vertices.length) {
|
|
1966
|
-
if (vertices.length >= 2 && layer.displayDistance(
|
|
1967
|
-
vertices[vertices.length - 2], null, evt.map, 'display') <=
|
|
1968
|
-
layer.options('adjacentPointProximity')) {
|
|
1969
|
-
skip = true;
|
|
1970
|
-
if (m_this._lastClick &&
|
|
1971
|
-
evt.time - m_this._lastClick < layer.options('dblClickTime')) {
|
|
1972
|
-
end = true;
|
|
1973
|
-
}
|
|
1974
|
-
} else if (vertices.length >= 2 && layer.displayDistance(
|
|
1975
|
-
vertices[0], null, evt.map, 'display') <=
|
|
1976
|
-
layer.options('finalPointProximity')) {
|
|
1977
|
-
end = true;
|
|
1978
|
-
} else {
|
|
1979
|
-
vertices[vertices.length - 1] = evt.mapgcs;
|
|
1980
|
-
}
|
|
1981
|
-
} else {
|
|
1982
|
-
vertices.push(evt.mapgcs);
|
|
1983
|
-
}
|
|
1984
|
-
if (!end && !skip) {
|
|
1985
|
-
vertices.push(evt.mapgcs);
|
|
1986
|
-
}
|
|
1987
|
-
m_this._lastClick = evt.time;
|
|
1988
|
-
m_this._lastClickVertexCount = vertices.length;
|
|
1989
|
-
}
|
|
1990
|
-
if (end) {
|
|
1991
|
-
if (vertices.length < 4) {
|
|
1992
|
-
return 'remove';
|
|
1993
|
-
}
|
|
1994
|
-
vertices.pop();
|
|
1995
|
-
m_this.state(annotationState.done);
|
|
1996
|
-
return 'done';
|
|
1997
|
-
}
|
|
1998
|
-
return !skip;
|
|
1999
|
-
};
|
|
2000
|
-
|
|
2001
|
-
/**
|
|
2002
|
-
* Return actions needed for the specified state of this annotation.
|
|
2003
|
-
*
|
|
2004
|
-
* @param {string} [state] The state to return actions for. Defaults to
|
|
2005
|
-
* the current state.
|
|
2006
|
-
* @returns {geo.actionRecord[]} A list of actions.
|
|
2007
|
-
*/
|
|
2008
|
-
this.actions = function (state) {
|
|
2009
|
-
return continuousVerticesActions(m_this, s_actions, state, 'polygon', arguments);
|
|
2010
|
-
};
|
|
2011
|
-
|
|
2012
|
-
/**
|
|
2013
|
-
* Process any actions for this annotation.
|
|
2014
|
-
*
|
|
2015
|
-
* @param {geo.event} evt The action event.
|
|
2016
|
-
* @returns {boolean|string} `true` to update the annotation, `'done'` if the
|
|
2017
|
-
* annotation was completed (changed from create to done state),
|
|
2018
|
-
* `'remove'` if the annotation should be removed, falsy to not update
|
|
2019
|
-
* anything.
|
|
2020
|
-
*/
|
|
2021
|
-
this.processAction = function (evt) {
|
|
2022
|
-
return continuousVerticesProcessAction(m_this, evt, 'polygon');
|
|
2023
|
-
};
|
|
2024
|
-
|
|
2025
|
-
/**
|
|
2026
|
-
* Return the coordinates to be stored in a geojson geometry object.
|
|
2027
|
-
*
|
|
2028
|
-
* @param {string|geo.transform|null} [gcs] `undefined` to use the interface
|
|
2029
|
-
* gcs, `null` to use the map gcs, or any other transform.
|
|
2030
|
-
* @returns {array} An array of flattened coordinates in the interface gcs
|
|
2031
|
-
* coordinate system. `undefined` if this annotation is incomplete.
|
|
2032
|
-
*/
|
|
2033
|
-
this._geojsonCoordinates = function (gcs) {
|
|
2034
|
-
var src = m_this.coordinates(gcs);
|
|
2035
|
-
if (!src || (!src.outer && src.length < 3) || m_this.state() === annotationState.create) {
|
|
2036
|
-
return;
|
|
2037
|
-
}
|
|
2038
|
-
var coord = [];
|
|
2039
|
-
if (!src.outer) {
|
|
2040
|
-
coord = [src.map((pt) => [pt.x, pt.y])];
|
|
2041
|
-
coord[0].push(coord[0][0].slice());
|
|
2042
|
-
} else {
|
|
2043
|
-
coord = [src.outer.map((pt) => [pt.x, pt.y])];
|
|
2044
|
-
coord[0].push(coord[0][0].slice());
|
|
2045
|
-
(src.inner || []).forEach((h) => {
|
|
2046
|
-
const poly = h.map((pt) => [pt.x, pt.y]);
|
|
2047
|
-
poly.push(poly[0].slice());
|
|
2048
|
-
coord.push(poly);
|
|
2049
|
-
});
|
|
2050
|
-
}
|
|
2051
|
-
return coord;
|
|
2052
|
-
};
|
|
2053
|
-
|
|
2054
|
-
/**
|
|
2055
|
-
* Return the geometry type that is used to store this annotation in geojson.
|
|
2056
|
-
*
|
|
2057
|
-
* @returns {string} A geojson geometry type.
|
|
2058
|
-
*/
|
|
2059
|
-
this._geojsonGeometryType = function () {
|
|
2060
|
-
return 'Polygon';
|
|
2061
|
-
};
|
|
2062
|
-
|
|
2063
|
-
/**
|
|
2064
|
-
* Return a list of styles that should be preserved in a geojson
|
|
2065
|
-
* representation of the annotation.
|
|
2066
|
-
*
|
|
2067
|
-
* @returns {string[]} A list of style names to store.
|
|
2068
|
-
*/
|
|
2069
|
-
this._geojsonStyles = function () {
|
|
2070
|
-
return [
|
|
2071
|
-
'fill', 'fillColor', 'fillOpacity', 'lineCap', 'lineJoin', 'stroke',
|
|
2072
|
-
'strokeColor', 'strokeOffset', 'strokeOpacity', 'strokeWidth'];
|
|
2073
|
-
};
|
|
2074
|
-
};
|
|
2075
|
-
inherit(polygonAnnotation, annotation);
|
|
2076
|
-
|
|
2077
|
-
var polygonRequiredFeatures = {};
|
|
2078
|
-
polygonRequiredFeatures[polygonFeature.capabilities.feature] = true;
|
|
2079
|
-
polygonRequiredFeatures[lineFeature.capabilities.basic] = [annotationState.create];
|
|
2080
|
-
registerAnnotation('polygon', polygonAnnotation, polygonRequiredFeatures);
|
|
2081
|
-
|
|
2082
|
-
/**
|
|
2083
|
-
* Line annotation specification. Extends {@link geo.annotation.spec}.
|
|
2084
|
-
*
|
|
2085
|
-
* @typedef {object} geo.lineAnnotation.spec
|
|
2086
|
-
* @extends geo.annotation.spec
|
|
2087
|
-
* @property {geo.geoPosition[]} [vertices] A list of vertices in map gcs
|
|
2088
|
-
* coordinates.
|
|
2089
|
-
* @property {geo.geoPosition[]} [coordinates] An alternate name for
|
|
2090
|
-
* `vertices`.
|
|
2091
|
-
* @property {geo.lineFeature.styleSpec} [style] The style to apply to a
|
|
2092
|
-
* finished line. This uses styles for {@link geo.lineFeature}.
|
|
2093
|
-
* @property {geo.lineFeature.styleSpec} [editStyle] The style to apply to a
|
|
2094
|
-
* line in edit mode.
|
|
2095
|
-
*/
|
|
2096
|
-
|
|
2097
|
-
/**
|
|
2098
|
-
* Line annotation class.
|
|
2099
|
-
*
|
|
2100
|
-
* @class
|
|
2101
|
-
* @alias geo.lineAnnotation
|
|
2102
|
-
* @extends geo.annotation
|
|
2103
|
-
*
|
|
2104
|
-
* @param {geo.lineAnnotation.spec?} [args] Options for the annotation.
|
|
2105
|
-
*/
|
|
2106
|
-
var lineAnnotation = function (args) {
|
|
2107
|
-
'use strict';
|
|
2108
|
-
if (!(this instanceof lineAnnotation)) {
|
|
2109
|
-
return new lineAnnotation(args);
|
|
2110
|
-
}
|
|
2111
|
-
|
|
2112
|
-
args = $.extend(true, {}, {
|
|
2113
|
-
style: {
|
|
2114
|
-
line: function (d) {
|
|
2115
|
-
/* Return an array that has the same number of items as we have
|
|
2116
|
-
* vertices. */
|
|
2117
|
-
return Array.apply(null, Array(m_this.options('vertices').length)).map(
|
|
2118
|
-
function () { return d; });
|
|
2119
|
-
},
|
|
2120
|
-
position: function (d, i) {
|
|
2121
|
-
return m_this.options('vertices')[i];
|
|
2122
|
-
},
|
|
2123
|
-
strokeColor: {r: 0, g: 0, b: 0},
|
|
2124
|
-
strokeOpacity: 1,
|
|
2125
|
-
strokeWidth: 3,
|
|
2126
|
-
closed: false,
|
|
2127
|
-
lineCap: 'butt',
|
|
2128
|
-
lineJoin: 'miter'
|
|
2129
|
-
},
|
|
2130
|
-
highlightStyle: {
|
|
2131
|
-
strokeWidth: 5
|
|
2132
|
-
},
|
|
2133
|
-
createStyle: {
|
|
2134
|
-
line: function (d) {
|
|
2135
|
-
/* Return an array that has the same number of items as we have
|
|
2136
|
-
* vertices. */
|
|
2137
|
-
return Array.apply(null, Array(m_this.options('vertices').length)).map(
|
|
2138
|
-
function () { return d; });
|
|
2139
|
-
},
|
|
2140
|
-
position: function (d, i) {
|
|
2141
|
-
return m_this.options('vertices')[i];
|
|
2142
|
-
},
|
|
2143
|
-
strokeColor: {r: 0, g: 0, b: 1},
|
|
2144
|
-
strokeOpacity: 1,
|
|
2145
|
-
strokeWidth: 3,
|
|
2146
|
-
closed: false,
|
|
2147
|
-
lineCap: 'butt',
|
|
2148
|
-
lineJoin: 'miter'
|
|
2149
|
-
}
|
|
2150
|
-
}, args || {});
|
|
2151
|
-
args.vertices = args.vertices || args.coordinates || [];
|
|
2152
|
-
delete args.coordinates;
|
|
2153
|
-
annotation.call(this, 'line', args);
|
|
2154
|
-
|
|
2155
|
-
var m_this = this,
|
|
2156
|
-
s_actions = this.actions,
|
|
2157
|
-
s_processEditAction = this.processEditAction;
|
|
2158
|
-
|
|
2159
|
-
/**
|
|
2160
|
-
* Get a list of renderable features for this annotation.
|
|
2161
|
-
*
|
|
2162
|
-
* @returns {array} An array of features.
|
|
2163
|
-
*/
|
|
2164
|
-
this.features = function () {
|
|
2165
|
-
var opt = m_this.options(),
|
|
2166
|
-
state = m_this.state(),
|
|
2167
|
-
features;
|
|
2168
|
-
switch (state) {
|
|
2169
|
-
case annotationState.create:
|
|
2170
|
-
features = [{
|
|
2171
|
-
line: {
|
|
2172
|
-
line: opt.vertices,
|
|
2173
|
-
style: m_this.styleForState(state)
|
|
2174
|
-
}
|
|
2175
|
-
}];
|
|
2176
|
-
break;
|
|
2177
|
-
default:
|
|
2178
|
-
features = [{
|
|
2179
|
-
line: {
|
|
2180
|
-
line: opt.vertices,
|
|
2181
|
-
style: m_this.styleForState(state)
|
|
2182
|
-
}
|
|
2183
|
-
}];
|
|
2184
|
-
if (state === annotationState.edit) {
|
|
2185
|
-
m_this._addEditHandles(features, opt.vertices, undefined, !m_this.style('closed'));
|
|
2186
|
-
}
|
|
2187
|
-
break;
|
|
2188
|
-
}
|
|
2189
|
-
return features;
|
|
2190
|
-
};
|
|
2191
|
-
|
|
2192
|
-
/**
|
|
2193
|
-
* Get and optionally set coordinates associated with this annotation in the
|
|
2194
|
-
* map gcs coordinate system.
|
|
2195
|
-
*
|
|
2196
|
-
* @param {geo.geoPosition[]} [coordinates] An optional array of coordinates
|
|
2197
|
-
* to set.
|
|
2198
|
-
* @returns {geo.geoPosition[]} The current array of coordinates.
|
|
2199
|
-
*/
|
|
2200
|
-
this._coordinates = function (coordinates) {
|
|
2201
|
-
if (coordinates) {
|
|
2202
|
-
m_this.options('vertices', coordinates);
|
|
2203
|
-
}
|
|
2204
|
-
return m_this.options('vertices');
|
|
2205
|
-
};
|
|
2206
|
-
|
|
2207
|
-
/**
|
|
2208
|
-
* Handle a mouse move on this annotation.
|
|
2209
|
-
*
|
|
2210
|
-
* @param {geo.event} evt The mouse move event.
|
|
2211
|
-
* @returns {boolean} Truthy to update the annotation, falsy to not
|
|
2212
|
-
* update anything.
|
|
2213
|
-
*/
|
|
2214
|
-
this.mouseMove = function (evt) {
|
|
2215
|
-
if (m_this.state() !== annotationState.create) {
|
|
2216
|
-
return;
|
|
2217
|
-
}
|
|
2218
|
-
var vertices = m_this.options('vertices');
|
|
2219
|
-
if (vertices.length) {
|
|
2220
|
-
vertices[vertices.length - 1] = evt.mapgcs;
|
|
2221
|
-
return true;
|
|
2222
|
-
}
|
|
2223
|
-
};
|
|
2224
|
-
|
|
2225
|
-
/**
|
|
2226
|
-
* Handle a mouse click on this annotation. If the event is processed,
|
|
2227
|
-
* evt.handled should be set to `true` to prevent further processing.
|
|
2228
|
-
*
|
|
2229
|
-
* @param {geo.event} evt The mouse click event.
|
|
2230
|
-
* @returns {boolean|string} `true` to update the annotation, `'done'` if
|
|
2231
|
-
* the annotation was completed (changed from create to done state),
|
|
2232
|
-
* `'remove'` if the annotation should be removed, falsy to not update
|
|
2233
|
-
* anything.
|
|
2234
|
-
*/
|
|
2235
|
-
this.mouseClick = function (evt) {
|
|
2236
|
-
var layer = m_this.layer();
|
|
2237
|
-
if (m_this.state() !== annotationState.create || !layer) {
|
|
2238
|
-
return;
|
|
2239
|
-
}
|
|
2240
|
-
var end = !!evt.buttonsDown.right, skip;
|
|
2241
|
-
if (!evt.buttonsDown.left && !evt.buttonsDown.right) {
|
|
2242
|
-
return;
|
|
2243
|
-
}
|
|
2244
|
-
var vertices = m_this.options('vertices');
|
|
2245
|
-
if (evt.buttonsDown.right && !vertices.length) {
|
|
2246
|
-
return;
|
|
2247
|
-
}
|
|
2248
|
-
evt.handled = true;
|
|
2249
|
-
if (evt.buttonsDown.left) {
|
|
2250
|
-
if (vertices.length) {
|
|
2251
|
-
if (vertices.length >= 2 && layer.displayDistance(
|
|
2252
|
-
vertices[vertices.length - 2], null, evt.map, 'display') <=
|
|
2253
|
-
layer.options('adjacentPointProximity')) {
|
|
2254
|
-
skip = true;
|
|
2255
|
-
if (m_this._lastClick &&
|
|
2256
|
-
evt.time - m_this._lastClick < layer.options('dblClickTime')) {
|
|
2257
|
-
end = true;
|
|
2258
|
-
}
|
|
2259
|
-
} else if (vertices.length >= 2 && layer.displayDistance(
|
|
2260
|
-
vertices[0], null, evt.map, 'display') <=
|
|
2261
|
-
layer.options('finalPointProximity')) {
|
|
2262
|
-
end = 'close';
|
|
2263
|
-
} else {
|
|
2264
|
-
vertices[vertices.length - 1] = evt.mapgcs;
|
|
2265
|
-
}
|
|
2266
|
-
} else {
|
|
2267
|
-
vertices.push(evt.mapgcs);
|
|
2268
|
-
}
|
|
2269
|
-
if (!end && !skip) {
|
|
2270
|
-
vertices.push(evt.mapgcs);
|
|
2271
|
-
}
|
|
2272
|
-
m_this._lastClick = evt.time;
|
|
2273
|
-
m_this._lastClickVertexCount = vertices.length;
|
|
2274
|
-
}
|
|
2275
|
-
if (end) {
|
|
2276
|
-
if (vertices.length < 3) {
|
|
2277
|
-
return 'remove';
|
|
2278
|
-
}
|
|
2279
|
-
vertices.pop();
|
|
2280
|
-
m_this.options('style').closed = end === 'close';
|
|
2281
|
-
m_this.state(annotationState.done);
|
|
2282
|
-
return 'done';
|
|
2283
|
-
}
|
|
2284
|
-
return !skip;
|
|
2285
|
-
};
|
|
2286
|
-
|
|
2287
|
-
/**
|
|
2288
|
-
* Return actions needed for the specified state of this annotation.
|
|
2289
|
-
*
|
|
2290
|
-
* @param {string} [state] The state to return actions for. Defaults to
|
|
2291
|
-
* the current state.
|
|
2292
|
-
* @returns {geo.actionRecord[]} A list of actions.
|
|
2293
|
-
*/
|
|
2294
|
-
this.actions = function (state) {
|
|
2295
|
-
return continuousVerticesActions(m_this, s_actions, state, 'line', arguments);
|
|
2296
|
-
};
|
|
2297
|
-
|
|
2298
|
-
/**
|
|
2299
|
-
* Process any actions for this annotation.
|
|
2300
|
-
*
|
|
2301
|
-
* @param {geo.event} evt The action event.
|
|
2302
|
-
* @returns {boolean|string} `true` to update the annotation, `'done'` if the
|
|
2303
|
-
* annotation was completed (changed from create to done state),
|
|
2304
|
-
* `'remove'` if the annotation should be removed, falsy to not update
|
|
2305
|
-
* anything.
|
|
2306
|
-
*/
|
|
2307
|
-
this.processAction = function (evt) {
|
|
2308
|
-
return continuousVerticesProcessAction(m_this, evt, 'line');
|
|
2309
|
-
};
|
|
2310
|
-
|
|
2311
|
-
/**
|
|
2312
|
-
* Return the coordinates to be stored in a geojson geometry object.
|
|
2313
|
-
*
|
|
2314
|
-
* @param {string|geo.transform|null} [gcs] `undefined` to use the interface
|
|
2315
|
-
* gcs, `null` to use the map gcs, or any other transform.
|
|
2316
|
-
* @returns {array} An array of flattened coordinates in the interface gcs
|
|
2317
|
-
* coordinate system. `undefined` if this annotation is incomplete.
|
|
2318
|
-
*/
|
|
2319
|
-
this._geojsonCoordinates = function (gcs) {
|
|
2320
|
-
var src = m_this.coordinates(gcs);
|
|
2321
|
-
if (!src || src.length < 2 || m_this.state() === annotationState.create) {
|
|
2322
|
-
return;
|
|
2323
|
-
}
|
|
2324
|
-
var coord = [];
|
|
2325
|
-
for (var i = 0; i < src.length; i += 1) {
|
|
2326
|
-
coord.push([src[i].x, src[i].y]);
|
|
2327
|
-
}
|
|
2328
|
-
return coord;
|
|
2329
|
-
};
|
|
2330
|
-
|
|
2331
|
-
/**
|
|
2332
|
-
* Return the geometry type that is used to store this annotation in geojson.
|
|
2333
|
-
*
|
|
2334
|
-
* @returns {string} A geojson geometry type.
|
|
2335
|
-
*/
|
|
2336
|
-
this._geojsonGeometryType = function () {
|
|
2337
|
-
return 'LineString';
|
|
2338
|
-
};
|
|
2339
|
-
|
|
2340
|
-
/**
|
|
2341
|
-
* Return a list of styles that should be preserved in a geojson
|
|
2342
|
-
* representation of the annotation.
|
|
2343
|
-
*
|
|
2344
|
-
* @returns {string[]} A list of style names to store.
|
|
2345
|
-
*/
|
|
2346
|
-
this._geojsonStyles = function () {
|
|
2347
|
-
return [
|
|
2348
|
-
'closed', 'lineCap', 'lineJoin', 'strokeColor', 'strokeOffset',
|
|
2349
|
-
'strokeOpacity', 'strokeWidth'];
|
|
2350
|
-
};
|
|
2351
|
-
|
|
2352
|
-
/**
|
|
2353
|
-
* Process any edit actions for this annotation.
|
|
2354
|
-
*
|
|
2355
|
-
* @param {geo.event} evt The action event.
|
|
2356
|
-
* @returns {boolean|string} `true` to update the annotation, falsy to not
|
|
2357
|
-
* update anything.
|
|
2358
|
-
*/
|
|
2359
|
-
this.processEditAction = function (evt) {
|
|
2360
|
-
switch (m_this._editHandle.handle.type) {
|
|
2361
|
-
case 'vertex':
|
|
2362
|
-
return m_this._processEditActionVertex(evt, true);
|
|
2363
|
-
}
|
|
2364
|
-
return s_processEditAction.apply(m_this, arguments);
|
|
2365
|
-
};
|
|
2366
|
-
|
|
2367
|
-
/**
|
|
2368
|
-
* Handle a mouse click on this annotation when in edit mode. If the event
|
|
2369
|
-
* is processed, evt.handled should be set to `true` to prevent further
|
|
2370
|
-
* processing.
|
|
2371
|
-
*
|
|
2372
|
-
* @param {geo.event} evt The mouse click event.
|
|
2373
|
-
* @returns {boolean|string} `true` to update the annotation, `'done'` if
|
|
2374
|
-
* the annotation was completed (changed from create to done state),
|
|
2375
|
-
* `'remove'` if the annotation should be removed, falsy to not update
|
|
2376
|
-
* anything.
|
|
2377
|
-
*/
|
|
2378
|
-
this.mouseClickEdit = function (evt) {
|
|
2379
|
-
// if we get a left double click on an edge on a closed line, break the
|
|
2380
|
-
// line at that edge
|
|
2381
|
-
var layer = m_this.layer(),
|
|
2382
|
-
handle = m_this._editHandle,
|
|
2383
|
-
split;
|
|
2384
|
-
// ensure we are in edit mode and this is a left click
|
|
2385
|
-
if (m_this.state() !== annotationState.edit || !layer || !evt.buttonsDown.left) {
|
|
2386
|
-
return;
|
|
2387
|
-
}
|
|
2388
|
-
// ensure this is an edge on a closed line
|
|
2389
|
-
if (!handle || !handle.handle.selected || handle.handle.type !== 'edge' || !m_this.options('style').closed) {
|
|
2390
|
-
return;
|
|
2391
|
-
}
|
|
2392
|
-
evt.handled = true;
|
|
2393
|
-
if (m_this._lastClick && evt.time - m_this._lastClick < layer.options('dblClickTime')) {
|
|
2394
|
-
split = true;
|
|
2395
|
-
}
|
|
2396
|
-
m_this._lastClick = evt.time;
|
|
2397
|
-
if (split) {
|
|
2398
|
-
var index = handle.handle.index,
|
|
2399
|
-
curPts = m_this._coordinates(),
|
|
2400
|
-
pts = curPts.slice(index + 1).concat(curPts.slice(0, index + 1));
|
|
2401
|
-
m_this._coordinates(pts);
|
|
2402
|
-
m_this.options('style').closed = false;
|
|
2403
|
-
handle.handle.index = undefined;
|
|
2404
|
-
return true;
|
|
2405
|
-
}
|
|
2406
|
-
};
|
|
2407
|
-
|
|
2408
|
-
};
|
|
2409
|
-
inherit(lineAnnotation, annotation);
|
|
2410
|
-
|
|
2411
|
-
var lineRequiredFeatures = {};
|
|
2412
|
-
lineRequiredFeatures[lineFeature.capabilities.basic] = [annotationState.create];
|
|
2413
|
-
registerAnnotation('line', lineAnnotation, lineRequiredFeatures);
|
|
2414
|
-
|
|
2415
|
-
/**
|
|
2416
|
-
* Point annotation specification. Extends {@link geo.annotation.spec}.
|
|
2417
|
-
*
|
|
2418
|
-
* @typedef {object} geo.pointAnnotation.spec
|
|
2419
|
-
* @extends geo.annotation.spec
|
|
2420
|
-
* @property {geo.geoPosition} [position] A coordinate in map gcs coordinates.
|
|
2421
|
-
* @property {geo.geoPosition[]} [coordinates] An array with one coordinate to
|
|
2422
|
-
* use in place of `position`.
|
|
2423
|
-
* @property {geo.pointFeature.styleSpec} [style] The style to apply to a
|
|
2424
|
-
* finished point. This uses styles for {@link geo.pointFeature}.
|
|
2425
|
-
* @property {boolean|number} [style.scaled=false] If `false`, the point is not
|
|
2426
|
-
* scaled with zoom level. If `true`, the radius is based on the zoom level
|
|
2427
|
-
* at first instantiation. If a number, the radius is used at the `scaled`
|
|
2428
|
-
* zoom level.
|
|
2429
|
-
* @property {geo.pointFeature.styleSpec} [editStyle] The style to apply to a
|
|
2430
|
-
* point in edit mode.
|
|
2431
|
-
*/
|
|
2432
|
-
|
|
2433
|
-
/**
|
|
2434
|
-
* Point annotation class.
|
|
2435
|
-
*
|
|
2436
|
-
* @class
|
|
2437
|
-
* @alias geo.pointAnnotation
|
|
2438
|
-
* @extends geo.annotation
|
|
2439
|
-
*
|
|
2440
|
-
* @param {geo.pointAnnotation.spec?} [args] Options for the annotation.
|
|
2441
|
-
*/
|
|
2442
|
-
var pointAnnotation = function (args) {
|
|
2443
|
-
'use strict';
|
|
2444
|
-
if (!(this instanceof pointAnnotation)) {
|
|
2445
|
-
return new pointAnnotation(args);
|
|
2446
|
-
}
|
|
2447
|
-
|
|
2448
|
-
args = $.extend(true, {}, {
|
|
2449
|
-
style: {
|
|
2450
|
-
fill: true,
|
|
2451
|
-
fillColor: {r: 0, g: 1, b: 0},
|
|
2452
|
-
fillOpacity: 0.25,
|
|
2453
|
-
radius: 10,
|
|
2454
|
-
scaled: false,
|
|
2455
|
-
stroke: true,
|
|
2456
|
-
strokeColor: {r: 0, g: 0, b: 0},
|
|
2457
|
-
strokeOpacity: 1,
|
|
2458
|
-
strokeWidth: 3
|
|
2459
|
-
},
|
|
2460
|
-
createStyle: {
|
|
2461
|
-
fillColor: {r: 0.3, g: 0.3, b: 0.3},
|
|
2462
|
-
fillOpacity: 0.25,
|
|
2463
|
-
strokeColor: {r: 0, g: 0, b: 1}
|
|
2464
|
-
},
|
|
2465
|
-
highlightStyle: {
|
|
2466
|
-
fillColor: {r: 0, g: 1, b: 1},
|
|
2467
|
-
fillOpacity: 0.5,
|
|
2468
|
-
strokeWidth: 5
|
|
2469
|
-
}
|
|
2470
|
-
}, args || {});
|
|
2471
|
-
args.position = args.position || (args.coordinates ? args.coordinates[0] : undefined);
|
|
2472
|
-
delete args.coordinates;
|
|
2473
|
-
annotation.call(this, 'point', args);
|
|
2474
|
-
|
|
2475
|
-
var m_this = this;
|
|
2476
|
-
|
|
2477
|
-
/**
|
|
2478
|
-
* Get a list of renderable features for this annotation.
|
|
2479
|
-
*
|
|
2480
|
-
* @returns {array} An array of features.
|
|
2481
|
-
*/
|
|
2482
|
-
this.features = function () {
|
|
2483
|
-
var opt = m_this.options(),
|
|
2484
|
-
state = m_this.state(),
|
|
2485
|
-
features, style, scaleOnZoom;
|
|
2486
|
-
switch (state) {
|
|
2487
|
-
case annotationState.create:
|
|
2488
|
-
features = [];
|
|
2489
|
-
break;
|
|
2490
|
-
default:
|
|
2491
|
-
style = m_this.styleForState(state);
|
|
2492
|
-
if (opt.style.scaled || opt.style.scaled === 0) {
|
|
2493
|
-
if (opt.style.scaled === true) {
|
|
2494
|
-
opt.style.scaled = m_this.layer().map().zoom();
|
|
2495
|
-
}
|
|
2496
|
-
style = $.extend({}, style, {
|
|
2497
|
-
radius: function () {
|
|
2498
|
-
var radius = opt.style.radius,
|
|
2499
|
-
zoom = m_this.layer().map().zoom();
|
|
2500
|
-
if (util.isFunction(radius)) {
|
|
2501
|
-
radius = radius.apply(m_this, arguments);
|
|
2502
|
-
}
|
|
2503
|
-
radius *= Math.pow(2, zoom - opt.style.scaled);
|
|
2504
|
-
return radius;
|
|
2505
|
-
}
|
|
2506
|
-
});
|
|
2507
|
-
scaleOnZoom = true;
|
|
2508
|
-
}
|
|
2509
|
-
features = [{
|
|
2510
|
-
point: {
|
|
2511
|
-
x: opt.position.x,
|
|
2512
|
-
y: opt.position.y,
|
|
2513
|
-
style: style,
|
|
2514
|
-
scaleOnZoom: scaleOnZoom
|
|
2515
|
-
}
|
|
2516
|
-
}];
|
|
2517
|
-
if (state === annotationState.edit) {
|
|
2518
|
-
m_this._addEditHandles(
|
|
2519
|
-
features, [opt.position],
|
|
2520
|
-
{edge: false, center: false, resize: false, rotate: false});
|
|
2521
|
-
}
|
|
2522
|
-
break;
|
|
2523
|
-
}
|
|
2524
|
-
return features;
|
|
2525
|
-
};
|
|
2526
|
-
|
|
2527
|
-
/**
|
|
2528
|
-
* Get and optionally set coordinates associated with this annotation in the
|
|
2529
|
-
* map gcs coordinate system.
|
|
2530
|
-
*
|
|
2531
|
-
* @param {geo.geoPosition[]} [coordinates] An optional array of coordinates
|
|
2532
|
-
* to set.
|
|
2533
|
-
* @returns {geo.geoPosition[]} The current array of coordinates.
|
|
2534
|
-
*/
|
|
2535
|
-
this._coordinates = function (coordinates) {
|
|
2536
|
-
if (coordinates && coordinates.length >= 1) {
|
|
2537
|
-
m_this.options('position', coordinates[0]);
|
|
2538
|
-
}
|
|
2539
|
-
if (m_this.state() === annotationState.create) {
|
|
2540
|
-
return [];
|
|
2541
|
-
}
|
|
2542
|
-
return [m_this.options('position')];
|
|
2543
|
-
};
|
|
2544
|
-
|
|
2545
|
-
this._coordinateOption = 'position';
|
|
2546
|
-
|
|
2547
|
-
/**
|
|
2548
|
-
* Handle a mouse click on this annotation. If the event is processed,
|
|
2549
|
-
* evt.handled should be set to `true` to prevent further processing.
|
|
2550
|
-
*
|
|
2551
|
-
* @param {geo.event} evt The mouse click event.
|
|
2552
|
-
* @returns {boolean|string} `true` to update the annotation, `'done'` if
|
|
2553
|
-
* the annotation was completed (changed from create to done state),
|
|
2554
|
-
* `'remove'` if the annotation should be removed, falsy to not update
|
|
2555
|
-
* anything.
|
|
2556
|
-
*/
|
|
2557
|
-
this.mouseClick = function (evt) {
|
|
2558
|
-
if (m_this.state() !== annotationState.create) {
|
|
2559
|
-
return;
|
|
2560
|
-
}
|
|
2561
|
-
if (!evt.buttonsDown.left) {
|
|
2562
|
-
return;
|
|
2563
|
-
}
|
|
2564
|
-
evt.handled = true;
|
|
2565
|
-
m_this.options('position', evt.mapgcs);
|
|
2566
|
-
m_this.state(annotationState.done);
|
|
2567
|
-
return 'done';
|
|
2568
|
-
};
|
|
2569
|
-
|
|
2570
|
-
/**
|
|
2571
|
-
* Return a list of styles that should be preserved in a geojson
|
|
2572
|
-
* representation of the annotation.
|
|
2573
|
-
*
|
|
2574
|
-
* @returns {string[]} A list of style names to store.
|
|
2575
|
-
*/
|
|
2576
|
-
this._geojsonStyles = function () {
|
|
2577
|
-
return [
|
|
2578
|
-
'fill', 'fillColor', 'fillOpacity', 'radius', 'scaled', 'stroke',
|
|
2579
|
-
'strokeColor', 'strokeOpacity', 'strokeWidth'];
|
|
2580
|
-
};
|
|
2581
|
-
|
|
2582
|
-
/**
|
|
2583
|
-
* Return the coordinates to be stored in a geojson geometry object.
|
|
2584
|
-
*
|
|
2585
|
-
* @param {string|geo.transform|null} [gcs] `undefined` to use the interface
|
|
2586
|
-
* gcs, `null` to use the map gcs, or any other transform.
|
|
2587
|
-
* @returns {array} An array of flattened coordinates in the interface gcs
|
|
2588
|
-
* coordinate system. `undefined` if this annotation is incomplete.
|
|
2589
|
-
*/
|
|
2590
|
-
this._geojsonCoordinates = function (gcs) {
|
|
2591
|
-
var src = m_this.coordinates(gcs);
|
|
2592
|
-
if (!src || m_this.state() === annotationState.create || src.length < 1 || src[0] === undefined) {
|
|
2593
|
-
return;
|
|
2594
|
-
}
|
|
2595
|
-
return [src[0].x, src[0].y];
|
|
2596
|
-
};
|
|
2597
|
-
|
|
2598
|
-
/**
|
|
2599
|
-
* Return the geometry type that is used to store this annotation in geojson.
|
|
2600
|
-
*
|
|
2601
|
-
* @returns {string} A geojson geometry type.
|
|
2602
|
-
*/
|
|
2603
|
-
this._geojsonGeometryType = function () {
|
|
2604
|
-
return 'Point';
|
|
2605
|
-
};
|
|
2606
|
-
};
|
|
2607
|
-
inherit(pointAnnotation, annotation);
|
|
2608
|
-
|
|
2609
|
-
var pointRequiredFeatures = {};
|
|
2610
|
-
pointRequiredFeatures[pointFeature.capabilities.feature] = true;
|
|
2611
|
-
registerAnnotation('point', pointAnnotation, pointRequiredFeatures);
|
|
2612
|
-
|
|
2613
1264
|
/**
|
|
2614
1265
|
* Return a function that can be used as a selectionConstraint that requires
|
|
2615
1266
|
* that the aspect ratio of a rectangle-like selection is a specific value or
|
|
2616
1267
|
* range of values.
|
|
2617
1268
|
*
|
|
2618
|
-
* @param {number|number[]} ratio Either a single
|
|
2619
|
-
*
|
|
2620
|
-
*
|
|
2621
|
-
*
|
|
1269
|
+
* @param {number|number[]|geo.geoSize|geo.geoSize[]} ratio Either a single
|
|
1270
|
+
* aspect ratio, a single size, or a list of allowed aspect ratios and sizes.
|
|
1271
|
+
* For instance, 1 will require that the selection square, 2 would require
|
|
1272
|
+
* that it is twice as wide as tall, [2, 1/2] would allow it to be twice as
|
|
1273
|
+
* wide or half as wide as it is tall. Sizes (e.g., {width: 400, height:
|
|
1274
|
+
* 500}) snap to that size.
|
|
2622
1275
|
* @returns {function} A function that can be passed to the mapIterator
|
|
2623
1276
|
* selectionConstraint or to an annotation constraint function.
|
|
2624
1277
|
*/
|
|
@@ -2664,16 +1317,23 @@ function constrainAspectRatio(ratio) {
|
|
|
2664
1317
|
const area = Math.abs(dist1 * dist3);
|
|
2665
1318
|
let shape, edge;
|
|
2666
1319
|
ratios.forEach((ratio) => {
|
|
2667
|
-
|
|
2668
|
-
|
|
1320
|
+
let width, height;
|
|
1321
|
+
if (ratio.width) {
|
|
1322
|
+
width = ratio.width;
|
|
1323
|
+
height = ratio.height;
|
|
1324
|
+
} else {
|
|
1325
|
+
width = (area * ratio) ** 0.5;
|
|
1326
|
+
height = width / ratio;
|
|
1327
|
+
}
|
|
1328
|
+
if (width !== height && !(index % 2)) {
|
|
1329
|
+
[width, height] = [height, width];
|
|
2669
1330
|
}
|
|
2670
|
-
const
|
|
2671
|
-
const score = (width - dist3) ** 2 + (width / ratio - dist1) ** 2;
|
|
1331
|
+
const score = (width - dist3) ** 2 + (height - dist1) ** 2;
|
|
2672
1332
|
if (best === undefined || score < best) {
|
|
2673
1333
|
best = score;
|
|
2674
1334
|
shape = {
|
|
2675
1335
|
w: width,
|
|
2676
|
-
h:
|
|
1336
|
+
h: height
|
|
2677
1337
|
};
|
|
2678
1338
|
}
|
|
2679
1339
|
});
|
|
@@ -2715,10 +1375,17 @@ function constrainAspectRatio(ratio) {
|
|
|
2715
1375
|
/* Not in edit vertex or edge mode */
|
|
2716
1376
|
const area = Math.abs((pos.x - origin.x) * (pos.y - origin.y));
|
|
2717
1377
|
ratios.forEach((ratio) => {
|
|
2718
|
-
|
|
1378
|
+
let width, height;
|
|
1379
|
+
if (ratio.width) {
|
|
1380
|
+
width = ratio.width;
|
|
1381
|
+
height = ratio.height;
|
|
1382
|
+
} else {
|
|
1383
|
+
width = (area * ratio) ** 0.5;
|
|
1384
|
+
height = width / ratio;
|
|
1385
|
+
}
|
|
2719
1386
|
const adjusted = {
|
|
2720
1387
|
x: origin.x + Math.sign(pos.x - origin.x) * width,
|
|
2721
|
-
y: origin.y + Math.sign(pos.y - origin.y) *
|
|
1388
|
+
y: origin.y + Math.sign(pos.y - origin.y) * height
|
|
2722
1389
|
};
|
|
2723
1390
|
const score = (adjusted.x - pos.x) ** 2 + (adjusted.y - pos.y) ** 2;
|
|
2724
1391
|
if (best === undefined || score < best) {
|
|
@@ -2745,14 +1412,11 @@ module.exports = {
|
|
|
2745
1412
|
state: annotationState,
|
|
2746
1413
|
actionOwner: annotationActionOwner,
|
|
2747
1414
|
annotation: annotation,
|
|
2748
|
-
lineAnnotation: lineAnnotation,
|
|
2749
|
-
pointAnnotation: pointAnnotation,
|
|
2750
|
-
polygonAnnotation: polygonAnnotation,
|
|
2751
|
-
rectangleAnnotation: rectangleAnnotation,
|
|
2752
|
-
squareAnnotation: squareAnnotation,
|
|
2753
|
-
ellipseAnnotation: ellipseAnnotation,
|
|
2754
|
-
circleAnnotation: circleAnnotation,
|
|
2755
1415
|
_editHandleFeatureLevel: editHandleFeatureLevel,
|
|
2756
|
-
defaultEditHandleStyle
|
|
2757
|
-
constrainAspectRatio
|
|
1416
|
+
defaultEditHandleStyle,
|
|
1417
|
+
constrainAspectRatio,
|
|
1418
|
+
// these aren't exposed in index.js
|
|
1419
|
+
annotationActionOwner,
|
|
1420
|
+
continuousVerticesActions,
|
|
1421
|
+
continuousVerticesProcessAction
|
|
2758
1422
|
};
|