From b0a3bd95114f2099fcd0b319b55a7b89cb1a277c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=B8=E5=B2=B3?= Date: Wed, 11 Dec 2019 18:26:45 +0800 Subject: [PATCH] feat(g-canvas & g-svg): add getTotalLength and getPoint method for Line, ref #295 --- docs/api/shape/line.en.md | 19 ++++++++++++ docs/api/shape/line.zh.md | 19 ++++++++++++ examples/animation/onFrame/demo/along-line.js | 30 +++++++++++++++++++ examples/animation/onFrame/demo/meta.json | 10 ++++++- packages/g-canvas/src/shape/line.ts | 22 ++++++++++++-- packages/g-canvas/src/shape/path.ts | 2 +- .../g-canvas/tests/unit/shape/line-spec.js | 19 ++++++++++++ .../g-canvas/tests/unit/shape/path-spec.js | 2 +- packages/g-svg/package.json | 1 + packages/g-svg/src/shape/line.ts | 21 ++++++++++++- packages/g-svg/src/shape/path.ts | 4 +-- packages/g-svg/tests/unit/shape/line-spec.js | 19 ++++++++++++ packages/g-svg/tests/unit/shape/path-spec.js | 2 +- 13 files changed, 161 insertions(+), 9 deletions(-) create mode 100644 examples/animation/onFrame/demo/along-line.js diff --git a/docs/api/shape/line.en.md b/docs/api/shape/line.en.md index 2156e9457..f218aa70b 100644 --- a/docs/api/shape/line.en.md +++ b/docs/api/shape/line.en.md @@ -26,3 +26,22 @@ order: 9 ### y2 - 结束点的 y 坐标; + +## Method + +### General [shape methods](/en/docs/api/shape#方法) + +### getTotalLength(): number + +- Get total length of path; + +### getPoint(ratio: number): Point + +- Get point according to ratio and the type of Point is shown below: + +```ts +export type Point = { + x: number; + y: number; +}; +``` diff --git a/docs/api/shape/line.zh.md b/docs/api/shape/line.zh.md index c14dd978f..60df48450 100644 --- a/docs/api/shape/line.zh.md +++ b/docs/api/shape/line.zh.md @@ -26,3 +26,22 @@ order: 9 ### y2 - 结束点的 y 坐标; + +## 方法 + +### 通用的 [图形方法](/zh/docs/api/shape#方法) + +### getTotalLength(): number + +- 获取路径长度; + +### getPoint(ratio: number): Point + +- 根据长度比例获取点,其中 `Point` 的格式为: + +```ts +export type Point = { + x: number; + y: number; +}; +``` diff --git a/examples/animation/onFrame/demo/along-line.js b/examples/animation/onFrame/demo/along-line.js new file mode 100644 index 000000000..dd223010c --- /dev/null +++ b/examples/animation/onFrame/demo/along-line.js @@ -0,0 +1,30 @@ +const canvas = new G.Canvas({ + container: 'container', + width: 600, + height: 500, +}); + +const line = canvas.addShape('line', { + attrs: { + x1: 100, + y1: 100, + x2: 400, + y2: 300, + lineWidth: 4, + stroke: '#1890FF', + }, +}); + +const circle = canvas.addShape('circle', { + attrs: { + x: 100, + y: 300, + r: 20, + fill: '#F04864', + }, +}); + +circle.animate((ratio) => line.getPoint(ratio), { + duration: 1000, + repeat: true, +}); diff --git a/examples/animation/onFrame/demo/meta.json b/examples/animation/onFrame/demo/meta.json index 96f5aa840..b4ed4233e 100644 --- a/examples/animation/onFrame/demo/meta.json +++ b/examples/animation/onFrame/demo/meta.json @@ -12,6 +12,14 @@ }, "screenshot": "https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*_uKETI3wWTQAAAAAAAAAAABkARQnAQ" }, + { + "filename": "along-line.js", + "title": { + "zh": "直线轨迹动画", + "en": "Animation along line" + }, + "screenshot": "https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*FINdTb9T1SQAAAAAAAAAAABkARQnAQ" + }, { "filename": "along-circle.js", "title": { @@ -42,7 +50,7 @@ "zh": "并行动画", "en": "Concurrent animation" }, - "screenshot": "https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*iNImR4naeOkAAAAAAAAAAABkARQnAQ" + "screenshot": "https://gw.alipayobjects.com/mdn/rms_6ae20b/afts/img/A*lf_pTI4N8C8AAAAAAAAAAABkARQnAQ" }, { "filename": "rotate.js", diff --git a/packages/g-canvas/src/shape/line.ts b/packages/g-canvas/src/shape/line.ts index 5fad8c000..80861864f 100644 --- a/packages/g-canvas/src/shape/line.ts +++ b/packages/g-canvas/src/shape/line.ts @@ -2,10 +2,9 @@ * @fileoverview 圆 * @author dxq613@gmail.com */ - +import LineUtil from '@antv/g-math/lib/line'; import ShapeBase from './base'; import inLine from '../util/in-stroke/line'; -import LineUtil from '@antv/g-math/lib/line'; class Line extends ShapeBase { getInnerBox(attrs) { @@ -27,6 +26,25 @@ class Line extends ShapeBase { context.moveTo(x1, y1); context.lineTo(x2, y2); } + + /** + * Get length of line + * @return {number} length + */ + getTotalLength() { + const { x1, y1, x2, y2 } = this.attr(); + return LineUtil.length(x1, y1, x2, y2); + } + + /** + * Get point according to ratio + * @param {number} ratio + * @return {Point} point + */ + getPoint(ratio: number) { + const { x1, y1, x2, y2 } = this.attr(); + return LineUtil.pointAt(x1, y1, x2, y2, ratio); + } } export default Line; diff --git a/packages/g-canvas/src/shape/path.ts b/packages/g-canvas/src/shape/path.ts index fd5bec5df..f86a6dcce 100644 --- a/packages/g-canvas/src/shape/path.ts +++ b/packages/g-canvas/src/shape/path.ts @@ -114,7 +114,7 @@ class Path extends ShapeBase { * @param {number} ratio * @return {Point} point */ - getPoint(ratio: number) { + getPoint(ratio: number): Point { let tCache = this.get('tCache'); if (!tCache) { this._calculateCurve(); diff --git a/packages/g-canvas/tests/unit/shape/line-spec.js b/packages/g-canvas/tests/unit/shape/line-spec.js index 55083ac11..d0df3e4c4 100644 --- a/packages/g-canvas/tests/unit/shape/line-spec.js +++ b/packages/g-canvas/tests/unit/shape/line-spec.js @@ -48,6 +48,25 @@ describe('line test', () => { expect(line.isHit(10, 11)).eqls(true); }); + it('getTotalLength', () => { + expect(line.getTotalLength()).eqls(Math.sqrt(Math.pow(100 - 0, 2) + Math.pow(100 - 0, 2))); + }); + + it('getPoint', () => { + expect(line.getPoint(0)).eqls({ + x: 0, + y: 0, + }); + expect(line.getPoint(0.5)).eqls({ + x: 50, + y: 50, + }); + expect(line.getPoint(1)).eqls({ + x: 100, + y: 100, + }); + }); + it('clear', () => { line.destroy(); expect(line.destroyed).eqls(true); diff --git a/packages/g-canvas/tests/unit/shape/path-spec.js b/packages/g-canvas/tests/unit/shape/path-spec.js index b09d04a10..9765bd3c1 100644 --- a/packages/g-canvas/tests/unit/shape/path-spec.js +++ b/packages/g-canvas/tests/unit/shape/path-spec.js @@ -225,7 +225,7 @@ describe('test path', () => { expect(path.getTotalLength()).eqls(1577.9692907990257); }); - it.only('getPoint', () => { + it('getPoint', () => { path.attr('path', p1); expect(path.getPoint(0)).eqls({ x: 10, diff --git a/packages/g-svg/package.json b/packages/g-svg/package.json index 3bbbdb3ed..7df882201 100644 --- a/packages/g-svg/package.json +++ b/packages/g-svg/package.json @@ -55,6 +55,7 @@ "homepage": "https://github.com/antvis/g#readme", "dependencies": { "@antv/g-base": "^0.1.1", + "@antv/g-math": "^0.1.0-beta.4", "@antv/util": "~2.0.0", "detect-browser": "^4.6.0" }, diff --git a/packages/g-svg/src/shape/line.ts b/packages/g-svg/src/shape/line.ts index 4265156db..e02a894c1 100644 --- a/packages/g-svg/src/shape/line.ts +++ b/packages/g-svg/src/shape/line.ts @@ -2,7 +2,7 @@ * @fileoverview line * @author dengfuping_develop@163.com */ - +import LineUtil from '@antv/g-math/lib/line'; import { each, isBoolean } from '@antv/util'; import { SVG_ATTR_MAP } from '../constant'; import ShapeBase from './base'; @@ -26,6 +26,25 @@ class Line extends ShapeBase { } }); } + + /** + * Use math calculation to get length of line + * @return {number} length + */ + getTotalLength() { + const { x1, y1, x2, y2 } = this.attr(); + return LineUtil.length(x1, y1, x2, y2); + } + + /** + * Use math calculation to get point according to ratio as same sa Canvas version + * @param {number} ratio + * @return {Point} point + */ + getPoint(ratio: number) { + const { x1, y1, x2, y2 } = this.attr(); + return LineUtil.pointAt(x1, y1, x2, y2, ratio); + } } export default Line; diff --git a/packages/g-svg/src/shape/path.ts b/packages/g-svg/src/shape/path.ts index 2c3ed5a93..bf6fcd58f 100644 --- a/packages/g-svg/src/shape/path.ts +++ b/packages/g-svg/src/shape/path.ts @@ -2,7 +2,7 @@ * @fileoverview path * @author dengfuping_develop@163.com */ - +import { Point } from '@antv/g-base/lib/types'; import { each, isArray, isBoolean } from '@antv/util'; import { SVG_ATTR_MAP } from '../constant'; import ShapeBase from './base'; @@ -57,7 +57,7 @@ class Path extends ShapeBase { * @param {number} ratio * @return {Point} point */ - getPoint(ratio: number) { + getPoint(ratio: number): Point { const el = this.get('el'); const totalLength = this.getTotalLength(); const point = el ? el.getPointAtLength(ratio * totalLength) : null; diff --git a/packages/g-svg/tests/unit/shape/line-spec.js b/packages/g-svg/tests/unit/shape/line-spec.js index ac424defd..7f429c845 100644 --- a/packages/g-svg/tests/unit/shape/line-spec.js +++ b/packages/g-svg/tests/unit/shape/line-spec.js @@ -47,6 +47,25 @@ describe('SVG Line', () => { expect(line.isHit(100, 0)).eql(false); }); + it('getTotalLength', () => { + expect(line.getTotalLength()).eqls(Math.sqrt(Math.pow(100 - 0, 2) + Math.pow(100 - 0, 2))); + }); + + it('getPoint', () => { + expect(line.getPoint(0)).eqls({ + x: 0, + y: 0, + }); + expect(line.getPoint(0.5)).eqls({ + x: 50, + y: 50, + }); + expect(line.getPoint(1)).eqls({ + x: 100, + y: 100, + }); + }); + it('change', () => { expect(line.attr('x1')).eql(0); expect(line.attr('y1')).eql(0); diff --git a/packages/g-svg/tests/unit/shape/path-spec.js b/packages/g-svg/tests/unit/shape/path-spec.js index e8b536c5a..6c0d1f278 100644 --- a/packages/g-svg/tests/unit/shape/path-spec.js +++ b/packages/g-svg/tests/unit/shape/path-spec.js @@ -127,7 +127,7 @@ describe('SVG path', () => { expect(path.getTotalLength()).eqls(1579.16943359375); }); - it.only('getPoint', () => { + it('getPoint', () => { path.attr('path', p1); expect(path.getPoint(0)).eqls({ x: 10,