Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

@leafer/path

Package Overview
Dependencies
Maintainers
1
Versions
116
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@leafer/path - npm Package Compare versions

Comparing version
1.0.0-alpha.23
to
1.0.0-alpha.30
+70
src/EllipseHelper.ts
import { IPathCommandData } from '@leafer/interface'
import { OneRadian, PI2 } from '@leafer/math'
import { PathCommandMap } from './PathCommandMap'
import { BezierHelper } from './BezierHelper'
const { sin, cos, sqrt, atan2 } = Math
const { ellipse } = BezierHelper
export const EllipseHelper = {
// svg
ellipticalArc(data: IPathCommandData, fromX: number, fromY: number, radiusX: number, radiusY: number, rotation: number, largeFlag: number, sweepFlag: number, toX: number, toY: number, curveMode?: boolean): void {
const halfX = (toX - fromX) / 2
const halfY = (toY - fromY) / 2
const rotationRadian = rotation * OneRadian
const rotationSin = sin(rotationRadian)
const rotationCos = cos(rotationRadian)
const px = -rotationCos * halfX - rotationSin * halfY
const py = -rotationCos * halfY + rotationSin * halfX
const rxSquare = radiusX * radiusX
const rySquare = radiusY * radiusY
const pySquare = py * py
const pxSquare = px * px
const a = rxSquare * rySquare - rxSquare * pySquare - rySquare * pxSquare
let s = 0
if (a < 0) {
const t = sqrt(1 - a / (rxSquare * rySquare))
radiusX *= t
radiusY *= t
} else {
s = (largeFlag === sweepFlag ? -1 : 1) * sqrt(a / (rxSquare * pySquare + rySquare * pxSquare))
}
const cx = s * radiusX * py / radiusY
const cy = -s * radiusY * px / radiusX
const startRadian = atan2((py - cy) / radiusY, (px - cx) / radiusX)
const endRadian = atan2((-py - cy) / radiusY, (-px - cx) / radiusX)
let totalRadian = endRadian - startRadian
if (sweepFlag === 0 && totalRadian > 0) {
totalRadian -= PI2
} else if (sweepFlag === 1 && totalRadian < 0) {
totalRadian += PI2
}
const centerX = fromX + halfX + rotationCos * cx - rotationSin * cy
const centerY = fromY + halfY + rotationSin * cx + rotationCos * cy
const anticlockwise = totalRadian < 0 ? 1 : 0
if (curveMode) {
ellipse(data, centerX, centerY, radiusX, radiusY, rotation, startRadian / OneRadian, endRadian / OneRadian, anticlockwise as unknown as boolean)
} else {
if (radiusX === radiusY && !rotation) {
data.push(PathCommandMap.O, centerX, centerY, radiusX, startRadian / OneRadian, endRadian / OneRadian, anticlockwise)
} else {
data.push(PathCommandMap.G, centerX, centerY, radiusX, radiusY, rotation, startRadian / OneRadian, endRadian / OneRadian, anticlockwise)
}
}
}
}
import { ITwoPointBoundsData, IPathCommandData, IBoundsData, IPointData } from '@leafer/interface'
import { TwoPointBoundsHelper } from '@leafer/math'
import { Debug } from '@leafer/debug'
import { BezierHelper } from './BezierHelper'
import { PathCommandMap as Command } from './PathCommandMap'
const { M, L, C, Q, Z, N, D, X, G, F, O, P, U } = Command
const { toTwoPointBounds, toTwoPointBoundsByQuadraticCurve, arcTo, arc, ellipse } = BezierHelper
const { add, copy, addPoint, setPoint, addBounds, toBounds } = TwoPointBoundsHelper
const debug = Debug.get('PathBounds')
let radius: number, radiusX: number, radiusY: number
const tempPointBounds = {} as ITwoPointBoundsData
const setPointBounds = {} as ITwoPointBoundsData
const setEndPoint = {} as IPointData
export const PathBounds = {
toBounds(data: IPathCommandData, setBounds: IBoundsData): void {
PathBounds.toTwoPointBounds(data, setPointBounds)
toBounds(setPointBounds, setBounds)
},
toTwoPointBounds(data: IPathCommandData, setPointBounds: ITwoPointBoundsData): void {
if (!data || !data.length) return setPoint(setPointBounds, 0, 0)
let command: number
let i: number = 0, x: number = 0, y: number = 0, x1: number, y1: number, toX: number, toY: number
const len = data.length
while (i < len) {
command = data[i]
if (i === 0) {
if (command === Z || command === C || command === Q) {
setPoint(setPointBounds, x, y)
} else {
setPoint(setPointBounds, data[i + 1], data[i + 2])
}
}
switch (command) {
case M: //moveto(x, y)
case L: //lineto(x, y)
x = data[i + 1]
y = data[i + 2]
addPoint(setPointBounds, x, y)
i += 3
break
case C: //bezierCurveTo(x1, y1, x2, y2, x,y)
toX = data[i + 5]
toY = data[i + 6]
toTwoPointBounds(x, y, data[i + 1], data[i + 2], data[i + 3], data[i + 4], toX, toY, tempPointBounds)
add(setPointBounds, tempPointBounds)
x = toX
y = toY
i += 7
break
case Q: //quadraticCurveTo(x1, y1, x, y)
x1 = data[i + 1]
y1 = data[i + 2]
toX = data[i + 3]
toY = data[i + 4]
toTwoPointBoundsByQuadraticCurve(x, y, x1, y1, toX, toY, tempPointBounds)
add(setPointBounds, tempPointBounds)
x = toX
y = toY
i += 5
break
case Z: //closepath()
i += 1
break
// canvas command
case N: // rect(x, y, width, height)
x = data[i + 1]
y = data[i + 2]
addBounds(setPointBounds, x, y, data[i + 3], data[i + 4])
i += 5
break
case D: // roundRect(x, y, width, height, radius1, radius2, radius3, radius4)
case X: // simple roundRect(x, y, width, height, radius)
x = data[i + 1]
y = data[i + 2]
addBounds(setPointBounds, x, y, data[i + 3], data[i + 4])
i += (command === D ? 9 : 6)
break
case G: // ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
ellipse(null, data[i + 1], data[i + 2], data[i + 3], data[i + 4], data[i + 5], data[i + 6], data[i + 7], data[i + 8] as unknown as boolean, tempPointBounds, setEndPoint)
i === 0 ? copy(setPointBounds, tempPointBounds) : add(setPointBounds, tempPointBounds)
x = setEndPoint.x
y = setEndPoint.y
i += 9
break
case F: // simple ellipse(x, y, radiusX, radiusY)
x = data[i + 1]
y = data[i + 2]
radiusX = data[i + 3]
radiusY = data[i + 4]
addBounds(setPointBounds, x - radiusX, y - radiusY, radiusX * 2, radiusY * 2)
x += radiusX
i += 5
break
case O: // arc(x, y, radius, startAngle, endAngle, anticlockwise)
arc(null, data[i + 1], data[i + 2], data[i + 3], data[i + 4], data[i + 5], data[i + 6] as unknown as boolean, tempPointBounds, setEndPoint)
i === 0 ? copy(setPointBounds, tempPointBounds) : add(setPointBounds, tempPointBounds)
x = setEndPoint.x
y = setEndPoint.y
i += 7
break
case P: // simple arc(x, y, radius)
x = data[i + 1]
y = data[i + 2]
radius = data[i + 3]
addBounds(setPointBounds, x - radius, y - radius, radius * 2, radius * 2)
x += radius
i += 4
break
case U: // arcTo(x1, y1, x2, y2, radius)
arcTo(null, x, y, data[i + 1], data[i + 2], data[i + 3], data[i + 4], data[i + 5], tempPointBounds, setEndPoint)
i === 0 ? copy(setPointBounds, tempPointBounds) : add(setPointBounds, tempPointBounds)
x = setEndPoint.x
y = setEndPoint.y
i += 6
break
default:
debug.error(`command: ${command} [index:${i}]`, data)
return
}
}
}
}
import { IPathCommandData, IPointData } from '@leafer/interface'
import { PathCommandMap } from './PathCommandMap'
import { BezierHelper } from './BezierHelper'
import { MathHelper } from '@leafer/math'
const { M, L, C, Q, Z, N, D, X, G, F, O, P, U } = PathCommandMap
const startPoint = {} as IPointData
export const PathCommandDataHelper = {
beginPath(data: IPathCommandData): void {
data.length = 0
},
// svg and canvas
moveTo(data: IPathCommandData, x: number, y: number): void {
data.push(M, x, y)
},
lineTo(data: IPathCommandData, x: number, y: number): void {
data.push(L, x, y)
},
bezierCurveTo(data: IPathCommandData, x1: number, y1: number, x2: number, y2: number, x: number, y: number): void {
data.push(C, x1, y1, x2, y2, x, y)
},
quadraticCurveTo(data: IPathCommandData, x1: number, y1: number, x: number, y: number): void {
data.push(Q, x1, y1, x, y)
},
closePath(data: IPathCommandData): void {
data.push(Z)
},
// canvas
rect(data: IPathCommandData, x: number, y: number, width: number, height: number): void {
data.push(N, x, y, width, height)
},
roundRect(data: IPathCommandData, x: number, y: number, width: number, height: number, cornerRadius: number | number[]): void {
if (typeof cornerRadius === 'number') {
data.push(X, x, y, width, height, cornerRadius)
} else {
const fourCorners = MathHelper.fourNumber(cornerRadius)
if (fourCorners) {
data.push(D, x, y, width, height, ...fourCorners)
} else {
data.push(N, x, y, width, height)
}
}
},
ellipse(data: IPathCommandData, x: number, y: number, radiusX: number, radiusY: number, rotation?: number, startAngle?: number, endAngle?: number, anticlockwise?: boolean): void {
if (rotation === undefined) {
data.push(F, x, y, radiusX, radiusY)
} else {
if (startAngle === undefined) startAngle = 0
if (endAngle === undefined) endAngle = 360
data.push(G, x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise ? 1 : 0)
}
},
arc(data: IPathCommandData, x: number, y: number, radius: number, startAngle?: number, endAngle?: number, anticlockwise?: boolean): void {
if (startAngle === undefined) {
data.push(P, x, y, radius)
} else {
if (endAngle === undefined) endAngle = 360
data.push(O, x, y, radius, startAngle, endAngle, anticlockwise ? 1 : 0)
}
},
moveToEllipse(data: IPathCommandData, x: number, y: number, radiusX: number, radiusY: number, rotation?: number, startAngle?: number, endAngle?: number, anticlockwise?: boolean): void {
if (rotation === undefined) rotation = 0
if (startAngle === undefined) startAngle = 0
if (endAngle === undefined) endAngle = 360
BezierHelper.ellipse(null, x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise, null, null, startPoint)
data.push(M, startPoint.x, startPoint.y)
ellipse(data, x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
},
moveToArc(data: IPathCommandData, x: number, y: number, radius: number, startAngle?: number, endAngle?: number, anticlockwise?: boolean): void {
if (startAngle === undefined) startAngle = 0
if (endAngle === undefined) endAngle = 360
BezierHelper.arc(null, x, y, radius, startAngle, endAngle, anticlockwise, null, null, startPoint)
data.push(M, startPoint.x, startPoint.y)
arc(data, x, y, radius, startAngle, endAngle, anticlockwise)
},
arcTo(data: IPathCommandData, x1: number, y1: number, x2: number, y2: number, radius: number): void {
data.push(U, x1, y1, x2, y2, radius)
}
}
const { ellipse, arc } = PathCommandDataHelper
import { IPathCommandData } from '@leafer/interface'
export const PathCorner = {
smooth(data: IPathCommandData, _cornerRadius: number, _cornerSmoothing?: number): IPathCommandData {
return data
}
}
import { IPathDrawer, IPathCommandData } from '@leafer/interface'
import { OneRadian, PI2 } from '@leafer/math'
import { Debug } from '@leafer/debug'
import { PathCommandMap as Command } from './PathCommandMap'
const { M, L, C, Q, Z, N, D, X, G, F, O, P, U } = Command
const debug = Debug.get('PathDrawer')
export const PathDrawer = {
drawPathByData(drawer: IPathDrawer, data: IPathCommandData): void {
if (!data) return
let command: number
let i = 0, len = data.length
while (i < len) {
command = data[i]
switch (command) {
case M: //moveto(x, y)
drawer.moveTo(data[i + 1], data[i + 2])
i += 3
break
case L: //lineto(x, y)
drawer.lineTo(data[i + 1], data[i + 2])
i += 3
break
case C: //bezierCurveTo(x1, y1, x2, y2, x, y)
drawer.bezierCurveTo(data[i + 1], data[i + 2], data[i + 3], data[i + 4], data[i + 5], data[i + 6])
i += 7
break
case Q: //quadraticCurveTo(x1, y1, x, y)
drawer.quadraticCurveTo(data[i + 1], data[i + 2], data[i + 3], data[i + 4])
i += 5
break
case Z: //closepath()
drawer.closePath()
i += 1
break
// canvas command
case N: // rect(x, y, width, height)
drawer.rect(data[i + 1], data[i + 2], data[i + 3], data[i + 4])
i += 5
break
case D: // roundRect(x, y, width, height, radius1, radius2, radius3, radius4)
drawer.roundRect(data[i + 1], data[i + 2], data[i + 3], data[i + 4], [data[i + 5], data[i + 6], data[i + 7], data[i + 8]])
i += 9
break
case X: // simple roundRect(x, y, width, height, radius)
drawer.roundRect(data[i + 1], data[i + 2], data[i + 3], data[i + 4], data[i + 5])
i += 6
break
case G: // ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
drawer.ellipse(data[i + 1], data[i + 2], data[i + 3], data[i + 4], data[i + 5] * OneRadian, data[i + 6] * OneRadian, data[i + 7] * OneRadian, data[i + 8] as unknown as boolean)
i += 9
break
case F: // simple ellipse(x, y, radiusX, radiusY)
drawer.ellipse(data[i + 1], data[i + 2], data[i + 3], data[i + 4], 0, 0, PI2, false)
i += 5
break
case O: // arc(x, y, radius, startAngle, endAngle, anticlockwise)
drawer.arc(data[i + 1], data[i + 2], data[i + 3], data[i + 4] * OneRadian, data[i + 5] * OneRadian, data[i + 6] as unknown as boolean)
i += 7
break
case P: // simple arc(x, y, radius)
drawer.arc(data[i + 1], data[i + 2], data[i + 3], 0, PI2, false)
i += 4
break
case U: // arcTo(x1, y1, x2, y2, radius)
drawer.arcTo(data[i + 1], data[i + 2], data[i + 3], data[i + 4], data[i + 5])
i += 6
break
default:
debug.error(`command: ${command} [index:${i}]`, data)
return
}
}
}
}
import { IPathDrawer } from '@leafer/interface'
import { MathHelper } from '@leafer/math'
export const RectHelper = {
drawRoundRect(drawer: IPathDrawer, x: number, y: number, width: number, height: number, cornerRadius: number | number[]): void {
let [topLeft, topRight, bottomRight, bottomLeft] = MathHelper.fourNumber(cornerRadius)
const max = Math.min(width / 2, height / 2)
if (topLeft > max) topLeft = max
if (topRight > max) topRight = max
if (bottomRight > max) bottomRight = max
if (bottomLeft > max) bottomLeft = max
topLeft ? drawer.moveTo(x + topLeft, y) : drawer.moveTo(x, y)
topRight ? drawer.arcTo(x + width, y, x + width, y + height, topRight) : drawer.lineTo(x + width, y)
bottomRight ? drawer.arcTo(x + width, y + height, x, y + height, bottomRight) : drawer.lineTo(x + width, y + height)
bottomLeft ? drawer.arcTo(x, y + height, x, y, bottomLeft) : drawer.lineTo(x, y + height)
topLeft ? drawer.arcTo(x, y, x + width, y, topLeft) : drawer.lineTo(x, y)
}
}
+4
-3
{
"name": "@leafer/path",
"version": "1.0.0-alpha.23",
"version": "1.0.0-alpha.30",
"description": "@leafer/path",

@@ -22,7 +22,8 @@ "author": "Chao (Leafer) Wan",

"dependencies": {
"@leafer/math": "1.0.0-alpha.23"
"@leafer/math": "1.0.0-alpha.30",
"@leafer/debug": "1.0.0-alpha.30"
},
"devDependencies": {
"@leafer/interface": "1.0.0-alpha.23"
"@leafer/interface": "1.0.0-alpha.30"
}
}
import { IPointData, ITwoPointBoundsData, IPathCommandData } from '@leafer/interface'
import { TwoPointBoundsHelper } from '@leafer/math'
import { OneRadian, PI2, PI_2, PointHelper, TwoPointBoundsHelper } from '@leafer/math'
import { PathCommandMap } from './PathCommandMap'
import { RectHelper } from './RectHelper'
import { PathHelper } from './PathHelper'
const { sin, cos, atan2, ceil, abs, PI } = Math
const { setPoint, addPoint } = TwoPointBoundsHelper
const { set } = PointHelper
const tempPoint = {} as IPointData
const { sin, cos, sqrt, atan2, ceil, abs, PI } = Math
const { setPoint, addPoint } = TwoPointBoundsHelper
export const BezierHelper = {
getFromACommand(fromX: number, fromY: number, rx: number, ry: number, rotateAngle: number, largeFlag: number, sweepFlag: number, toX: number, toY: number): IPathCommandData { // [...CCommandData, ...CCommandData]
rect(data: IPathCommandData, x: number, y: number, width: number, height: number) {
PathHelper.creator.path = data
PathHelper.creator.moveTo(x, y).lineTo(x + width, y).lineTo(x + width, y + height).lineTo(x, y + height).lineTo(x, y)
},
const localToX = toX - fromX
const localToY = toY - fromY
roundRect(data: IPathCommandData, x: number, y: number, width: number, height: number, radius: number | number[]): void {
PathHelper.creator.path = []
RectHelper.drawRoundRect(PathHelper.creator, x, y, width, height, radius)
data.push(...PathHelper.convertToCanvasData(PathHelper.creator.path, true))
},
const rotation = rotateAngle * PI / 180
const sinRotation = sin(rotation)
const cosRotation = cos(rotation)
arcTo(data: IPathCommandData | null | void, fromX: number, fromY: number, x1: number, y1: number, toX: number, toY: number, radius: number, setPointBounds?: ITwoPointBoundsData, setEndPoint?: IPointData, setStartPoint?: IPointData): void {
const BAx = x1 - fromX
const BAy = y1 - fromY
const CBx = toX - x1
const CBy = toY - y1
const ax = -cosRotation * localToX * 0.5 - sinRotation * localToY * 0.5
const ay = -cosRotation * localToY * 0.5 + sinRotation * localToX * 0.5
const rxSquare = rx * rx
const rySquare = ry * ry
const pySquare = ay * ay
const pxSquare = ax * ax
const a = rxSquare * rySquare - rxSquare * pySquare - rySquare * pxSquare
let sr = 0
let startRadian = atan2(BAy, BAx)
let endRadian = atan2(CBy, CBx)
let totalRadian = endRadian - startRadian
if (totalRadian < 0) totalRadian += PI2
if (a < 0) {
const scale = sqrt(1 - a / (rxSquare * rySquare))
rx *= scale
ry *= scale
} else {
const sign = largeFlag === sweepFlag ? -1 : 1
sr = sign * sqrt(a / (rxSquare * pySquare + rySquare * pxSquare))
if (totalRadian === PI || (abs(BAx + BAy) < 1.e-12) || (abs(CBx + CBy) < 1.e-12)) { // invalid
if (data) data.push(PathCommandMap.L, x1, y1)
if (setPointBounds) {
setPoint(setPointBounds, fromX, fromY)
addPoint(setPointBounds, x1, y1)
}
if (setStartPoint) set(setStartPoint, fromX, fromY)
if (setEndPoint) set(setEndPoint, x1, y1)
return
}
const cx = sr * rx * ay / ry
const cy = -sr * ry * ax / rx
const cx1 = cosRotation * cx - sinRotation * cy + localToX * 0.5
const cy1 = sinRotation * cx + cosRotation * cy + localToY * 0.5
const anticlockwise = BAx * CBy - CBx * BAy < 0
const sign = anticlockwise ? -1 : 1
const c = radius / cos(totalRadian / 2)
let r1 = atan2((ay - cy) / ry, (ax - cx) / rx)
let r2 = atan2((-ay - cy) / ry, (-ax - cx) / rx)
let totalRadian = r2 - r1
const centerX = x1 + c * cos(startRadian + totalRadian / 2 + PI_2 * sign)
const centerY = y1 + c * sin(startRadian + totalRadian / 2 + PI_2 * sign)
startRadian -= PI_2 * sign
endRadian -= PI_2 * sign
if (sweepFlag === 0 && totalRadian > 0) {
totalRadian -= 2 * PI
} else if (sweepFlag === 1 && totalRadian < 0) {
totalRadian += 2 * PI
}
return ellipse(data, centerX, centerY, radius, radius, 0, startRadian / OneRadian, endRadian / OneRadian, anticlockwise, setPointBounds, setEndPoint, setStartPoint)
},
// segments arc
const data: IPathCommandData = []
const segments = ceil(abs(totalRadian / PI * 2))
const segmentRadian = totalRadian / segments
const sinSegmentRadian2 = sin(segmentRadian / 2)
const sinSegmentRadian4 = sin(segmentRadian / 4)
const controlRadian = 8 / 3 * sinSegmentRadian4 * sinSegmentRadian4 / sinSegmentRadian2
arc(data: IPathCommandData | null | void, x: number, y: number, radius: number, startAngle: number, endAngle: number, anticlockwise?: boolean, setPointBounds?: ITwoPointBoundsData, setEndPoint?: IPointData, setStartPoint?: IPointData): void {
return ellipse(data, x, y, radius, radius, 0, startAngle, endAngle, anticlockwise, setPointBounds, setEndPoint, setStartPoint)
},
r1 = 0
r2 = atan2((ay - cy) / ry, (ax - cx) / rx)
let startRadian = r2 - r1
let endRadian = startRadian + segmentRadian
let cosStart = cos(startRadian)
let sinStart = sin(startRadian)
let cosEnd: number, sinEnd: number
let startX = 0, startY = 0
ellipse(data: IPathCommandData | null | void, cx: number, cy: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, anticlockwise?: boolean, setPointBounds?: ITwoPointBoundsData, setEndPoint?: IPointData, setStartPoint?: IPointData): void {
const rotationRadian = rotation * OneRadian
const rotationSin = sin(rotationRadian)
const rotationCos = cos(rotationRadian)
let startRadian = startAngle * OneRadian
let endRadian = endAngle * OneRadian
if (startRadian > PI) startRadian -= PI2
if (endRadian < 0) endRadian += PI2
let totalRadian = endRadian - startRadian
if (totalRadian < 0) totalRadian += PI2
else if (totalRadian > PI2) totalRadian -= PI2
if (anticlockwise) totalRadian -= PI2
const parts = ceil(abs(totalRadian / PI_2))
const partRadian = totalRadian / parts
const partRadian4Sin = sin(partRadian / 4)
const control = 8 / 3 * partRadian4Sin * partRadian4Sin / sin(partRadian / 2)
endRadian = startRadian + partRadian
let startCos = cos(startRadian)
let startSin = sin(startRadian)
let endCos: number, endSin: number
let x: number, y: number, x1: number, y1: number, x2: number, y2: number
for (let i = 0; i < segments; i++) {
cosEnd = cos(endRadian)
sinEnd = sin(endRadian)
let startX = x = rotationCos * radiusX * startCos - rotationSin * radiusY * startSin
let startY = y = rotationSin * radiusX * startCos + rotationCos * radiusY * startSin
// segment bezier
x = cosRotation * rx * cosEnd - sinRotation * ry * sinEnd + cx1
y = sinRotation * rx * cosEnd + cosRotation * ry * sinEnd + cy1
x1 = startX + controlRadian * (-cosRotation * rx * sinStart - sinRotation * ry * cosStart)
y1 = startY + controlRadian * (-sinRotation * rx * sinStart + cosRotation * ry * cosStart)
x2 = x + controlRadian * (cosRotation * rx * sinEnd + sinRotation * ry * cosEnd)
y2 = y + controlRadian * (sinRotation * rx * sinEnd - cosRotation * ry * cosEnd)
let fromX = cx + x, fromY = cy + y
data.push(PathCommandMap.C, x1 + fromX, y1 + fromY, x2 + fromX, y2 + fromY, x + fromX, y + fromY)
if (data) data.push(PathCommandMap.L, fromX, fromY)
if (setPointBounds) setPoint(setPointBounds, fromX, fromY)
if (setStartPoint) set(setStartPoint, fromX, fromY)
for (let i = 0; i < parts; i++) {
endCos = cos(endRadian)
endSin = sin(endRadian)
x = rotationCos * radiusX * endCos - rotationSin * radiusY * endSin
y = rotationSin * radiusX * endCos + rotationCos * radiusY * endSin
x1 = cx + startX - control * (rotationCos * radiusX * startSin + rotationSin * radiusY * startCos)
y1 = cy + startY - control * (rotationSin * radiusX * startSin - rotationCos * radiusY * startCos)
x2 = cx + x + control * (rotationCos * radiusX * endSin + rotationSin * radiusY * endCos)
y2 = cy + y + control * (rotationSin * radiusX * endSin - rotationCos * radiusY * endCos)
if (data) data.push(PathCommandMap.C, x1, y1, x2, y2, cx + x, cy + y)
if (setPointBounds) toTwoPointBounds(cx + startX, cy + startY, x1, y1, x2, y2, cx + x, cy + y, setPointBounds, true)
startX = x
startY = y
startCos = endCos
startSin = endSin
startRadian = endRadian
cosStart = cosEnd
sinStart = sinEnd
endRadian += segmentRadian
endRadian += partRadian
}
return data
if (setEndPoint) set(setEndPoint, cx + x, cy + y)
},
toTwoPointBounds(fromX: number, fromY: number, x1: number, y1: number, x2: number, y2: number, toX: number, toY: number, pointBounds: ITwoPointBoundsData): void {
quadraticCurveTo(data: IPathCommandData, fromX: number, fromY: number, x1: number, y1: number, toX: number, toY: number): void {
data.push(PathCommandMap.C, (fromX + 2 * x1) / 3, (fromY + 2 * y1) / 3, (toX + 2 * x1) / 3, (toY + 2 * y1) / 3, toX, toY)
},
toTwoPointBoundsByQuadraticCurve(fromX: number, fromY: number, x1: number, y1: number, toX: number, toY: number, pointBounds: ITwoPointBoundsData, addMode?: boolean): void {
toTwoPointBounds(fromX, fromY, (fromX + 2 * x1) / 3, (fromY + 2 * y1) / 3, (toX + 2 * x1) / 3, (toY + 2 * y1) / 3, toX, toY, pointBounds, addMode)
},
toTwoPointBounds(fromX: number, fromY: number, x1: number, y1: number, x2: number, y2: number, toX: number, toY: number, pointBounds: ITwoPointBoundsData, addMode?: boolean): void {
const tList = []

@@ -134,9 +172,10 @@ let a, b, c, t, t1, t2, v, sqrtV

setPoint(pointBounds, fromX, fromY)
addMode ? addPoint(pointBounds, fromX, fromY) : setPoint(pointBounds, fromX, fromY)
addPoint(pointBounds, toX, toY)
for (let i = 0, len = tList.length; i < len; i++) {
B.getPointAndSet(tList[i], fromX, fromY, x1, y1, x2, y2, toX, toY, tempPoint)
getPointAndSet(tList[i], fromX, fromY, x1, y1, x2, y2, toX, toY, tempPoint)
addPoint(pointBounds, tempPoint.x, tempPoint.y)
}
},

@@ -152,8 +191,7 @@

const point = {} as IPointData
B.getPointAndSet(t, fromX, fromY, x1, y1, x2, y2, toX, toY, point)
getPointAndSet(t, fromX, fromY, x1, y1, x2, y2, toX, toY, point)
return point
}
}
const B = BezierHelper
const { getPointAndSet, toTwoPointBounds, ellipse } = BezierHelper

@@ -0,5 +1,21 @@

export { PathHelper } from './PathHelper'
export { PathConvert } from './PathConvert'
export { PathHelper } from './PathHelper'
export { PathCreator } from './PathCreator'
export { PathCommandDataHelper } from './PathCommandDataHelper'
export { PathDrawer } from './PathDrawer'
export { PathBounds } from './PathBounds'
export { PathCorner } from './PathCorner'
export { BezierHelper } from './BezierHelper'
export { PathCommandMap, PathCommandNeedConvertMap, NumberPathCommandMap, NumberPathCommandLengthMap } from './PathCommandMap'
export { EllipseHelper } from './EllipseHelper'
export { RectHelper } from './RectHelper'
export { PathCommandMap, NeedConvertToCanvasCommandMap, PathNumberCommandMap, PathNumberCommandLengthMap } from './PathCommandMap'
// rewrite, prevent circular references
import { PathConvert } from './PathConvert'
import { PathCreator } from './PathCreator'
import { PathHelper } from './PathHelper'
PathHelper.creator = new PathCreator()
PathHelper.parse = PathConvert.parse
PathHelper.convertToCanvasData = PathConvert.toCanvasData
import { INumberMap, IStringMap } from '@leafer/interface'
export const CanvasCommandOnlyMap: INumberMap = {
N: 21, // rect
D: 22, // roundRect
X: 23, // simple roundRect
G: 24, // ellipse
F: 25, // simple ellipse
O: 26, // arc
P: 27, // simple arc
U: 28 // arcTo
}
export const PathCommandMap: INumberMap = {
M: 1, //moveto
// svg and canvas
M: 1, // moveto
m: 10,
L: 2, //lineto
L: 2, // lineto
l: 20,
H: 3, //horizontal lineto
H: 3, // horizontal lineto
h: 30,
V: 4, //vertical lineto
V: 4, // vertical lineto
v: 40,
C: 5, //curveto
C: 5, // curveto
c: 50,
S: 6, //smooth curveto
S: 6, // smooth curveto
s: 60,
Q: 7, //quadratic Belzier curve
Q: 7, // quadratic Belzier curve
q: 70,
T: 8, //smooth quadratic Belzier curveto
T: 8, // smooth quadratic Belzier curveto
t: 80,
A: 9, //elliptical Arc
A: 9, //e lliptical Arc
a: 90,
Z: 11, //closepath
Z: 11, // closepath
z: 11,
// 非svg标准的canvas绘图命令
rect: 100,
roundRect: 101,
ellipse: 102,
arc: 103,
arcTo: 104
R: 12, // Catmull Rom
// canvas
...CanvasCommandOnlyMap
}
export const PathCommandLengthMap: INumberMap = {
M: 3, //moveto

@@ -56,11 +70,17 @@ m: 3,

// 非svg标准的canvas绘图命令
rect: 5,
roundRect: 6,
ellipse: 9,
arc: 7,
arcTo: 6
// canvas
N: 5, // rect
D: 9, // roundRect
X: 6, // simple roundRect
G: 9, // ellipse
F: 5, // simple ellipse
O: 7, // arc
P: 4, // simple arc
U: 6 // arcTo
}
export const PathCommandNeedConvertMap: INumberMap = { // convert to: M L C Q Z
export const NeedConvertToCanvasCommandMap: INumberMap = { // convert to: M L C Q Z
// M: 1, //moveto

@@ -87,23 +107,22 @@ m: 10,

// 非svg标准的canvas绘图命令
rect: 100,
roundRect: 101,
ellipse: 102,
arc: 103,
arcTo: 104
}
export const NeedConvertToCurveCommandMap: INumberMap = {
...NeedConvertToCanvasCommandMap,
...CanvasCommandOnlyMap
}
const P = PathCommandMap
export const NumberPathCommandMap: IStringMap = {}
export const PathNumberCommandMap: IStringMap = {}
for (let key in P) {
NumberPathCommandMap[P[key]] = key
PathNumberCommandMap[P[key]] = key
}
// {1: 'M'}
export const NumberPathCommandLengthMap: INumberMap = {}
export const PathNumberCommandLengthMap: INumberMap = {}
for (let key in P) {
NumberPathCommandLengthMap[P[key]] = PathCommandLengthMap[key]
PathNumberCommandLengthMap[P[key]] = PathCommandLengthMap[key]
}
// {1: 3}

@@ -1,6 +0,8 @@

import { IPathCommandData } from '@leafer/interface'
import { IPathCommandData, IPointData } from '@leafer/interface'
import { StringNumberMap } from '@leafer/math'
import { PathCommandMap as Command, PathCommandNeedConvertMap as NeedConvertCommand, PathCommandLengthMap as CommandLength, NumberPathCommandMap as CommandName, NumberPathCommandLengthMap as NumberCommandLength } from './PathCommandMap'
import { Debug } from '@leafer/debug'
import { PathCommandMap as Command, NeedConvertToCanvasCommandMap, NeedConvertToCurveCommandMap, PathCommandLengthMap, PathNumberCommandMap, PathNumberCommandLengthMap } from './PathCommandMap'
import { BezierHelper } from './BezierHelper'
import { EllipseHelper } from './EllipseHelper'

@@ -15,5 +17,9 @@

const { M, m, L, l, H, h, V, v, C, c, S, s, Q, q, T, t, A, a, Z, z } = Command
const { getFromACommand } = BezierHelper
const { M, m, L, l, H, h, V, v, C, c, S, s, Q, q, T, t, A, a, Z, z, N, D, X, G, F, O, P, U } = Command
const { rect, roundRect, arcTo, arc, ellipse, quadraticCurveTo } = BezierHelper
const { ellipticalArc } = EllipseHelper
const debug = Debug.get('PathConvert')
const setEndPoint = {} as IPointData
export const PathConvert = {

@@ -27,7 +33,7 @@

command = data[i]
count = NumberCommandLength[command]
count = PathNumberCommandLengthMap[command]
if (command === lastCommand) {
str += ' ' // 重复的命令可以省略
} else {
str += CommandName[command]
str += PathNumberCommandMap[command]
}

@@ -46,6 +52,7 @@

parse(pathString: string, convert: boolean = true): IPathCommandData {
parse(pathString: string, curveMode?: boolean): IPathCommandData {
let needConvert: boolean, char: string, num = ''
let needConvert: boolean, char: string, lastChar: string, num = ''
const data: IPathCommandData = []
const convertCommand = curveMode ? NeedConvertToCurveCommandMap : NeedConvertToCanvasCommandMap

@@ -65,13 +72,19 @@ for (let i = 0, len = pathString.length; i < len; i++) {

current.name = Command[char]
current.length = CommandLength[char]
current.length = PathCommandLengthMap[char]
current.index = 0
pushData(data, current.name)
if (!needConvert && NeedConvertCommand[char]) needConvert = true
if (!needConvert && convertCommand[char]) needConvert = true
} else {
if (char === '-') { // L-34-35
if (num) { pushData(data, Number(num)) }
num = char
if (char === '-' || char === '+') {
if (lastChar === 'e' || lastChar === 'E') { // L45e-12 21e+22
num += char
} else {
if (num) pushData(data, Number(num)) // L-34-35 L+12+28
num = char
}
} else {

@@ -83,2 +96,4 @@ if (num) { pushData(data, Number(num)); num = '' }

lastChar = char
}

@@ -88,6 +103,6 @@

return (convert && needConvert) ? PathConvert.convertToSimple(data) : data
return needConvert ? PathConvert.toCanvasData(data, curveMode) : data
},
convertToSimple(old: IPathCommandData): IPathCommandData {
toCanvasData(old: IPathCommandData, curveMode?: boolean): IPathCommandData {

@@ -102,3 +117,3 @@ let x = 0, y = 0, x1 = 0, y1 = 0, i = 0, len = old.length, controlX: number, controlY: number, command: number, lastCommand: number, smooth: boolean

switch (command) {
//moveto x,y
//moveto(x, y)
case m:

@@ -114,3 +129,3 @@ old[i + 1] += x

//horizontal lineto x
//horizontal lineto(x)
case h:

@@ -124,3 +139,3 @@ old[i + 1] += x

//vertical lineto y
//vertical lineto(y)
case v:

@@ -134,3 +149,3 @@ old[i + 1] += y

//lineto x,y
//lineto(x,y)
case l:

@@ -146,3 +161,3 @@ old[i + 1] += x

//smooth bezierCurveTo x2,y2,x,y
//smooth bezierCurveTo(x2, y2, x, y)
case s: //smooth

@@ -166,3 +181,3 @@ old[i + 1] += x

//bezierCurveTo x1,y1,x2,y2,x,y
//bezierCurveTo(x1, y1, x2, y2, x, y)
case c:

@@ -185,3 +200,3 @@ old[i + 1] += x

//smooth quadraticCurveTo x,y
//smooth quadraticCurveTo(x, y)
case t:

@@ -195,9 +210,9 @@ old[i + 1] += x

controlY = smooth ? (y * 2 - controlY) : old[i + 2]
curveMode ? quadraticCurveTo(data, x, y, controlX, controlY, old[i + 1], old[i + 2]) : data.push(Q, controlX, controlY, old[i + 1], old[i + 2])
x = old[i + 1]
y = old[i + 2]
data.push(Q, controlX, controlY, x, y)
i += 3
break
//quadraticCurveTo x1,y1,x,y
//quadraticCurveTo(x1, y1, x, y)
case q:

@@ -212,9 +227,9 @@ old[i + 1] += x

controlY = old[i + 2]
curveMode ? quadraticCurveTo(data, x, y, controlX, controlY, old[i + 3], old[i + 4]) : data.push(Q, controlX, controlY, old[i + 3], old[i + 4])
x = old[i + 3]
y = old[i + 4]
data.push(Q, controlX, controlY, x, y)
i += 5
break
//ellipticalArc rx ry x-axis-rotation large-arc-flag sweep-flag x y
//ellipticalArc(rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y)
case a:

@@ -224,3 +239,3 @@ old[i + 6] += x

case A:
data.push(...getFromACommand(x, y, old[i + 1], old[i + 2], old[i + 3], old[i + 4], old[i + 5], old[i + 6], old[i + 7])) // convert bezier
ellipticalArc(data, x, y, old[i + 1], old[i + 2], old[i + 3], old[i + 4], old[i + 5], old[i + 6], old[i + 7], curveMode) // convert to canvas ellipse or curve
x = old[i + 6]

@@ -235,2 +250,57 @@ y = old[i + 7]

break
// canvas command
case N: // rect(x, y, width, height)
x = old[i + 1]
y = old[i + 2]
curveMode ? rect(data, x, y, old[i + 3], old[i + 4]) : copyData(data, old, i, 5)
i += 5
break
case D: // roundRect(x, y, width, height, radius1, radius2, radius3, radius4)
x = old[i + 1]
y = old[i + 2]
curveMode ? roundRect(data, x, y, old[i + 3], old[i + 4], [old[i + 5], old[i + 6], old[i + 7], old[i + 8]]) : copyData(data, old, i, 9)
i += 9
break
case X: // simple roundRect(x, y, width, height, radius)
x = old[i + 1]
y = old[i + 2]
curveMode ? roundRect(data, x, y, old[i + 3], old[i + 4], old[i + 5]) : copyData(data, old, i, 6)
i += 6
break
case G: // ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
ellipse(curveMode ? data : copyData(data, old, i, 9), old[i + 1], old[i + 2], old[i + 3], old[i + 4], old[i + 5], old[i + 6], old[i + 7], old[i + 8] as unknown as boolean, null, setEndPoint)
x = setEndPoint.x
y = setEndPoint.y
i += 9
break
case F: // simple ellipse(x, y, radiusX, radiusY)
curveMode ? ellipse(data, old[i + 1], old[i + 2], old[i + 3], old[i + 4], 0, 0, 360, false) : copyData(data, old, i, 5)
x = old[i + 1] + old[i + 3]
y = old[i + 2]
i += 5
break
case O: // arc(x, y, radius, startAngle, endAngle, anticlockwise)
arc(curveMode ? data : copyData(data, old, i, 7), old[i + 1], old[i + 2], old[i + 3], old[i + 4], old[i + 5], old[i + 6] as unknown as boolean, null, setEndPoint)
x = setEndPoint.x
y = setEndPoint.y
i += 7
break
case P: // simple arc(x, y, radius)
curveMode ? arc(data, old[i + 1], old[i + 2], old[i + 3], 0, 360, false) : copyData(data, old, i, 4)
x = old[i + 1] + old[i + 3]
y = old[i + 2]
i += 4
break
case U: // arcTo(x1, y1, x2, y2, radius)
arcTo(curveMode ? data : copyData(data, old, i, 6), x, y, old[i + 1], old[i + 2], old[i + 3], old[i + 4], old[i + 5], null, setEndPoint)
x = setEndPoint.x
y = setEndPoint.y
i += 6
break
default:
debug.error(`command: ${command} [index:${i}]`, old)
return data
}

@@ -245,2 +315,8 @@

copyData(data: IPathCommandData, old: IPathCommandData, index: number, count: number): void {
for (let i = index, end = index + count; i < end; i++) {
data.push(old[i])
}
},
pushData(data: IPathCommandData, num: number) {

@@ -258,2 +334,2 @@ if (current.index === current.length) { // 单个命令,多个数据的情况

const { current, pushData } = PathConvert
const { current, pushData, copyData } = PathConvert

@@ -1,64 +0,92 @@

import { IPathCommandData } from '@leafer/interface'
import { PathCommandMap } from './PathCommandMap'
import { IPathCommandData, IPathDrawer } from '@leafer/interface'
import { PathCommandDataHelper } from './PathCommandDataHelper'
import { IPathString } from '@leafer-ui/interface'
import { PathHelper } from './PathHelper'
let data: IPathCommandData
const { M, L, C, Q, Z, rect, roundRect, ellipse, arc, arcTo } = PathCommandMap
const { moveTo, lineTo, quadraticCurveTo, bezierCurveTo, closePath, beginPath, rect, roundRect, ellipse, arc, arcTo, moveToEllipse, moveToArc } = PathCommandDataHelper
export const PathCreator = {
export class PathCreator implements IPathDrawer {
begin(commandData: IPathCommandData): void {
data = commandData
},
public path: IPathCommandData
end(): void {
data = null
},
constructor(path?: IPathCommandData | IPathString) {
if (path) {
this.path = typeof path === 'string' ? PathHelper.parse(path) : path
} else {
this.path = []
}
}
// draw
public beginPath(): PathCreator {
beginPath(this.path)
return this
}
moveTo(x: number, y: number): void {
data.push(M, x, y)
},
// svg and canvas
lineTo(x: number, y: number): void {
data.push(L, x, y)
},
public moveTo(x: number, y: number): PathCreator {
moveTo(this.path, x, y)
return this
}
bezierCurveTo(x1: number, y1: number, x2: number, y2: number, x: number, y: number): void {
data.push(C, x1, y1, x2, y2, x, y)
},
public lineTo(x: number, y: number): PathCreator {
lineTo(this.path, x, y)
return this
}
quadraticCurveTo(x1: number, y1: number, x: number, y: number): void {
data.push(Q, x1, y1, x, y)
},
public bezierCurveTo(x1: number, y1: number, x2: number, y2: number, x: number, y: number): PathCreator {
bezierCurveTo(this.path, x1, y1, x2, y2, x, y)
return this
}
close(end?: boolean): void {
data.push(Z)
if (end) data = null
},
public quadraticCurveTo(x1: number, y1: number, x: number, y: number): PathCreator {
quadraticCurveTo(this.path, x1, y1, x, y)
return this
}
public closePath(): PathCreator {
closePath(this.path)
return this
}
// 非svg标准的canvas绘图命令
// canvas
rect(x: number, y: number, width: number, height: number): void {
data.push(rect, x, y, width, height)
},
public rect(x: number, y: number, width: number, height: number): PathCreator {
rect(this.path, x, y, width, height)
return this
}
roundRect(x: number, y: number, width: number, height: number, cornerRadius?: number | number[]): void {
data.push(roundRect, x, y, width, height, cornerRadius as unknown as number)
},
public roundRect(x: number, y: number, width: number, height: number, cornerRadius: number | number[]): PathCreator {
roundRect(this.path, x, y, width, height, cornerRadius)
return this
}
ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void {
data.push(ellipse, x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise as unknown as number)
},
public ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation?: number, startAngle?: number, endAngle?: number, anticlockwise?: boolean): PathCreator {
ellipse(this.path, x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
return this
}
arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void {
data.push(arc, x, y, radius, startAngle, endAngle, counterclockwise as unknown as number)
},
public arc(x: number, y: number, radius: number, startAngle?: number, endAngle?: number, anticlockwise?: boolean): PathCreator {
arc(this.path, x, y, radius, startAngle, endAngle, anticlockwise)
return this
}
arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void {
data.push(arcTo, x1, y1, x2, y2, radius)
public arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): PathCreator {
arcTo(this.path, x1, y1, x2, y2, radius)
return this
}
// moveTo, then draw
public moveToEllipse(x: number, y: number, radiusX: number, radiusY: number, rotation?: number, startAngle?: number, endAngle?: number, anticlockwise?: boolean): PathCreator {
moveToEllipse(this.path, x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
return this
}
public moveToArc(x: number, y: number, radius: number, startAngle?: number, endAngle?: number, anticlockwise?: boolean): PathCreator {
moveToArc(this.path, x, y, radius, startAngle, endAngle, anticlockwise)
return this
}
}

@@ -1,123 +0,8 @@

import { IPathDrawer, ITwoPointBoundsData, IPathCommandData, IBoundsData } from '@leafer/interface'
import { TwoPointBoundsHelper } from '@leafer/math'
import { IPathCommandData, IPathCreator } from '@leafer/interface'
import { BezierHelper } from './BezierHelper'
import { PathCommandMap as Command } from './PathCommandMap'
const { M, L, C, Q, Z, ellipse: E } = Command
const { toTwoPointBounds } = BezierHelper
const { add, addPoint, setPoint, toBounds } = TwoPointBoundsHelper
const tempPointBounds = {} as ITwoPointBoundsData
const setPointBounds = {} as ITwoPointBoundsData
export const PathHelper = {
smoothCorner(data: IPathCommandData, _cornerRadius: number, _cornerSmoothing?: number): IPathCommandData {
return data
},
toBounds(data: IPathCommandData, setBounds: IBoundsData): void {
P.toTwoPointBounds(data, setPointBounds)
toBounds(setPointBounds, setBounds)
},
toTwoPointBounds(data: IPathCommandData, setPointBounds: ITwoPointBoundsData): void {
let command: number
let i: number = 0, x: number, y: number, x1: number, y1: number, toX: number, toY: number
const len = data.length
while (i < len) {
command = data[i]
if (i === 0) {
(command === M) ? setPoint(setPointBounds, data[1], data[2]) : setPoint(setPointBounds, 0, 0)
}
switch (command) {
case M: //moveto x,y
case L: //lineto x,y
x = data[i + 1]
y = data[i + 2]
addPoint(setPointBounds, x, y)
i += 3
break
case C: //bezierCurveTo x1,y1,x2,y2,x,y
toX = data[i + 5]
toY = data[i + 6]
toTwoPointBounds(x, y, data[i + 1], data[i + 2], data[i + 3], data[i + 4], toX, toY, tempPointBounds)
add(setPointBounds, tempPointBounds)
x = toX
y = toY
i += 7
break
case Q: //quadraticCurveTo x1,y1,x,y
x1 = data[i + 1]
y1 = data[i + 2]
toX = data[i + 3]
toY = data[i + 4]
toTwoPointBounds(x, y, x1, y1, x1, y1, toX, toY, tempPointBounds)
add(setPointBounds, tempPointBounds)
x = toX
y = toY
i += 5
break
case Z: //closepath
i += 1
break
}
}
// 增加1px的扩展,否则会有问题
setPointBounds.minX--
setPointBounds.minY--
setPointBounds.maxX++
setPointBounds.maxY++
},
drawData(drawer: IPathDrawer, data: IPathCommandData): void {
if (data) {
let command: number
let i = 0, len = data.length
while (i < len) {
command = data[i]
switch (command) {
case M: //moveto x,y
drawer.moveTo(data[i + 1], data[i + 2])
i += 3
break
case L: //lineto x,y
drawer.lineTo(data[i + 1], data[i + 2])
i += 3
break
case C: //bezierCurveTo x1,y1,x2,y2,x,y
drawer.bezierCurveTo(data[i + 1], data[i + 2], data[i + 3], data[i + 4], data[i + 5], data[i + 6])
i += 7
break
case Q: //quadraticCurveTo x1,y1,x,y
drawer.quadraticCurveTo(data[i + 1], data[i + 2], data[i + 3], data[i + 4])
i += 5
break
case Z: //closepath
drawer.closePath()
i += 1
break
// 非svg标准的canvas绘图命令
case E:
drawer.ellipse(data[i + 1], data[i + 2], data[i + 3], data[i + 4], data[i + 5], data[i + 6], data[i + 7], data[i + 8] as unknown as boolean)
i += 9
break
}
}
}
}
}
const P = PathHelper
// index.ts rewrite
creator: {} as IPathCreator,
parse(_pathString: string, _curveMode?: boolean): IPathCommandData { return undefined },
convertToCanvasData(_old: IPathCommandData, _curveMode?: boolean): IPathCommandData { return undefined }
}