@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.
- package/dist/arrow.cjs +144 -45
- package/dist/arrow.esm.js +144 -45
- package/dist/arrow.esm.min.js +1 -1
- package/dist/arrow.esm.min.js.map +1 -1
- package/dist/arrow.js +127 -45
- package/dist/arrow.min.cjs +1 -1
- package/dist/arrow.min.cjs.map +1 -1
- package/dist/arrow.min.js +1 -1
- package/dist/arrow.min.js.map +1 -1
- package/package.json +4 -4
- package/src/PathArrowModule.ts +47 -17
- package/src/data/arrows.ts +53 -21
- package/src/index.ts +20 -4
package/src/PathArrowModule.ts
CHANGED
|
@@ -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
|
|
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)
|
|
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)
|
|
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 =
|
|
91
|
-
const pathForArrow: IPathCommandData = ui.__.__pathForArrow = []
|
|
104
|
+
const path = uData.__pathForRender = clonePathForArrow ? [...data] : data
|
|
92
105
|
|
|
93
106
|
if (useStartArrow) {
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
106
|
-
|
|
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
|
-
|
|
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 {
|
package/src/data/arrows.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IArrowStyle, IArrowTypeData, IPathDataArrow, IPathDataArrowMap, IUI,
|
|
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
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
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
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
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):
|
|
59
|
-
let pathData: IPathDataArrow, scale:
|
|
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
|
-
|
|
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(
|
|
24
|
-
|
|
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,
|
|
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
|
})
|