diff --git a/.travis.yml b/.travis.yml
index 79ea7e1..62fef0c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -12,4 +12,3 @@ before_script:
- sleep 3 # give xvfb some time to start
script:
- npm run build
-- npm run karma.test
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e5664c8..0e48bd6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,11 @@
+## 0.0.2 (暂时添加所有符号类型)
+
+* 添加部分点,圆,椭圆,8种箭头类型符号
+
## 0.0.1 (完善PlotDraw)
* 完善PlotDraw
-* 添加部分geometry构造类(Ployline,Arror,Polygon)
+* 添加部分geometry构造类(Ployline,Arror,Polygon, Flag)
## 0.0.0 (搭建框架)
diff --git a/build/rollup-base-config.js b/build/rollup-base-config.js
index 689cf89..60b093f 100644
--- a/build/rollup-base-config.js
+++ b/build/rollup-base-config.js
@@ -70,6 +70,7 @@ module.exports = [
{
file: resolve(_package.unpkg),
format: 'umd',
+ sourceMap: true,
env: 'development'
},
{
diff --git a/examples/circle.html b/examples/circle.html
new file mode 100644
index 0000000..be9213e
--- /dev/null
+++ b/examples/circle.html
@@ -0,0 +1,72 @@
+
+
+
+
+
Geometry - Rectangle, Circle, Ellipse and Sector
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/index.html b/examples/index.html
index 19c290e..9ada597 100644
--- a/examples/index.html
+++ b/examples/index.html
@@ -43,11 +43,10 @@
console.log(param.geometry);
layer.addGeometry(param.geometry);
});
- var items = ['Polyline', 'Curve',
+ var itemsLeft = ['Point', 'Polyline', 'Curve',
'Arc', 'FreeLine', 'AttackArrow',
'ClosedCurve', 'FreePolygon',
- 'GatheringPlace', 'Lune', 'Sector', 'Polygon',
- 'RectAngle'].map(function (value) {
+ 'GatheringPlace', 'Lune', 'Sector'].map(function (value) {
return {
item: value,
click: function () {
@@ -55,11 +54,79 @@
}
};
});
+ var itemsCenter = ['AttackArrow', 'DoubleArrow', 'FineArrow',
+ 'StraightArrow', 'AssaultDirection', 'SquadCombat', 'TailedAttackArrow', 'TailedSquadCombat'].map(function (value) {
+ return {
+ item: value,
+ click: function () {
+ drawTool.setMode(value).enable();
+ }
+ };
+ });
+ var itemsRight = ['Polygon',
+ 'CurveFlag', 'TriangleFlag', 'RectFlag',
+ 'RectAngle', 'Circle', 'Ellipse'].map(function (value) {
+ return {
+ item: value,
+ click: function () {
+ drawTool.setMode(value).enable();
+ }
+ };
+ });
+ // left
new maptalks.control.Toolbar({
+ position : 'top-left',
items: [
{
item: 'Shape',
- children: items
+ children: itemsLeft
+ },
+ {
+ item: 'Disable',
+ click: function () {
+ drawTool.disable();
+ }
+ },
+ {
+ item: 'Clear',
+ click: function () {
+ layer.clear();
+ }
+ }
+ ]
+ }).addTo(map);
+ // center
+ new maptalks.control.Toolbar({
+ position : {
+ 'top' : 20,
+ 'left' : 580
+ },
+ items: [
+ {
+ item: 'Shape',
+ children: itemsCenter
+ },
+ {
+ item: 'Disable',
+ click: function () {
+ drawTool.disable();
+ }
+ },
+ {
+ item: 'Clear',
+ click: function () {
+ layer.clear();
+ }
+ }
+ ]
+ }).addTo(map);
+ // right
+ new maptalks.control.Toolbar({
+ position : 'top-right',
+ items: [
+ {
+ item: 'Shape',
+ children: itemsRight
},
{
item: 'Disable',
diff --git a/src/core/PlotDraw.js b/src/core/PlotDraw.js
index b27900d..d3c82b2 100644
--- a/src/core/PlotDraw.js
+++ b/src/core/PlotDraw.js
@@ -191,7 +191,11 @@ class PlotDraw extends maptalks.MapTool {
const registerMode = this._getRegisterMode()
const coordinate = event['coordinate']
if (this._geometry) {
- if (!registerMode.freehand) {
+ if (this.getMode() === 'point') {
+ this.endDraw(event)
+ return
+ }
+ if (!registerMode.freehand && registerMode['limitClickCount'] > 1) {
if (MathDistance([
coordinate['x'], coordinate['y']], [
this._clickCoords[this._clickCoords.length - 1]['x'],
diff --git a/src/geometry/Arrow/AssaultDirection.js b/src/geometry/Arrow/AssaultDirection.js
new file mode 100644
index 0000000..24c54ea
--- /dev/null
+++ b/src/geometry/Arrow/AssaultDirection.js
@@ -0,0 +1,97 @@
+/**
+ * Created by FDD on 2017/12/31.
+ * @desc 粗单直箭头
+ * @Inherits maptalks.Polygon
+ */
+
+import * as maptalks from 'maptalks'
+import * as Constants from '../../Constants'
+import {
+ getThirdPoint,
+ getBaseLength
+} from '../helper/index'
+const Coordinate = maptalks.Coordinate
+
+const _options = {
+ tailWidthFactor: 0.05,
+ headWidthFactor: 0.15,
+ neckWidthFactor: 0.1,
+ headAngle: Math.PI / 4,
+ neckAngle: Math.PI * 0.17741
+}
+
+class AssaultDirection extends maptalks.Polygon {
+ constructor (coordinates, options = {}) {
+ super(options)
+ this.type = 'AssaultDirection'
+ this._coordinates = []
+ if (coordinates) {
+ this.setPoints(coordinates)
+ }
+ }
+
+ /**
+ * 处理插值
+ */
+ _generate () {
+ try {
+ const count = this._coordinates.length
+ const _points = Coordinate.toNumberArrays(this._coordinates)
+ if (count < 2) return
+ let [points1, points2] = [_points[0], _points[1]]
+ let len = getBaseLength(_points)
+ let tailWidth = len * _options.tailWidthFactor
+ let neckWidth = len * _options.neckWidthFactor
+ let headWidth = len * _options.headWidthFactor
+ let tailLeft = getThirdPoint(points2, points1, Constants.HALF_PI, tailWidth, true)
+ let tailRight = getThirdPoint(points2, points1, Constants.HALF_PI, tailWidth, false)
+ let headLeft = getThirdPoint(points1, points2, _options.headAngle, headWidth, false)
+ let headRight = getThirdPoint(points1, points2, _options.headAngle, headWidth, true)
+ let neckLeft = getThirdPoint(points1, points2, _options.neckAngle, neckWidth, false)
+ let neckRight = getThirdPoint(points1, points2, _options.neckAngle, neckWidth, true)
+ let pList = [tailLeft, neckLeft, headLeft, points2, headRight, neckRight, tailRight]
+ this.setCoordinates([
+ Coordinate.toCoordinates(pList)
+ ])
+ } catch (e) {
+ console.log(e)
+ }
+ }
+
+ setPoints (coordinates) {
+ this._coordinates = !coordinates ? [] : coordinates
+ if (this._coordinates.length >= 1) {
+ this._generate()
+ }
+ }
+
+ _exportGeoJSONGeometry () {
+ const coordinates = Coordinate.toNumberArrays([this.getShell()])
+ return {
+ 'type': 'Polygon',
+ 'coordinates': coordinates
+ }
+ }
+
+ _toJSON (options) {
+ const opts = maptalks.Util.extend({}, options)
+ opts.geometry = false
+ const feature = this.toGeoJSON(opts)
+ return {
+ 'feature': feature,
+ 'coordinates': feature['coordinates'],
+ 'subType': 'AssaultDirection'
+ }
+ }
+
+ static fromJSON (json) {
+ const feature = json['feature']
+ const assaultDirection = new AssaultDirection(json['coordinates'], json['options'])
+ assaultDirection.setProperties(feature['properties'])
+ return assaultDirection
+ }
+}
+
+AssaultDirection.registerJSONType('AssaultDirection')
+
+export default AssaultDirection
diff --git a/src/geometry/Arrow/AttackArrow.js b/src/geometry/Arrow/AttackArrow.js
index 5c9c13b..a05461d 100644
--- a/src/geometry/Arrow/AttackArrow.js
+++ b/src/geometry/Arrow/AttackArrow.js
@@ -43,27 +43,27 @@ class AttackArrow extends maptalks.Polygon {
if (count === 2) {
this.setCoordinates([this._coordinates])
} else {
- let pnts = Coordinate.toNumberArrays(this._coordinates)
- let [tailLeft, tailRight] = [pnts[0], pnts[1]]
- if (isClockWise(pnts[0], pnts[1], pnts[2])) {
- tailLeft = pnts[1]
- tailRight = pnts[0]
+ let _points = Coordinate.toNumberArrays(this._coordinates)
+ let [tailLeft, tailRight] = [_points[0], _points[1]]
+ if (isClockWise(_points[0], _points[1], _points[2])) {
+ tailLeft = _points[1]
+ tailRight = _points[0]
}
let midTail = Mid(tailLeft, tailRight)
- let bonePnts = [midTail].concat(pnts.slice(2))
- let headPnts = this._getArrowHeadPoints(bonePnts, tailLeft, tailRight)
- let [neckLeft, neckRight] = [headPnts[0], headPnts[4]]
- let tailWidthFactor = MathDistance(tailLeft, tailRight) / getBaseLength(bonePnts)
- let bodyPnts = this._getArrowBodyPoints(bonePnts, neckLeft, neckRight, tailWidthFactor)
- let count = bodyPnts.length
- let leftPnts = [tailLeft].concat(bodyPnts.slice(0, count / 2))
- leftPnts.push(neckLeft)
- let rightPnts = [tailRight].concat(bodyPnts.slice(count / 2, count))
- rightPnts.push(neckRight)
- leftPnts = getQBSplinePoints(leftPnts)
- rightPnts = getQBSplinePoints(rightPnts)
+ let bonePoints = [midTail].concat(_points.slice(2))
+ let headPoints = this._getArrowHeadPoints(bonePoints, tailLeft, tailRight)
+ let [neckLeft, neckRight] = [headPoints[0], headPoints[4]]
+ let tailWidthFactor = MathDistance(tailLeft, tailRight) / getBaseLength(bonePoints)
+ let bodyPoints = AttackArrow._getArrowBodyPoints(bonePoints, neckLeft, neckRight, tailWidthFactor)
+ let count = bodyPoints.length
+ let leftPoints = [tailLeft].concat(bodyPoints.slice(0, count / 2))
+ leftPoints.push(neckLeft)
+ let rightPoints = [tailRight].concat(bodyPoints.slice(count / 2, count))
+ rightPoints.push(neckRight)
+ leftPoints = getQBSplinePoints(leftPoints)
+ rightPoints = getQBSplinePoints(rightPoints)
this.setCoordinates([
- Coordinate.toCoordinates(leftPnts.concat(headPnts, rightPnts.reverse()))
+ Coordinate.toCoordinates(leftPoints.concat(headPoints, rightPoints.reverse()))
])
}
} catch (e) {
@@ -100,33 +100,6 @@ class AttackArrow extends maptalks.Polygon {
return [neckLeft, headLeft, headPnt, headRight, neckRight]
}
- /**
- * 插值面部分数据
- * @param points
- * @param neckLeft
- * @param neckRight
- * @param tailWidthFactor
- * @returns {*|T[]|string}
- */
- _getArrowBodyPoints (points, neckLeft, neckRight, tailWidthFactor) {
- let allLen = wholeDistance(points)
- let len = getBaseLength(points)
- let tailWidth = len * tailWidthFactor
- let neckWidth = MathDistance(neckLeft, neckRight)
- let widthDif = (tailWidth - neckWidth) / 2
- let [tempLen, leftBodyPnts, rightBodyPnts] = [0, [], []]
- for (let i = 1; i < points.length - 1; i++) {
- let angle = getAngleOfThreePoints(points[i - 1], points[i], points[i + 1]) / 2
- tempLen += MathDistance(points[i - 1], points[i])
- let w = (tailWidth / 2 - tempLen / allLen * widthDif) / Math.sin(angle)
- let left = getThirdPoint(points[i - 1], points[i], Math.PI - angle, w, true)
- let right = getThirdPoint(points[i - 1], points[i], angle, w, false)
- leftBodyPnts.push(left)
- rightBodyPnts.push(right)
- }
- return leftBodyPnts.concat(rightBodyPnts)
- }
-
setPoints (coordinates) {
this._coordinates = !coordinates ? [] : coordinates
if (this._coordinates.length >= 1) {
@@ -143,15 +116,46 @@ class AttackArrow extends maptalks.Polygon {
}
_toJSON (options) {
+ const opts = maptalks.Util.extend({}, options)
+ opts.geometry = false
+ const feature = this.toGeoJSON(opts)
return {
- 'feature': this.toGeoJSON(options),
+ 'feature': feature,
+ 'coordinates': feature['coordinates'],
'subType': 'AttackArrow'
}
}
+ /**
+ * 插值面部分数据
+ * @param points
+ * @param neckLeft
+ * @param neckRight
+ * @param tailWidthFactor
+ * @returns {*|T[]|string}
+ */
+ static _getArrowBodyPoints (points, neckLeft, neckRight, tailWidthFactor) {
+ let allLen = wholeDistance(points)
+ let len = getBaseLength(points)
+ let tailWidth = len * tailWidthFactor
+ let neckWidth = MathDistance(neckLeft, neckRight)
+ let widthDif = (tailWidth - neckWidth) / 2
+ let [tempLen, leftBodyPoints, rightBodyPoints] = [0, [], []]
+ for (let i = 1; i < points.length - 1; i++) {
+ let angle = getAngleOfThreePoints(points[i - 1], points[i], points[i + 1]) / 2
+ tempLen += MathDistance(points[i - 1], points[i])
+ let w = (tailWidth / 2 - tempLen / allLen * widthDif) / Math.sin(angle)
+ let left = getThirdPoint(points[i - 1], points[i], Math.PI - angle, w, true)
+ let right = getThirdPoint(points[i - 1], points[i], angle, w, false)
+ leftBodyPoints.push(left)
+ rightBodyPoints.push(right)
+ }
+ return leftBodyPoints.concat(rightBodyPoints)
+ }
+
static fromJSON (json) {
const feature = json['feature']
- const attackArrow = new AttackArrow(json['coordinates'], json['width'], json['height'], json['options'])
+ const attackArrow = new AttackArrow(json['coordinates'], json['options'])
attackArrow.setProperties(feature['properties'])
return attackArrow
}
diff --git a/src/geometry/Arrow/DoubleArrow.js b/src/geometry/Arrow/DoubleArrow.js
new file mode 100644
index 0000000..48ac5bc
--- /dev/null
+++ b/src/geometry/Arrow/DoubleArrow.js
@@ -0,0 +1,247 @@
+/**
+ * Created by FDD on 2017/12/31.
+ * @desc 双箭头
+ * @Inherits maptalks.Polygon
+ */
+
+import * as maptalks from 'maptalks'
+import * as Constants from '../../Constants'
+import {
+ Mid,
+ getThirdPoint,
+ MathDistance,
+ getBaseLength,
+ wholeDistance,
+ isClockWise,
+ getBezierPoints,
+ getAngleOfThreePoints
+} from '../helper/index'
+const Coordinate = maptalks.Coordinate
+
+const _options = {
+ headHeightFactor: 0.25,
+ headWidthFactor: 0.3,
+ neckHeightFactor: 0.85,
+ neckWidthFactor: 0.15
+}
+
+class DoubleArrow extends maptalks.Polygon {
+ constructor (coordinates, options = {}) {
+ super(options)
+ this.type = 'DoubleArrow'
+ this._coordinates = []
+ this.connetPoints = []
+ this.symmetricalPoints = []
+ if (coordinates) {
+ this.setPoints(coordinates)
+ }
+ }
+
+ /**
+ * 处理插值
+ */
+ _generate () {
+ try {
+ const count = this._coordinates.length
+ const _points = Coordinate.toNumberArrays(this._coordinates)
+ if (count < 2) return
+ if (count === 2) {
+ this.setCoordinates([this._coordinates])
+ } else {
+ let [pnt1, pnt2, pnt3] = [_points[0], _points[1], _points[2]]
+ if (count === 3) {
+ this.symmetricalPoints = DoubleArrow.getSymmetricalPoints(pnt1, pnt2, pnt3)
+ this.connetPoints = Mid(pnt1, pnt2)
+ } else if (count === 4) {
+ this.symmetricalPoints = _points[3]
+ this.connetPoints = Mid(pnt1, pnt2)
+ } else {
+ this.symmetricalPoints = _points[3]
+ this.connetPoints = _points[4]
+ }
+ let [leftArrowPoints, rightArrowPoints] = [undefined, undefined]
+ if (isClockWise(pnt1, pnt2, pnt3)) {
+ leftArrowPoints = DoubleArrow.getArrowPoints(pnt1, this.connetPoints, this.symmetricalPoints, false)
+ rightArrowPoints = DoubleArrow.getArrowPoints(this.connetPoints, pnt2, pnt3, true)
+ } else {
+ leftArrowPoints = DoubleArrow.getArrowPoints(pnt2, this.connetPoints, pnt3, false)
+ rightArrowPoints = DoubleArrow.getArrowPoints(this.connetPoints, pnt1, this.symmetricalPoints, true)
+ }
+ let m = leftArrowPoints.length
+ let t = (m - 5) / 2
+ let llBodyPoints = leftArrowPoints.slice(0, t)
+ let lArrowPoints = leftArrowPoints.slice(t, t + 5)
+ let lrBodyPoints = leftArrowPoints.slice(t + 5, m)
+ let rlBodyPoints = rightArrowPoints.slice(0, t)
+ let rArrowPoints = rightArrowPoints.slice(t, t + 5)
+ let rrBodyPoints = rightArrowPoints.slice(t + 5, m)
+ rlBodyPoints = getBezierPoints(rlBodyPoints)
+ let bodyPoints = getBezierPoints(rrBodyPoints.concat(llBodyPoints.slice(1)))
+ lrBodyPoints = getBezierPoints(lrBodyPoints)
+ let Points = rlBodyPoints.concat(rArrowPoints, bodyPoints, lArrowPoints, lrBodyPoints)
+ this.setCoordinates([
+ Coordinate.toCoordinates(Points)
+ ])
+ }
+ } catch (e) {
+ console.log(e)
+ }
+ }
+
+ setPoints (coordinates) {
+ this._coordinates = !coordinates ? [] : coordinates
+ if (this._coordinates.length >= 1) {
+ this._generate()
+ }
+ }
+
+ _exportGeoJSONGeometry () {
+ const coordinates = Coordinate.toNumberArrays([this.getShell()])
+ return {
+ 'type': 'Polygon',
+ 'coordinates': coordinates
+ }
+ }
+
+ _toJSON (options) {
+ const opts = maptalks.Util.extend({}, options)
+ opts.geometry = false
+ const feature = this.toGeoJSON(opts)
+ return {
+ 'feature': feature,
+ 'coordinates': feature['coordinates'],
+ 'subType': 'DoubleArrow'
+ }
+ }
+
+ /**
+ * 插值箭形上的点
+ * @param pnt1
+ * @param pnt2
+ * @param pnt3
+ * @param clockWise
+ * @returns {*[]}
+ */
+ static getArrowPoints (pnt1, pnt2, pnt3, clockWise) {
+ let midPnt = Mid(pnt1, pnt2)
+ let len = MathDistance(midPnt, pnt3)
+ let midPnt1 = getThirdPoint(pnt3, midPnt, 0, len * 0.3, true)
+ let midPnt2 = getThirdPoint(pnt3, midPnt, 0, len * 0.5, true)
+ midPnt1 = getThirdPoint(midPnt, midPnt1, Constants.HALF_PI, len / 5, clockWise)
+ midPnt2 = getThirdPoint(midPnt, midPnt2, Constants.HALF_PI, len / 4, clockWise)
+ let points = [midPnt, midPnt1, midPnt2, pnt3]
+ let arrowPnts = DoubleArrow._getArrowHeadPoints(points)
+ if (arrowPnts && Array.isArray(arrowPnts) && arrowPnts.length > 0) {
+ let [neckLeftPoint, neckRightPoint] = [arrowPnts[0], arrowPnts[4]]
+ let tailWidthFactor = MathDistance(pnt1, pnt2) / getBaseLength(points) / 2
+ let bodyPnts = DoubleArrow._getArrowBodyPoints(points, neckLeftPoint, neckRightPoint, tailWidthFactor)
+ if (bodyPnts) {
+ let n = bodyPnts.length
+ let lPoints = bodyPnts.slice(0, n / 2)
+ let rPoints = bodyPnts.slice(n / 2, n)
+ lPoints.push(neckLeftPoint)
+ rPoints.push(neckRightPoint)
+ lPoints = lPoints.reverse()
+ lPoints.push(pnt2)
+ rPoints = rPoints.reverse()
+ rPoints.push(pnt1)
+ return (lPoints.reverse().concat(arrowPnts, rPoints))
+ }
+ }
+ }
+
+ /**
+ * 插值头部点
+ * @param points
+ * @returns {*[]}
+ */
+ static _getArrowHeadPoints (points) {
+ let len = getBaseLength(points)
+ let headHeight = len * _options.headHeightFactor
+ let headPnt = points[points.length - 1]
+ let headWidth = headHeight * _options.headWidthFactor
+ let neckWidth = headHeight * _options.neckWidthFactor
+ let neckHeight = headHeight * _options.neckHeightFactor
+ let headEndPnt = getThirdPoint(points[points.length - 2], headPnt, 0, headHeight, true)
+ let neckEndPnt = getThirdPoint(points[points.length - 2], headPnt, 0, neckHeight, true)
+ let headLeft = getThirdPoint(headPnt, headEndPnt, Constants.HALF_PI, headWidth, false)
+ let headRight = getThirdPoint(headPnt, headEndPnt, Constants.HALF_PI, headWidth, true)
+ let neckLeft = getThirdPoint(headPnt, neckEndPnt, Constants.HALF_PI, neckWidth, false)
+ let neckRight = getThirdPoint(headPnt, neckEndPnt, Constants.HALF_PI, neckWidth, true)
+ return [neckLeft, headLeft, headPnt, headRight, neckRight]
+ }
+
+ /**
+ * 插值面部分数据
+ * @param points
+ * @param neckLeft
+ * @param neckRight
+ * @param tailWidthFactor
+ * @returns {*|T[]|string}
+ */
+ static _getArrowBodyPoints (points, neckLeft, neckRight, tailWidthFactor) {
+ let allLen = wholeDistance(points)
+ let len = getBaseLength(points)
+ let tailWidth = len * tailWidthFactor
+ let neckWidth = MathDistance(neckLeft, neckRight)
+ let widthDif = (tailWidth - neckWidth) / 2
+ let [tempLen, leftBodyPnts, rightBodyPnts] = [0, [], []]
+ for (let i = 1; i < points.length - 1; i++) {
+ let angle = getAngleOfThreePoints(points[i - 1], points[i], points[i + 1]) / 2
+ tempLen += MathDistance(points[i - 1], points[i])
+ let w = (tailWidth / 2 - tempLen / allLen * widthDif) / Math.sin(angle)
+ let left = getThirdPoint(points[i - 1], points[i], Math.PI - angle, w, true)
+ let right = getThirdPoint(points[i - 1], points[i], angle, w, false)
+ leftBodyPnts.push(left)
+ rightBodyPnts.push(right)
+ }
+ return leftBodyPnts.concat(rightBodyPnts)
+ }
+
+ /**
+ * 获取对称点
+ * @param linePnt1
+ * @param linePnt2
+ * @param point
+ * @returns {undefined}
+ */
+ static getSymmetricalPoints (linePnt1, linePnt2, point) {
+ let midPnt = Mid(linePnt1, linePnt2)
+ let len = MathDistance(midPnt, point)
+ let angle = getAngleOfThreePoints(linePnt1, midPnt, point)
+ let [symPnt, distance1, distance2, mid] = [undefined, undefined, undefined, undefined]
+ if (angle < Constants.HALF_PI) {
+ distance1 = len * Math.sin(angle)
+ distance2 = len * Math.cos(angle)
+ mid = getThirdPoint(linePnt1, midPnt, Constants.HALF_PI, distance1, false)
+ symPnt = getThirdPoint(midPnt, mid, Constants.HALF_PI, distance2, true)
+ } else if (angle >= Constants.HALF_PI && angle < Math.PI) {
+ distance1 = len * Math.sin(Math.PI - angle)
+ distance2 = len * Math.cos(Math.PI - angle)
+ mid = getThirdPoint(linePnt1, midPnt, Constants.HALF_PI, distance1, false)
+ symPnt = getThirdPoint(midPnt, mid, Constants.HALF_PI, distance2, false)
+ } else if (angle >= Math.PI && angle < Math.PI * 1.5) {
+ distance1 = len * Math.sin(angle - Math.PI)
+ distance2 = len * Math.cos(angle - Math.PI)
+ mid = getThirdPoint(linePnt1, midPnt, Constants.HALF_PI, distance1, true)
+ symPnt = getThirdPoint(midPnt, mid, Constants.HALF_PI, distance2, true)
+ } else {
+ distance1 = len * Math.sin(Math.PI * 2 - angle)
+ distance2 = len * Math.cos(Math.PI * 2 - angle)
+ mid = getThirdPoint(linePnt1, midPnt, Constants.HALF_PI, distance1, true)
+ symPnt = getThirdPoint(midPnt, mid, Constants.HALF_PI, distance2, false)
+ }
+ return symPnt
+ }
+
+ static fromJSON (json) {
+ const feature = json['feature']
+ const doubleArrow = new DoubleArrow(json['coordinates'], json['options'])
+ doubleArrow.setProperties(feature['properties'])
+ return doubleArrow
+ }
+}
+
+DoubleArrow.registerJSONType('DoubleArrow')
+
+export default DoubleArrow
diff --git a/src/geometry/Arrow/FineArrow.js b/src/geometry/Arrow/FineArrow.js
new file mode 100644
index 0000000..b2a784c
--- /dev/null
+++ b/src/geometry/Arrow/FineArrow.js
@@ -0,0 +1,97 @@
+/**
+ * Created by FDD on 2017/12/31.
+ * @desc 粗单尖头箭头
+ * @Inherits maptalks.Polygon
+ */
+
+import * as maptalks from 'maptalks'
+import * as Constants from '../../Constants'
+import {
+ getThirdPoint,
+ getBaseLength
+} from '../helper/index'
+const Coordinate = maptalks.Coordinate
+
+const _options = {
+ tailWidthFactor: 0.1,
+ headWidthFactor: 0.25,
+ neckWidthFactor: 0.2,
+ headAngle: Math.PI / 8.5,
+ neckAngle: Math.PI / 13
+}
+
+class FineArrow extends maptalks.Polygon {
+ constructor (coordinates, options = {}) {
+ super(options)
+ this.type = 'FineArrow'
+ this._coordinates = []
+ if (coordinates) {
+ this.setPoints(coordinates)
+ }
+ }
+
+ /**
+ * 处理插值
+ */
+ _generate () {
+ try {
+ const count = this._coordinates.length
+ const _points = Coordinate.toNumberArrays(this._coordinates)
+ if (count < 2) return
+ let [points1, points2] = [_points[0], _points[1]]
+ let len = getBaseLength(_points)
+ let tailWidth = len * _options.tailWidthFactor
+ let neckWidth = len * _options.neckWidthFactor
+ let headWidth = len * _options.headWidthFactor
+ let tailLeft = getThirdPoint(points2, points1, Constants.HALF_PI, tailWidth, true)
+ let tailRight = getThirdPoint(points2, points1, Constants.HALF_PI, tailWidth, false)
+ let headLeft = getThirdPoint(points1, points2, _options.headAngle, headWidth, false)
+ let headRight = getThirdPoint(points1, points2, _options.headAngle, headWidth, true)
+ let neckLeft = getThirdPoint(points1, points2, _options.neckAngle, neckWidth, false)
+ let neckRight = getThirdPoint(points1, points2, _options.neckAngle, neckWidth, true)
+ let pList = [tailLeft, neckLeft, headLeft, points2, headRight, neckRight, tailRight]
+ this.setCoordinates([
+ Coordinate.toCoordinates(pList)
+ ])
+ } catch (e) {
+ console.log(e)
+ }
+ }
+
+ setPoints (coordinates) {
+ this._coordinates = !coordinates ? [] : coordinates
+ if (this._coordinates.length >= 1) {
+ this._generate()
+ }
+ }
+
+ _exportGeoJSONGeometry () {
+ const coordinates = Coordinate.toNumberArrays([this.getShell()])
+ return {
+ 'type': 'Polygon',
+ 'coordinates': coordinates
+ }
+ }
+
+ _toJSON (options) {
+ const opts = maptalks.Util.extend({}, options)
+ opts.geometry = false
+ const feature = this.toGeoJSON(opts)
+ return {
+ 'feature': feature,
+ 'coordinates': feature['coordinates'],
+ 'subType': 'FineArrow'
+ }
+ }
+
+ static fromJSON (json) {
+ const feature = json['feature']
+ const fineArrow = new FineArrow(json['coordinates'], json['options'])
+ fineArrow.setProperties(feature['properties'])
+ return fineArrow
+ }
+}
+
+FineArrow.registerJSONType('FineArrow')
+
+export default FineArrow
diff --git a/src/geometry/Arrow/SquadCombat.js b/src/geometry/Arrow/SquadCombat.js
new file mode 100644
index 0000000..26fd92a
--- /dev/null
+++ b/src/geometry/Arrow/SquadCombat.js
@@ -0,0 +1,91 @@
+/**
+ * Created by FDD on 2017/12/26.
+ * @desc 分队战斗行动
+ * @Inherits AttackArrow
+ */
+
+import AttackArrow from './AttackArrow'
+import * as maptalks from 'maptalks'
+import * as Constants from '../../Constants'
+import {
+ getBaseLength,
+ getThirdPoint,
+ getQBSplinePoints
+} from '../helper/index'
+const Coordinate = maptalks.Coordinate
+
+class SquadCombat extends AttackArrow {
+ constructor (coordinates, options = {}) {
+ super(coordinates, options)
+ this.type = 'SquadCombat'
+ this._coordinates = []
+ this.headHeightFactor = 0.18
+ this.headWidthFactor = 0.3
+ this.neckHeightFactor = 0.85
+ this.neckWidthFactor = 0.15
+ this.tailWidthFactor = 0.1
+ if (coordinates) {
+ this.setPoints(coordinates)
+ }
+ }
+
+ /**
+ * 处理插值
+ */
+ _generate () {
+ try {
+ const count = this._coordinates.length
+ if (count < 2) return
+ if (count === 2) {
+ this.setCoordinates([this._coordinates])
+ } else {
+ let _points = Coordinate.toNumberArrays(this._coordinates)
+ let tailPoints = this.getTailPoints(_points)
+ let headPoints = this._getArrowHeadPoints(_points, tailPoints[0], tailPoints[1])
+ let neckLeft = headPoints[0]
+ let neckRight = headPoints[4]
+ let bodyPoints = AttackArrow._getArrowBodyPoints(_points, neckLeft, neckRight, this.tailWidthFactor)
+ let count = bodyPoints.length
+ let leftPoints = [tailPoints[0]].concat(bodyPoints.slice(0, count / 2))
+ leftPoints.push(neckLeft)
+ let rightPoints = [tailPoints[1]].concat(bodyPoints.slice(count / 2, count))
+ rightPoints.push(neckRight)
+ leftPoints = getQBSplinePoints(leftPoints)
+ rightPoints = getQBSplinePoints(rightPoints)
+ this.setCoordinates(Coordinate.toCoordinates([leftPoints.concat(headPoints, rightPoints.reverse())]))
+ }
+ } catch (e) {
+ console.log(e)
+ }
+ }
+
+ getTailPoints (points) {
+ let allLen = getBaseLength(points)
+ let tailWidth = allLen * this.tailWidthFactor
+ let tailLeft = getThirdPoint(points[1], points[0], Constants.HALF_PI, tailWidth, false)
+ let tailRight = getThirdPoint(points[1], points[0], Constants.HALF_PI, tailWidth, true)
+ return ([tailLeft, tailRight])
+ }
+
+ _toJSON (options) {
+ const opts = maptalks.Util.extend({}, options)
+ opts.geometry = false
+ const feature = this.toGeoJSON(opts)
+ return {
+ 'feature': feature,
+ 'coordinates': feature['coordinates'],
+ 'subType': 'SquadCombat'
+ }
+ }
+
+ static fromJSON (json) {
+ const feature = json['feature']
+ const squadCombat = new SquadCombat(json['coordinates'], json['options'])
+ squadCombat.setProperties(feature['properties'])
+ return squadCombat
+ }
+}
+
+SquadCombat.registerJSONType('SquadCombat')
+
+export default SquadCombat
diff --git a/src/geometry/Arrow/StraightArrow.js b/src/geometry/Arrow/StraightArrow.js
new file mode 100644
index 0000000..7cf865c
--- /dev/null
+++ b/src/geometry/Arrow/StraightArrow.js
@@ -0,0 +1,78 @@
+/**
+ * Created by FDD on 2017/12/31.
+ * @desc 细直箭头
+ * @Inherits maptalks.LineString
+ */
+
+import * as maptalks from 'maptalks'
+import {
+ getThirdPoint,
+ MathDistance
+} from '../helper/index'
+const Coordinate = maptalks.Coordinate
+
+const _options = {
+ 'maxArrowLength': 3000000,
+ 'arrowLengthScale': 5,
+ 'arrowStyle': null,
+ 'arrowPlacement': 'vertex-last', // vertex-first, vertex-last, vertex-firstlast, point
+ 'clipToPaint': true
+}
+
+class StraightArrow extends maptalks.LineString {
+ constructor (coordinates, options = {}) {
+ super(options)
+ this.type = 'StraightArrow'
+ this._coordinates = []
+ if (coordinates) {
+ this.setPoints(coordinates)
+ }
+ }
+
+ /**
+ * 处理插值
+ */
+ _generate () {
+ try {
+ const count = this._coordinates.length
+ const _points = Coordinate.toNumberArrays(this._coordinates)
+ if (count < 2) return
+ let [points1, points2] = [_points[0], _points[1]]
+ let distance = MathDistance(points1, points2)
+ let len = distance / _options.arrowLengthScale
+ len = ((len > _options.maxArrowLength) ? _options.maxArrowLength : len)
+ let leftPnt = getThirdPoint(points1, points2, Math.PI / 6, len, false)
+ let rightPnt = getThirdPoint(points1, points2, Math.PI / 6, len, true)
+ this.setCoordinates(Coordinate.toCoordinates([points1, points2, leftPnt, points2, rightPnt]))
+ } catch (e) {
+ console.log(e)
+ }
+ }
+
+ setPoints (coordinates) {
+ this._coordinates = !coordinates ? [] : coordinates
+ if (this._coordinates.length >= 1) {
+ this._generate()
+ }
+ }
+
+ _exportGeoJSONGeometry () {
+ const points = this.getCoordinates()
+ const coordinates = Coordinate.toNumberArrays(points)
+ return {
+ 'type': 'LineString',
+ 'coordinates': coordinates
+ }
+ }
+
+ _toJSON (options) {
+ return {
+ 'feature': this.toGeoJSON(options)
+ }
+ }
+}
+
+StraightArrow.registerJSONType('StraightArrow')
+StraightArrow.mergeOptions(_options)
+
+export default StraightArrow
diff --git a/src/geometry/Arrow/TailedAttackArrow.js b/src/geometry/Arrow/TailedAttackArrow.js
new file mode 100644
index 0000000..09455cf
--- /dev/null
+++ b/src/geometry/Arrow/TailedAttackArrow.js
@@ -0,0 +1,98 @@
+/**
+ * Created by FDD on 2017/12/31.
+ * @desc 进攻方向(尾)
+ * @Inherits AttackArrow
+ */
+
+import AttackArrow from './AttackArrow'
+import * as maptalks from 'maptalks'
+import {
+ isClockWise,
+ getBaseLength,
+ getThirdPoint,
+ getQBSplinePoints,
+ MathDistance,
+ Mid
+} from '../helper/index'
+const Coordinate = maptalks.Coordinate
+
+class TailedAttackArrow extends AttackArrow {
+ constructor (coordinates, options = {}) {
+ super(coordinates, options)
+ this.type = 'TailedAttackArrow'
+ this._coordinates = []
+ this.headHeightFactor = 0.18
+ this.headWidthFactor = 0.3
+ this.neckHeightFactor = 0.85
+ this.neckWidthFactor = 0.15
+ this.tailWidthFactor = 0.1
+ this.headTailFactor = 0.8
+ this.swallowTailFactor = 1
+ this.swallowTailPnt = null
+ if (coordinates) {
+ this.setPoints(coordinates)
+ }
+ }
+
+ /**
+ * 处理插值
+ */
+ _generate () {
+ try {
+ const count = this._coordinates.length
+ if (count < 2) return
+ if (count === 2) {
+ this.setCoordinates([this._coordinates])
+ } else {
+ let _points = Coordinate.toNumberArrays(this._coordinates)
+ let [tailLeft, tailRight] = [_points[0], _points[1]]
+ if (isClockWise(_points[0], _points[1], _points[2])) {
+ tailLeft = _points[1]
+ tailRight = _points[0]
+ }
+ let midTail = Mid(tailLeft, tailRight)
+ let bonePoints = [midTail].concat(_points.slice(2))
+ let headPoints = this._getArrowHeadPoints(bonePoints, tailLeft, tailRight)
+ let [neckLeft, neckRight] = [headPoints[0], headPoints[4]]
+ let tailWidth = MathDistance(tailLeft, tailRight)
+ let allLen = getBaseLength(bonePoints)
+ let len = allLen * this.tailWidthFactor * this.swallowTailFactor
+ this.swallowTailPnt = getThirdPoint(bonePoints[1], bonePoints[0], 0, len, true)
+ let factor = tailWidth / allLen
+ let bodyPoints = AttackArrow._getArrowBodyPoints(bonePoints, neckLeft, neckRight, factor)
+ let count = bodyPoints.length
+ let leftPoints = [tailLeft].concat(bodyPoints.slice(0, count / 2))
+ leftPoints.push(neckLeft)
+ let rightPoints = [tailRight].concat(bodyPoints.slice(count / 2, count))
+ rightPoints.push(neckRight)
+ leftPoints = getQBSplinePoints(leftPoints)
+ rightPoints = getQBSplinePoints(rightPoints)
+ this.setCoordinates(Coordinate.toCoordinates([leftPoints.concat(headPoints, rightPoints.reverse(), [this.swallowTailPnt, leftPoints[0]])]))
+ }
+ } catch (e) {
+ console.log(e)
+ }
+ }
+
+ _toJSON (options) {
+ const opts = maptalks.Util.extend({}, options)
+ opts.geometry = false
+ const feature = this.toGeoJSON(opts)
+ return {
+ 'feature': feature,
+ 'coordinates': feature['coordinates'],
+ 'subType': 'TailedAttackArrow'
+ }
+ }
+
+ static fromJSON (json) {
+ const feature = json['feature']
+ const _geometry = new TailedAttackArrow(json['coordinates'], json['options'])
+ _geometry.setProperties(feature['properties'])
+ return _geometry
+ }
+}
+
+TailedAttackArrow.registerJSONType('TailedAttackArrow')
+
+export default TailedAttackArrow
diff --git a/src/geometry/Arrow/TailedSquadCombat.js b/src/geometry/Arrow/TailedSquadCombat.js
new file mode 100644
index 0000000..15e28c6
--- /dev/null
+++ b/src/geometry/Arrow/TailedSquadCombat.js
@@ -0,0 +1,91 @@
+/**
+ * Created by FDD on 2017/12/31.
+ * @desc 燕尾直箭头
+ * @Inherits AttackArrow
+ */
+
+import AttackArrow from './AttackArrow'
+import * as maptalks from 'maptalks'
+import * as Constants from '../../Constants'
+import {
+ getBaseLength,
+ getThirdPoint,
+ getQBSplinePoints
+} from '../helper/index'
+const Coordinate = maptalks.Coordinate
+
+class TailedSquadCombat extends AttackArrow {
+ constructor (coordinates, options = {}) {
+ super(coordinates, options)
+ this.type = 'TailedSquadCombat'
+ this._coordinates = []
+ this.headHeightFactor = 0.18
+ this.headWidthFactor = 0.3
+ this.neckHeightFactor = 0.85
+ this.neckWidthFactor = 0.15
+ this.tailWidthFactor = 0.1
+ this.swallowTailFactor = 1
+ this.swallowTailPnt = null
+ if (coordinates) {
+ this.setPoints(coordinates)
+ }
+ }
+
+ /**
+ * 处理插值
+ */
+ _generate () {
+ try {
+ const count = this._coordinates.length
+ const _points = Coordinate.toNumberArrays(this._coordinates)
+ if (count < 2) return
+ let tailPoints = this.getTailPoints(_points)
+ let headPoints = this._getArrowHeadPoints(_points, tailPoints[0], tailPoints[2])
+ let neckLeft = headPoints[0]
+ let neckRight = headPoints[4]
+ let bodyPoints = AttackArrow._getArrowBodyPoints(_points, neckLeft, neckRight, this.tailWidthFactor)
+ let _count = bodyPoints.length
+ let leftPoints = [tailPoints[0]].concat(bodyPoints.slice(0, _count / 2))
+ leftPoints.push(neckLeft)
+ let rightPoints = [tailPoints[2]].concat(bodyPoints.slice(_count / 2, _count))
+ rightPoints.push(neckRight)
+ leftPoints = getQBSplinePoints(leftPoints)
+ rightPoints = getQBSplinePoints(rightPoints)
+ this.setCoordinates(Coordinate.toCoordinates([leftPoints.concat(headPoints, rightPoints.reverse(), [tailPoints[1], leftPoints[0]])]))
+ } catch (e) {
+ console.warn(e)
+ }
+ }
+
+ getTailPoints (points) {
+ let allLen = getBaseLength(points)
+ let tailWidth = allLen * this.tailWidthFactor
+ let tailLeft = getThirdPoint(points[1], points[0], Constants.HALF_PI, tailWidth, false)
+ let tailRight = getThirdPoint(points[1], points[0], Constants.HALF_PI, tailWidth, true)
+ let len = tailWidth * this.swallowTailFactor
+ let swallowTailPnt = getThirdPoint(points[1], points[0], 0, len, true)
+ return ([tailLeft, swallowTailPnt, tailRight])
+ }
+
+ _toJSON (options) {
+ const opts = maptalks.Util.extend({}, options)
+ opts.geometry = false
+ const feature = this.toGeoJSON(opts)
+ return {
+ 'feature': feature,
+ 'coordinates': feature['coordinates'],
+ 'subType': 'TailedSquadCombat'
+ }
+ }
+
+ static fromJSON (json) {
+ const feature = json['feature']
+ const _geometry = new TailedSquadCombat(json['coordinates'], json['options'])
+ _geometry.setProperties(feature['properties'])
+ return _geometry
+ }
+}
+
+TailedSquadCombat.registerJSONType('TailedSquadCombat')
+
+export default TailedSquadCombat
diff --git a/src/geometry/Circle/Circle.js b/src/geometry/Circle/Circle.js
new file mode 100644
index 0000000..a6a4a1b
--- /dev/null
+++ b/src/geometry/Circle/Circle.js
@@ -0,0 +1,53 @@
+/**
+ * Created by FDD on 2017/12/28.
+ * @desc 标绘画圆算法
+ * @Inherits maptalks.Circle
+ */
+
+import * as maptalks from 'maptalks'
+const Coordinate = maptalks.Coordinate
+class PlotCircle extends maptalks.Circle {
+ constructor (coordinate, radius, options = {}) {
+ super(null, options)
+ this.type = 'Circle'
+ if (coordinate) {
+ this.setCoordinates(coordinate)
+ }
+ this._radius = radius
+ }
+
+ _exportGeoJSONGeometry () {
+ const coordinates = Coordinate.toNumberArrays([this.getShell()])
+ return {
+ 'type': 'Polygon',
+ 'coordinates': coordinates
+ }
+ }
+
+ _toJSON (options) {
+ const center = this.getCenter()
+ const opts = maptalks.Util.extend({}, options)
+ opts.geometry = false
+ const feature = this.toGeoJSON(opts)
+ feature['geometry'] = {
+ 'type': 'Polygon'
+ }
+ return {
+ 'feature': feature,
+ 'subType': 'PlotCircle',
+ 'coordinates': [center.x, center.y],
+ 'radius': this.getRadius()
+ }
+ }
+
+ static fromJSON (json) {
+ const GeoJSON = json['feature']
+ const feature = new PlotCircle(json['coordinates'], json['radius'], json['options'])
+ feature.setProperties(GeoJSON['properties'])
+ return feature
+ }
+}
+
+PlotCircle.registerJSONType('PlotCircle')
+
+export default PlotCircle
diff --git a/src/geometry/Circle/Ellipse.js b/src/geometry/Circle/Ellipse.js
new file mode 100644
index 0000000..d5a33a3
--- /dev/null
+++ b/src/geometry/Circle/Ellipse.js
@@ -0,0 +1,47 @@
+/**
+ * Created by FDD on 2017/12/31.
+ * @desc 标绘椭圆算法
+ * @Inherits maptalks.Ellipse
+ */
+
+import * as maptalks from 'maptalks'
+
+class PlotEllipse extends maptalks.Ellipse {
+ constructor (coordinates, width, height, options = {}) {
+ super(null, options)
+ this.type = 'Ellipse'
+ if (coordinates) {
+ this.setCoordinates(coordinates)
+ }
+ this.width = width
+ this.height = height
+ }
+
+ _toJSON (options) {
+ const opts = maptalks.Util.extend({}, options)
+ const center = this.getCenter()
+ opts.geometry = false
+ const feature = this.toGeoJSON(opts)
+ feature['geometry'] = {
+ 'type': 'Polygon'
+ }
+ return {
+ 'feature': feature,
+ 'subType': 'PlotEllipse',
+ 'coordinates': [center.x, center.y],
+ 'width': this.getWidth(),
+ 'height': this.getHeight()
+ }
+ }
+
+ static fromJSON (json) {
+ const GeoJSON = json['feature']
+ const feature = new PlotEllipse(json['coordinates'], json['width'], json['height'], json['options'])
+ feature.setProperties(GeoJSON['properties'])
+ return feature
+ }
+}
+
+PlotEllipse.registerJSONType('PlotEllipse')
+
+export default PlotEllipse
diff --git a/src/geometry/Flag/CurveFlag.js b/src/geometry/Flag/CurveFlag.js
new file mode 100644
index 0000000..94a0e69
--- /dev/null
+++ b/src/geometry/Flag/CurveFlag.js
@@ -0,0 +1,116 @@
+/**
+ * Created by FDD on 2017/12/26.
+ * @desc 曲线旗标
+ * @Inherits maptalks.Polygon
+ */
+
+import * as maptalks from 'maptalks'
+import {
+ getBezierPoints
+} from '../helper/index'
+const Coordinate = maptalks.Coordinate
+class CurveFlag extends maptalks.Polygon {
+ constructor (coordinates, options = {}) {
+ super(options)
+ this.type = 'CurveFlag'
+ this._coordinates = []
+ if (coordinates) {
+ this.setPoints(coordinates)
+ }
+ }
+
+ /**
+ * handle coordinates
+ * @private
+ */
+ _generate () {
+ const count = this._coordinates.length
+ let _points = Coordinate.toNumberArrays(this._coordinates)
+ if (count < 2) return
+ this.setCoordinates([
+ Coordinate.toCoordinates(CurveFlag.calculatePoints(_points))
+ ])
+ }
+
+ /**
+ * set point
+ * @param coordinates
+ */
+ setPoints (coordinates) {
+ this._coordinates = !coordinates ? [] : coordinates
+ if (this._coordinates.length >= 1) {
+ this._generate()
+ }
+ }
+
+ _exportGeoJSONGeometry () {
+ const coordinates = Coordinate.toNumberArrays([this.getShell()])
+ return {
+ 'type': 'Polygon',
+ 'coordinates': coordinates
+ }
+ }
+
+ _toJSON (options) {
+ return {
+ 'feature': this.toGeoJSON(options),
+ 'subType': 'CurveFlag'
+ }
+ }
+ /**
+ * 插值点数据
+ * @param points
+ * @returns {Array}
+ */
+ static calculatePoints (points) {
+ let components = []
+ // 至少需要两个控制点
+ if (points.length > 1) {
+ // 取第一个
+ let startPoint = points[0]
+ // 取最后一个
+ let endPoint = points[points.length - 1]
+ // 上曲线起始点
+ let point1 = startPoint
+ // 上曲线第一控制点
+ let point2 = [(endPoint[0] - startPoint[0]) / 4 + startPoint[0], (endPoint[1] - startPoint[1]) / 8 + startPoint[1]]
+ // 上曲线第二个点
+ let point3 = [(startPoint[0] + endPoint[0]) / 2, startPoint[1]]
+ // 上曲线第二控制点
+ let point4 = [(endPoint[0] - startPoint[0]) * 3 / 4 + startPoint[0], -(endPoint[1] - startPoint[1]) / 8 + startPoint[1]]
+ // 上曲线结束点
+ let point5 = [endPoint[0], startPoint[1]]
+ // 下曲线结束点
+ let point6 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+ // 下曲线第二控制点
+ let point7 = [(endPoint[0] - startPoint[0]) * 3 / 4 + startPoint[0], (endPoint[1] - startPoint[1]) * 3 / 8 + startPoint[1]]
+ // 下曲线第二个点
+ let point8 = [(startPoint[0] + endPoint[0]) / 2, (startPoint[1] + endPoint[1]) / 2]
+ // 下曲线第一控制点
+ let point9 = [(endPoint[0] - startPoint[0]) / 4 + startPoint[0], (endPoint[1] - startPoint[1]) * 5 / 8 + startPoint[1]]
+ // 下曲线起始点
+ let point10 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+ // 旗杆底部点
+ let point11 = [startPoint[0], endPoint[1]]
+ // 计算上曲线
+ let curve1 = getBezierPoints([point1, point2, point3, point4, point5])
+ // 计算下曲线
+ let curve2 = getBezierPoints([point6, point7, point8, point9, point10])
+ // 合并
+ components = curve1.concat(curve2)
+ components.push(point11)
+ }
+ return components
+ }
+
+ static fromJSON (json) {
+ const feature = json['feature']
+ const attackArrow = new CurveFlag(json['coordinates'], json['width'], json['height'], json['options'])
+ attackArrow.setProperties(feature['properties'])
+ return attackArrow
+ }
+}
+
+CurveFlag.registerJSONType('CurveFlag')
+
+export default CurveFlag
diff --git a/src/geometry/Flag/RectFlag.js b/src/geometry/Flag/RectFlag.js
new file mode 100644
index 0000000..ab88d72
--- /dev/null
+++ b/src/geometry/Flag/RectFlag.js
@@ -0,0 +1,89 @@
+/**
+ * Created by FDD on 2017/12/26.
+ * @desc 直角旗标(使用两个控制点直接创建直角旗标)
+ * @Inherits maptalks.Polygon
+ */
+
+import * as maptalks from 'maptalks'
+const Coordinate = maptalks.Coordinate
+class RectFlag extends maptalks.Polygon {
+ constructor (coordinates, options = {}) {
+ super(options)
+ this.type = 'RectFlag'
+ this._coordinates = []
+ if (coordinates) {
+ this.setPoints(coordinates)
+ }
+ }
+
+ /**
+ * handle coordinates
+ * @private
+ */
+ _generate () {
+ const count = this._coordinates.length
+ let _points = Coordinate.toNumberArrays(this._coordinates)
+ if (count < 2) return
+ this.setCoordinates([
+ Coordinate.toCoordinates(RectFlag.calculatePoints(_points))
+ ])
+ }
+
+ /**
+ * set point
+ * @param coordinates
+ */
+ setPoints (coordinates) {
+ this._coordinates = !coordinates ? [] : coordinates
+ if (this._coordinates.length >= 1) {
+ this._generate()
+ }
+ }
+
+ _exportGeoJSONGeometry () {
+ const coordinates = Coordinate.toNumberArrays([this.getShell()])
+ return {
+ 'type': 'Polygon',
+ 'coordinates': coordinates
+ }
+ }
+
+ _toJSON (options) {
+ return {
+ 'feature': this.toGeoJSON(options),
+ 'subType': 'RectFlag'
+ }
+ }
+ /**
+ * 插值点数据
+ * @param points
+ * @returns {Array}
+ */
+ static calculatePoints (points) {
+ let components = []
+ // 至少需要两个控制点
+ if (points.length > 1) {
+ // 取第一个
+ let startPoint = points[0]
+ // 取最后一个
+ let endPoint = points[points.length - 1]
+ let point1 = [endPoint[0], startPoint[1]]
+ let point2 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+ let point3 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+ let point4 = [startPoint[0], endPoint[1]]
+ components = [startPoint, point1, point2, point3, point4]
+ }
+ return components
+ }
+
+ static fromJSON (json) {
+ const feature = json['feature']
+ const rectFlag = new RectFlag(json['coordinates'], json['width'], json['height'], json['options'])
+ rectFlag.setProperties(feature['properties'])
+ return rectFlag
+ }
+}
+
+RectFlag.registerJSONType('RectFlag')
+
+export default RectFlag
diff --git a/src/geometry/Flag/TriangleFlag.js b/src/geometry/Flag/TriangleFlag.js
new file mode 100644
index 0000000..1c78a36
--- /dev/null
+++ b/src/geometry/Flag/TriangleFlag.js
@@ -0,0 +1,88 @@
+/**
+ * Created by FDD on 2017/12/26.
+ * @desc 曲线旗标
+ * @Inherits maptalks.Polygon
+ */
+
+import * as maptalks from 'maptalks'
+const Coordinate = maptalks.Coordinate
+class TriangleFlag extends maptalks.Polygon {
+ constructor (coordinates, options = {}) {
+ super(options)
+ this.type = 'TriangleFlag'
+ this._coordinates = []
+ if (coordinates) {
+ this.setPoints(coordinates)
+ }
+ }
+
+ /**
+ * handle coordinates
+ * @private
+ */
+ _generate () {
+ const count = this._coordinates.length
+ let _points = Coordinate.toNumberArrays(this._coordinates)
+ if (count < 2) return
+ this.setCoordinates([
+ Coordinate.toCoordinates(TriangleFlag.calculatePoints(_points))
+ ])
+ }
+
+ /**
+ * set point
+ * @param coordinates
+ */
+ setPoints (coordinates) {
+ this._coordinates = !coordinates ? [] : coordinates
+ if (this._coordinates.length >= 1) {
+ this._generate()
+ }
+ }
+
+ _exportGeoJSONGeometry () {
+ const coordinates = Coordinate.toNumberArrays([this.getShell()])
+ return {
+ 'type': 'Polygon',
+ 'coordinates': coordinates
+ }
+ }
+
+ _toJSON (options) {
+ return {
+ 'feature': this.toGeoJSON(options),
+ 'subType': 'TriangleFlag'
+ }
+ }
+ /**
+ * 插值点数据
+ * @param points
+ * @returns {Array}
+ */
+ static calculatePoints (points) {
+ let components = []
+ // 至少需要两个控制点
+ if (points.length > 1) {
+ // 取第一个
+ let startPoint = points[0]
+ // 取最后一个
+ let endPoint = points[points.length - 1]
+ let point1 = [endPoint[0], (startPoint[1] + endPoint[1]) / 2]
+ let point2 = [startPoint[0], (startPoint[1] + endPoint[1]) / 2]
+ let point3 = [startPoint[0], endPoint[1]]
+ components = [startPoint, point1, point2, point3]
+ }
+ return components
+ }
+
+ static fromJSON (json) {
+ const feature = json['feature']
+ const triangleFlag = new TriangleFlag(json['coordinates'], json['width'], json['height'], json['options'])
+ triangleFlag.setProperties(feature['properties'])
+ return triangleFlag
+ }
+}
+
+TriangleFlag.registerJSONType('TriangleFlag')
+
+export default TriangleFlag
diff --git a/src/geometry/Polygon/RectAngle.js b/src/geometry/Polygon/RectAngle.js
index 1ac37cb..ddc68ed 100644
--- a/src/geometry/Polygon/RectAngle.js
+++ b/src/geometry/Polygon/RectAngle.js
@@ -6,25 +6,11 @@
import * as maptalks from 'maptalks'
const Coordinate = maptalks.Coordinate
-maptalks.Polygon.getCoordinateFromExtent = function (extent) {
- let [minX, minY, maxX, maxY] = [extent[0], extent[1], extent[2], extent[3]]
- return [minX, minY, minX, maxY, maxX, maxY, maxX, minY, minX, minY]
-}
-
-const boundingExtent = function (coordinates) {
- let extent = new maptalks.Extent()
- for (let i = 0, ii = coordinates.length; i < ii; ++i) {
- extent.add(extent, coordinates[i])
- }
- return extent
-}
-
class RectAngle extends maptalks.Polygon {
constructor (coordinates, options = {}) {
super(options)
this.type = 'RectAngle'
this._coordinates = []
- this.isFill = ((options['isFill'] === false) ? options['isFill'] : true)
if (coordinates) {
this.setPoints(coordinates)
}
@@ -39,18 +25,10 @@ class RectAngle extends maptalks.Polygon {
let _points = Coordinate.toNumberArrays(this._coordinates)
if (count < 2) return
if (count === 2) {
- let coordinates = []
- if (this.isFill) {
- let extent = boundingExtent(this._coordinates)
- coordinates = maptalks.Polygon.getCoordinateFromExtent(extent)
- } else {
- let start = _points[0]
- let end = _points[1]
- coordinates = [start, [start[0], end[1]], end, [end[0], start[1]], start]
- }
- this.setCoordinates([
- Coordinate.toCoordinates(coordinates)
- ])
+ let start = _points[0]
+ let end = _points[1]
+ let coordinates = [start, [start[0], end[1]], end, [end[0], start[1]], start]
+ this.setCoordinates(Coordinate.toCoordinates(coordinates))
}
}
@@ -78,9 +56,9 @@ class RectAngle extends maptalks.Polygon {
static fromJSON (json) {
const feature = json['feature']
- const attackArrow = new RectAngle(json['coordinates'], json['width'], json['height'], json['options'])
- attackArrow.setProperties(feature['properties'])
- return attackArrow
+ const reactAngle = new RectAngle(json['coordinates'], json['options'])
+ reactAngle.setProperties(feature['properties'])
+ return reactAngle
}
}
diff --git a/src/geometry/Polyline/Arc.js b/src/geometry/Polyline/Arc.js
index 2987f4f..e7526a1 100644
--- a/src/geometry/Polyline/Arc.js
+++ b/src/geometry/Polyline/Arc.js
@@ -65,6 +65,7 @@ class Arc extends maptalks.LineString {
const coordinates = Coordinate.toNumberArrays(points)
return {
'type': 'LineString',
+ 'subType': 'Arc',
'coordinates': coordinates
}
}
diff --git a/src/geometry/index.js b/src/geometry/index.js
index d26ad58..3fef843 100644
--- a/src/geometry/index.js
+++ b/src/geometry/index.js
@@ -9,7 +9,20 @@ import Curve from './Polyline/Curve'
import Polyline from './Polyline/Polyline'
import FreeLine from './Polyline/FreeLine'
+import PlotCircle from './Circle/Circle'
+import PlotEllipse from './Circle/Ellipse'
import AttackArrow from './Arrow/AttackArrow'
+import DoubleArrow from './Arrow/DoubleArrow'
+import FineArrow from './Arrow/FineArrow'
+import StraightArrow from './Arrow/StraightArrow'
+import AssaultDirection from './Arrow/AssaultDirection'
+import SquadCombat from './Arrow/SquadCombat'
+import TailedAttackArrow from './Arrow/TailedAttackArrow'
+import TailedSquadCombat from './Arrow/TailedSquadCombat'
+
+import CurveFlag from './Flag/CurveFlag'
+import RectFlag from './Flag/RectFlag'
+import TriangleFlag from './Flag/TriangleFlag'
import Lune from './Polygon/Lune'
import Sector from './Polygon/Sector'
@@ -20,7 +33,21 @@ import GatheringPlace from './Polygon/GatheringPlace'
import * as PlotTypes from '../core/PlotTypes'
const Polygon = maptalks.Polygon
+const Coordinate = maptalks.Coordinate
const RegisterModes = {}
+RegisterModes[PlotTypes.POINT] = {
+ 'freehand': false,
+ 'limitClickCount': 1,
+ 'action': ['click'],
+ 'create': function (path) {
+ return new maptalks.Marker(path[0])
+ },
+ 'update': function (path, geometry) {
+ },
+ 'generate': function (geometry) {
+ return geometry
+ }
+}
RegisterModes[PlotTypes.ARC] = {
'freehand': false,
'limitClickCount': 3,
@@ -83,12 +110,118 @@ RegisterModes[PlotTypes.ATTACK_ARROW] = {
'update': function (path, geometry) {
geometry.setPoints(path)
},
+ 'generate': function (geometry) {
+ return geometry
+ }
+}
+RegisterModes[PlotTypes.DOUBLE_ARROW] = {
+ 'freehand': false,
+ 'limitClickCount': 4,
+ 'action': ['click', 'mousemove', 'dblclick'],
+ 'create': function (path) {
+ return new DoubleArrow(path)
+ },
+ 'update': function (path, geometry) {
+ geometry.setPoints(path)
+ },
'generate': function (geometry) {
return new Polygon(geometry.getCoordinates(), {
'symbol': geometry.getSymbol()
})
}
}
+RegisterModes[PlotTypes.FINE_ARROW] = {
+ 'freehand': false,
+ 'limitClickCount': 2,
+ 'action': ['click', 'mousemove', 'click'],
+ 'create': function (path) {
+ return new FineArrow(path)
+ },
+ 'update': function (path, geometry) {
+ geometry.setPoints(path)
+ },
+ 'generate': function (geometry) {
+ return new Polygon(geometry.getCoordinates(), {
+ 'symbol': geometry.getSymbol()
+ })
+ }
+}
+RegisterModes[PlotTypes.ASSAULT_DIRECTION] = {
+ 'freehand': false,
+ 'limitClickCount': 2,
+ 'action': ['click', 'mousemove', 'click'],
+ 'create': function (path) {
+ return new AssaultDirection(path)
+ },
+ 'update': function (path, geometry) {
+ geometry.setPoints(path)
+ },
+ 'generate': function (geometry) {
+ return new Polygon(geometry.getCoordinates(), {
+ 'symbol': geometry.getSymbol()
+ })
+ }
+}
+RegisterModes[PlotTypes.SQUAD_COMBAT] = {
+ 'freehand': false,
+ 'action': ['click', 'mousemove', 'dblclick'],
+ 'create': function (path) {
+ return new SquadCombat(path)
+ },
+ 'update': function (path, geometry) {
+ geometry.setPoints(path)
+ },
+ 'generate': function (geometry) {
+ return new Polygon(geometry.getCoordinates(), {
+ 'symbol': geometry.getSymbol()
+ })
+ }
+}
+RegisterModes[PlotTypes.TAILED_ATTACK_ARROW] = {
+ 'freehand': false,
+ 'action': ['click', 'mousemove', 'dblclick'],
+ 'create': function (path) {
+ return new TailedAttackArrow(path)
+ },
+ 'update': function (path, geometry) {
+ geometry.setPoints(path)
+ },
+ 'generate': function (geometry) {
+ return new Polygon(geometry.getCoordinates(), {
+ 'symbol': geometry.getSymbol()
+ })
+ }
+}
+RegisterModes[PlotTypes.TAILED_SQUAD_COMBAT] = {
+ 'freehand': false,
+ 'limitClickCount': 2,
+ 'action': ['click', 'mousemove', 'dblclick'],
+ 'create': function (path) {
+ return new TailedSquadCombat(path)
+ },
+ 'update': function (path, geometry) {
+ geometry.setPoints(path)
+ },
+ 'generate': function (geometry) {
+ return new Polygon(geometry.getCoordinates(), {
+ 'symbol': geometry.getSymbol()
+ })
+ }
+}
+RegisterModes[PlotTypes.STRAIGHT_ARROW] = {
+ 'freehand': false,
+ 'limitClickCount': 2,
+ 'action': ['click', 'mousemove', 'click'],
+ 'create': function (path) {
+ return new StraightArrow(path)
+ },
+ 'update': function (path, geometry) {
+ geometry.setPoints(path)
+ },
+ 'generate': function (geometry) {
+ return geometry
+ }
+}
RegisterModes[PlotTypes.CLOSED_CURVE] = {
'freehand': false,
'action': ['click', 'mousemove', 'dblclick'],
@@ -159,7 +292,7 @@ RegisterModes[PlotTypes.RECTANGLE] = {
return new RectAngle(path)
},
'update': function (path, geometry) {
- geometry.setCoordinates(path)
+ geometry.setPoints(path)
},
'generate': function (geometry) {
return new Polygon(geometry.getCoordinates(), {
@@ -198,5 +331,92 @@ RegisterModes[PlotTypes.GATHERING_PLACE] = {
})
}
}
+RegisterModes[PlotTypes.CURVEFLAG] = {
+ 'freehand': false,
+ 'limitClickCount': 2,
+ 'action': ['click', 'mousemove', 'click'],
+ 'create': function (path) {
+ return new CurveFlag(path)
+ },
+ 'update': function (path, geometry) {
+ geometry.setPoints(path)
+ },
+ 'generate': function (geometry) {
+ return new Polygon(geometry.getCoordinates(), {
+ 'symbol': geometry.getSymbol()
+ })
+ }
+}
+RegisterModes[PlotTypes.RECTFLAG] = {
+ 'freehand': false,
+ 'limitClickCount': 2,
+ 'action': ['click', 'mousemove', 'click'],
+ 'create': function (path) {
+ return new RectFlag(path)
+ },
+ 'update': function (path, geometry) {
+ geometry.setPoints(path)
+ },
+ 'generate': function (geometry) {
+ return new Polygon(geometry.getCoordinates(), {
+ 'symbol': geometry.getSymbol()
+ })
+ }
+}
+RegisterModes[PlotTypes.TRIANGLEFLAG] = {
+ 'freehand': false,
+ 'limitClickCount': 2,
+ 'action': ['click', 'mousemove', 'click'],
+ 'create': function (path) {
+ return new TriangleFlag(path)
+ },
+ 'update': function (path, geometry) {
+ geometry.setPoints(path)
+ },
+ 'generate': function (geometry) {
+ return new Polygon(geometry.getCoordinates(), {
+ 'symbol': geometry.getSymbol()
+ })
+ }
+}
+RegisterModes[PlotTypes.CIRCLE] = {
+ 'freehand': true,
+ 'action': ['mousedown', 'drag', 'mouseup'],
+ 'create': function (coordinate) {
+ return new PlotCircle(coordinate[0], 0)
+ },
+ 'update': function (path, geometry) {
+ const map = geometry.getMap()
+ const radius = map.computeLength(geometry.getCenter(), path[path.length - 1])
+ geometry.setRadius(radius)
+ },
+ 'generate': function (geometry) {
+ return geometry
+ }
+}
+RegisterModes[PlotTypes.ELLIPSE] = {
+ 'freehand': true,
+ 'action': ['mousedown', 'drag', 'mouseup'],
+ 'create': function (coordinate) {
+ return new PlotEllipse(coordinate[0], 0, 0)
+ },
+ 'update': function (path, geometry) {
+ const map = geometry.getMap()
+ const center = geometry.getCenter()
+ const rx = map.computeLength(center, new Coordinate({
+ x: path[path.length - 1].x,
+ y: center.y
+ }))
+ const ry = map.computeLength(center, new Coordinate({
+ x: center.x,
+ y: path[path.length - 1].y
+ }))
+ geometry.setWidth(rx * 2)
+ geometry.setHeight(ry * 2)
+ },
+ 'generate': function (geometry) {
+ return geometry
+ }
+}
export default RegisterModes