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