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/geo.js CHANGED
@@ -41,13 +41,11 @@ module.exports = geo_action;
41
41
 
42
42
  /***/ }),
43
43
 
44
- /***/ 7800:
44
+ /***/ 5784:
45
45
  /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
46
46
 
47
47
  var $ = __webpack_require__(5638);
48
48
 
49
- var inherit = __webpack_require__(5699);
50
-
51
49
  var geo_event = __webpack_require__(5108);
52
50
 
53
51
  var geo_action = __webpack_require__(7839);
@@ -56,16 +54,6 @@ var transform = __webpack_require__(6853);
56
54
 
57
55
  var util = __webpack_require__(4634);
58
56
 
59
- var registerAnnotation = (__webpack_require__(4647).registerAnnotation);
60
-
61
- var lineFeature = __webpack_require__(4708);
62
-
63
- var markerFeature = __webpack_require__(7098);
64
-
65
- var pointFeature = __webpack_require__(2557);
66
-
67
- var polygonFeature = __webpack_require__(4343);
68
-
69
57
  var textFeature = __webpack_require__(9757);
70
58
 
71
59
  var annotationId = 0;
@@ -1542,186 +1530,282 @@ function continuousVerticesProcessAction(m_this, evt, name) {
1542
1530
  }
1543
1531
  }
1544
1532
  /**
1545
- * Rectangle annotation specification. Extends {@link geo.annotation.spec}.
1533
+ * Return a function that can be used as a selectionConstraint that requires
1534
+ * that the aspect ratio of a rectangle-like selection is a specific value or
1535
+ * range of values.
1546
1536
  *
1547
- * @typedef {object} geo.rectangleAnnotation.spec
1548
- * @extends geo.annotation.spec
1549
- * @property {geo.geoPosition[]} [corners] A list of four corners in map gcs
1550
- * coordinates. These must be in order around the perimeter of the
1551
- * rectangle (in either direction).
1552
- * @property {geo.geoPosition[]} [coordinates] An alternate name for `corners`.
1553
- * @property {geo.polygonFeature.styleSpec} [style] The style to apply to a
1554
- * finished rectangle. This uses styles for {@link geo.polygonFeature}.
1555
- * @property {geo.polygonFeature.styleSpec} [editStyle] The style to apply to a
1556
- * rectangle in edit mode.
1557
- * @property {number|number[]|function} [constraint] If specified, an aspect
1558
- * ratio or list of aspect ratios to constraint the rectangle to. If a
1559
- * function, a selection constraint function to call to adjust the
1560
- * rectangle.
1537
+ * @param {number|number[]|geo.geoSize|geo.geoSize[]} ratio Either a single
1538
+ * aspect ratio, a single size, or a list of allowed aspect ratios and sizes.
1539
+ * For instance, 1 will require that the selection square, 2 would require
1540
+ * that it is twice as wide as tall, [2, 1/2] would allow it to be twice as
1541
+ * wide or half as wide as it is tall. Sizes (e.g., {width: 400, height:
1542
+ * 500}) snap to that size.
1543
+ * @returns {function} A function that can be passed to the mapIterator
1544
+ * selectionConstraint or to an annotation constraint function.
1561
1545
  */
1562
1546
 
1547
+
1548
+ function constrainAspectRatio(ratio) {
1549
+ var ratios = Array.isArray(ratio) ? ratio : [ratio];
1550
+ /**
1551
+ * Constrain a mouse action or annotation action to a list of aspect ratios.
1552
+ *
1553
+ * @param {geo.geoPosition} pos Mouse or new location in map gcs.
1554
+ * @param {geo.geoPosition} origin Origin in map gcs when the activity
1555
+ * started.
1556
+ * @param {geo.geoPosition} [corners] If specified, an array of corner
1557
+ * locations in mapgcs. This may be modified.
1558
+ * @param {string?} [mode] 'edge', 'vertex' or falsy. A falsy value implies
1559
+ * this is just the most recent point in the annotation, otherwise it is
1560
+ * the portion of the annotation being modified.
1561
+ * @param {number} [ang] A list of angles of each side of the polygon
1562
+ * represented by corners or the original annotation.
1563
+ * @param {integer} [index] The specific vertex or edge that is being
1564
+ * modified.
1565
+ * @returns {object} An object with the ``origin`` (this is what is passed
1566
+ * in), a new position as ``pos``, and the updated corners as ``corners``.
1567
+ */
1568
+
1569
+ function constraintFunction(pos, origin, corners, mode, ang, index) {
1570
+ var newpos = pos;
1571
+ var best;
1572
+
1573
+ if (!corners) {
1574
+ corners = [{
1575
+ x: origin.x,
1576
+ y: origin.y
1577
+ }, {
1578
+ x: pos.x,
1579
+ y: origin.y
1580
+ }, {
1581
+ x: pos.x,
1582
+ y: pos.y
1583
+ }, {
1584
+ x: origin.x,
1585
+ y: pos.y
1586
+ }];
1587
+ }
1588
+
1589
+ if (mode) {
1590
+ /* Edit a vertex or edge */
1591
+ var i1 = (index + 1) % 4;
1592
+ var i2 = (index + 2) % 4;
1593
+ var i3 = (index + 3) % 4;
1594
+ var dist1 = Math.pow(Math.pow(corners[index].x - corners[i1].x, 2) + Math.pow(corners[index].y - corners[i1].y, 2), 0.5);
1595
+ var dist3 = Math.pow(Math.pow(corners[index].x - corners[i3].x, 2) + Math.pow(corners[index].y - corners[i3].y, 2), 0.5);
1596
+ var area = Math.abs(dist1 * dist3);
1597
+ var shape, edge;
1598
+ ratios.forEach(function (ratio) {
1599
+ var width, height;
1600
+
1601
+ if (ratio.width) {
1602
+ width = ratio.width;
1603
+ height = ratio.height;
1604
+ } else {
1605
+ width = Math.pow(area * ratio, 0.5);
1606
+ height = width / ratio;
1607
+ }
1608
+
1609
+ if (width !== height && !(index % 2)) {
1610
+ var _ref = [height, width];
1611
+ width = _ref[0];
1612
+ height = _ref[1];
1613
+ }
1614
+
1615
+ var score = Math.pow(width - dist3, 2) + Math.pow(height - dist1, 2);
1616
+
1617
+ if (best === undefined || score < best) {
1618
+ best = score;
1619
+ shape = {
1620
+ w: width,
1621
+ h: height
1622
+ };
1623
+ }
1624
+ });
1625
+ var ang1 = ang[i1];
1626
+ var delta1 = {
1627
+ x: -shape.w * Math.cos(ang1),
1628
+ y: -shape.w * Math.sin(ang1)
1629
+ };
1630
+ var ang2 = ang[index];
1631
+ var delta2 = {
1632
+ x: -shape.h * Math.cos(ang2),
1633
+ y: -shape.h * Math.sin(ang2)
1634
+ };
1635
+
1636
+ switch (mode) {
1637
+ case 'vertex':
1638
+ corners[index].x = corners[i2].x + delta1.x + delta2.x;
1639
+ corners[index].y = corners[i2].y + delta1.y + delta2.y;
1640
+ corners[i1].x = corners[i2].x + delta1.x;
1641
+ corners[i1].y = corners[i2].y + delta1.y;
1642
+ corners[i3].x = corners[i2].x + delta2.x;
1643
+ corners[i3].y = corners[i2].y + delta2.y;
1644
+ break;
1645
+
1646
+ case 'edge':
1647
+ edge = {
1648
+ x: (corners[i2].x + corners[i3].x) * 0.5,
1649
+ y: (corners[i2].y + corners[i3].y) * 0.5
1650
+ };
1651
+ corners[i2].x = edge.x + delta2.x / 2;
1652
+ corners[i2].y = edge.y + delta2.y / 2;
1653
+ corners[index].x = edge.x + delta1.x - delta2.x / 2;
1654
+ corners[index].y = edge.y + delta1.y - delta2.y / 2;
1655
+ corners[i1].x = edge.x + delta1.x + delta2.x / 2;
1656
+ corners[i1].y = edge.y + delta1.y + delta2.y / 2;
1657
+ corners[i3].x = edge.x - delta2.x / 2;
1658
+ corners[i3].y = edge.y - delta2.y / 2;
1659
+ break;
1660
+ }
1661
+ } else {
1662
+ /* Not in edit vertex or edge mode */
1663
+ var _area = Math.abs((pos.x - origin.x) * (pos.y - origin.y));
1664
+
1665
+ ratios.forEach(function (ratio) {
1666
+ var width, height;
1667
+
1668
+ if (ratio.width) {
1669
+ width = ratio.width;
1670
+ height = ratio.height;
1671
+ } else {
1672
+ width = Math.pow(_area * ratio, 0.5);
1673
+ height = width / ratio;
1674
+ }
1675
+
1676
+ var adjusted = {
1677
+ x: origin.x + Math.sign(pos.x - origin.x) * width,
1678
+ y: origin.y + Math.sign(pos.y - origin.y) * height
1679
+ };
1680
+ var score = Math.pow(adjusted.x - pos.x, 2) + Math.pow(adjusted.y - pos.y, 2);
1681
+
1682
+ if (best === undefined || score < best) {
1683
+ best = score;
1684
+ newpos = adjusted;
1685
+ }
1686
+ });
1687
+ corners[0].y = corners[1].y = origin.y;
1688
+ corners[0].x = corners[3].x = origin.x;
1689
+ corners[1].x = corners[2].x = newpos.x;
1690
+ corners[2].y = corners[3].y = newpos.y;
1691
+ }
1692
+
1693
+ return {
1694
+ corners: corners,
1695
+ origin: origin,
1696
+ pos: newpos
1697
+ };
1698
+ }
1699
+
1700
+ return constraintFunction;
1701
+ }
1702
+
1703
+ module.exports = {
1704
+ state: annotationState,
1705
+ actionOwner: annotationActionOwner,
1706
+ annotation: annotation,
1707
+ _editHandleFeatureLevel: editHandleFeatureLevel,
1708
+ defaultEditHandleStyle: defaultEditHandleStyle,
1709
+ constrainAspectRatio: constrainAspectRatio,
1710
+ // these aren't exposed in index.js
1711
+ annotationActionOwner: annotationActionOwner,
1712
+ continuousVerticesActions: continuousVerticesActions,
1713
+ continuousVerticesProcessAction: continuousVerticesProcessAction
1714
+ };
1715
+
1716
+ /***/ }),
1717
+
1718
+ /***/ 7196:
1719
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
1720
+
1721
+ var $ = __webpack_require__(5638);
1722
+
1723
+ var inherit = __webpack_require__(5699);
1724
+
1725
+ var registerAnnotation = (__webpack_require__(4647).registerAnnotation);
1726
+
1727
+ var markerFeature = __webpack_require__(7098);
1728
+
1729
+ var ellipseAnnotation = __webpack_require__(7505);
1563
1730
  /**
1564
- * Rectangle annotation class.
1731
+ * Circle annotation class.
1565
1732
  *
1566
- * Rectangles are always rendered as polygons. This could be changed -- if no
1567
- * stroke is specified, the quad feature would be sufficient and work on more
1568
- * renderers.
1733
+ * Circles are a subset of rectangles with a fixed aspect ratio.
1569
1734
  *
1570
1735
  * @class
1571
- * @alias geo.rectangleAnnotation
1736
+ * @alias geo.circleAnnotation
1572
1737
  * @extends geo.annotation
1573
1738
  *
1574
- * @param {geo.rectangleAnnotation.spec?} [args] Options for the annotation.
1575
- * @param {string} [annotationName='rectangle'] Override the annotation name.
1739
+ * @param {geo.circleAnnotation.spec?} [args] Options for the annotation.
1740
+ * @param {string} [annotationName='circle'] Override the annotation name.
1576
1741
  */
1577
1742
 
1578
1743
 
1579
- var rectangleAnnotation = function rectangleAnnotation(args, annotationName) {
1744
+ var circleAnnotation = function circleAnnotation(args, annotationName) {
1580
1745
  'use strict';
1581
1746
 
1582
- if (!(this instanceof rectangleAnnotation)) {
1583
- return new rectangleAnnotation(args, annotationName);
1747
+ args = $.extend({}, args, {
1748
+ constraint: 1
1749
+ });
1750
+
1751
+ if (!(this instanceof circleAnnotation)) {
1752
+ return new circleAnnotation(args, annotationName);
1584
1753
  }
1585
1754
 
1586
- args = $.extend(true, {}, {
1587
- style: {
1588
- fill: true,
1589
- fillColor: {
1590
- r: 0,
1591
- g: 1,
1592
- b: 0
1593
- },
1594
- fillOpacity: 0.25,
1595
- polygon: function polygon(d) {
1596
- return d.polygon;
1597
- },
1598
- stroke: true,
1599
- strokeColor: {
1600
- r: 0,
1601
- g: 0,
1602
- b: 0
1603
- },
1604
- strokeOpacity: 1,
1605
- strokeWidth: 3,
1606
- uniformPolygon: true
1607
- },
1608
- highlightStyle: {
1609
- fillColor: {
1610
- r: 0,
1611
- g: 1,
1612
- b: 1
1613
- },
1614
- fillOpacity: 0.5,
1615
- strokeWidth: 5
1616
- },
1617
- createStyle: {
1618
- fillColor: {
1619
- r: 0.3,
1620
- g: 0.3,
1621
- b: 0.3
1622
- },
1623
- fillOpacity: 0.25,
1624
- strokeColor: {
1625
- r: 0,
1626
- g: 0,
1627
- b: 1
1628
- }
1629
- }
1630
- }, args || {});
1631
- args.corners = args.corners || args.coordinates || [];
1632
- delete args.coordinates;
1633
- annotation.call(this, annotationName || 'rectangle', args);
1634
- var m_this = this,
1635
- s_actions = this.actions,
1636
- s_processEditAction = this.processEditAction;
1637
- /**
1638
- * Return actions needed for the specified state of this annotation.
1639
- *
1640
- * @param {string} [state] The state to return actions for. Defaults to
1641
- * the current state.
1642
- * @returns {geo.actionRecord[]} A list of actions.
1643
- */
1755
+ ellipseAnnotation.call(this, args, annotationName || 'circle');
1756
+ };
1644
1757
 
1645
- this.actions = function (state) {
1646
- if (!state) {
1647
- state = m_this.state();
1648
- }
1758
+ inherit(circleAnnotation, ellipseAnnotation);
1759
+ var circleRequiredFeatures = {};
1760
+ circleRequiredFeatures[markerFeature.capabilities.feature] = true;
1761
+ registerAnnotation('circle', circleAnnotation, circleRequiredFeatures);
1762
+ module.exports = circleAnnotation;
1649
1763
 
1650
- switch (state) {
1651
- case annotationState.create:
1652
- return [{
1653
- action: geo_action.annotation_rectangle,
1654
- name: 'rectangle create',
1655
- owner: annotationActionOwner,
1656
- input: 'left',
1657
- modifiers: {
1658
- shift: false,
1659
- ctrl: false
1660
- },
1661
- selectionRectangle: true,
1662
- selectionConstraint: this._selectionConstraint
1663
- }];
1764
+ /***/ }),
1664
1765
 
1665
- default:
1666
- return s_actions.apply(m_this, arguments);
1667
- }
1668
- };
1669
- /**
1670
- * Process any actions for this annotation.
1671
- *
1672
- * @param {geo.event} evt The action event.
1673
- * @returns {boolean|string} `true` to update the annotation, `'done'` if the
1674
- * annotation was completed (changed from create to done state),
1675
- * `'remove'` if the annotation should be removed, falsy to not update
1676
- * anything.
1677
- */
1766
+ /***/ 7505:
1767
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
1678
1768
 
1769
+ var $ = __webpack_require__(5638);
1679
1770
 
1680
- this.processAction = function (evt) {
1681
- var layer = m_this.layer();
1771
+ var inherit = __webpack_require__(5699);
1682
1772
 
1683
- if (m_this.state() !== annotationState.create || !layer || evt.event !== geo_event.actionselection || evt.state.action !== geo_action.annotation_rectangle) {
1684
- return;
1685
- }
1773
+ var registerAnnotation = (__webpack_require__(4647).registerAnnotation);
1686
1774
 
1687
- var map = layer.map(),
1688
- corners = [
1689
- /* Keep in map gcs, not interface gcs to avoid wrapping issues */
1690
- map.displayToGcs({
1691
- x: evt.lowerLeft.x,
1692
- y: evt.lowerLeft.y
1693
- }, null), map.displayToGcs({
1694
- x: evt.lowerLeft.x,
1695
- y: evt.upperRight.y
1696
- }, null), map.displayToGcs({
1697
- x: evt.upperRight.x,
1698
- y: evt.upperRight.y
1699
- }, null), map.displayToGcs({
1700
- x: evt.upperRight.x,
1701
- y: evt.lowerLeft.y
1702
- }, null)];
1775
+ var markerFeature = __webpack_require__(7098);
1703
1776
 
1704
- if (this._selectionConstraint && evt.mouse && evt.state.origin) {
1705
- this._selectionConstraint(evt.mouse.mapgcs, evt.state.origin.mapgcs, corners);
1706
- }
1707
- /* Don't keep rectangles that have nearly zero area in display pixels */
1777
+ var annotationState = (__webpack_require__(5784).state);
1708
1778
 
1779
+ var rectangleAnnotation = __webpack_require__(3442);
1780
+ /**
1781
+ * Ellipse annotation class.
1782
+ *
1783
+ * Ellipses are always rendered as markers.
1784
+ *
1785
+ * @class
1786
+ * @alias geo.ellipseAnnotation
1787
+ * @extends geo.annotation
1788
+ *
1789
+ * @param {geo.ellipseAnnotation.spec?} [args] Options for the annotation.
1790
+ * @param {string} [annotationName='ellipse'] Override the annotation name.
1791
+ */
1709
1792
 
1710
- if (layer.displayDistance(corners[0], null, corners[1], null) * layer.displayDistance(corners[0], null, corners[3], null) < 0.01) {
1711
- return 'remove';
1712
- }
1713
1793
 
1714
- m_this.options('corners', corners);
1715
- m_this.state(annotationState.done);
1716
- return 'done';
1717
- };
1794
+ var ellipseAnnotation = function ellipseAnnotation(args, annotationName) {
1795
+ 'use strict';
1796
+
1797
+ if (!(this instanceof ellipseAnnotation)) {
1798
+ return new ellipseAnnotation(args, annotationName);
1799
+ }
1800
+
1801
+ rectangleAnnotation.call(this, args, annotationName || 'ellipse');
1802
+ var m_this = this;
1718
1803
  /**
1719
1804
  * Get a list of renderable features for this annotation.
1720
1805
  *
1721
1806
  * @returns {array} An array of features.
1722
1807
  */
1723
1808
 
1724
-
1725
1809
  this.features = function () {
1726
1810
  var opt = m_this.options(),
1727
1811
  state = m_this.state(),
@@ -1729,10 +1813,27 @@ var rectangleAnnotation = function rectangleAnnotation(args, annotationName) {
1729
1813
  features = [];
1730
1814
 
1731
1815
  if (opt.corners && opt.corners.length >= 4) {
1816
+ var style = m_this.styleForState(state);
1817
+ var w = Math.pow(Math.pow(opt.corners[0].x - opt.corners[1].x, 2) + Math.pow(opt.corners[0].y - opt.corners[1].y, 2), 0.5);
1818
+ var h = Math.pow(Math.pow(opt.corners[0].x - opt.corners[3].x, 2) + Math.pow(opt.corners[0].y - opt.corners[3].y, 2), 0.5);
1819
+ var radius = Math.max(w, h) / 2 / m_this.layer().map().unitsPerPixel(0);
1820
+ var aspect = w ? h / w : 1e20;
1821
+ var rotation = -Math.atan2(opt.corners[1].y - opt.corners[0].y, opt.corners[1].x - opt.corners[0].x);
1732
1822
  features = [{
1733
- polygon: {
1734
- polygon: opt.corners,
1735
- style: m_this.styleForState(state)
1823
+ marker: {
1824
+ x: (opt.corners[0].x + opt.corners[1].x + opt.corners[2].x + opt.corners[3].x) / 4,
1825
+ y: (opt.corners[0].y + opt.corners[1].y + opt.corners[2].y + opt.corners[3].y) / 4,
1826
+ style: $.extend({}, style, {
1827
+ radius: radius,
1828
+ symbolValue: aspect,
1829
+ rotation: rotation,
1830
+ strokeOffset: 0,
1831
+ radiusIncludesStroke: false,
1832
+ scaleWithZoom: markerFeature.scaleMode.fill,
1833
+ rotateWithMap: true,
1834
+ strokeOpacity: style.stroke === false ? 0 : style.strokeOpacity,
1835
+ fillOpacity: style.fill === false ? 0 : style.fillOpacity
1836
+ })
1736
1837
  }
1737
1838
  }];
1738
1839
  }
@@ -1743,123 +1844,223 @@ var rectangleAnnotation = function rectangleAnnotation(args, annotationName) {
1743
1844
 
1744
1845
  return features;
1745
1846
  };
1746
- /**
1747
- * Get and optionally set coordinates associated with this annotation in the
1748
- * map gcs coordinate system.
1749
- *
1750
- * @param {geo.geoPosition[]} [coordinates] An optional array of coordinates
1751
- * to set.
1752
- * @returns {geo.geoPosition[]} The current array of coordinates.
1753
- */
1754
-
1847
+ };
1755
1848
 
1756
- this._coordinates = function (coordinates) {
1757
- if (coordinates && coordinates.length >= 4) {
1758
- m_this.options('corners', coordinates.slice(0, 4));
1759
- /* Should we ensure that the four points form a rectangle in the current
1760
- * projection, though this might not be rectangular in another gcs? */
1761
- }
1849
+ inherit(ellipseAnnotation, rectangleAnnotation);
1850
+ var ellipseRequiredFeatures = {};
1851
+ ellipseRequiredFeatures[markerFeature.capabilities.feature] = true;
1852
+ registerAnnotation('ellipse', ellipseAnnotation, ellipseRequiredFeatures);
1853
+ module.exports = ellipseAnnotation;
1762
1854
 
1763
- return m_this.options('corners');
1764
- };
1855
+ /***/ }),
1765
1856
 
1766
- this._coordinateOption = 'corners';
1767
- /**
1768
- * Return the coordinates to be stored in a geojson geometry object.
1769
- *
1770
- * @param {string|geo.transform|null} [gcs] `undefined` to use the interface
1771
- * gcs, `null` to use the map gcs, or any other transform.
1772
- * @returns {array} An array of flattened coordinates in the interface gcs
1773
- * coordinate system. `undefined` if this annotation is incomplete.
1774
- */
1857
+ /***/ 4213:
1858
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
1775
1859
 
1776
- this._geojsonCoordinates = function (gcs) {
1777
- var src = m_this.coordinates(gcs);
1860
+ var annotation = __webpack_require__(5784);
1861
+ /**
1862
+ * @namespace geo.annotation
1863
+ */
1778
1864
 
1779
- if (!src || m_this.state() === annotationState.create || src.length < 4) {
1780
- return;
1781
- }
1782
1865
 
1783
- var coord = [];
1866
+ module.exports = {
1867
+ state: annotation.state,
1868
+ actionOwner: annotation.actionOwner,
1869
+ annotation: annotation.annotation,
1870
+ _editHandleFeatureLevel: annotation._editHandleFeatureLevel,
1871
+ defaultEditHandleStyle: annotation.defaultEditHandleStyle,
1872
+ constrainAspectRatio: annotation.constrainAspectRatio,
1873
+ baseAnnotation: annotation,
1874
+ circleAnnotation: __webpack_require__(7196),
1875
+ ellipseAnnotation: __webpack_require__(7505),
1876
+ lineAnnotation: __webpack_require__(3984),
1877
+ pointAnnotation: __webpack_require__(8296),
1878
+ polygonAnnotation: __webpack_require__(56),
1879
+ rectangleAnnotation: __webpack_require__(3442),
1880
+ squareAnnotation: __webpack_require__(4932)
1881
+ };
1784
1882
 
1785
- for (var i = 0; i < 4; i += 1) {
1786
- coord.push([src[i].x, src[i].y]);
1787
- }
1883
+ /***/ }),
1788
1884
 
1789
- coord.push([src[0].x, src[0].y]);
1790
- return [coord];
1791
- };
1792
- /**
1793
- * Return the geometry type that is used to store this annotation in geojson.
1794
- *
1795
- * @returns {string} A geojson geometry type.
1796
- */
1885
+ /***/ 3984:
1886
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
1797
1887
 
1888
+ var $ = __webpack_require__(5638);
1798
1889
 
1799
- this._geojsonGeometryType = function () {
1800
- return 'Polygon';
1801
- };
1802
- /**
1803
- * Return a list of styles that should be preserved in a geojson
1804
- * representation of the annotation.
1805
- *
1806
- * @returns {string[]} A list of style names to store.
1807
- */
1890
+ var inherit = __webpack_require__(5699);
1808
1891
 
1892
+ var registerAnnotation = (__webpack_require__(4647).registerAnnotation);
1809
1893
 
1810
- this._geojsonStyles = function () {
1811
- return ['fill', 'fillColor', 'fillOpacity', 'lineCap', 'lineJoin', 'stroke', 'strokeColor', 'strokeOffset', 'strokeOpacity', 'strokeWidth'];
1812
- };
1813
- /**
1814
- * Set three corners based on an initial corner and a mouse event.
1815
- *
1816
- * @param {geo.geoPosition} corners An array of four corners to update.
1817
- * @param {geo.event} evt The mouse move event.
1818
- */
1894
+ var lineFeature = __webpack_require__(4708);
1819
1895
 
1896
+ var annotation = (__webpack_require__(5784).annotation);
1820
1897
 
1821
- this._setCornersFromMouse = function (corners, evt) {
1822
- var map = m_this.layer().map(),
1823
- c0 = map.gcsToDisplay({
1824
- x: corners[0].x,
1825
- y: corners[0].y
1826
- }, null),
1827
- c2 = map.gcsToDisplay(evt.mapgcs, null),
1828
- c1 = {
1829
- x: c2.x,
1830
- y: c0.y
1831
- },
1832
- c3 = {
1833
- x: c0.x,
1834
- y: c2.y
1835
- };
1836
- corners[2] = $.extend({}, evt.mapgcs);
1837
- corners[1] = map.displayToGcs(c1, null);
1838
- corners[3] = map.displayToGcs(c3, null);
1898
+ var annotationState = (__webpack_require__(5784).state);
1839
1899
 
1840
- if (this._selectionConstraint) {
1841
- this._selectionConstraint(evt.mapgcs, corners[0], corners);
1842
- }
1843
- };
1844
- /**
1845
- * Handle a mouse move on this annotation.
1846
- *
1847
- * @param {geo.event} evt The mouse move event.
1848
- * @returns {boolean} Truthy to update the annotation, falsy to not
1849
- * update anything.
1850
- */
1900
+ var continuousVerticesActions = (__webpack_require__(5784).continuousVerticesActions);
1851
1901
 
1902
+ var continuousVerticesProcessAction = (__webpack_require__(5784).continuousVerticesProcessAction);
1903
+ /**
1904
+ * Line annotation specification. Extends {@link geo.annotation.spec}.
1905
+ *
1906
+ * @typedef {object} geo.lineAnnotation.spec
1907
+ * @extends geo.annotation.spec
1908
+ * @property {geo.geoPosition[]} [vertices] A list of vertices in map gcs
1909
+ * coordinates.
1910
+ * @property {geo.geoPosition[]} [coordinates] An alternate name for
1911
+ * `vertices`.
1912
+ * @property {geo.lineFeature.styleSpec} [style] The style to apply to a
1913
+ * finished line. This uses styles for {@link geo.lineFeature}.
1914
+ * @property {geo.lineFeature.styleSpec} [editStyle] The style to apply to a
1915
+ * line in edit mode.
1916
+ */
1852
1917
 
1853
- this.mouseMove = function (evt) {
1854
- if (m_this.state() !== annotationState.create) {
1855
- return;
1918
+ /**
1919
+ * Line annotation class.
1920
+ *
1921
+ * @class
1922
+ * @alias geo.lineAnnotation
1923
+ * @extends geo.annotation
1924
+ *
1925
+ * @param {geo.lineAnnotation.spec?} [args] Options for the annotation.
1926
+ */
1927
+
1928
+
1929
+ var lineAnnotation = function lineAnnotation(args) {
1930
+ 'use strict';
1931
+
1932
+ if (!(this instanceof lineAnnotation)) {
1933
+ return new lineAnnotation(args);
1934
+ }
1935
+
1936
+ args = $.extend(true, {}, {
1937
+ style: {
1938
+ line: function line(d) {
1939
+ /* Return an array that has the same number of items as we have
1940
+ * vertices. */
1941
+ return Array.apply(null, Array(m_this.options('vertices').length)).map(function () {
1942
+ return d;
1943
+ });
1944
+ },
1945
+ position: function position(d, i) {
1946
+ return m_this.options('vertices')[i];
1947
+ },
1948
+ strokeColor: {
1949
+ r: 0,
1950
+ g: 0,
1951
+ b: 0
1952
+ },
1953
+ strokeOpacity: 1,
1954
+ strokeWidth: 3,
1955
+ closed: false,
1956
+ lineCap: 'butt',
1957
+ lineJoin: 'miter'
1958
+ },
1959
+ highlightStyle: {
1960
+ strokeWidth: 5
1961
+ },
1962
+ createStyle: {
1963
+ line: function line(d) {
1964
+ /* Return an array that has the same number of items as we have
1965
+ * vertices. */
1966
+ return Array.apply(null, Array(m_this.options('vertices').length)).map(function () {
1967
+ return d;
1968
+ });
1969
+ },
1970
+ position: function position(d, i) {
1971
+ return m_this.options('vertices')[i];
1972
+ },
1973
+ strokeColor: {
1974
+ r: 0,
1975
+ g: 0,
1976
+ b: 1
1977
+ },
1978
+ strokeOpacity: 1,
1979
+ strokeWidth: 3,
1980
+ closed: false,
1981
+ lineCap: 'butt',
1982
+ lineJoin: 'miter'
1856
1983
  }
1984
+ }, args || {});
1985
+ args.vertices = args.vertices || args.coordinates || [];
1986
+ delete args.coordinates;
1987
+ annotation.call(this, 'line', args);
1988
+ var m_this = this,
1989
+ s_actions = this.actions,
1990
+ s_processEditAction = this.processEditAction;
1991
+ /**
1992
+ * Get a list of renderable features for this annotation.
1993
+ *
1994
+ * @returns {array} An array of features.
1995
+ */
1857
1996
 
1858
- var corners = m_this.options('corners');
1997
+ this.features = function () {
1998
+ var opt = m_this.options(),
1999
+ state = m_this.state(),
2000
+ features;
1859
2001
 
1860
- if (corners.length) {
1861
- m_this._setCornersFromMouse(corners, evt);
2002
+ switch (state) {
2003
+ case annotationState.create:
2004
+ features = [{
2005
+ line: {
2006
+ line: opt.vertices,
2007
+ style: m_this.styleForState(state)
2008
+ }
2009
+ }];
2010
+ break;
2011
+
2012
+ default:
2013
+ features = [{
2014
+ line: {
2015
+ line: opt.vertices,
2016
+ style: m_this.styleForState(state)
2017
+ }
2018
+ }];
2019
+
2020
+ if (state === annotationState.edit) {
2021
+ m_this._addEditHandles(features, opt.vertices, undefined, !m_this.style('closed'));
2022
+ }
2023
+
2024
+ break;
2025
+ }
2026
+
2027
+ return features;
2028
+ };
2029
+ /**
2030
+ * Get and optionally set coordinates associated with this annotation in the
2031
+ * map gcs coordinate system.
2032
+ *
2033
+ * @param {geo.geoPosition[]} [coordinates] An optional array of coordinates
2034
+ * to set.
2035
+ * @returns {geo.geoPosition[]} The current array of coordinates.
2036
+ */
2037
+
2038
+
2039
+ this._coordinates = function (coordinates) {
2040
+ if (coordinates) {
2041
+ m_this.options('vertices', coordinates);
2042
+ }
2043
+
2044
+ return m_this.options('vertices');
2045
+ };
2046
+ /**
2047
+ * Handle a mouse move on this annotation.
2048
+ *
2049
+ * @param {geo.event} evt The mouse move event.
2050
+ * @returns {boolean} Truthy to update the annotation, falsy to not
2051
+ * update anything.
2052
+ */
2053
+
2054
+
2055
+ this.mouseMove = function (evt) {
2056
+ if (m_this.state() !== annotationState.create) {
2057
+ return;
2058
+ }
2059
+
2060
+ var vertices = m_this.options('vertices');
1862
2061
 
2062
+ if (vertices.length) {
2063
+ vertices[vertices.length - 1] = evt.mapgcs;
1863
2064
  return true;
1864
2065
  }
1865
2066
  };
@@ -1882,38 +2083,130 @@ var rectangleAnnotation = function rectangleAnnotation(args, annotationName) {
1882
2083
  return;
1883
2084
  }
1884
2085
 
2086
+ var end = !!evt.buttonsDown.right,
2087
+ skip;
2088
+
1885
2089
  if (!evt.buttonsDown.left && !evt.buttonsDown.right) {
1886
2090
  return;
1887
2091
  }
1888
2092
 
1889
- var corners = m_this.options('corners');
2093
+ var vertices = m_this.options('vertices');
1890
2094
 
1891
- if (evt.buttonsDown.right && !corners.length) {
2095
+ if (evt.buttonsDown.right && !vertices.length) {
1892
2096
  return;
1893
2097
  }
1894
2098
 
1895
2099
  evt.handled = true;
1896
2100
 
1897
- if (corners.length) {
1898
- m_this._setCornersFromMouse(corners, evt);
1899
- /* Don't keep rectangles that have nearly zero area in display pixels */
2101
+ if (evt.buttonsDown.left) {
2102
+ if (vertices.length) {
2103
+ if (vertices.length >= 2 && layer.displayDistance(vertices[vertices.length - 2], null, evt.map, 'display') <= layer.options('adjacentPointProximity')) {
2104
+ skip = true;
2105
+
2106
+ if (m_this._lastClick && evt.time - m_this._lastClick < layer.options('dblClickTime')) {
2107
+ end = true;
2108
+ }
2109
+ } else if (vertices.length >= 2 && layer.displayDistance(vertices[0], null, evt.map, 'display') <= layer.options('finalPointProximity')) {
2110
+ end = 'close';
2111
+ } else {
2112
+ vertices[vertices.length - 1] = evt.mapgcs;
2113
+ }
2114
+ } else {
2115
+ vertices.push(evt.mapgcs);
2116
+ }
1900
2117
 
2118
+ if (!end && !skip) {
2119
+ vertices.push(evt.mapgcs);
2120
+ }
1901
2121
 
1902
- if (layer.displayDistance(corners[0], null, corners[1], null) * layer.displayDistance(corners[0], null, corners[3], null) < 0.01) {
2122
+ m_this._lastClick = evt.time;
2123
+ m_this._lastClickVertexCount = vertices.length;
2124
+ }
2125
+
2126
+ if (end) {
2127
+ if (vertices.length < 3) {
1903
2128
  return 'remove';
1904
2129
  }
1905
2130
 
2131
+ vertices.pop();
2132
+ m_this.options('style').closed = end === 'close';
1906
2133
  m_this.state(annotationState.done);
1907
2134
  return 'done';
1908
2135
  }
1909
2136
 
1910
- if (evt.buttonsDown.left) {
1911
- corners.push($.extend({}, evt.mapgcs));
1912
- corners.push($.extend({}, evt.mapgcs));
1913
- corners.push($.extend({}, evt.mapgcs));
1914
- corners.push($.extend({}, evt.mapgcs));
1915
- return true;
2137
+ return !skip;
2138
+ };
2139
+ /**
2140
+ * Return actions needed for the specified state of this annotation.
2141
+ *
2142
+ * @param {string} [state] The state to return actions for. Defaults to
2143
+ * the current state.
2144
+ * @returns {geo.actionRecord[]} A list of actions.
2145
+ */
2146
+
2147
+
2148
+ this.actions = function (state) {
2149
+ return continuousVerticesActions(m_this, s_actions, state, 'line', arguments);
2150
+ };
2151
+ /**
2152
+ * Process any actions for this annotation.
2153
+ *
2154
+ * @param {geo.event} evt The action event.
2155
+ * @returns {boolean|string} `true` to update the annotation, `'done'` if the
2156
+ * annotation was completed (changed from create to done state),
2157
+ * `'remove'` if the annotation should be removed, falsy to not update
2158
+ * anything.
2159
+ */
2160
+
2161
+
2162
+ this.processAction = function (evt) {
2163
+ return continuousVerticesProcessAction(m_this, evt, 'line');
2164
+ };
2165
+ /**
2166
+ * Return the coordinates to be stored in a geojson geometry object.
2167
+ *
2168
+ * @param {string|geo.transform|null} [gcs] `undefined` to use the interface
2169
+ * gcs, `null` to use the map gcs, or any other transform.
2170
+ * @returns {array} An array of flattened coordinates in the interface gcs
2171
+ * coordinate system. `undefined` if this annotation is incomplete.
2172
+ */
2173
+
2174
+
2175
+ this._geojsonCoordinates = function (gcs) {
2176
+ var src = m_this.coordinates(gcs);
2177
+
2178
+ if (!src || src.length < 2 || m_this.state() === annotationState.create) {
2179
+ return;
1916
2180
  }
2181
+
2182
+ var coord = [];
2183
+
2184
+ for (var i = 0; i < src.length; i += 1) {
2185
+ coord.push([src[i].x, src[i].y]);
2186
+ }
2187
+
2188
+ return coord;
2189
+ };
2190
+ /**
2191
+ * Return the geometry type that is used to store this annotation in geojson.
2192
+ *
2193
+ * @returns {string} A geojson geometry type.
2194
+ */
2195
+
2196
+
2197
+ this._geojsonGeometryType = function () {
2198
+ return 'LineString';
2199
+ };
2200
+ /**
2201
+ * Return a list of styles that should be preserved in a geojson
2202
+ * representation of the annotation.
2203
+ *
2204
+ * @returns {string[]} A list of style names to store.
2205
+ */
2206
+
2207
+
2208
+ this._geojsonStyles = function () {
2209
+ return ['closed', 'lineCap', 'lineJoin', 'strokeColor', 'strokeOffset', 'strokeOpacity', 'strokeWidth'];
1917
2210
  };
1918
2211
  /**
1919
2212
  * Process any edit actions for this annotation.
@@ -1925,154 +2218,170 @@ var rectangleAnnotation = function rectangleAnnotation(args, annotationName) {
1925
2218
 
1926
2219
 
1927
2220
  this.processEditAction = function (evt) {
1928
- var start = m_this._editHandle.startCoordinates,
1929
- delta = {
1930
- x: evt.mouse.mapgcs.x - evt.state.origin.mapgcs.x,
1931
- y: evt.mouse.mapgcs.y - evt.state.origin.mapgcs.y
1932
- },
1933
- type = m_this._editHandle.handle.type,
1934
- index = m_this._editHandle.handle.index,
1935
- ang = [Math.atan2(start[1].y - start[0].y, start[1].x - start[0].x), Math.atan2(start[2].y - start[1].y, start[2].x - start[1].x), Math.atan2(start[3].y - start[2].y, start[3].x - start[2].x), Math.atan2(start[0].y - start[3].y, start[0].x - start[3].x)],
1936
- corners,
1937
- delta1,
1938
- delta2,
1939
- ang1,
1940
- ang2; // an angle can be zero because it is horizontal or undefined. If opposite
1941
- // angles are both zero, this is a degenerate rectangle (a line or a point)
1942
-
1943
- if (!ang[0] && !ang[1] && !ang[2] && !ang[3]) {
1944
- ang[1] = Math.PI / 2;
1945
- ang[2] = Math.PI;
1946
- ang[3] = -Math.PI / 2;
2221
+ switch (m_this._editHandle.handle.type) {
2222
+ case 'vertex':
2223
+ return m_this._processEditActionVertex(evt, true);
1947
2224
  }
1948
2225
 
1949
- if (!ang[0] && !ang[2]) {
1950
- ang[0] = ang[1] - Math.PI / 2;
1951
- ang[2] = ang[1] + Math.PI / 2;
1952
- }
2226
+ return s_processEditAction.apply(m_this, arguments);
2227
+ };
2228
+ /**
2229
+ * Handle a mouse click on this annotation when in edit mode. If the event
2230
+ * is processed, evt.handled should be set to `true` to prevent further
2231
+ * processing.
2232
+ *
2233
+ * @param {geo.event} evt The mouse click event.
2234
+ * @returns {boolean|string} `true` to update the annotation, `'done'` if
2235
+ * the annotation was completed (changed from create to done state),
2236
+ * `'remove'` if the annotation should be removed, falsy to not update
2237
+ * anything.
2238
+ */
1953
2239
 
1954
- if (!ang[1] && !ang[3]) {
1955
- ang[1] = ang[2] - Math.PI / 2;
1956
- ang[3] = ang[2] + Math.PI / 2;
1957
- }
1958
2240
 
1959
- switch (type) {
1960
- case 'vertex':
1961
- corners = start.map(function (elem) {
1962
- return {
1963
- x: elem.x,
1964
- y: elem.y
1965
- };
1966
- });
1967
- ang1 = ang[(index + 1) % 4];
1968
- delta1 = {
1969
- x: (delta.x * Math.cos(ang1) + delta.y * Math.sin(ang1)) * Math.cos(ang1),
1970
- y: (delta.y * Math.sin(ang1) + delta.x * Math.cos(ang1)) * Math.sin(ang1)
1971
- };
1972
- ang2 = ang[index];
1973
- delta2 = {
1974
- x: (delta.x * Math.cos(ang2) + delta.y * Math.sin(ang2)) * Math.cos(ang2),
1975
- y: (delta.y * Math.sin(ang2) + delta.x * Math.cos(ang2)) * Math.sin(ang2)
1976
- };
1977
- corners[index].x += delta.x;
1978
- corners[index].y += delta.y;
1979
- corners[(index + 1) % 4].x += delta1.x;
1980
- corners[(index + 1) % 4].y += delta1.y;
1981
- corners[(index + 3) % 4].x += delta2.x;
1982
- corners[(index + 3) % 4].y += delta2.y;
2241
+ this.mouseClickEdit = function (evt) {
2242
+ // if we get a left double click on an edge on a closed line, break the
2243
+ // line at that edge
2244
+ var layer = m_this.layer(),
2245
+ handle = m_this._editHandle,
2246
+ split; // ensure we are in edit mode and this is a left click
1983
2247
 
1984
- if (this._selectionConstraint) {
1985
- corners = this._selectionConstraint(evt.mouse.mapgcs, evt.state.origin.mapgcs, corners, 'vertex', ang, index).corners;
1986
- }
2248
+ if (m_this.state() !== annotationState.edit || !layer || !evt.buttonsDown.left) {
2249
+ return;
2250
+ } // ensure this is an edge on a closed line
1987
2251
 
1988
- m_this.options('corners', corners);
1989
- return true;
1990
2252
 
1991
- case 'edge':
1992
- corners = start.map(function (elem) {
1993
- return {
1994
- x: elem.x,
1995
- y: elem.y
1996
- };
1997
- });
1998
- ang1 = ang[(index + 1) % 4];
1999
- delta = {
2000
- x: (delta.x * Math.cos(ang1) + delta.y * Math.sin(ang1)) * Math.cos(ang1),
2001
- y: (delta.y * Math.sin(ang1) + delta.x * Math.cos(ang1)) * Math.sin(ang1)
2002
- };
2003
- corners[index].x += delta.x;
2004
- corners[index].y += delta.y;
2005
- corners[(index + 1) % 4].x += delta.x;
2006
- corners[(index + 1) % 4].y += delta.y;
2253
+ if (!handle || !handle.handle.selected || handle.handle.type !== 'edge' || !m_this.options('style').closed) {
2254
+ return;
2255
+ }
2007
2256
 
2008
- if (this._selectionConstraint) {
2009
- corners = this._selectionConstraint(evt.mouse.mapgcs, evt.state.origin.mapgcs, corners, 'edge', ang, index).corners;
2010
- }
2257
+ evt.handled = true;
2011
2258
 
2012
- m_this.options('corners', corners);
2013
- return true;
2259
+ if (m_this._lastClick && evt.time - m_this._lastClick < layer.options('dblClickTime')) {
2260
+ split = true;
2014
2261
  }
2015
2262
 
2016
- return s_processEditAction.apply(m_this, arguments);
2263
+ m_this._lastClick = evt.time;
2264
+
2265
+ if (split) {
2266
+ var index = handle.handle.index,
2267
+ curPts = m_this._coordinates(),
2268
+ pts = curPts.slice(index + 1).concat(curPts.slice(0, index + 1));
2269
+
2270
+ m_this._coordinates(pts);
2271
+
2272
+ m_this.options('style').closed = false;
2273
+ handle.handle.index = undefined;
2274
+ return true;
2275
+ }
2017
2276
  };
2018
2277
  };
2019
2278
 
2020
- inherit(rectangleAnnotation, annotation);
2021
- var rectangleRequiredFeatures = {};
2022
- rectangleRequiredFeatures[polygonFeature.capabilities.feature] = true;
2023
- registerAnnotation('rectangle', rectangleAnnotation, rectangleRequiredFeatures);
2024
- /**
2025
- * Square annotation class.
2026
- *
2027
- * Squares are a subset of rectangles with a fixed aspect ratio.
2028
- *
2029
- * @class
2030
- * @alias geo.squareAnnotation
2031
- * @extends geo.annotation
2032
- *
2033
- * @param {geo.squareAnnotation.spec?} [args] Options for the annotation.
2034
- * @param {string} [annotationName='square'] Override the annotation name.
2035
- */
2279
+ inherit(lineAnnotation, annotation);
2280
+ var lineRequiredFeatures = {};
2281
+ lineRequiredFeatures[lineFeature.capabilities.basic] = [annotationState.create];
2282
+ registerAnnotation('line', lineAnnotation, lineRequiredFeatures);
2283
+ module.exports = lineAnnotation;
2036
2284
 
2037
- var squareAnnotation = function squareAnnotation(args, annotationName) {
2038
- 'use strict';
2285
+ /***/ }),
2039
2286
 
2040
- args = $.extend({}, args, {
2041
- constraint: 1
2042
- });
2287
+ /***/ 8296:
2288
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
2043
2289
 
2044
- if (!(this instanceof squareAnnotation)) {
2045
- return new squareAnnotation(args, annotationName);
2046
- }
2290
+ var $ = __webpack_require__(5638);
2047
2291
 
2048
- rectangleAnnotation.call(this, args, annotationName || 'square');
2049
- };
2292
+ var inherit = __webpack_require__(5699);
2050
2293
 
2051
- inherit(squareAnnotation, rectangleAnnotation);
2052
- var squareRequiredFeatures = {};
2053
- squareRequiredFeatures[polygonFeature.capabilities.feature] = true;
2054
- registerAnnotation('square', squareAnnotation, squareRequiredFeatures);
2294
+ var util = __webpack_require__(4634);
2295
+
2296
+ var registerAnnotation = (__webpack_require__(4647).registerAnnotation);
2297
+
2298
+ var pointFeature = __webpack_require__(2557);
2299
+
2300
+ var annotation = (__webpack_require__(5784).annotation);
2301
+
2302
+ var annotationState = (__webpack_require__(5784).state);
2055
2303
  /**
2056
- * Ellipse annotation class.
2304
+ * Point annotation specification. Extends {@link geo.annotation.spec}.
2057
2305
  *
2058
- * Ellipses are always rendered as markers.
2306
+ * @typedef {object} geo.pointAnnotation.spec
2307
+ * @extends geo.annotation.spec
2308
+ * @property {geo.geoPosition} [position] A coordinate in map gcs coordinates.
2309
+ * @property {geo.geoPosition[]} [coordinates] An array with one coordinate to
2310
+ * use in place of `position`.
2311
+ * @property {geo.pointFeature.styleSpec} [style] The style to apply to a
2312
+ * finished point. This uses styles for {@link geo.pointFeature}.
2313
+ * @property {boolean|number} [style.scaled=false] If `false`, the point is not
2314
+ * scaled with zoom level. If `true`, the radius is based on the zoom level
2315
+ * at first instantiation. If a number, the radius is used at the `scaled`
2316
+ * zoom level.
2317
+ * @property {geo.pointFeature.styleSpec} [editStyle] The style to apply to a
2318
+ * point in edit mode.
2319
+ */
2320
+
2321
+ /**
2322
+ * Point annotation class.
2059
2323
  *
2060
2324
  * @class
2061
- * @alias geo.ellipseAnnotation
2325
+ * @alias geo.pointAnnotation
2062
2326
  * @extends geo.annotation
2063
2327
  *
2064
- * @param {geo.ellipseAnnotation.spec?} [args] Options for the annotation.
2065
- * @param {string} [annotationName='ellipse'] Override the annotation name.
2328
+ * @param {geo.pointAnnotation.spec?} [args] Options for the annotation.
2066
2329
  */
2067
2330
 
2068
- var ellipseAnnotation = function ellipseAnnotation(args, annotationName) {
2331
+
2332
+ var pointAnnotation = function pointAnnotation(args) {
2069
2333
  'use strict';
2070
2334
 
2071
- if (!(this instanceof ellipseAnnotation)) {
2072
- return new ellipseAnnotation(args, annotationName);
2335
+ if (!(this instanceof pointAnnotation)) {
2336
+ return new pointAnnotation(args);
2073
2337
  }
2074
2338
 
2075
- rectangleAnnotation.call(this, args, annotationName || 'ellipse');
2339
+ args = $.extend(true, {}, {
2340
+ style: {
2341
+ fill: true,
2342
+ fillColor: {
2343
+ r: 0,
2344
+ g: 1,
2345
+ b: 0
2346
+ },
2347
+ fillOpacity: 0.25,
2348
+ radius: 10,
2349
+ scaled: false,
2350
+ stroke: true,
2351
+ strokeColor: {
2352
+ r: 0,
2353
+ g: 0,
2354
+ b: 0
2355
+ },
2356
+ strokeOpacity: 1,
2357
+ strokeWidth: 3
2358
+ },
2359
+ createStyle: {
2360
+ fillColor: {
2361
+ r: 0.3,
2362
+ g: 0.3,
2363
+ b: 0.3
2364
+ },
2365
+ fillOpacity: 0.25,
2366
+ strokeColor: {
2367
+ r: 0,
2368
+ g: 0,
2369
+ b: 1
2370
+ }
2371
+ },
2372
+ highlightStyle: {
2373
+ fillColor: {
2374
+ r: 0,
2375
+ g: 1,
2376
+ b: 1
2377
+ },
2378
+ fillOpacity: 0.5,
2379
+ strokeWidth: 5
2380
+ }
2381
+ }, args || {});
2382
+ args.position = args.position || (args.coordinates ? args.coordinates[0] : undefined);
2383
+ delete args.coordinates;
2384
+ annotation.call(this, 'point', args);
2076
2385
  var m_this = this;
2077
2386
  /**
2078
2387
  * Get a list of renderable features for this annotation.
@@ -2083,78 +2392,180 @@ var ellipseAnnotation = function ellipseAnnotation(args, annotationName) {
2083
2392
  this.features = function () {
2084
2393
  var opt = m_this.options(),
2085
2394
  state = m_this.state(),
2086
- features;
2087
- features = [];
2395
+ features,
2396
+ style,
2397
+ scaleOnZoom;
2088
2398
 
2089
- if (opt.corners && opt.corners.length >= 4) {
2090
- var style = m_this.styleForState(state);
2091
- var w = Math.pow(Math.pow(opt.corners[0].x - opt.corners[1].x, 2) + Math.pow(opt.corners[0].y - opt.corners[1].y, 2), 0.5);
2092
- var h = Math.pow(Math.pow(opt.corners[0].x - opt.corners[3].x, 2) + Math.pow(opt.corners[0].y - opt.corners[3].y, 2), 0.5);
2093
- var radius = Math.max(w, h) / 2 / m_this.layer().map().unitsPerPixel(0);
2094
- var aspect = w ? h / w : 1e20;
2095
- var rotation = -Math.atan2(opt.corners[1].y - opt.corners[0].y, opt.corners[1].x - opt.corners[0].x);
2096
- features = [{
2097
- marker: {
2098
- x: (opt.corners[0].x + opt.corners[1].x + opt.corners[2].x + opt.corners[3].x) / 4,
2099
- y: (opt.corners[0].y + opt.corners[1].y + opt.corners[2].y + opt.corners[3].y) / 4,
2100
- style: $.extend({}, style, {
2101
- radius: radius,
2102
- symbolValue: aspect,
2103
- rotation: rotation,
2104
- strokeOffset: 0,
2105
- radiusIncludesStroke: false,
2106
- scaleWithZoom: markerFeature.scaleMode.fill,
2107
- rotateWithMap: true,
2108
- strokeOpacity: style.stroke === false ? 0 : style.strokeOpacity,
2109
- fillOpacity: style.fill === false ? 0 : style.fillOpacity
2110
- })
2399
+ switch (state) {
2400
+ case annotationState.create:
2401
+ features = [];
2402
+ break;
2403
+
2404
+ default:
2405
+ style = m_this.styleForState(state);
2406
+
2407
+ if (opt.style.scaled || opt.style.scaled === 0) {
2408
+ if (opt.style.scaled === true) {
2409
+ opt.style.scaled = m_this.layer().map().zoom();
2410
+ }
2411
+
2412
+ style = $.extend({}, style, {
2413
+ radius: function radius() {
2414
+ var radius = opt.style.radius,
2415
+ zoom = m_this.layer().map().zoom();
2416
+
2417
+ if (util.isFunction(radius)) {
2418
+ radius = radius.apply(m_this, arguments);
2419
+ }
2420
+
2421
+ radius *= Math.pow(2, zoom - opt.style.scaled);
2422
+ return radius;
2423
+ }
2424
+ });
2425
+ scaleOnZoom = true;
2111
2426
  }
2112
- }];
2113
- }
2114
2427
 
2115
- if (state === annotationState.edit) {
2116
- m_this._addEditHandles(features, opt.corners);
2428
+ features = [{
2429
+ point: {
2430
+ x: opt.position.x,
2431
+ y: opt.position.y,
2432
+ style: style,
2433
+ scaleOnZoom: scaleOnZoom
2434
+ }
2435
+ }];
2436
+
2437
+ if (state === annotationState.edit) {
2438
+ m_this._addEditHandles(features, [opt.position], {
2439
+ edge: false,
2440
+ center: false,
2441
+ resize: false,
2442
+ rotate: false
2443
+ });
2444
+ }
2445
+
2446
+ break;
2117
2447
  }
2118
2448
 
2119
2449
  return features;
2120
2450
  };
2451
+ /**
2452
+ * Get and optionally set coordinates associated with this annotation in the
2453
+ * map gcs coordinate system.
2454
+ *
2455
+ * @param {geo.geoPosition[]} [coordinates] An optional array of coordinates
2456
+ * to set.
2457
+ * @returns {geo.geoPosition[]} The current array of coordinates.
2458
+ */
2459
+
2460
+
2461
+ this._coordinates = function (coordinates) {
2462
+ if (coordinates && coordinates.length >= 1) {
2463
+ m_this.options('position', coordinates[0]);
2464
+ }
2465
+
2466
+ if (m_this.state() === annotationState.create) {
2467
+ return [];
2468
+ }
2469
+
2470
+ return [m_this.options('position')];
2471
+ };
2472
+
2473
+ this._coordinateOption = 'position';
2474
+ /**
2475
+ * Handle a mouse click on this annotation. If the event is processed,
2476
+ * evt.handled should be set to `true` to prevent further processing.
2477
+ *
2478
+ * @param {geo.event} evt The mouse click event.
2479
+ * @returns {boolean|string} `true` to update the annotation, `'done'` if
2480
+ * the annotation was completed (changed from create to done state),
2481
+ * `'remove'` if the annotation should be removed, falsy to not update
2482
+ * anything.
2483
+ */
2484
+
2485
+ this.mouseClick = function (evt) {
2486
+ if (m_this.state() !== annotationState.create) {
2487
+ return;
2488
+ }
2489
+
2490
+ if (!evt.buttonsDown.left) {
2491
+ return;
2492
+ }
2493
+
2494
+ evt.handled = true;
2495
+ m_this.options('position', evt.mapgcs);
2496
+ m_this.state(annotationState.done);
2497
+ return 'done';
2498
+ };
2499
+ /**
2500
+ * Return a list of styles that should be preserved in a geojson
2501
+ * representation of the annotation.
2502
+ *
2503
+ * @returns {string[]} A list of style names to store.
2504
+ */
2505
+
2506
+
2507
+ this._geojsonStyles = function () {
2508
+ return ['fill', 'fillColor', 'fillOpacity', 'radius', 'scaled', 'stroke', 'strokeColor', 'strokeOpacity', 'strokeWidth'];
2509
+ };
2510
+ /**
2511
+ * Return the coordinates to be stored in a geojson geometry object.
2512
+ *
2513
+ * @param {string|geo.transform|null} [gcs] `undefined` to use the interface
2514
+ * gcs, `null` to use the map gcs, or any other transform.
2515
+ * @returns {array} An array of flattened coordinates in the interface gcs
2516
+ * coordinate system. `undefined` if this annotation is incomplete.
2517
+ */
2518
+
2519
+
2520
+ this._geojsonCoordinates = function (gcs) {
2521
+ var src = m_this.coordinates(gcs);
2522
+
2523
+ if (!src || m_this.state() === annotationState.create || src.length < 1 || src[0] === undefined) {
2524
+ return;
2525
+ }
2526
+
2527
+ return [src[0].x, src[0].y];
2528
+ };
2529
+ /**
2530
+ * Return the geometry type that is used to store this annotation in geojson.
2531
+ *
2532
+ * @returns {string} A geojson geometry type.
2533
+ */
2534
+
2535
+
2536
+ this._geojsonGeometryType = function () {
2537
+ return 'Point';
2538
+ };
2121
2539
  };
2122
2540
 
2123
- inherit(ellipseAnnotation, rectangleAnnotation);
2124
- var ellipseRequiredFeatures = {};
2125
- ellipseRequiredFeatures[markerFeature.capabilities.feature] = true;
2126
- registerAnnotation('ellipse', ellipseAnnotation, ellipseRequiredFeatures);
2127
- /**
2128
- * Circle annotation class.
2129
- *
2130
- * Circles are a subset of rectangles with a fixed aspect ratio.
2131
- *
2132
- * @class
2133
- * @alias geo.circleAnnotation
2134
- * @extends geo.annotation
2135
- *
2136
- * @param {geo.circleAnnotation.spec?} [args] Options for the annotation.
2137
- * @param {string} [annotationName='circle'] Override the annotation name.
2138
- */
2541
+ inherit(pointAnnotation, annotation);
2542
+ var pointRequiredFeatures = {};
2543
+ pointRequiredFeatures[pointFeature.capabilities.feature] = true;
2544
+ registerAnnotation('point', pointAnnotation, pointRequiredFeatures);
2545
+ module.exports = pointAnnotation;
2546
+
2547
+ /***/ }),
2548
+
2549
+ /***/ 56:
2550
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
2551
+
2552
+ var $ = __webpack_require__(5638);
2553
+
2554
+ var inherit = __webpack_require__(5699);
2139
2555
 
2140
- var circleAnnotation = function circleAnnotation(args, annotationName) {
2141
- 'use strict';
2556
+ var registerAnnotation = (__webpack_require__(4647).registerAnnotation);
2142
2557
 
2143
- args = $.extend({}, args, {
2144
- constraint: 1
2145
- });
2558
+ var lineFeature = __webpack_require__(4708);
2146
2559
 
2147
- if (!(this instanceof circleAnnotation)) {
2148
- return new circleAnnotation(args, annotationName);
2149
- }
2560
+ var polygonFeature = __webpack_require__(4343);
2150
2561
 
2151
- ellipseAnnotation.call(this, args, annotationName || 'circle');
2152
- };
2562
+ var annotation = (__webpack_require__(5784).annotation);
2153
2563
 
2154
- inherit(circleAnnotation, ellipseAnnotation);
2155
- var circleRequiredFeatures = {};
2156
- circleRequiredFeatures[markerFeature.capabilities.feature] = true;
2157
- registerAnnotation('circle', circleAnnotation, circleRequiredFeatures);
2564
+ var annotationState = (__webpack_require__(5784).state);
2565
+
2566
+ var continuousVerticesActions = (__webpack_require__(5784).continuousVerticesActions);
2567
+
2568
+ var continuousVerticesProcessAction = (__webpack_require__(5784).continuousVerticesProcessAction);
2158
2569
  /**
2159
2570
  * Polygon annotation specification. Extends {@link geo.annotation.spec}.
2160
2571
  *
@@ -2184,6 +2595,7 @@ registerAnnotation('circle', circleAnnotation, circleRequiredFeatures);
2184
2595
  * @param {geo.polygonAnnotation.spec?} [args] Options for the annotation.
2185
2596
  */
2186
2597
 
2598
+
2187
2599
  var polygonAnnotation = function polygonAnnotation(args) {
2188
2600
  'use strict';
2189
2601
 
@@ -2518,50 +2930,85 @@ var polygonRequiredFeatures = {};
2518
2930
  polygonRequiredFeatures[polygonFeature.capabilities.feature] = true;
2519
2931
  polygonRequiredFeatures[lineFeature.capabilities.basic] = [annotationState.create];
2520
2932
  registerAnnotation('polygon', polygonAnnotation, polygonRequiredFeatures);
2933
+ module.exports = polygonAnnotation;
2934
+
2935
+ /***/ }),
2936
+
2937
+ /***/ 3442:
2938
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
2939
+
2940
+ var $ = __webpack_require__(5638);
2941
+
2942
+ var inherit = __webpack_require__(5699);
2943
+
2944
+ var geo_event = __webpack_require__(5108);
2945
+
2946
+ var geo_action = __webpack_require__(7839);
2947
+
2948
+ var registerAnnotation = (__webpack_require__(4647).registerAnnotation);
2949
+
2950
+ var polygonFeature = __webpack_require__(4343);
2951
+
2952
+ var annotation = (__webpack_require__(5784).annotation);
2953
+
2954
+ var annotationState = (__webpack_require__(5784).state);
2955
+
2956
+ var annotationActionOwner = (__webpack_require__(5784).annotationActionOwner);
2521
2957
  /**
2522
- * Line annotation specification. Extends {@link geo.annotation.spec}.
2958
+ * Rectangle annotation specification. Extends {@link geo.annotation.spec}.
2523
2959
  *
2524
- * @typedef {object} geo.lineAnnotation.spec
2960
+ * @typedef {object} geo.rectangleAnnotation.spec
2525
2961
  * @extends geo.annotation.spec
2526
- * @property {geo.geoPosition[]} [vertices] A list of vertices in map gcs
2527
- * coordinates.
2528
- * @property {geo.geoPosition[]} [coordinates] An alternate name for
2529
- * `vertices`.
2530
- * @property {geo.lineFeature.styleSpec} [style] The style to apply to a
2531
- * finished line. This uses styles for {@link geo.lineFeature}.
2532
- * @property {geo.lineFeature.styleSpec} [editStyle] The style to apply to a
2533
- * line in edit mode.
2962
+ * @property {geo.geoPosition[]} [corners] A list of four corners in map gcs
2963
+ * coordinates. These must be in order around the perimeter of the
2964
+ * rectangle (in either direction).
2965
+ * @property {geo.geoPosition[]} [coordinates] An alternate name for `corners`.
2966
+ * @property {geo.polygonFeature.styleSpec} [style] The style to apply to a
2967
+ * finished rectangle. This uses styles for {@link geo.polygonFeature}.
2968
+ * @property {geo.polygonFeature.styleSpec} [editStyle] The style to apply to a
2969
+ * rectangle in edit mode.
2970
+ * @property {number|number[]|function} [constraint] If specified, an aspect
2971
+ * ratio or list of aspect ratios to constraint the rectangle to. If a
2972
+ * function, a selection constraint function to call to adjust the
2973
+ * rectangle.
2534
2974
  */
2535
2975
 
2536
2976
  /**
2537
- * Line annotation class.
2977
+ * Rectangle annotation class.
2978
+ *
2979
+ * Rectangles are always rendered as polygons. This could be changed -- if no
2980
+ * stroke is specified, the quad feature would be sufficient and work on more
2981
+ * renderers.
2538
2982
  *
2539
2983
  * @class
2540
- * @alias geo.lineAnnotation
2984
+ * @alias geo.rectangleAnnotation
2541
2985
  * @extends geo.annotation
2542
2986
  *
2543
- * @param {geo.lineAnnotation.spec?} [args] Options for the annotation.
2987
+ * @param {geo.rectangleAnnotation.spec?} [args] Options for the annotation.
2988
+ * @param {string} [annotationName='rectangle'] Override the annotation name.
2544
2989
  */
2545
2990
 
2546
- var lineAnnotation = function lineAnnotation(args) {
2991
+
2992
+ var rectangleAnnotation = function rectangleAnnotation(args, annotationName) {
2547
2993
  'use strict';
2548
2994
 
2549
- if (!(this instanceof lineAnnotation)) {
2550
- return new lineAnnotation(args);
2995
+ if (!(this instanceof rectangleAnnotation)) {
2996
+ return new rectangleAnnotation(args, annotationName);
2551
2997
  }
2552
2998
 
2553
2999
  args = $.extend(true, {}, {
2554
3000
  style: {
2555
- line: function line(d) {
2556
- /* Return an array that has the same number of items as we have
2557
- * vertices. */
2558
- return Array.apply(null, Array(m_this.options('vertices').length)).map(function () {
2559
- return d;
2560
- });
3001
+ fill: true,
3002
+ fillColor: {
3003
+ r: 0,
3004
+ g: 1,
3005
+ b: 0
2561
3006
  },
2562
- position: function position(d, i) {
2563
- return m_this.options('vertices')[i];
3007
+ fillOpacity: 0.25,
3008
+ polygon: function polygon(d) {
3009
+ return d.polygon;
2564
3010
  },
3011
+ stroke: true,
2565
3012
  strokeColor: {
2566
3013
  r: 0,
2567
3014
  g: 0,
@@ -2569,201 +3016,68 @@ var lineAnnotation = function lineAnnotation(args) {
2569
3016
  },
2570
3017
  strokeOpacity: 1,
2571
3018
  strokeWidth: 3,
2572
- closed: false,
2573
- lineCap: 'butt',
2574
- lineJoin: 'miter'
3019
+ uniformPolygon: true
2575
3020
  },
2576
3021
  highlightStyle: {
3022
+ fillColor: {
3023
+ r: 0,
3024
+ g: 1,
3025
+ b: 1
3026
+ },
3027
+ fillOpacity: 0.5,
2577
3028
  strokeWidth: 5
2578
3029
  },
2579
3030
  createStyle: {
2580
- line: function line(d) {
2581
- /* Return an array that has the same number of items as we have
2582
- * vertices. */
2583
- return Array.apply(null, Array(m_this.options('vertices').length)).map(function () {
2584
- return d;
2585
- });
2586
- },
2587
- position: function position(d, i) {
2588
- return m_this.options('vertices')[i];
3031
+ fillColor: {
3032
+ r: 0.3,
3033
+ g: 0.3,
3034
+ b: 0.3
2589
3035
  },
3036
+ fillOpacity: 0.25,
2590
3037
  strokeColor: {
2591
3038
  r: 0,
2592
3039
  g: 0,
2593
3040
  b: 1
2594
- },
2595
- strokeOpacity: 1,
2596
- strokeWidth: 3,
2597
- closed: false,
2598
- lineCap: 'butt',
2599
- lineJoin: 'miter'
3041
+ }
2600
3042
  }
2601
3043
  }, args || {});
2602
- args.vertices = args.vertices || args.coordinates || [];
3044
+ args.corners = args.corners || args.coordinates || [];
2603
3045
  delete args.coordinates;
2604
- annotation.call(this, 'line', args);
3046
+ annotation.call(this, annotationName || 'rectangle', args);
2605
3047
  var m_this = this,
2606
3048
  s_actions = this.actions,
2607
3049
  s_processEditAction = this.processEditAction;
2608
3050
  /**
2609
- * Get a list of renderable features for this annotation.
3051
+ * Return actions needed for the specified state of this annotation.
2610
3052
  *
2611
- * @returns {array} An array of features.
3053
+ * @param {string} [state] The state to return actions for. Defaults to
3054
+ * the current state.
3055
+ * @returns {geo.actionRecord[]} A list of actions.
2612
3056
  */
2613
3057
 
2614
- this.features = function () {
2615
- var opt = m_this.options(),
2616
- state = m_this.state(),
2617
- features;
3058
+ this.actions = function (state) {
3059
+ if (!state) {
3060
+ state = m_this.state();
3061
+ }
2618
3062
 
2619
3063
  switch (state) {
2620
3064
  case annotationState.create:
2621
- features = [{
2622
- line: {
2623
- line: opt.vertices,
2624
- style: m_this.styleForState(state)
2625
- }
3065
+ return [{
3066
+ action: geo_action.annotation_rectangle,
3067
+ name: 'rectangle create',
3068
+ owner: annotationActionOwner,
3069
+ input: 'left',
3070
+ modifiers: {
3071
+ shift: false,
3072
+ ctrl: false
3073
+ },
3074
+ selectionRectangle: true,
3075
+ selectionConstraint: this._selectionConstraint
2626
3076
  }];
2627
- break;
2628
3077
 
2629
3078
  default:
2630
- features = [{
2631
- line: {
2632
- line: opt.vertices,
2633
- style: m_this.styleForState(state)
2634
- }
2635
- }];
2636
-
2637
- if (state === annotationState.edit) {
2638
- m_this._addEditHandles(features, opt.vertices, undefined, !m_this.style('closed'));
2639
- }
2640
-
2641
- break;
2642
- }
2643
-
2644
- return features;
2645
- };
2646
- /**
2647
- * Get and optionally set coordinates associated with this annotation in the
2648
- * map gcs coordinate system.
2649
- *
2650
- * @param {geo.geoPosition[]} [coordinates] An optional array of coordinates
2651
- * to set.
2652
- * @returns {geo.geoPosition[]} The current array of coordinates.
2653
- */
2654
-
2655
-
2656
- this._coordinates = function (coordinates) {
2657
- if (coordinates) {
2658
- m_this.options('vertices', coordinates);
2659
- }
2660
-
2661
- return m_this.options('vertices');
2662
- };
2663
- /**
2664
- * Handle a mouse move on this annotation.
2665
- *
2666
- * @param {geo.event} evt The mouse move event.
2667
- * @returns {boolean} Truthy to update the annotation, falsy to not
2668
- * update anything.
2669
- */
2670
-
2671
-
2672
- this.mouseMove = function (evt) {
2673
- if (m_this.state() !== annotationState.create) {
2674
- return;
2675
- }
2676
-
2677
- var vertices = m_this.options('vertices');
2678
-
2679
- if (vertices.length) {
2680
- vertices[vertices.length - 1] = evt.mapgcs;
2681
- return true;
2682
- }
2683
- };
2684
- /**
2685
- * Handle a mouse click on this annotation. If the event is processed,
2686
- * evt.handled should be set to `true` to prevent further processing.
2687
- *
2688
- * @param {geo.event} evt The mouse click event.
2689
- * @returns {boolean|string} `true` to update the annotation, `'done'` if
2690
- * the annotation was completed (changed from create to done state),
2691
- * `'remove'` if the annotation should be removed, falsy to not update
2692
- * anything.
2693
- */
2694
-
2695
-
2696
- this.mouseClick = function (evt) {
2697
- var layer = m_this.layer();
2698
-
2699
- if (m_this.state() !== annotationState.create || !layer) {
2700
- return;
2701
- }
2702
-
2703
- var end = !!evt.buttonsDown.right,
2704
- skip;
2705
-
2706
- if (!evt.buttonsDown.left && !evt.buttonsDown.right) {
2707
- return;
2708
- }
2709
-
2710
- var vertices = m_this.options('vertices');
2711
-
2712
- if (evt.buttonsDown.right && !vertices.length) {
2713
- return;
2714
- }
2715
-
2716
- evt.handled = true;
2717
-
2718
- if (evt.buttonsDown.left) {
2719
- if (vertices.length) {
2720
- if (vertices.length >= 2 && layer.displayDistance(vertices[vertices.length - 2], null, evt.map, 'display') <= layer.options('adjacentPointProximity')) {
2721
- skip = true;
2722
-
2723
- if (m_this._lastClick && evt.time - m_this._lastClick < layer.options('dblClickTime')) {
2724
- end = true;
2725
- }
2726
- } else if (vertices.length >= 2 && layer.displayDistance(vertices[0], null, evt.map, 'display') <= layer.options('finalPointProximity')) {
2727
- end = 'close';
2728
- } else {
2729
- vertices[vertices.length - 1] = evt.mapgcs;
2730
- }
2731
- } else {
2732
- vertices.push(evt.mapgcs);
2733
- }
2734
-
2735
- if (!end && !skip) {
2736
- vertices.push(evt.mapgcs);
2737
- }
2738
-
2739
- m_this._lastClick = evt.time;
2740
- m_this._lastClickVertexCount = vertices.length;
2741
- }
2742
-
2743
- if (end) {
2744
- if (vertices.length < 3) {
2745
- return 'remove';
2746
- }
2747
-
2748
- vertices.pop();
2749
- m_this.options('style').closed = end === 'close';
2750
- m_this.state(annotationState.done);
2751
- return 'done';
3079
+ return s_actions.apply(m_this, arguments);
2752
3080
  }
2753
-
2754
- return !skip;
2755
- };
2756
- /**
2757
- * Return actions needed for the specified state of this annotation.
2758
- *
2759
- * @param {string} [state] The state to return actions for. Defaults to
2760
- * the current state.
2761
- * @returns {geo.actionRecord[]} A list of actions.
2762
- */
2763
-
2764
-
2765
- this.actions = function (state) {
2766
- return continuousVerticesActions(m_this, s_actions, state, 'line', arguments);
2767
3081
  };
2768
3082
  /**
2769
3083
  * Process any actions for this annotation.
@@ -2777,269 +3091,67 @@ var lineAnnotation = function lineAnnotation(args) {
2777
3091
 
2778
3092
 
2779
3093
  this.processAction = function (evt) {
2780
- return continuousVerticesProcessAction(m_this, evt, 'line');
2781
- };
2782
- /**
2783
- * Return the coordinates to be stored in a geojson geometry object.
2784
- *
2785
- * @param {string|geo.transform|null} [gcs] `undefined` to use the interface
2786
- * gcs, `null` to use the map gcs, or any other transform.
2787
- * @returns {array} An array of flattened coordinates in the interface gcs
2788
- * coordinate system. `undefined` if this annotation is incomplete.
2789
- */
2790
-
2791
-
2792
- this._geojsonCoordinates = function (gcs) {
2793
- var src = m_this.coordinates(gcs);
2794
-
2795
- if (!src || src.length < 2 || m_this.state() === annotationState.create) {
2796
- return;
2797
- }
2798
-
2799
- var coord = [];
2800
-
2801
- for (var i = 0; i < src.length; i += 1) {
2802
- coord.push([src[i].x, src[i].y]);
2803
- }
2804
-
2805
- return coord;
2806
- };
2807
- /**
2808
- * Return the geometry type that is used to store this annotation in geojson.
2809
- *
2810
- * @returns {string} A geojson geometry type.
2811
- */
2812
-
2813
-
2814
- this._geojsonGeometryType = function () {
2815
- return 'LineString';
2816
- };
2817
- /**
2818
- * Return a list of styles that should be preserved in a geojson
2819
- * representation of the annotation.
2820
- *
2821
- * @returns {string[]} A list of style names to store.
2822
- */
2823
-
2824
-
2825
- this._geojsonStyles = function () {
2826
- return ['closed', 'lineCap', 'lineJoin', 'strokeColor', 'strokeOffset', 'strokeOpacity', 'strokeWidth'];
2827
- };
2828
- /**
2829
- * Process any edit actions for this annotation.
2830
- *
2831
- * @param {geo.event} evt The action event.
2832
- * @returns {boolean|string} `true` to update the annotation, falsy to not
2833
- * update anything.
2834
- */
2835
-
2836
-
2837
- this.processEditAction = function (evt) {
2838
- switch (m_this._editHandle.handle.type) {
2839
- case 'vertex':
2840
- return m_this._processEditActionVertex(evt, true);
2841
- }
2842
-
2843
- return s_processEditAction.apply(m_this, arguments);
2844
- };
2845
- /**
2846
- * Handle a mouse click on this annotation when in edit mode. If the event
2847
- * is processed, evt.handled should be set to `true` to prevent further
2848
- * processing.
2849
- *
2850
- * @param {geo.event} evt The mouse click event.
2851
- * @returns {boolean|string} `true` to update the annotation, `'done'` if
2852
- * the annotation was completed (changed from create to done state),
2853
- * `'remove'` if the annotation should be removed, falsy to not update
2854
- * anything.
2855
- */
2856
-
2857
-
2858
- this.mouseClickEdit = function (evt) {
2859
- // if we get a left double click on an edge on a closed line, break the
2860
- // line at that edge
2861
- var layer = m_this.layer(),
2862
- handle = m_this._editHandle,
2863
- split; // ensure we are in edit mode and this is a left click
2864
-
2865
- if (m_this.state() !== annotationState.edit || !layer || !evt.buttonsDown.left) {
2866
- return;
2867
- } // ensure this is an edge on a closed line
2868
-
3094
+ var layer = m_this.layer();
2869
3095
 
2870
- if (!handle || !handle.handle.selected || handle.handle.type !== 'edge' || !m_this.options('style').closed) {
3096
+ if (m_this.state() !== annotationState.create || !layer || evt.event !== geo_event.actionselection || evt.state.action !== geo_action.annotation_rectangle) {
2871
3097
  return;
2872
3098
  }
2873
3099
 
2874
- evt.handled = true;
2875
-
2876
- if (m_this._lastClick && evt.time - m_this._lastClick < layer.options('dblClickTime')) {
2877
- split = true;
2878
- }
2879
-
2880
- m_this._lastClick = evt.time;
2881
-
2882
- if (split) {
2883
- var index = handle.handle.index,
2884
- curPts = m_this._coordinates(),
2885
- pts = curPts.slice(index + 1).concat(curPts.slice(0, index + 1));
2886
-
2887
- m_this._coordinates(pts);
3100
+ var map = layer.map(),
3101
+ corners = [
3102
+ /* Keep in map gcs, not interface gcs to avoid wrapping issues */
3103
+ map.displayToGcs({
3104
+ x: evt.lowerLeft.x,
3105
+ y: evt.lowerLeft.y
3106
+ }, null), map.displayToGcs({
3107
+ x: evt.lowerLeft.x,
3108
+ y: evt.upperRight.y
3109
+ }, null), map.displayToGcs({
3110
+ x: evt.upperRight.x,
3111
+ y: evt.upperRight.y
3112
+ }, null), map.displayToGcs({
3113
+ x: evt.upperRight.x,
3114
+ y: evt.lowerLeft.y
3115
+ }, null)];
2888
3116
 
2889
- m_this.options('style').closed = false;
2890
- handle.handle.index = undefined;
2891
- return true;
3117
+ if (this._selectionConstraint && evt.mouse && evt.state.origin) {
3118
+ this._selectionConstraint(evt.mouse.mapgcs, evt.state.origin.mapgcs, corners);
2892
3119
  }
2893
- };
2894
- };
2895
-
2896
- inherit(lineAnnotation, annotation);
2897
- var lineRequiredFeatures = {};
2898
- lineRequiredFeatures[lineFeature.capabilities.basic] = [annotationState.create];
2899
- registerAnnotation('line', lineAnnotation, lineRequiredFeatures);
2900
- /**
2901
- * Point annotation specification. Extends {@link geo.annotation.spec}.
2902
- *
2903
- * @typedef {object} geo.pointAnnotation.spec
2904
- * @extends geo.annotation.spec
2905
- * @property {geo.geoPosition} [position] A coordinate in map gcs coordinates.
2906
- * @property {geo.geoPosition[]} [coordinates] An array with one coordinate to
2907
- * use in place of `position`.
2908
- * @property {geo.pointFeature.styleSpec} [style] The style to apply to a
2909
- * finished point. This uses styles for {@link geo.pointFeature}.
2910
- * @property {boolean|number} [style.scaled=false] If `false`, the point is not
2911
- * scaled with zoom level. If `true`, the radius is based on the zoom level
2912
- * at first instantiation. If a number, the radius is used at the `scaled`
2913
- * zoom level.
2914
- * @property {geo.pointFeature.styleSpec} [editStyle] The style to apply to a
2915
- * point in edit mode.
2916
- */
2917
-
2918
- /**
2919
- * Point annotation class.
2920
- *
2921
- * @class
2922
- * @alias geo.pointAnnotation
2923
- * @extends geo.annotation
2924
- *
2925
- * @param {geo.pointAnnotation.spec?} [args] Options for the annotation.
2926
- */
2927
-
2928
- var pointAnnotation = function pointAnnotation(args) {
2929
- 'use strict';
3120
+ /* Don't keep rectangles that have nearly zero area in display pixels */
2930
3121
 
2931
- if (!(this instanceof pointAnnotation)) {
2932
- return new pointAnnotation(args);
2933
- }
2934
3122
 
2935
- args = $.extend(true, {}, {
2936
- style: {
2937
- fill: true,
2938
- fillColor: {
2939
- r: 0,
2940
- g: 1,
2941
- b: 0
2942
- },
2943
- fillOpacity: 0.25,
2944
- radius: 10,
2945
- scaled: false,
2946
- stroke: true,
2947
- strokeColor: {
2948
- r: 0,
2949
- g: 0,
2950
- b: 0
2951
- },
2952
- strokeOpacity: 1,
2953
- strokeWidth: 3
2954
- },
2955
- createStyle: {
2956
- fillColor: {
2957
- r: 0.3,
2958
- g: 0.3,
2959
- b: 0.3
2960
- },
2961
- fillOpacity: 0.25,
2962
- strokeColor: {
2963
- r: 0,
2964
- g: 0,
2965
- b: 1
2966
- }
2967
- },
2968
- highlightStyle: {
2969
- fillColor: {
2970
- r: 0,
2971
- g: 1,
2972
- b: 1
2973
- },
2974
- fillOpacity: 0.5,
2975
- strokeWidth: 5
3123
+ if (layer.displayDistance(corners[0], null, corners[1], null) * layer.displayDistance(corners[0], null, corners[3], null) < 0.01) {
3124
+ return 'remove';
2976
3125
  }
2977
- }, args || {});
2978
- args.position = args.position || (args.coordinates ? args.coordinates[0] : undefined);
2979
- delete args.coordinates;
2980
- annotation.call(this, 'point', args);
2981
- var m_this = this;
3126
+
3127
+ m_this.options('corners', corners);
3128
+ m_this.state(annotationState.done);
3129
+ return 'done';
3130
+ };
2982
3131
  /**
2983
3132
  * Get a list of renderable features for this annotation.
2984
3133
  *
2985
3134
  * @returns {array} An array of features.
2986
3135
  */
2987
3136
 
3137
+
2988
3138
  this.features = function () {
2989
3139
  var opt = m_this.options(),
2990
3140
  state = m_this.state(),
2991
- features,
2992
- style,
2993
- scaleOnZoom;
2994
-
2995
- switch (state) {
2996
- case annotationState.create:
2997
- features = [];
2998
- break;
2999
-
3000
- default:
3001
- style = m_this.styleForState(state);
3002
-
3003
- if (opt.style.scaled || opt.style.scaled === 0) {
3004
- if (opt.style.scaled === true) {
3005
- opt.style.scaled = m_this.layer().map().zoom();
3006
- }
3007
-
3008
- style = $.extend({}, style, {
3009
- radius: function radius() {
3010
- var radius = opt.style.radius,
3011
- zoom = m_this.layer().map().zoom();
3012
-
3013
- if (util.isFunction(radius)) {
3014
- radius = radius.apply(m_this, arguments);
3015
- }
3016
-
3017
- radius *= Math.pow(2, zoom - opt.style.scaled);
3018
- return radius;
3019
- }
3020
- });
3021
- scaleOnZoom = true;
3022
- }
3023
-
3024
- features = [{
3025
- point: {
3026
- x: opt.position.x,
3027
- y: opt.position.y,
3028
- style: style,
3029
- scaleOnZoom: scaleOnZoom
3030
- }
3031
- }];
3141
+ features;
3142
+ features = [];
3032
3143
 
3033
- if (state === annotationState.edit) {
3034
- m_this._addEditHandles(features, [opt.position], {
3035
- edge: false,
3036
- center: false,
3037
- resize: false,
3038
- rotate: false
3039
- });
3144
+ if (opt.corners && opt.corners.length >= 4) {
3145
+ features = [{
3146
+ polygon: {
3147
+ polygon: opt.corners,
3148
+ style: m_this.styleForState(state)
3040
3149
  }
3150
+ }];
3151
+ }
3041
3152
 
3042
- break;
3153
+ if (state === annotationState.edit) {
3154
+ m_this._addEditHandles(features, opt.corners);
3043
3155
  }
3044
3156
 
3045
3157
  return features;
@@ -3055,42 +3167,50 @@ var pointAnnotation = function pointAnnotation(args) {
3055
3167
 
3056
3168
 
3057
3169
  this._coordinates = function (coordinates) {
3058
- if (coordinates && coordinates.length >= 1) {
3059
- m_this.options('position', coordinates[0]);
3060
- }
3061
-
3062
- if (m_this.state() === annotationState.create) {
3063
- return [];
3170
+ if (coordinates && coordinates.length >= 4) {
3171
+ m_this.options('corners', coordinates.slice(0, 4));
3172
+ /* Should we ensure that the four points form a rectangle in the current
3173
+ * projection, though this might not be rectangular in another gcs? */
3064
3174
  }
3065
3175
 
3066
- return [m_this.options('position')];
3176
+ return m_this.options('corners');
3067
3177
  };
3068
3178
 
3069
- this._coordinateOption = 'position';
3179
+ this._coordinateOption = 'corners';
3070
3180
  /**
3071
- * Handle a mouse click on this annotation. If the event is processed,
3072
- * evt.handled should be set to `true` to prevent further processing.
3181
+ * Return the coordinates to be stored in a geojson geometry object.
3073
3182
  *
3074
- * @param {geo.event} evt The mouse click event.
3075
- * @returns {boolean|string} `true` to update the annotation, `'done'` if
3076
- * the annotation was completed (changed from create to done state),
3077
- * `'remove'` if the annotation should be removed, falsy to not update
3078
- * anything.
3183
+ * @param {string|geo.transform|null} [gcs] `undefined` to use the interface
3184
+ * gcs, `null` to use the map gcs, or any other transform.
3185
+ * @returns {array} An array of flattened coordinates in the interface gcs
3186
+ * coordinate system. `undefined` if this annotation is incomplete.
3079
3187
  */
3080
3188
 
3081
- this.mouseClick = function (evt) {
3082
- if (m_this.state() !== annotationState.create) {
3189
+ this._geojsonCoordinates = function (gcs) {
3190
+ var src = m_this.coordinates(gcs);
3191
+
3192
+ if (!src || m_this.state() === annotationState.create || src.length < 4) {
3083
3193
  return;
3084
3194
  }
3085
3195
 
3086
- if (!evt.buttonsDown.left) {
3087
- return;
3196
+ var coord = [];
3197
+
3198
+ for (var i = 0; i < 4; i += 1) {
3199
+ coord.push([src[i].x, src[i].y]);
3088
3200
  }
3089
3201
 
3090
- evt.handled = true;
3091
- m_this.options('position', evt.mapgcs);
3092
- m_this.state(annotationState.done);
3093
- return 'done';
3202
+ coord.push([src[0].x, src[0].y]);
3203
+ return [coord];
3204
+ };
3205
+ /**
3206
+ * Return the geometry type that is used to store this annotation in geojson.
3207
+ *
3208
+ * @returns {string} A geojson geometry type.
3209
+ */
3210
+
3211
+
3212
+ this._geojsonGeometryType = function () {
3213
+ return 'Polygon';
3094
3214
  };
3095
3215
  /**
3096
3216
  * Return a list of styles that should be preserved in a geojson
@@ -3101,207 +3221,269 @@ var pointAnnotation = function pointAnnotation(args) {
3101
3221
 
3102
3222
 
3103
3223
  this._geojsonStyles = function () {
3104
- return ['fill', 'fillColor', 'fillOpacity', 'radius', 'scaled', 'stroke', 'strokeColor', 'strokeOpacity', 'strokeWidth'];
3224
+ return ['fill', 'fillColor', 'fillOpacity', 'lineCap', 'lineJoin', 'stroke', 'strokeColor', 'strokeOffset', 'strokeOpacity', 'strokeWidth'];
3105
3225
  };
3106
3226
  /**
3107
- * Return the coordinates to be stored in a geojson geometry object.
3227
+ * Set three corners based on an initial corner and a mouse event.
3108
3228
  *
3109
- * @param {string|geo.transform|null} [gcs] `undefined` to use the interface
3110
- * gcs, `null` to use the map gcs, or any other transform.
3111
- * @returns {array} An array of flattened coordinates in the interface gcs
3112
- * coordinate system. `undefined` if this annotation is incomplete.
3229
+ * @param {geo.geoPosition} corners An array of four corners to update.
3230
+ * @param {geo.event} evt The mouse move event.
3113
3231
  */
3114
3232
 
3115
3233
 
3116
- this._geojsonCoordinates = function (gcs) {
3117
- var src = m_this.coordinates(gcs);
3234
+ this._setCornersFromMouse = function (corners, evt) {
3235
+ var map = m_this.layer().map(),
3236
+ c0 = map.gcsToDisplay({
3237
+ x: corners[0].x,
3238
+ y: corners[0].y
3239
+ }, null),
3240
+ c2 = map.gcsToDisplay(evt.mapgcs, null),
3241
+ c1 = {
3242
+ x: c2.x,
3243
+ y: c0.y
3244
+ },
3245
+ c3 = {
3246
+ x: c0.x,
3247
+ y: c2.y
3248
+ };
3249
+ corners[2] = $.extend({}, evt.mapgcs);
3250
+ corners[1] = map.displayToGcs(c1, null);
3251
+ corners[3] = map.displayToGcs(c3, null);
3118
3252
 
3119
- if (!src || m_this.state() === annotationState.create || src.length < 1 || src[0] === undefined) {
3253
+ if (this._selectionConstraint) {
3254
+ this._selectionConstraint(evt.mapgcs, corners[0], corners);
3255
+ }
3256
+ };
3257
+ /**
3258
+ * Handle a mouse move on this annotation.
3259
+ *
3260
+ * @param {geo.event} evt The mouse move event.
3261
+ * @returns {boolean} Truthy to update the annotation, falsy to not
3262
+ * update anything.
3263
+ */
3264
+
3265
+
3266
+ this.mouseMove = function (evt) {
3267
+ if (m_this.state() !== annotationState.create) {
3120
3268
  return;
3121
3269
  }
3122
3270
 
3123
- return [src[0].x, src[0].y];
3271
+ var corners = m_this.options('corners');
3272
+
3273
+ if (corners.length) {
3274
+ m_this._setCornersFromMouse(corners, evt);
3275
+
3276
+ return true;
3277
+ }
3124
3278
  };
3125
3279
  /**
3126
- * Return the geometry type that is used to store this annotation in geojson.
3280
+ * Handle a mouse click on this annotation. If the event is processed,
3281
+ * evt.handled should be set to `true` to prevent further processing.
3127
3282
  *
3128
- * @returns {string} A geojson geometry type.
3283
+ * @param {geo.event} evt The mouse click event.
3284
+ * @returns {boolean|string} `true` to update the annotation, `'done'` if
3285
+ * the annotation was completed (changed from create to done state),
3286
+ * `'remove'` if the annotation should be removed, falsy to not update
3287
+ * anything.
3129
3288
  */
3130
3289
 
3131
3290
 
3132
- this._geojsonGeometryType = function () {
3133
- return 'Point';
3134
- };
3135
- };
3291
+ this.mouseClick = function (evt) {
3292
+ var layer = m_this.layer();
3136
3293
 
3137
- inherit(pointAnnotation, annotation);
3138
- var pointRequiredFeatures = {};
3139
- pointRequiredFeatures[pointFeature.capabilities.feature] = true;
3140
- registerAnnotation('point', pointAnnotation, pointRequiredFeatures);
3141
- /**
3142
- * Return a function that can be used as a selectionConstraint that requires
3143
- * that the aspect ratio of a rectangle-like selection is a specific value or
3144
- * range of values.
3145
- *
3146
- * @param {number|number[]} ratio Either a single aspect ratio or a list of
3147
- * allowed aspect ratios. For instance, 1 will require that the selection
3148
- * square, 2 would require that it is twice as wide as tall, [2, 1/2] would
3149
- * allow it to be twice as wide or half as wide as it is tall.
3150
- * @returns {function} A function that can be passed to the mapIterator
3151
- * selectionConstraint or to an annotation constraint function.
3152
- */
3294
+ if (m_this.state() !== annotationState.create || !layer) {
3295
+ return;
3296
+ }
3153
3297
 
3154
- function constrainAspectRatio(ratio) {
3155
- var ratios = Array.isArray(ratio) ? ratio : [ratio];
3298
+ if (!evt.buttonsDown.left && !evt.buttonsDown.right) {
3299
+ return;
3300
+ }
3301
+
3302
+ var corners = m_this.options('corners');
3303
+
3304
+ if (evt.buttonsDown.right && !corners.length) {
3305
+ return;
3306
+ }
3307
+
3308
+ evt.handled = true;
3309
+
3310
+ if (corners.length) {
3311
+ m_this._setCornersFromMouse(corners, evt);
3312
+ /* Don't keep rectangles that have nearly zero area in display pixels */
3313
+
3314
+
3315
+ if (layer.displayDistance(corners[0], null, corners[1], null) * layer.displayDistance(corners[0], null, corners[3], null) < 0.01) {
3316
+ return 'remove';
3317
+ }
3318
+
3319
+ m_this.state(annotationState.done);
3320
+ return 'done';
3321
+ }
3322
+
3323
+ if (evt.buttonsDown.left) {
3324
+ corners.push($.extend({}, evt.mapgcs));
3325
+ corners.push($.extend({}, evt.mapgcs));
3326
+ corners.push($.extend({}, evt.mapgcs));
3327
+ corners.push($.extend({}, evt.mapgcs));
3328
+ return true;
3329
+ }
3330
+ };
3156
3331
  /**
3157
- * Constrain a mouse action or annotation action to a list of aspect ratios.
3332
+ * Process any edit actions for this annotation.
3158
3333
  *
3159
- * @param {geo.geoPosition} pos Mouse or new location in map gcs.
3160
- * @param {geo.geoPosition} origin Origin in map gcs when the activity
3161
- * started.
3162
- * @param {geo.geoPosition} [corners] If specified, an array of corner
3163
- * locations in mapgcs. This may be modified.
3164
- * @param {string?} [mode] 'edge', 'vertex' or falsy. A falsy value implies
3165
- * this is just the most recent point in the annotation, otherwise it is
3166
- * the portion of the annotation being modified.
3167
- * @param {number} [ang] A list of angles of each side of the polygon
3168
- * represented by corners or the original annotation.
3169
- * @param {integer} [index] The specific vertex or edge that is being
3170
- * modified.
3171
- * @returns {object} An object with the ``origin`` (this is what is passed
3172
- * in), a new position as ``pos``, and the updated corners as ``corners``.
3334
+ * @param {geo.event} evt The action event.
3335
+ * @returns {boolean|string} `true` to update the annotation, falsy to not
3336
+ * update anything.
3173
3337
  */
3174
3338
 
3175
- function constraintFunction(pos, origin, corners, mode, ang, index) {
3176
- var newpos = pos;
3177
- var best;
3178
3339
 
3179
- if (!corners) {
3180
- corners = [{
3181
- x: origin.x,
3182
- y: origin.y
3183
- }, {
3184
- x: pos.x,
3185
- y: origin.y
3186
- }, {
3187
- x: pos.x,
3188
- y: pos.y
3189
- }, {
3190
- x: origin.x,
3191
- y: pos.y
3192
- }];
3340
+ this.processEditAction = function (evt) {
3341
+ var start = m_this._editHandle.startCoordinates,
3342
+ delta = {
3343
+ x: evt.mouse.mapgcs.x - evt.state.origin.mapgcs.x,
3344
+ y: evt.mouse.mapgcs.y - evt.state.origin.mapgcs.y
3345
+ },
3346
+ type = m_this._editHandle.handle.type,
3347
+ index = m_this._editHandle.handle.index,
3348
+ ang = [Math.atan2(start[1].y - start[0].y, start[1].x - start[0].x), Math.atan2(start[2].y - start[1].y, start[2].x - start[1].x), Math.atan2(start[3].y - start[2].y, start[3].x - start[2].x), Math.atan2(start[0].y - start[3].y, start[0].x - start[3].x)],
3349
+ corners,
3350
+ delta1,
3351
+ delta2,
3352
+ ang1,
3353
+ ang2; // an angle can be zero because it is horizontal or undefined. If opposite
3354
+ // angles are both zero, this is a degenerate rectangle (a line or a point)
3355
+
3356
+ if (!ang[0] && !ang[1] && !ang[2] && !ang[3]) {
3357
+ ang[1] = Math.PI / 2;
3358
+ ang[2] = Math.PI;
3359
+ ang[3] = -Math.PI / 2;
3193
3360
  }
3194
3361
 
3195
- if (mode) {
3196
- /* Edit a vertex or edge */
3197
- var i1 = (index + 1) % 4;
3198
- var i2 = (index + 2) % 4;
3199
- var i3 = (index + 3) % 4;
3200
- var dist1 = Math.pow(Math.pow(corners[index].x - corners[i1].x, 2) + Math.pow(corners[index].y - corners[i1].y, 2), 0.5);
3201
- var dist3 = Math.pow(Math.pow(corners[index].x - corners[i3].x, 2) + Math.pow(corners[index].y - corners[i3].y, 2), 0.5);
3202
- var area = Math.abs(dist1 * dist3);
3203
- var shape, edge;
3204
- ratios.forEach(function (ratio) {
3205
- if (ratio !== 1 && !(index % 2)) {
3206
- ratio = 1.0 / ratio;
3207
- }
3362
+ if (!ang[0] && !ang[2]) {
3363
+ ang[0] = ang[1] - Math.PI / 2;
3364
+ ang[2] = ang[1] + Math.PI / 2;
3365
+ }
3208
3366
 
3209
- var width = Math.pow(area * ratio, 0.5);
3210
- var score = Math.pow(width - dist3, 2) + Math.pow(width / ratio - dist1, 2);
3367
+ if (!ang[1] && !ang[3]) {
3368
+ ang[1] = ang[2] - Math.PI / 2;
3369
+ ang[3] = ang[2] + Math.PI / 2;
3370
+ }
3211
3371
 
3212
- if (best === undefined || score < best) {
3213
- best = score;
3214
- shape = {
3215
- w: width,
3216
- h: width / ratio
3372
+ switch (type) {
3373
+ case 'vertex':
3374
+ corners = start.map(function (elem) {
3375
+ return {
3376
+ x: elem.x,
3377
+ y: elem.y
3217
3378
  };
3379
+ });
3380
+ ang1 = ang[(index + 1) % 4];
3381
+ delta1 = {
3382
+ x: (delta.x * Math.cos(ang1) + delta.y * Math.sin(ang1)) * Math.cos(ang1),
3383
+ y: (delta.y * Math.sin(ang1) + delta.x * Math.cos(ang1)) * Math.sin(ang1)
3384
+ };
3385
+ ang2 = ang[index];
3386
+ delta2 = {
3387
+ x: (delta.x * Math.cos(ang2) + delta.y * Math.sin(ang2)) * Math.cos(ang2),
3388
+ y: (delta.y * Math.sin(ang2) + delta.x * Math.cos(ang2)) * Math.sin(ang2)
3389
+ };
3390
+ corners[index].x += delta.x;
3391
+ corners[index].y += delta.y;
3392
+ corners[(index + 1) % 4].x += delta1.x;
3393
+ corners[(index + 1) % 4].y += delta1.y;
3394
+ corners[(index + 3) % 4].x += delta2.x;
3395
+ corners[(index + 3) % 4].y += delta2.y;
3396
+
3397
+ if (this._selectionConstraint) {
3398
+ corners = this._selectionConstraint(evt.mouse.mapgcs, evt.state.origin.mapgcs, corners, 'vertex', ang, index).corners;
3218
3399
  }
3219
- });
3220
- var ang1 = ang[i1];
3221
- var delta1 = {
3222
- x: -shape.w * Math.cos(ang1),
3223
- y: -shape.w * Math.sin(ang1)
3224
- };
3225
- var ang2 = ang[index];
3226
- var delta2 = {
3227
- x: -shape.h * Math.cos(ang2),
3228
- y: -shape.h * Math.sin(ang2)
3229
- };
3230
3400
 
3231
- switch (mode) {
3232
- case 'vertex':
3233
- corners[index].x = corners[i2].x + delta1.x + delta2.x;
3234
- corners[index].y = corners[i2].y + delta1.y + delta2.y;
3235
- corners[i1].x = corners[i2].x + delta1.x;
3236
- corners[i1].y = corners[i2].y + delta1.y;
3237
- corners[i3].x = corners[i2].x + delta2.x;
3238
- corners[i3].y = corners[i2].y + delta2.y;
3239
- break;
3401
+ m_this.options('corners', corners);
3402
+ return true;
3240
3403
 
3241
- case 'edge':
3242
- edge = {
3243
- x: (corners[i2].x + corners[i3].x) * 0.5,
3244
- y: (corners[i2].y + corners[i3].y) * 0.5
3404
+ case 'edge':
3405
+ corners = start.map(function (elem) {
3406
+ return {
3407
+ x: elem.x,
3408
+ y: elem.y
3245
3409
  };
3246
- corners[i2].x = edge.x + delta2.x / 2;
3247
- corners[i2].y = edge.y + delta2.y / 2;
3248
- corners[index].x = edge.x + delta1.x - delta2.x / 2;
3249
- corners[index].y = edge.y + delta1.y - delta2.y / 2;
3250
- corners[i1].x = edge.x + delta1.x + delta2.x / 2;
3251
- corners[i1].y = edge.y + delta1.y + delta2.y / 2;
3252
- corners[i3].x = edge.x - delta2.x / 2;
3253
- corners[i3].y = edge.y - delta2.y / 2;
3254
- break;
3255
- }
3256
- } else {
3257
- /* Not in edit vertex or edge mode */
3258
- var _area = Math.abs((pos.x - origin.x) * (pos.y - origin.y));
3259
-
3260
- ratios.forEach(function (ratio) {
3261
- var width = Math.pow(_area * ratio, 0.5);
3262
- var adjusted = {
3263
- x: origin.x + Math.sign(pos.x - origin.x) * width,
3264
- y: origin.y + Math.sign(pos.y - origin.y) * width / ratio
3410
+ });
3411
+ ang1 = ang[(index + 1) % 4];
3412
+ delta = {
3413
+ x: (delta.x * Math.cos(ang1) + delta.y * Math.sin(ang1)) * Math.cos(ang1),
3414
+ y: (delta.y * Math.sin(ang1) + delta.x * Math.cos(ang1)) * Math.sin(ang1)
3265
3415
  };
3266
- var score = Math.pow(adjusted.x - pos.x, 2) + Math.pow(adjusted.y - pos.y, 2);
3416
+ corners[index].x += delta.x;
3417
+ corners[index].y += delta.y;
3418
+ corners[(index + 1) % 4].x += delta.x;
3419
+ corners[(index + 1) % 4].y += delta.y;
3267
3420
 
3268
- if (best === undefined || score < best) {
3269
- best = score;
3270
- newpos = adjusted;
3421
+ if (this._selectionConstraint) {
3422
+ corners = this._selectionConstraint(evt.mouse.mapgcs, evt.state.origin.mapgcs, corners, 'edge', ang, index).corners;
3271
3423
  }
3272
- });
3273
- corners[0].y = corners[1].y = origin.y;
3274
- corners[0].x = corners[3].x = origin.x;
3275
- corners[1].x = corners[2].x = newpos.x;
3276
- corners[2].y = corners[3].y = newpos.y;
3424
+
3425
+ m_this.options('corners', corners);
3426
+ return true;
3277
3427
  }
3278
3428
 
3279
- return {
3280
- corners: corners,
3281
- origin: origin,
3282
- pos: newpos
3283
- };
3284
- }
3429
+ return s_processEditAction.apply(m_this, arguments);
3430
+ };
3431
+ };
3285
3432
 
3286
- return constraintFunction;
3287
- }
3433
+ inherit(rectangleAnnotation, annotation);
3434
+ var rectangleRequiredFeatures = {};
3435
+ rectangleRequiredFeatures[polygonFeature.capabilities.feature] = true;
3436
+ registerAnnotation('rectangle', rectangleAnnotation, rectangleRequiredFeatures);
3437
+ module.exports = rectangleAnnotation;
3288
3438
 
3289
- module.exports = {
3290
- state: annotationState,
3291
- actionOwner: annotationActionOwner,
3292
- annotation: annotation,
3293
- lineAnnotation: lineAnnotation,
3294
- pointAnnotation: pointAnnotation,
3295
- polygonAnnotation: polygonAnnotation,
3296
- rectangleAnnotation: rectangleAnnotation,
3297
- squareAnnotation: squareAnnotation,
3298
- ellipseAnnotation: ellipseAnnotation,
3299
- circleAnnotation: circleAnnotation,
3300
- _editHandleFeatureLevel: editHandleFeatureLevel,
3301
- defaultEditHandleStyle: defaultEditHandleStyle,
3302
- constrainAspectRatio: constrainAspectRatio
3439
+ /***/ }),
3440
+
3441
+ /***/ 4932:
3442
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
3443
+
3444
+ var $ = __webpack_require__(5638);
3445
+
3446
+ var inherit = __webpack_require__(5699);
3447
+
3448
+ var registerAnnotation = (__webpack_require__(4647).registerAnnotation);
3449
+
3450
+ var polygonFeature = __webpack_require__(4343);
3451
+
3452
+ var rectangleAnnotation = __webpack_require__(3442);
3453
+ /**
3454
+ * Square annotation class.
3455
+ *
3456
+ * Squares are a subset of rectangles with a fixed aspect ratio.
3457
+ *
3458
+ * @class
3459
+ * @alias geo.squareAnnotation
3460
+ * @extends geo.annotation
3461
+ *
3462
+ * @param {geo.squareAnnotation.spec?} [args] Options for the annotation.
3463
+ * @param {string} [annotationName='square'] Override the annotation name.
3464
+ */
3465
+
3466
+
3467
+ var squareAnnotation = function squareAnnotation(args, annotationName) {
3468
+ 'use strict';
3469
+
3470
+ args = $.extend({}, args, {
3471
+ constraint: 1
3472
+ });
3473
+
3474
+ if (!(this instanceof squareAnnotation)) {
3475
+ return new squareAnnotation(args, annotationName);
3476
+ }
3477
+
3478
+ rectangleAnnotation.call(this, args, annotationName || 'square');
3303
3479
  };
3304
3480
 
3481
+ inherit(squareAnnotation, rectangleAnnotation);
3482
+ var squareRequiredFeatures = {};
3483
+ squareRequiredFeatures[polygonFeature.capabilities.feature] = true;
3484
+ registerAnnotation('square', squareAnnotation, squareRequiredFeatures);
3485
+ module.exports = squareAnnotation;
3486
+
3305
3487
  /***/ }),
3306
3488
 
3307
3489
  /***/ 836:
@@ -3311,7 +3493,7 @@ var inherit = __webpack_require__(5699);
3311
3493
 
3312
3494
  var featureLayer = __webpack_require__(3715);
3313
3495
 
3314
- var geo_annotation = __webpack_require__(7800);
3496
+ var geo_annotation = __webpack_require__(4213);
3315
3497
 
3316
3498
  var geo_event = __webpack_require__(5108);
3317
3499
 
@@ -10905,9 +11087,8 @@ var fetchQueue = function fetchQueue(options) {
10905
11087
  var pos = $.inArray(defer, m_this._queue);
10906
11088
 
10907
11089
  if (pos >= 0) {
10908
- m_this._queue.splice(pos, 1);
10909
-
10910
- m_this._addToQueue(defer, atEnd);
11090
+ // m_this._queue.splice(pos, 1);
11091
+ m_this._addToQueue(defer, atEnd, pos);
10911
11092
 
10912
11093
  return defer;
10913
11094
  }
@@ -10941,24 +11122,40 @@ var fetchQueue = function fetchQueue(options) {
10941
11122
  * @param {boolean} atEnd If falsy, add the item to the front of the queue
10942
11123
  * if batching is turned off or at the end of the current batch if it is
10943
11124
  * turned on. If truthy, always add the item to the end of the queue.
11125
+ * @param {number} [pos] If specified, the current location in the queue of
11126
+ * the object being added. This avoids having to splice, push, or unshift
11127
+ * the queue.
10944
11128
  */
10945
11129
 
10946
11130
 
10947
- this._addToQueue = function (defer, atEnd) {
11131
+ this._addToQueue = function (defer, atEnd, pos) {
11132
+ var move = atEnd ? m_this._queue.length - 1 : 0;
10948
11133
  defer.__fetchQueue._batch = m_this._batch;
10949
11134
 
10950
- if (atEnd) {
10951
- m_this._queue.push(defer);
10952
- } else if (!m_this._batch) {
10953
- m_this._queue.unshift(defer);
10954
- } else {
10955
- for (var i = 0; i < m_this._queue.length; i += 1) {
10956
- if (m_this._queue[i].__fetchQueue._batch !== m_this._batch) {
11135
+ if (!atEnd && m_this._batch) {
11136
+ for (move = 0; move < m_this._queue.length - (pos === undefined ? 0 : 1); move += 1) {
11137
+ if (m_this._queue[move].__fetchQueue._batch !== m_this._batch) {
10957
11138
  break;
10958
11139
  }
10959
11140
  }
11141
+ }
11142
+
11143
+ if (pos === undefined) {
11144
+ if (atEnd) {
11145
+ m_this._queue.push(defer);
11146
+ } else if (!move) {
11147
+ m_this._queue.unshift(defer);
11148
+ } else {
11149
+ m_this._queue.splice(move, 0, defer);
11150
+ }
11151
+ } else if (pos !== move) {
11152
+ var dir = pos < move ? 1 : -1;
11153
+
11154
+ for (var i = pos; i !== move; i += dir) {
11155
+ m_this._queue[i] = m_this._queue[i + dir];
11156
+ }
10960
11157
 
10961
- m_this._queue.splice(i, 0, defer);
11158
+ m_this._queue[move] = defer;
10962
11159
  }
10963
11160
  };
10964
11161
  /**
@@ -12801,7 +12998,6 @@ $.htmlPrefilter = function (html) {
12801
12998
  __webpack_require__(8701);
12802
12999
 
12803
13000
  module.exports = $.extend({
12804
- annotation: __webpack_require__(7800),
12805
13001
  annotationLayer: __webpack_require__(836),
12806
13002
  camera: __webpack_require__(9986),
12807
13003
  choroplethFeature: __webpack_require__(8719),
@@ -12847,6 +13043,7 @@ module.exports = $.extend({
12847
13043
  inherit: __webpack_require__(5699),
12848
13044
  version: __webpack_require__(2978),
12849
13045
  sha: __webpack_require__(5381),
13046
+ annotation: __webpack_require__(4213),
12850
13047
  util: __webpack_require__(4634),
12851
13048
  jQuery: $,
12852
13049
  canvas: __webpack_require__(7562),
@@ -26856,7 +27053,7 @@ module.exports = sceneObject;
26856
27053
  * @constant
26857
27054
  * @type {string}
26858
27055
  */
26859
- module.exports = "aa7a52c0facebedfe694ae91d1f9a295ade8765e";
27056
+ module.exports = "493ff30a20fb5c5febb2c3521372398121e0cdee";
26860
27057
 
26861
27058
  /***/ }),
26862
27059
 
@@ -33724,6 +33921,22 @@ transform.vincentyDistance = function (pt1, pt2, gcs, baseGcs, ellipsoid, maxIte
33724
33921
  alpha2: Math.atan2(cosU1 * Math.sin(lambda), -sinU1 * cosU2 + cosU1 * sinU2 * Math.cos(lambda))
33725
33922
  };
33726
33923
  };
33924
+ /**
33925
+ * Return a boolean indicating if the projections only differ in their y
33926
+ * coordinate.
33927
+ *
33928
+ * @param {string} srcPrj The source projection.
33929
+ * @param {string} tgtPrj The destination projection.
33930
+ * @returns {boolean} truthy if only the y coordinate is different between
33931
+ * projections.
33932
+ */
33933
+
33934
+
33935
+ transform.onlyInvertedY = function (srcPrj, tgtPrj) {
33936
+ var smatch = srcPrj.match(axisPattern),
33937
+ tmatch = tgtPrj.match(axisPattern);
33938
+ return smatch && tmatch && smatch[1] === tmatch[1] && smatch[3] === tmatch[3];
33939
+ };
33727
33940
  /* Expose proj4 to make it easier to debug */
33728
33941
 
33729
33942
 
@@ -33811,6 +34024,15 @@ module.exports = transform;
33811
34024
  * @property {number} [z=0] Altitude coordinate, often zero.
33812
34025
  */
33813
34026
 
34027
+ /**
34028
+ * Represention of a size in gcs coordinates.
34029
+ *
34030
+ * @typedef geo.geoSize
34031
+ * @type {object}
34032
+ * @property {number} width Width in gcs coordinates.
34033
+ * @property {number} height Height in gcs coordinates.
34034
+ */
34035
+
33814
34036
  /**
33815
34037
  * Represention of a size in pixels.
33816
34038
  *
@@ -39346,7 +39568,7 @@ module.exports = vectorFeature;
39346
39568
  * @constant
39347
39569
  * @type {string}
39348
39570
  */
39349
- module.exports = "1.8.4";
39571
+ module.exports = "1.8.7";
39350
39572
 
39351
39573
  /***/ }),
39352
39574
 
@@ -40577,6 +40799,9 @@ var webgl_lineFeature = function webgl_lineFeature(arg) {
40577
40799
  negStrokeOffset: 0
40578
40800
  }],
40579
40801
  v = vert[1],
40802
+ target_gcs = m_this.gcs(),
40803
+ map_gcs = m_this.layer().map().gcs(),
40804
+ simpleInverse = transform.onlyInvertedY(target_gcs, map_gcs),
40580
40805
  pos,
40581
40806
  posIdx3,
40582
40807
  firstpos,
@@ -40657,7 +40882,7 @@ var webgl_lineFeature = function webgl_lineFeature(arg) {
40657
40882
  for (j = 0; j < lineItem.length; j += 1) {
40658
40883
  pos = posFunc(lineItem[j], j, d, i);
40659
40884
  position.push(pos.x);
40660
- position.push(pos.y);
40885
+ position.push(simpleInverse ? -pos.y : pos.y);
40661
40886
  position.push(pos.z || 0.0);
40662
40887
 
40663
40888
  if (!j) {
@@ -40680,7 +40905,10 @@ var webgl_lineFeature = function webgl_lineFeature(arg) {
40680
40905
  }
40681
40906
  }
40682
40907
 
40683
- position = transform.transformCoordinates(m_this.gcs(), m_this.layer().map().gcs(), position, 3);
40908
+ if (!simpleInverse) {
40909
+ position = transform.transformCoordinates(target_gcs, map_gcs, position, 3);
40910
+ }
40911
+
40684
40912
  m_origin = new Float32Array(m_this.style.get('origin')(position));
40685
40913
 
40686
40914
  if (m_origin[0] || m_origin[1] || m_origin[2]) {
@@ -43204,6 +43432,7 @@ var webgl_polygonFeature = function webgl_polygonFeature(arg) {
43204
43432
  items = [],
43205
43433
  target_gcs = m_this.gcs(),
43206
43434
  map_gcs = m_this.layer().map().gcs(),
43435
+ simpleInverse = transform.onlyInvertedY(target_gcs, map_gcs),
43207
43436
  numPts = 0,
43208
43437
  geom = m_mapper.geometryData(),
43209
43438
  color,
@@ -43254,7 +43483,7 @@ var webgl_polygonFeature = function webgl_polygonFeature(arg) {
43254
43483
  for (i = d3 = 0; i < outer.length; i += 1, d3 += 3) {
43255
43484
  c = posFunc(outer[i], i, item, itemIndex);
43256
43485
  geometry[d3] = c.x;
43257
- geometry[d3 + 1] = c.y; // ignore the z values until we support them
43486
+ geometry[d3 + 1] = simpleInverse ? -c.y : c.y; // ignore the z values until we support them
43258
43487
 
43259
43488
  geometry[d3 + 2] = 0; // c.z || 0;
43260
43489
  }
@@ -43278,7 +43507,7 @@ var webgl_polygonFeature = function webgl_polygonFeature(arg) {
43278
43507
  for (i = 0; i < hole.length; i += 1, d3 += 3) {
43279
43508
  c = posFunc(hole[i], i, item, itemIndex);
43280
43509
  geometry.vertices[d3] = c.x;
43281
- geometry.vertices[d3 + 1] = c.y; // ignore the z values until we support them
43510
+ geometry.vertices[d3 + 1] = simpleInverse ? -c.y : c.y; // ignore the z values until we support them
43282
43511
 
43283
43512
  geometry.vertices[d3 + 2] = 0; // c.z || 0;
43284
43513
  }
@@ -43286,7 +43515,10 @@ var webgl_polygonFeature = function webgl_polygonFeature(arg) {
43286
43515
  } // transform to map gcs
43287
43516
 
43288
43517
 
43289
- geometry.vertices = transform.transformCoordinates(target_gcs, map_gcs, geometry.vertices, geometry.dimensions);
43518
+ if (!simpleInverse) {
43519
+ geometry.vertices = transform.transformCoordinates(target_gcs, map_gcs, geometry.vertices, geometry.dimensions);
43520
+ }
43521
+
43290
43522
  record = {
43291
43523
  // triangulate
43292
43524
  triangles: earcut(geometry.vertices, geometry.holes, geometry.dimensions),