mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-05-21 20:01:52 +00:00
138 lines
3.8 KiB
JavaScript
138 lines
3.8 KiB
JavaScript
|
|
(function() {
|
||
|
|
|
||
|
|
var arcToSegmentsCache = { },
|
||
|
|
segmentToBezierCache = { },
|
||
|
|
_join = Array.prototype.join,
|
||
|
|
argsString;
|
||
|
|
|
||
|
|
// Generous contribution by Raph Levien, from libsvg-0.1.0.tar.gz
|
||
|
|
function arcToSegments(x, y, rx, ry, large, sweep, rotateX, ox, oy) {
|
||
|
|
|
||
|
|
argsString = _join.call(arguments);
|
||
|
|
|
||
|
|
if (arcToSegmentsCache[argsString]) {
|
||
|
|
return arcToSegmentsCache[argsString];
|
||
|
|
}
|
||
|
|
|
||
|
|
var coords = getXYCoords(rotateX, rx, ry, ox, oy, x, y);
|
||
|
|
|
||
|
|
var d = (coords.x1-coords.x0) * (coords.x1-coords.x0) +
|
||
|
|
(coords.y1-coords.y0) * (coords.y1-coords.y0);
|
||
|
|
|
||
|
|
var sfactor_sq = 1 / d - 0.25;
|
||
|
|
if (sfactor_sq < 0) sfactor_sq = 0;
|
||
|
|
|
||
|
|
var sfactor = Math.sqrt(sfactor_sq);
|
||
|
|
if (sweep === large) sfactor = -sfactor;
|
||
|
|
|
||
|
|
var xc = 0.5 * (coords.x0 + coords.x1) - sfactor * (coords.y1-coords.y0);
|
||
|
|
var yc = 0.5 * (coords.y0 + coords.y1) + sfactor * (coords.x1-coords.x0);
|
||
|
|
|
||
|
|
var th0 = Math.atan2(coords.y0-yc, coords.x0-xc);
|
||
|
|
var th1 = Math.atan2(coords.y1-yc, coords.x1-xc);
|
||
|
|
|
||
|
|
var th_arc = th1-th0;
|
||
|
|
if (th_arc < 0 && sweep === 1) {
|
||
|
|
th_arc += 2*Math.PI;
|
||
|
|
}
|
||
|
|
else if (th_arc > 0 && sweep === 0) {
|
||
|
|
th_arc -= 2 * Math.PI;
|
||
|
|
}
|
||
|
|
|
||
|
|
var segments = Math.ceil(Math.abs(th_arc / (Math.PI * 0.5 + 0.001)));
|
||
|
|
var result = [];
|
||
|
|
for (var i=0; i<segments; i++) {
|
||
|
|
var th2 = th0 + i * th_arc / segments;
|
||
|
|
var th3 = th0 + (i+1) * th_arc / segments;
|
||
|
|
result[i] = [xc, yc, th2, th3, rx, ry, coords.sin_th, coords.cos_th];
|
||
|
|
}
|
||
|
|
|
||
|
|
arcToSegmentsCache[argsString] = result;
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
function getXYCoords(rotateX, rx, ry, ox, oy, x, y) {
|
||
|
|
|
||
|
|
var th = rotateX * (Math.PI/180);
|
||
|
|
var sin_th = Math.sin(th);
|
||
|
|
var cos_th = Math.cos(th);
|
||
|
|
rx = Math.abs(rx);
|
||
|
|
ry = Math.abs(ry);
|
||
|
|
var px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5;
|
||
|
|
var py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5;
|
||
|
|
var pl = (px*px) / (rx*rx) + (py*py) / (ry*ry);
|
||
|
|
if (pl > 1) {
|
||
|
|
pl = Math.sqrt(pl);
|
||
|
|
rx *= pl;
|
||
|
|
ry *= pl;
|
||
|
|
}
|
||
|
|
|
||
|
|
var a00 = cos_th / rx;
|
||
|
|
var a01 = sin_th / rx;
|
||
|
|
var a10 = (-sin_th) / ry;
|
||
|
|
var a11 = (cos_th) / ry;
|
||
|
|
|
||
|
|
return {
|
||
|
|
x0: a00 * ox + a01 * oy,
|
||
|
|
y0: a10 * ox + a11 * oy,
|
||
|
|
x1: a00 * x + a01 * y,
|
||
|
|
y1: a10 * x + a11 * y,
|
||
|
|
sin_th: sin_th,
|
||
|
|
cos_th: cos_th
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function segmentToBezier(cx, cy, th0, th1, rx, ry, sin_th, cos_th) {
|
||
|
|
argsString = _join.call(arguments);
|
||
|
|
if (segmentToBezierCache[argsString]) {
|
||
|
|
return segmentToBezierCache[argsString];
|
||
|
|
}
|
||
|
|
|
||
|
|
var a00 = cos_th * rx;
|
||
|
|
var a01 = -sin_th * ry;
|
||
|
|
var a10 = sin_th * rx;
|
||
|
|
var a11 = cos_th * ry;
|
||
|
|
|
||
|
|
var th_half = 0.5 * (th1 - th0);
|
||
|
|
var t = (8/3) * Math.sin(th_half * 0.5) *
|
||
|
|
Math.sin(th_half * 0.5) / Math.sin(th_half);
|
||
|
|
|
||
|
|
var x1 = cx + Math.cos(th0) - t * Math.sin(th0);
|
||
|
|
var y1 = cy + Math.sin(th0) + t * Math.cos(th0);
|
||
|
|
var x3 = cx + Math.cos(th1);
|
||
|
|
var y3 = cy + Math.sin(th1);
|
||
|
|
var x2 = x3 + t * Math.sin(th1);
|
||
|
|
var y2 = y3 - t * Math.cos(th1);
|
||
|
|
|
||
|
|
segmentToBezierCache[argsString] = [
|
||
|
|
a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
|
||
|
|
a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
|
||
|
|
a00 * x3 + a01 * y3, a10 * x3 + a11 * y3
|
||
|
|
];
|
||
|
|
|
||
|
|
return segmentToBezierCache[argsString];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Draws arc
|
||
|
|
* @param {CanvasRenderingContext2D} ctx
|
||
|
|
* @param {Number} x
|
||
|
|
* @param {Number} y
|
||
|
|
* @param {Array} coords
|
||
|
|
*/
|
||
|
|
fabric.util.drawArc = function(ctx, x, y, coords) {
|
||
|
|
var rx = coords[0];
|
||
|
|
var ry = coords[1];
|
||
|
|
var rot = coords[2];
|
||
|
|
var large = coords[3];
|
||
|
|
var sweep = coords[4];
|
||
|
|
var ex = coords[5];
|
||
|
|
var ey = coords[6];
|
||
|
|
var segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y);
|
||
|
|
for (var i=0; i<segs.length; i++) {
|
||
|
|
var bez = segmentToBezier.apply(this, segs[i]);
|
||
|
|
ctx.bezierCurveTo.apply(ctx, bez);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
})();
|