@leafer-in/arrow 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,25 +1,31 @@
1
- import { IPathArrowModule, IUI, IPathCommandData, IPointData, IPathDataArrow } from '@leafer-ui/interface'
2
- import { PathCommandMap as Command, PointHelper } from '@leafer-ui/draw'
1
+ import { IPathArrowModule, IUI, IPathCommandData, IPointData, IPathDataArrow, IArrowPathData } from '@leafer-ui/interface'
2
+ import { PathCommandMap as Command, PointHelper, DataHelper } from '@leafer-ui/draw'
3
3
 
4
- import { arrows, getArrowPath } from './data/arrows'
4
+ import { arrows, fillArrows, getArrowPath } from './data/arrows'
5
5
 
6
6
 
7
7
  const { M, L, C, Q, Z, N, D, X, G, F, O, P, U } = Command
8
- const { copy, copyFrom, getDistancePoint, } = PointHelper
8
+ const { copy, copyFrom, getDistancePoint, isSame } = PointHelper
9
+ const { stintSet } = DataHelper
9
10
 
10
11
  const connectPoint = {} as IPointData
11
12
  const first = {} as IPointData, second = {} as IPointData
12
- const last = {} as IPointData, now = {} as IPointData
13
+ const old = {} as IPointData, last = {} as IPointData, now = {} as IPointData
13
14
 
14
15
  export const PathArrowModule: IPathArrowModule = {
15
16
 
16
17
  list: arrows,
18
+ fillList: fillArrows,
17
19
 
18
- addArrows(ui: IUI): void {
19
- const { startArrow, endArrow, strokeWidth, dashPattern, __pathForRender: data, cornerRadius } = ui.__
20
+ addArrows(ui: IUI, updateCache?: boolean): void {
21
+ const uData = ui.__
22
+ const { startArrow, endArrow, __strokeWidth: strokeWidth, dashPattern, __pathForRender: data, cornerRadius } = uData
20
23
 
21
24
  const clonePathForArrow = !cornerRadius // cornerRadius会创建新的render路径,所以不用再clone
22
25
 
26
+ if (!updateCache) uData.__strokeWidthCache = strokeWidth
27
+
28
+ let startArrowPath: IArrowPathData, singleStartArrow: boolean, endArrowPath: IArrowPathData, singleEndArrow: boolean
23
29
  let command: number, i = 0, len = data.length, count = 0, useStartArrow = startArrow && startArrow !== 'none'
24
30
 
25
31
  while (i < len) {
@@ -30,17 +36,24 @@ export const PathArrowModule: IPathArrowModule = {
30
36
  case M: // moveto(x, y)
31
37
  case L: // lineto(x, y)
32
38
  if (count < 2 || i + 6 >= len) { // 3 + 3 可能是两个连续L命令结束
39
+ copy(old, now)
33
40
  copyFrom(now, data[i + 1], data[i + 2])
34
41
  if (!count && useStartArrow) copy(first, now)
35
42
  }
36
43
  i += 3
37
44
  break
38
45
  case C: // bezierCurveTo(x1, y1, x2, y2, x, y)
39
- if (count === 1 || i + 7 >= len - 3) copyPoints(data, last, now, i + 3) // C 或 C + L结束
46
+ if (count === 1 || i + 7 >= len - 3) {
47
+ copyPoints(data, last, now, i + 3) // C 或 C + L结束
48
+ old.x = data[i + 1], old.y = data[i + 2]
49
+ }
40
50
  i += 7
41
51
  break
42
52
  case Q: // quadraticCurveTo(x1, y1, x, y)
43
- if (count === 1 || i + 5 >= len - 3) copyPoints(data, last, now, i + 1) // Q 或 Q + L结束
53
+ if (count === 1 || i + 5 >= len - 3) {
54
+ copyPoints(data, last, now, i + 1) // Q 或 Q + L结束
55
+ copy(old, last)
56
+ }
44
57
  i += 5
45
58
  break
46
59
  case Z: // closepath()
@@ -72,6 +85,7 @@ export const PathArrowModule: IPathArrowModule = {
72
85
  case U: // arcTo(x1, y1, x2, y2, radius)
73
86
  if (count === 1 || i + 6 >= len - 3) { // U 或 U + L结束
74
87
  copyPoints(data, last, now, i + 1)
88
+ copy(old, last)
75
89
  if (i + 6 !== len) { // 避免与结束点重合
76
90
  now.x -= (now.x - last.x) / 10
77
91
  now.y -= (now.y - last.y) / 10
@@ -84,15 +98,15 @@ export const PathArrowModule: IPathArrowModule = {
84
98
  count++
85
99
 
86
100
  if (count === 1 && command !== M) return // no arrow
87
- if (count === 2 && useStartArrow) copy(second, command === L ? now : last)
101
+ if (count === 2 && useStartArrow) copy(second, command === L ? now : (isSame(old, first) ? last : old)) // 获取第二个点, 防止C命令起点和控制点相同的情况
88
102
 
89
103
  if (i === len) {
90
- const path = ui.__.__pathForRender = clonePathForArrow ? [...data] : data
91
- const pathForArrow: IPathCommandData = ui.__.__pathForArrow = []
104
+ const path = uData.__pathForRender = clonePathForArrow ? [...data] : data
92
105
 
93
106
  if (useStartArrow) {
94
- const startArrowPath = getArrowPath(ui, startArrow, second, first, strokeWidth, connectPoint, !!dashPattern)
95
- dashPattern ? pathForArrow.push(...startArrowPath) : path.push(...startArrowPath)
107
+ startArrowPath = getArrowPath(ui, startArrow, second, first, strokeWidth, connectPoint, !!dashPattern)
108
+ singleStartArrow = (startArrowPath.fill || dashPattern) as boolean
109
+ if (!singleStartArrow) path.push(...startArrowPath.data)
96
110
 
97
111
  if (connectPoint.x) {
98
112
  getDistancePoint(first, second, -connectPoint.x, true)
@@ -102,8 +116,11 @@ export const PathArrowModule: IPathArrowModule = {
102
116
  }
103
117
 
104
118
  if (endArrow && endArrow !== 'none') {
105
- const endArrowPath = getArrowPath(ui, endArrow, last, now, strokeWidth, connectPoint, !!dashPattern)
106
- dashPattern ? pathForArrow.push(...endArrowPath) : path.push(...endArrowPath)
119
+ if (isSame(last, now)) copy(last, old) // 防止C命令结束点和控制点相同的情况
120
+
121
+ endArrowPath = getArrowPath(ui, endArrow, last, now, strokeWidth, connectPoint, !!dashPattern)
122
+ singleEndArrow = (endArrowPath.fill || dashPattern) as boolean
123
+ if (!singleEndArrow) path.push(...endArrowPath.data)
107
124
 
108
125
  if (connectPoint.x) {
109
126
  getDistancePoint(now, last, -connectPoint.x, true)
@@ -129,13 +146,26 @@ export const PathArrowModule: IPathArrowModule = {
129
146
  } else {
130
147
  copy(last, now)
131
148
  }
149
+
150
+ stintSet(uData, '__startArrowPath', singleStartArrow && startArrowPath)
151
+ stintSet(uData, '__endArrowPath', singleEndArrow && endArrowPath)
132
152
  }
133
153
 
134
154
 
135
155
  },
136
156
 
137
- register(name: string, data: IPathDataArrow): void {
157
+ updateArrow(ui: IUI): void {
158
+ const data = ui.__
159
+ if (data.strokeScaleFixed) {
160
+ if (data.__strokeWidthCache !== data.__strokeWidth) {
161
+ ui.__updateRenderPath(true)
162
+ }
163
+ }
164
+ },
165
+
166
+ register(name: string, data: IPathDataArrow, fillData?: IPathDataArrow): void {
138
167
  this.list[name] = data
168
+ if (fillData) this.fillList[name] = data
139
169
  },
140
170
 
141
171
  get(name: string): IPathDataArrow {
@@ -1,4 +1,4 @@
1
- import { IArrowStyle, IArrowTypeData, IPathDataArrow, IPathDataArrowMap, IUI, IPathCommandData, IPointData } from '@leafer-ui/interface'
1
+ import { IArrowStyle, IArrowTypeData, IPathDataArrow, IPathDataArrowMap, IUI, IPointData, IArrowPathData } from '@leafer-ui/interface'
2
2
  import { DataHelper, PointHelper, isObject } from '@leafer-ui/draw'
3
3
 
4
4
  import { PathMatrixHelper } from '../PathMatrixHelper'
@@ -6,30 +6,44 @@ import { PathMatrixHelper } from '../PathMatrixHelper'
6
6
 
7
7
  const { layout, rotate } = PathMatrixHelper
8
8
  const { getAngle } = PointHelper
9
- const half = { x: -0.5 }
9
+ const zero = { x: 0 }, half = { x: -0.5 }
10
10
 
11
-
12
- const angle: IPathDataArrow = { connect: half, offset: { x: -0.71, bevelJoin: 0.36, roundJoin: 0.22 }, path: [1, -3, -3, 2, 0, 0, 2, -3, 3] } // moveTo(-3, -3).lineTo(0, 0).lineTo(-3, 3)
11
+ const angle: IPathDataArrow = { connect: zero, offset: { x: -0.71, bevelJoin: 0.36, roundJoin: 0.22 }, path: [1, -3, -3, 2, 0, 0, 2, -3, 3] } // moveTo(-3, -3).lineTo(0, 0).lineTo(-3, 3)
13
12
  const angleSide: IPathDataArrow = { connect: half, offset: { x: -1.207, bevelJoin: 0.854, roundJoin: 0.707 }, path: [1, -3, -3, 2, 0, 0, 2, -1, 0] } // moveTo(-3, -3).lineTo(0, 0).lineTo(-1, 0)
14
13
 
15
14
  const triangleLinePath = [1, -3, 0, 2, -3, -2, 2, 0, 0, 2, -3, 2, 2, -3, 0] // moveTo(-3, 0).lineTo(-3, -2).lineTo(0, 0).lineTo(-3, 2).lineTo(-3, 0)
16
- const triangle: IPathDataArrow = { connect: half, offset: { x: -0.9, bevelJoin: 0.624, roundJoin: 0.4 }, path: [...triangleLinePath, 1, -2.05, 1.1, 2, -2.05, -1.1], dashPath: [1, -2, 0, 2, -0.5, 0] } // fill: moveTo(-2.05, 1.1).lineTo(-2.05, -1.1)
17
-
18
- const arrowLinePath = [1, -3, 0, 2, -3.5, -1.8, 2, 0, 0, 2, -3.5, 1.8, 2, -3, 0] // moveTo(-3, 0).lineTo(-3.5, -1.8).lineTo(0, 0).lineTo(-3.5, 1.8).lineTo(-3, 0)
19
- const arrow: IPathDataArrow = { connect: half, offset: { x: -1.1, bevelJoin: 0.872, roundJoin: 0.6 }, path: [...arrowLinePath, 1, -2.25, 0.95, 2, -2.25, -0.95], dashPath: [1, -3, 0, 2, -0.5, 0] } // fill: moveTo(-2.25, 0.95).lineTo(-2.25, -0.95)
20
-
21
- const triangleFlip: IPathDataArrow = { offset: half, path: [...triangle.path], dashPath: [1, -2.5, 0, 2, -1, 0] } // triangle rotate 180
15
+ const triangleFill: IPathDataArrow = { connect: zero, offset: { x: -0.9, bevelJoin: 0.624, roundJoin: 0.4 }, path: [...triangleLinePath] }
16
+ const triangle: IPathDataArrow = DataHelper.clone(triangleFill) as IPathDataArrow
17
+ triangle.path = [...triangleLinePath, 1, -2.05, 1.1, 2, -2.05, -1.1] // fill: moveTo(-2.05, 1.1).lineTo(-2.05, -1.1)
18
+ triangle.dashPath = [1, -2, 0, 2, -0.5, 0]
19
+
20
+ const triangleFlipFill: IPathDataArrow = { connect: zero, offset: half, path: [...triangleFill.path] } // triangle rotate 180
21
+ const triangleFlip: IPathDataArrow = { connect: zero, offset: half, path: [...triangle.path], dashPath: [1, -2.5, 0, 2, -1, 0] } // triangle rotate 180
22
+ rotate(triangleFlipFill.path, 180, { x: -1.5, y: 0 })
22
23
  rotate(triangleFlip.path, 180, { x: -1.5, y: 0 })
23
24
 
24
- const circleLine: IPathDataArrow = { connect: { x: -1.3 }, path: [1, 1.8, -0.1, 2, 1.8, 0, 26, 0, 0, 1.8, 0, 359, 0], } //drawArc(0, 0, 2, 0, 360)
25
- const circle: IPathDataArrow = { connect: { x: 0.5 }, path: [...circleLine.path, 1, 0, 0, 26, 0, 0, 1, 0, 360, 0], dashPath: [1, -0.5, 0, 2, 0.5, 0] } // fill: moveTo(0,0).arc(0, 0, 1, 0, 360)
26
-
27
- const squareLine: IPathDataArrow = { connect: { x: -1.3 }, path: [1, -1.4, 0, 2, -1.4, -1.4, 2, 1.4, -1.4, 2, 1.4, 1.4, 2, -1.4, 1.4, 2, -1.4, 0] } // moveTo(-1.4, 0).lineTo(-1.4, -1.4).lineTo(1.4, -1.4).lineTo(1.4, 1.4).lineTo(-1.4, 1.4).lineTo(-1.4, 0)
25
+ const arrowLinePath = [1, -3, 0, 2, -3.5, -1.8, 2, 0, 0, 2, -3.5, 1.8, 2, -3, 0] // moveTo(-3, 0).lineTo(-3.5, -1.8).lineTo(0, 0).lineTo(-3.5, 1.8).lineTo(-3, 0)
26
+ const arrowFill: IPathDataArrow = { connect: zero, offset: { x: -1.1, bevelJoin: 0.872, roundJoin: 0.6 }, path: [...arrowLinePath] }
27
+ const arrow: IPathDataArrow = DataHelper.clone(arrowFill) as IPathDataArrow
28
+ arrow.path = [...arrowLinePath, 1, -2.25, 0.95, 2, -2.25, -0.95] // fill: moveTo(-2.25, 0.95).lineTo(-2.25, -0.95)
29
+ arrow.dashPath = [1, -3, 0, 2, -0.5, 0]
30
+
31
+ const circleLine: IPathDataArrow = { connect: { x: -1.8 }, path: [1, 1.8, -0.1, 2, 1.8, 0, 26, 0, 0, 1.8, 0, 359, 0], } //drawArc(0, 0, 2, 0, 360)
32
+ const circleFill: IPathDataArrow = { connect: { x: 0.5 }, path: [...circleLine.path] }
33
+ const circle: IPathDataArrow = DataHelper.clone(circleFill) as IPathDataArrow
34
+ circle.path = [...circleLine.path, 1, 0, 0, 26, 0, 0, 1, 0, 360, 0] // fill: moveTo(0,0).arc(0, 0, 1, 0, 360)
35
+ circle.dashPath = [1, -0.5, 0, 2, 0.5, 0]
36
+
37
+ const squareLine: IPathDataArrow = { connect: { x: -1.4 }, path: [1, -1.4, 0, 2, -1.4, -1.4, 2, 1.4, -1.4, 2, 1.4, 1.4, 2, -1.4, 1.4, 2, -1.4, 0] } // moveTo(-1.4, 0).lineTo(-1.4, -1.4).lineTo(1.4, -1.4).lineTo(1.4, 1.4).lineTo(-1.4, 1.4).lineTo(-1.4, 0)
38
+ const squareFill: IPathDataArrow = { path: [...squareLine.path] }
28
39
  const square: IPathDataArrow = { path: [...squareLine.path, 2, -1.4, -0.49, 2, 1, -0.49, 1, -1.4, 0.49, 2, 1, 0.49] } // fill: moveTo(-1.4, -0.49).lineTo(1, -0.49).moveTo(-1.4, 0.49).lineTo(1, 0.49)
29
40
 
30
41
  const diamondLine = DataHelper.clone(squareLine) as IPathDataArrow // square-line rotate 45
42
+ diamondLine.connect.x = -1.9
43
+ const diamondFill: IPathDataArrow = DataHelper.clone(squareFill) as IPathDataArrow // squareFill rotate 45
31
44
  const diamond: IPathDataArrow = DataHelper.clone(square) as IPathDataArrow // square rotate 45
32
45
  rotate(diamondLine.path, 45)
46
+ rotate(diamondFill.path, 45)
33
47
  rotate(diamond.path, 45)
34
48
 
35
49
  const mark: IPathDataArrow = { offset: half, path: [1, 0, -2, 2, 0, 2] } // moveTo(0, -2).lineTo(0, 2)
@@ -52,26 +66,41 @@ export const arrows: IPathDataArrowMap = {
52
66
  'diamond-line': diamondLine,
53
67
 
54
68
  mark,
69
+ }
55
70
 
71
+ export const fillArrows: IPathDataArrowMap = {
72
+ triangle: triangleFill,
73
+ 'triangle-flip': triangleFlipFill,
74
+ arrow: arrowFill,
75
+ circle: circleFill,
76
+ square: squareFill,
77
+ diamond: diamondFill
56
78
  }
57
79
 
58
- export function getArrowPath(ui: IUI, arrow: IArrowStyle, from: IPointData, to: IPointData, size: number, connectOffset: IPointData, hasDashPattern?: boolean): IPathCommandData {
59
- let pathData: IPathDataArrow, scale: number
80
+ export function getArrowPath(ui: IUI, arrow: IArrowStyle, from: IPointData, to: IPointData, size: number, connectOffset: IPointData, hasDashPattern?: boolean): IArrowPathData {
81
+ let pathData: IPathDataArrow, scale = 1, rotation = 0, fill: boolean
60
82
 
61
83
  const { strokeCap, strokeJoin } = ui.__
62
84
 
63
85
  if (isObject(arrow)) {
64
86
  if ((arrow as IArrowTypeData).type) {
65
- scale = (arrow as IArrowTypeData).scale
87
+ scale = (arrow as IArrowTypeData).scale || 1
88
+ rotation = (arrow as IArrowTypeData).rotation || 0
66
89
  pathData = arrows[(arrow as IArrowTypeData).type]
90
+ if (scale > 1) { // 放大后,优先使用fill路径数据
91
+ const fillData = fillArrows[(arrow as IArrowTypeData).type]
92
+ if (fillData) pathData = fillData, fill = true
93
+ }
67
94
  } else pathData = arrow as IPathDataArrow
68
95
  } else {
69
96
  pathData = arrows[arrow]
70
97
  }
71
98
 
99
+ if (!fill) fill = pathData.fill
100
+
72
101
  const { offset, connect, path, dashPath } = pathData
73
102
 
74
- let connectX = connect ? connect.x : 0
103
+ let connectX = connect ? connect.x * scale : 0
75
104
  let offsetX = offset ? offset.x : 0
76
105
 
77
106
  const data = [...path]
@@ -83,12 +112,15 @@ export function getArrowPath(ui: IUI, arrow: IArrowStyle, from: IPointData, to:
83
112
  else if (strokeJoin === 'bevel' && offset.bevelJoin) offsetX += offset.bevelJoin
84
113
  }
85
114
 
86
- if (scale) layout(data, 0, 0, scale, scale) // 预留箭头比例缩放功能
115
+ if (scale !== 1) layout(data, 0, 0, scale, scale) // 缩放箭头比例
87
116
 
88
117
  if (offsetX) layout(data, offsetX, 0)
89
118
 
90
- layout(data, to.x, to.y, size, size, getAngle(from, to)) // scale rotate 先围绕 data 数据应用后,再加 to
119
+ layout(data, to.x, to.y, size, size, getAngle(from, to) + rotation) // scale rotate 先围绕 data 数据应用后,再加 to
91
120
 
92
121
  connectOffset.x = (connectX + offsetX) * size
93
- return data
122
+
123
+ const arrowData: IArrowPathData = { data }
124
+ if (fill) arrowData.fill = fill
125
+ return arrowData
94
126
  }
package/src/index.ts CHANGED
@@ -20,12 +20,28 @@ UI.addAttr('endArrow', 'none', arrowType)
20
20
 
21
21
  Object.assign(PathArrow, PathArrowModule)
22
22
  Object.assign(Paint, {
23
- strokeArrow(_stroke: string, ui: IUI, canvas: ILeaferCanvas, _renderOptions: IRenderOptions): void {
24
- if (ui.__.dashPattern) { // fix: dashPattern Arrow
23
+ strokeArrow(stroke: string, ui: IUI, canvas: ILeaferCanvas, _renderOptions: IRenderOptions): void {
24
+ const { __startArrowPath, __endArrowPath, dashPattern } = ui.__
25
+ if (dashPattern) canvas.dashPattern = null // fix: dashPattern Arrow
26
+
27
+ if (__startArrowPath) {
28
+ canvas.beginPath()
29
+ ui.__drawPathByData(canvas, __startArrowPath.data)
30
+ canvas.stroke()
31
+ if (__startArrowPath.fill) {
32
+ canvas.fillStyle = stroke
33
+ canvas.fill()
34
+ }
35
+ }
36
+
37
+ if (__endArrowPath) {
25
38
  canvas.beginPath()
26
- ui.__drawPathByData(canvas, ui.__.__pathForArrow)
27
- canvas.dashPattern = null
39
+ ui.__drawPathByData(canvas, __endArrowPath.data)
28
40
  canvas.stroke()
41
+ if (__endArrowPath.fill) {
42
+ canvas.fillStyle = stroke
43
+ canvas.fill()
44
+ }
29
45
  }
30
46
  }
31
47
  })