680 lines
16 KiB
JavaScript
680 lines
16 KiB
JavaScript
/**
|
||
* svg路径绘制。
|
||
* 作者:tmzdy
|
||
* url:https://jx2d.cn
|
||
*/
|
||
function parsePathData(data) {
|
||
if (!data) {
|
||
return [];
|
||
}
|
||
var cs = data;
|
||
var cc = [
|
||
'm',
|
||
'M',
|
||
'l',
|
||
'L',
|
||
'v',
|
||
'V',
|
||
'h',
|
||
'H',
|
||
'z',
|
||
'Z',
|
||
'c',
|
||
'C',
|
||
'q',
|
||
'Q',
|
||
't',
|
||
'T',
|
||
's',
|
||
'S',
|
||
'a',
|
||
'A',
|
||
];
|
||
cs = cs.replace(new RegExp(' ', 'g'), ',');
|
||
for (var n = 0; n < cc.length; n++) {
|
||
cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);
|
||
}
|
||
var arr = cs.split('|');
|
||
var ca = [];
|
||
var coords = [];
|
||
var cpx = 0;
|
||
var cpy = 0;
|
||
var re = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/gi;
|
||
var match;
|
||
for (n = 1; n < arr.length; n++) {
|
||
var str = arr[n];
|
||
var c = str.charAt(0);
|
||
str = str.slice(1);
|
||
coords.length = 0;
|
||
while ((match = re.exec(str))) {
|
||
coords.push(match[0]);
|
||
}
|
||
var p = [];
|
||
for (var j = 0, jlen = coords.length; j < jlen; j++) {
|
||
if (coords[j] === '00') {
|
||
p.push(0, 0);
|
||
continue;
|
||
}
|
||
var parsed = parseFloat(coords[j]);
|
||
if (!isNaN(parsed)) {
|
||
p.push(parsed);
|
||
} else {
|
||
p.push(0);
|
||
}
|
||
}
|
||
while (p.length > 0) {
|
||
if (isNaN(p[0])) {
|
||
break;
|
||
}
|
||
var cmd = null;
|
||
var points = [];
|
||
var startX = cpx,
|
||
startY = cpy;
|
||
var prevCmd, ctlPtx, ctlPty;
|
||
var rx, ry, psi, fa, fs, x1, y1;
|
||
switch (c) {
|
||
case 'l':
|
||
cpx += p.shift();
|
||
cpy += p.shift();
|
||
cmd = 'L';
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 'L':
|
||
cpx = p.shift();
|
||
cpy = p.shift();
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 'm':
|
||
var dx = p.shift();
|
||
var dy = p.shift();
|
||
cpx += dx;
|
||
cpy += dy;
|
||
cmd = 'M';
|
||
if (ca.length > 2 && ca[ca.length - 1].command === 'z') {
|
||
for (var idx = ca.length - 2; idx >= 0; idx--) {
|
||
if (ca[idx].command === 'M') {
|
||
cpx = ca[idx].points[0] + dx;
|
||
cpy = ca[idx].points[1] + dy;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
points.push(cpx, cpy);
|
||
c = 'l';
|
||
break;
|
||
case 'M':
|
||
cpx = p.shift();
|
||
cpy = p.shift();
|
||
cmd = 'M';
|
||
points.push(cpx, cpy);
|
||
c = 'L';
|
||
break;
|
||
case 'h':
|
||
cpx += p.shift();
|
||
cmd = 'L';
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 'H':
|
||
cpx = p.shift();
|
||
cmd = 'L';
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 'v':
|
||
cpy += p.shift();
|
||
cmd = 'L';
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 'V':
|
||
cpy = p.shift();
|
||
cmd = 'L';
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 'C':
|
||
points.push(p.shift(), p.shift(), p.shift(), p.shift());
|
||
cpx = p.shift();
|
||
cpy = p.shift();
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 'c':
|
||
points.push(cpx + p.shift(), cpy + p.shift(), cpx + p.shift(), cpy + p.shift());
|
||
cpx += p.shift();
|
||
cpy += p.shift();
|
||
cmd = 'C';
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 'S':
|
||
ctlPtx = cpx;
|
||
ctlPty = cpy;
|
||
prevCmd = ca[ca.length - 1];
|
||
if (prevCmd.command === 'C') {
|
||
ctlPtx = cpx + (cpx - prevCmd.points[2]);
|
||
ctlPty = cpy + (cpy - prevCmd.points[3]);
|
||
}
|
||
points.push(ctlPtx, ctlPty, p.shift(), p.shift());
|
||
cpx = p.shift();
|
||
cpy = p.shift();
|
||
cmd = 'C';
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 's':
|
||
ctlPtx = cpx;
|
||
ctlPty = cpy;
|
||
prevCmd = ca[ca.length - 1];
|
||
if (prevCmd.command === 'C') {
|
||
ctlPtx = cpx + (cpx - prevCmd.points[2]);
|
||
ctlPty = cpy + (cpy - prevCmd.points[3]);
|
||
}
|
||
points.push(ctlPtx, ctlPty, cpx + p.shift(), cpy + p.shift());
|
||
cpx += p.shift();
|
||
cpy += p.shift();
|
||
cmd = 'C';
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 'Q':
|
||
points.push(p.shift(), p.shift());
|
||
cpx = p.shift();
|
||
cpy = p.shift();
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 'q':
|
||
points.push(cpx + p.shift(), cpy + p.shift());
|
||
cpx += p.shift();
|
||
cpy += p.shift();
|
||
cmd = 'Q';
|
||
points.push(cpx, cpy);
|
||
break;
|
||
case 'T':
|
||
ctlPtx = cpx;
|
||
ctlPty = cpy;
|
||
prevCmd = ca[ca.length - 1];
|
||
if (prevCmd.command === 'Q') {
|
||
ctlPtx = cpx + (cpx - prevCmd.points[0]);
|
||
ctlPty = cpy + (cpy - prevCmd.points[1]);
|
||
}
|
||
cpx = p.shift();
|
||
cpy = p.shift();
|
||
cmd = 'Q';
|
||
points.push(ctlPtx, ctlPty, cpx, cpy);
|
||
break;
|
||
case 't':
|
||
ctlPtx = cpx;
|
||
ctlPty = cpy;
|
||
prevCmd = ca[ca.length - 1];
|
||
if (prevCmd.command === 'Q') {
|
||
ctlPtx = cpx + (cpx - prevCmd.points[0]);
|
||
ctlPty = cpy + (cpy - prevCmd.points[1]);
|
||
}
|
||
cpx += p.shift();
|
||
cpy += p.shift();
|
||
cmd = 'Q';
|
||
points.push(ctlPtx, ctlPty, cpx, cpy);
|
||
break;
|
||
case 'A':
|
||
rx = p.shift();
|
||
ry = p.shift();
|
||
psi = p.shift();
|
||
fa = p.shift();
|
||
fs = p.shift();
|
||
x1 = cpx;
|
||
y1 = cpy;
|
||
cpx = p.shift();
|
||
cpy = p.shift();
|
||
cmd = 'A';
|
||
points = convertEndpointToCenterParameterization(x1, y1, cpx, cpy, fa, fs, rx, ry, psi);
|
||
break;
|
||
case 'a':
|
||
rx = p.shift();
|
||
ry = p.shift();
|
||
psi = p.shift();
|
||
fa = p.shift();
|
||
fs = p.shift();
|
||
x1 = cpx;
|
||
y1 = cpy;
|
||
cpx += p.shift();
|
||
cpy += p.shift();
|
||
cmd = 'A';
|
||
points = convertEndpointToCenterParameterization(x1, y1, cpx, cpy, fa, fs, rx, ry, psi);
|
||
break;
|
||
}
|
||
ca.push({
|
||
command: cmd || c,
|
||
points: points,
|
||
start: {
|
||
x: startX,
|
||
y: startY,
|
||
},
|
||
pathLength: calcLength(startX, startY, cmd || c, points),
|
||
});
|
||
}
|
||
if (c === 'z' || c === 'Z') {
|
||
ca.push({
|
||
command: 'z',
|
||
points: [],
|
||
start: undefined,
|
||
pathLength: 0,
|
||
});
|
||
}
|
||
}
|
||
return ca;
|
||
}
|
||
|
||
function calcLength(x, y, cmd, points) {
|
||
var len, p1, p2, t;
|
||
|
||
switch (cmd) {
|
||
case 'L':
|
||
return getLineLength(x, y, points[0], points[1]);
|
||
case 'C':
|
||
len = 0.0;
|
||
p1 = getPointOnCubicBezier(0, x, y, points[0], points[1], points[2], points[3], points[4], points[5]);
|
||
for (t = 0.01; t <= 1; t += 0.01) {
|
||
p2 = getPointOnCubicBezier(t, x, y, points[0], points[1], points[2], points[3], points[4], points[
|
||
5]);
|
||
len += getLineLength(p1.x, p1.y, p2.x, p2.y);
|
||
p1 = p2;
|
||
}
|
||
return len;
|
||
case 'Q':
|
||
len = 0.0;
|
||
p1 = getPointOnQuadraticBezier(0, x, y, points[0], points[1], points[2], points[3]);
|
||
for (t = 0.01; t <= 1; t += 0.01) {
|
||
p2 = getPointOnQuadraticBezier(t, x, y, points[0], points[1], points[2], points[3]);
|
||
len += getLineLength(p1.x, p1.y, p2.x, p2.y);
|
||
p1 = p2;
|
||
}
|
||
return len;
|
||
case 'A':
|
||
len = 0.0;
|
||
var start = points[4];
|
||
var dTheta = points[5];
|
||
var end = points[4] + dTheta;
|
||
var inc = Math.PI / 180.0;
|
||
if (Math.abs(start - end) < inc) {
|
||
inc = Math.abs(start - end);
|
||
}
|
||
p1 = getPointOnEllipticalArc(points[0], points[1], points[2], points[3], start, 0);
|
||
if (dTheta < 0) {
|
||
for (t = start - inc; t > end; t -= inc) {
|
||
p2 = getPointOnEllipticalArc(points[0], points[1], points[2], points[3], t, 0);
|
||
len += getLineLength(p1.x, p1.y, p2.x, p2.y);
|
||
p1 = p2;
|
||
}
|
||
} else {
|
||
for (t = start + inc; t < end; t += inc) {
|
||
p2 = getPointOnEllipticalArc(points[0], points[1], points[2], points[3], t, 0);
|
||
len += getLineLength(p1.x, p1.y, p2.x, p2.y);
|
||
p1 = p2;
|
||
}
|
||
}
|
||
p2 = getPointOnEllipticalArc(points[0], points[1], points[2], points[3], end, 0);
|
||
len += getLineLength(p1.x, p1.y, p2.x, p2.y);
|
||
return len;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
function convertEndpointToCenterParameterization(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg) {
|
||
var psi = psiDeg * (Math.PI / 180.0);
|
||
var xp = (Math.cos(psi) * (x1 - x2)) / 2.0 + (Math.sin(psi) * (y1 - y2)) / 2.0;
|
||
var yp = (-1 * Math.sin(psi) * (x1 - x2)) / 2.0 +
|
||
(Math.cos(psi) * (y1 - y2)) / 2.0;
|
||
var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);
|
||
if (lambda > 1) {
|
||
rx *= Math.sqrt(lambda);
|
||
ry *= Math.sqrt(lambda);
|
||
}
|
||
var f = Math.sqrt((rx * rx * (ry * ry) - rx * rx * (yp * yp) - ry * ry * (xp * xp)) /
|
||
(rx * rx * (yp * yp) + ry * ry * (xp * xp)));
|
||
if (fa === fs) {
|
||
f *= -1;
|
||
}
|
||
if (isNaN(f)) {
|
||
f = 0;
|
||
}
|
||
var cxp = (f * rx * yp) / ry;
|
||
var cyp = (f * -ry * xp) / rx;
|
||
var cx = (x1 + x2) / 2.0 + Math.cos(psi) * cxp - Math.sin(psi) * cyp;
|
||
var cy = (y1 + y2) / 2.0 + Math.sin(psi) * cxp + Math.cos(psi) * cyp;
|
||
var vMag = function(v) {
|
||
return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
||
};
|
||
var vRatio = function(u, v) {
|
||
return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
|
||
};
|
||
var vAngle = function(u, v) {
|
||
return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v));
|
||
};
|
||
var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]);
|
||
var u = [(xp - cxp) / rx, (yp - cyp) / ry];
|
||
var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry];
|
||
var dTheta = vAngle(u, v);
|
||
if (vRatio(u, v) <= -1) {
|
||
dTheta = Math.PI;
|
||
}
|
||
if (vRatio(u, v) >= 1) {
|
||
dTheta = 0;
|
||
}
|
||
if (fs === 0 && dTheta > 0) {
|
||
dTheta = dTheta - 2 * Math.PI;
|
||
}
|
||
if (fs === 1 && dTheta < 0) {
|
||
dTheta = dTheta + 2 * Math.PI;
|
||
}
|
||
return [cx, cy, rx, ry, theta, dTheta, psi, fs];
|
||
}
|
||
|
||
function getSelfRect() {
|
||
var points = [];
|
||
this.dataArray.forEach(function(data) {
|
||
if (data.command === 'A') {
|
||
var start = data.points[4];
|
||
var dTheta = data.points[5];
|
||
var end = data.points[4] + dTheta;
|
||
var inc = Math.PI / 180.0;
|
||
if (Math.abs(start - end) < inc) {
|
||
inc = Math.abs(start - end);
|
||
}
|
||
if (dTheta < 0) {
|
||
for (let t = start - inc; t > end; t -= inc) {
|
||
const point = Path.getPointOnEllipticalArc(data.points[0], data.points[1], data.points[2],
|
||
data.points[3], t, 0);
|
||
points.push(point.x, point.y);
|
||
}
|
||
} else {
|
||
for (let t = start + inc; t < end; t += inc) {
|
||
const point = Path.getPointOnEllipticalArc(data.points[0], data.points[1], data.points[2],
|
||
data.points[3], t, 0);
|
||
points.push(point.x, point.y);
|
||
}
|
||
}
|
||
} else if (data.command === 'C') {
|
||
for (let t = 0.0; t <= 1; t += 0.01) {
|
||
const point = Path.getPointOnCubicBezier(t, data.start.x, data.start.y, data.points[0], data
|
||
.points[1], data.points[2], data.points[3], data.points[4], data.points[5]);
|
||
points.push(point.x, point.y);
|
||
}
|
||
} else {
|
||
points = points.concat(data.points);
|
||
}
|
||
});
|
||
var minX = points[0];
|
||
var maxX = points[0];
|
||
var minY = points[1];
|
||
var maxY = points[1];
|
||
var x, y;
|
||
for (var i = 0; i < points.length / 2; i++) {
|
||
x = points[i * 2];
|
||
y = points[i * 2 + 1];
|
||
if (!isNaN(x)) {
|
||
minX = Math.min(minX, x);
|
||
maxX = Math.max(maxX, x);
|
||
}
|
||
if (!isNaN(y)) {
|
||
minY = Math.min(minY, y);
|
||
maxY = Math.max(maxY, y);
|
||
}
|
||
}
|
||
return {
|
||
x: Math.round(minX),
|
||
y: Math.round(minY),
|
||
width: Math.round(maxX - minX),
|
||
height: Math.round(maxY - minY),
|
||
};
|
||
}
|
||
|
||
|
||
|
||
function getPointAtLength(length) {
|
||
var point, i = 0,
|
||
ii = this.dataArray.length;
|
||
if (!ii) {
|
||
return null;
|
||
}
|
||
while (i < ii && length > this.dataArray[i].pathLength) {
|
||
length -= this.dataArray[i].pathLength;
|
||
++i;
|
||
}
|
||
if (i === ii) {
|
||
point = this.dataArray[i - 1].points.slice(-2);
|
||
return {
|
||
x: point[0],
|
||
y: point[1],
|
||
};
|
||
}
|
||
if (length < 0.01) {
|
||
point = this.dataArray[i].points.slice(0, 2);
|
||
return {
|
||
x: point[0],
|
||
y: point[1],
|
||
};
|
||
}
|
||
var cp = this.dataArray[i];
|
||
var p = cp.points;
|
||
switch (cp.command) {
|
||
case 'L':
|
||
return Path.getPointOnLine(length, cp.start.x, cp.start.y, p[0], p[1]);
|
||
case 'C':
|
||
return Path.getPointOnCubicBezier(length / cp.pathLength, cp.start.x, cp.start.y, p[0], p[1], p[2], p[3], p[
|
||
4], p[5]);
|
||
case 'Q':
|
||
return Path.getPointOnQuadraticBezier(length / cp.pathLength, cp.start.x, cp.start.y, p[0], p[1], p[2], p[
|
||
3]);
|
||
case 'A':
|
||
var cx = p[0],
|
||
cy = p[1],
|
||
rx = p[2],
|
||
ry = p[3],
|
||
theta = p[4],
|
||
dTheta = p[5],
|
||
psi = p[6];
|
||
theta += (dTheta * length) / cp.pathLength;
|
||
return Path.getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function getLineLength(x1, y1, x2, y2) {
|
||
return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
|
||
}
|
||
|
||
function getPointOnLine(dist, P1x, P1y, P2x, P2y, fromX, fromY) {
|
||
if (fromX === undefined) {
|
||
fromX = P1x;
|
||
}
|
||
if (fromY === undefined) {
|
||
fromY = P1y;
|
||
}
|
||
var m = (P2y - P1y) / (P2x - P1x + 0.00000001);
|
||
var run = Math.sqrt((dist * dist) / (1 + m * m));
|
||
if (P2x < P1x) {
|
||
run *= -1;
|
||
}
|
||
var rise = m * run;
|
||
var pt;
|
||
if (P2x === P1x) {
|
||
pt = {
|
||
x: fromX,
|
||
y: fromY + rise,
|
||
};
|
||
} else if ((fromY - P1y) / (fromX - P1x + 0.00000001) === m) {
|
||
pt = {
|
||
x: fromX + run,
|
||
y: fromY + rise,
|
||
};
|
||
} else {
|
||
var ix, iy;
|
||
var len = this.getLineLength(P1x, P1y, P2x, P2y);
|
||
var u = (fromX - P1x) * (P2x - P1x) + (fromY - P1y) * (P2y - P1y);
|
||
u = u / (len * len);
|
||
ix = P1x + u * (P2x - P1x);
|
||
iy = P1y + u * (P2y - P1y);
|
||
var pRise = this.getLineLength(fromX, fromY, ix, iy);
|
||
var pRun = Math.sqrt(dist * dist - pRise * pRise);
|
||
run = Math.sqrt((pRun * pRun) / (1 + m * m));
|
||
if (P2x < P1x) {
|
||
run *= -1;
|
||
}
|
||
rise = m * run;
|
||
pt = {
|
||
x: ix + run,
|
||
y: iy + rise,
|
||
};
|
||
}
|
||
return pt;
|
||
}
|
||
function getPointOnCubicBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y, P4x, P4y) {
|
||
function CB1(t) {
|
||
return t * t * t;
|
||
}
|
||
|
||
function CB2(t) {
|
||
return 3 * t * t * (1 - t);
|
||
}
|
||
|
||
function CB3(t) {
|
||
return 3 * t * (1 - t) * (1 - t);
|
||
}
|
||
|
||
function CB4(t) {
|
||
return (1 - t) * (1 - t) * (1 - t);
|
||
}
|
||
var x = P4x * CB1(pct) + P3x * CB2(pct) + P2x * CB3(pct) + P1x * CB4(pct);
|
||
var y = P4y * CB1(pct) + P3y * CB2(pct) + P2y * CB3(pct) + P1y * CB4(pct);
|
||
return {
|
||
x: x,
|
||
y: y,
|
||
};
|
||
}
|
||
function getPointOnQuadraticBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y) {
|
||
function QB1(t) {
|
||
return t * t;
|
||
}
|
||
|
||
function QB2(t) {
|
||
return 2 * t * (1 - t);
|
||
}
|
||
|
||
function QB3(t) {
|
||
return (1 - t) * (1 - t);
|
||
}
|
||
var x = P3x * QB1(pct) + P2x * QB2(pct) + P1x * QB3(pct);
|
||
var y = P3y * QB1(pct) + P2y * QB2(pct) + P1y * QB3(pct);
|
||
return {
|
||
x: x,
|
||
y: y,
|
||
};
|
||
}
|
||
function getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi) {
|
||
var cosPsi = Math.cos(psi),
|
||
sinPsi = Math.sin(psi);
|
||
var pt = {
|
||
x: rx * Math.cos(theta),
|
||
y: ry * Math.sin(theta),
|
||
};
|
||
return {
|
||
x: cx + (pt.x * cosPsi - pt.y * sinPsi),
|
||
y: cy + (pt.x * sinPsi + pt.y * cosPsi),
|
||
};
|
||
}
|
||
|
||
|
||
let path2d = function(render, config = {}) {
|
||
const [w, h] = render.area;
|
||
|
||
let cfg = {
|
||
name: 'path',
|
||
animationCurve: 'easeOutBack',
|
||
hover: true,
|
||
drag: true,
|
||
shape: {
|
||
path: '',
|
||
close:true,
|
||
points:[]
|
||
},
|
||
style: {
|
||
stroke: '#000',
|
||
fill:'#000',
|
||
lineWidth: 1,
|
||
hoverCursor: 'pointer',
|
||
},
|
||
...config,
|
||
draw({ ctx }, { shape, style: { lineWidth } }){
|
||
let { points, close,x,y ,path} = shape
|
||
|
||
|
||
|
||
var ca=[]
|
||
if(this.shape['points'].length>0&&this.shape['points']){
|
||
ca = this.shape['svg']
|
||
}else{
|
||
ca = parsePathData(path);
|
||
// ca = ca.map(el=>{
|
||
// if(el.points.length){
|
||
// return {...el,points:[el.points[0]+x,el.points[1]+y]}
|
||
// }
|
||
// return el
|
||
// })
|
||
let ar = ca.map(el=> el.points)
|
||
this.shape['points'] = ar.filter((el)=>el.length==2)
|
||
this.shape['svg'] = ca;
|
||
}
|
||
const context=ctx
|
||
context.beginPath();
|
||
|
||
|
||
for (var n = 0; n < ca.length; n++) {
|
||
var c = ca[n].command;
|
||
var p = ca[n].points;
|
||
switch (c) {
|
||
case 'L':
|
||
context.lineTo(p[0], p[1]);
|
||
break;
|
||
case 'M':
|
||
context.moveTo(p[0], p[1]);
|
||
break;
|
||
case 'C':
|
||
context.bezierCurveTo(p[0], p[1], p[2], p[3], p[4], p[5]);
|
||
break;
|
||
case 'Q':
|
||
context.quadraticCurveTo(p[0], p[1], p[2], p[3]);
|
||
break;
|
||
case 'A':
|
||
var cx = p[0], cy = p[1], rx = p[2], ry = p[3], theta = p[4], dTheta = p[5], psi = p[6], fs = p[7];
|
||
var r = rx > ry ? rx : ry;
|
||
var scaleX = rx > ry ? 1 : rx / ry;
|
||
var scaleY = rx > ry ? ry / rx : 1;
|
||
context.translate(cx, cy);
|
||
context.rotate(psi);
|
||
context.scale(scaleX, scaleY);
|
||
context.arc(0, 0, r, theta, theta + dTheta, 1 - fs);
|
||
context.scale(1 / scaleX, 1 / scaleY);
|
||
context.rotate(-psi);
|
||
context.translate(-cx, -cy);
|
||
break;
|
||
case 'z':
|
||
close = true;
|
||
context.closePath();
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
if (close) {
|
||
ctx.closePath()
|
||
|
||
ctx.fill()
|
||
ctx.stroke()
|
||
} else {
|
||
ctx.stroke()
|
||
}
|
||
|
||
},
|
||
|
||
};
|
||
|
||
return cfg;
|
||
}
|
||
|
||
export default path2d;
|