diff --git a/dist/fabric.js b/dist/fabric.js index 04ef1e02..0b52f8c2 100644 --- a/dist/fabric.js +++ b/dist/fabric.js @@ -885,132 +885,107 @@ fabric.Collection = { 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); + _join = Array.prototype.join; + /* Adapted from http://dxr.mozilla.org/mozilla-central/source/content/svg/content/src/nsSVGPathDataParser.cpp + * by Andrea Bogazzi code is under MPL. if you don't have a copy of the license you can take it here + * http://mozilla.org/MPL/2.0/ + */ + function arcToSegments(toX, toY, rx, ry, large, sweep, rotateX) { + var argsString = _join.call(arguments); if (arcToSegmentsCache[argsString]) { return arcToSegmentsCache[argsString]; } - var coords = getXYCoords(rotateX, rx, ry, ox, oy, x, y), - - d = (coords.x1 - coords.x0) * (coords.x1 - coords.x0) + - (coords.y1 - coords.y0) * (coords.y1 - coords.y0), - - sfactorSq = 1 / d - 0.25; - - if (sfactorSq < 0) { - sfactorSq = 0; - } - - var sfactor = Math.sqrt(sfactorSq); - if (sweep === large) { - sfactor = -sfactor; - } - - var xc = 0.5 * (coords.x0 + coords.x1) - sfactor * (coords.y1 - coords.y0), - yc = 0.5 * (coords.y0 + coords.y1) + sfactor * (coords.x1 - coords.x0), - th0 = Math.atan2(coords.y0 - yc, coords.x0 - xc), - th1 = Math.atan2(coords.y1 - yc, coords.x1 - xc), - thArc = th1 - th0; - - if (thArc < 0 && sweep === 1) { - thArc += 2 * Math.PI; - } - else if (thArc > 0 && sweep === 0) { - thArc -= 2 * Math.PI; - } - - var segments = Math.ceil(Math.abs(thArc / (Math.PI * 0.5 + 0.001))), - result = []; - - for (var i = 0; i < segments; i++) { - var th2 = th0 + i * thArc / segments, - th3 = th0 + (i + 1) * thArc / segments; - - result[i] = [xc, yc, th2, th3, rx, ry, coords.sinTh, coords.cosTh]; - } - - arcToSegmentsCache[argsString] = result; - return result; - } - - function getXYCoords(rotateX, rx, ry, ox, oy, x, y) { - - var th = rotateX * (Math.PI / 180), + var PI = Math.PI, th = rotateX * (PI / 180), sinTh = Math.sin(th), - cosTh = Math.cos(th); + cosTh = Math.cos(th), + fromX = 0, fromY = 0; rx = Math.abs(rx); ry = Math.abs(ry); - var px = cosTh * (ox - x) + sinTh * (oy - y), - py = cosTh * (oy - y) - sinTh * (ox - x), - pl = (px * px) / (rx * rx) + (py * py) / (ry * ry); + var px = -cosTh * toX - sinTh * toY, + py = -cosTh * toY + sinTh * toX, + rx2 = rx * rx, ry2 = ry * ry, py2 = py * py, px2 = px * px, + pl = 4 * rx2 * ry2 - rx2 * py2 - ry2 * px2, + root = 0; - pl *= 0.25; - - if (pl > 1) { - pl = Math.sqrt(pl); - rx *= pl; - ry *= pl; + if (pl < 0) { + var s = Math.sqrt(1 - 0.25 * pl/(rx2 * ry2)); + rx *= s; + ry *= s; + } else { + root = (large === sweep ? -0.5 : 0.5) * + Math.sqrt( pl /(rx2 * py2 + ry2 * px2)); } - var a00 = cosTh / rx, - a01 = sinTh / rx, - a10 = (-sinTh) / ry, - a11 = (cosTh) / ry; + var cx = root * rx * py / ry, + cy = -root * ry * px / rx, + cx1 = cosTh * cx - sinTh * cy + toX / 2, + cy1 = sinTh * cx + cosTh * cy + toY / 2, + mTheta = calcVectorAngle(1, 0, (px - cx) / rx, (py - cy) / ry), + dtheta = calcVectorAngle((px - cx) / rx, (py - cy) / ry, (-px -cx) / rx, (-py -cy) / ry); - return { - x0: a00 * ox + a01 * oy, - y0: a10 * ox + a11 * oy, - x1: a00 * x + a01 * y, - y1: a10 * x + a11 * y, - sinTh: sinTh, - cosTh: cosTh - }; + if (sweep === 0 && dtheta > 0) { + dtheta -= 2 * PI; + } else if (sweep === 1 && dtheta < 0) { + dtheta += 2 * PI; + } + + // Convert into cubic bezier segments <= 90deg + var segments = Math.ceil(Math.abs(dtheta / (PI * 0.5))), + result = [], mDelta = dtheta / segments, + mT = 8 / 3 * Math.sin(mDelta / 4) * Math.sin(mDelta / 4) / Math.sin(mDelta / 2), + th3 = mTheta + mDelta; + + for (var i = 0; i < segments; i++) { + result[i] = segmentToBezier(mTheta, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY); + fromX = result[i][4]; + fromY = result[i][5]; + mTheta += mDelta; + th3 += mDelta; + } + arcToSegmentsCache[argsString] = result; + return result; } - function segmentToBezier(cx, cy, th0, th1, rx, ry, sinTh, cosTh) { - argsString = _join.call(arguments); - - if (segmentToBezierCache[argsString]) { - return segmentToBezierCache[argsString]; + function segmentToBezier(th2, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY) { + var argsString2 = _join.call(arguments); + if (segmentToBezierCache[argsString2]) { + return segmentToBezierCache[argsString2]; } + + var costh2 = Math.cos(th2), + sinth2 = Math.sin(th2), + costh3 = Math.cos(th3), + sinth3 = Math.sin(th3), + toX = cosTh * rx * costh3 - sinTh * ry * sinth3 + cx1, + toY = sinTh * rx * costh3 + cosTh * ry * sinth3 + cy1, + cp1X = fromX + mT * ( - cosTh * rx * sinth2 - sinTh * ry * costh2), + cp1Y = fromY + mT * ( - sinTh * rx * sinth2 + cosTh * ry * costh2), + cp2X = toX + mT * ( cosTh * rx * sinth3 + sinTh * ry * costh3), + cp2Y = toY + mT * ( sinTh * rx * sinth3 - cosTh * ry * costh3); - var sinTh0 = Math.sin(th0), - cosTh0 = Math.cos(th0), - sinTh1 = Math.sin(th1), - cosTh1 = Math.cos(th1), - - a00 = cosTh * rx, - a01 = -sinTh * ry, - a10 = sinTh * rx, - a11 = cosTh * ry, - thHalf = 0.25 * (th1 - th0), - - t = (8 / 3) * Math.sin(thHalf) * - Math.sin(thHalf) / Math.sin(thHalf * 2), - - x1 = cx + cosTh0 - t * sinTh0, - y1 = cy + sinTh0 + t * cosTh0, - x3 = cx + cosTh1, - y3 = cy + sinTh1, - x2 = x3 + t * sinTh1, - y2 = y3 - t * cosTh1; - - 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 + segmentToBezierCache[argsString2] = [ + cp1X, cp1Y, + cp2X, cp2Y, + toX, toY ]; + return segmentToBezierCache[argsString2]; + } - return segmentToBezierCache[argsString]; + /* + * Private + */ + function calcVectorAngle(ux, uy, vx, vy) { + var ta = Math.atan2(uy, ux), + tb = Math.atan2(vy, vx); + if (tb >= ta) { + return tb - ta; + } else { + return 2 * Math.PI - (ta - tb); + } } /** @@ -1020,18 +995,24 @@ fabric.Collection = { * @param {Number} y * @param {Array} coords */ - fabric.util.drawArc = function(ctx, x, y, coords) { + fabric.util.drawArc = function(ctx, fx, fy, coords) { var rx = coords[0], ry = coords[1], rot = coords[2], large = coords[3], sweep = coords[4], - ex = coords[5], - ey = coords[6], - 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); + tx = coords[5], + ty = coords[6], + segs = [[ ], [ ], [ ], [ ]], + segs_norm = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot); + for (var i = 0; i < segs_norm.length; i++) { + segs[i][0] = segs_norm[i][0] + fx; + segs[i][1] = segs_norm[i][1] + fy; + segs[i][2] = segs_norm[i][2] + fx; + segs[i][3] = segs_norm[i][3] + fy; + segs[i][4] = segs_norm[i][4] + fx; + segs[i][5] = segs_norm[i][5] + fy; + ctx.bezierCurveTo.apply(ctx, segs[i]); } }; })(); @@ -4704,7 +4685,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() { function getColorStop(el) { var style = el.getAttribute('style'), offset = el.getAttribute('offset'), - color, opacity; + color, colorAlpha, opacity; // convert percents to absolute values offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1); @@ -4738,13 +4719,15 @@ fabric.ElementsParser.prototype.checkIfDone = function() { opacity = el.getAttribute('stop-opacity'); } - // convert rgba color to rgb color - alpha value has no affect in svg - color = new fabric.Color(color).toRgb(); + color = new fabric.Color(color); + colorAlpha = color.getAlpha(); + opacity = isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity); + opacity *= colorAlpha; return { offset: offset, - color: color, - opacity: isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity) + color: color.toRgb(), + opacity: opacity }; } @@ -4821,8 +4804,8 @@ fabric.ElementsParser.prototype.checkIfDone = function() { if (options.gradientTransform) { this.gradientTransform = options.gradientTransform; } - this.origX = options.left; - this.orgiY = options.top; + this.origX = options.left || this.origX; + this.origY = options.top || this.origY; }, /** @@ -5089,10 +5072,10 @@ fabric.ElementsParser.prototype.checkIfDone = function() { for (var prop in options) { //convert to percent units if (prop === 'x1' || prop === 'x2' || prop === 'r2') { - options[prop] = fabric.util.toFixed((options[prop] - object.origX) / object.width * 100, 2) + '%'; + options[prop] = fabric.util.toFixed((options[prop] - object.fill.origX) / object.width * 100, 2) + '%'; } else if (prop === 'y1' || prop === 'y2') { - options[prop] = fabric.util.toFixed((options[prop] - object.origY) / object.height * 100, 2) + '%'; + options[prop] = fabric.util.toFixed((options[prop] - object.fill.origY) / object.height * 100, 2) + '%'; } } } @@ -18342,10 +18325,30 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag data[i + 2] = Math.min(255, b + tb); break; case 'diff': + case 'difference': data[i] = Math.abs(r - tr); data[i + 1] = Math.abs(g - tg); data[i + 2] = Math.abs(b - tb); break; + case 'subtract': + var _r = r-tr; + var _g = g-tg; + var _b = b-tb; + + data[i] = (_r < 0) ? 0 : _r; + data[i + 1] = (_g < 0) ? 0 : _g; + data[i + 2] = (_b < 0) ? 0 : _b; + break; + case 'darken': + data[i] = Math.min(r, tr); + data[i + 1] = Math.min(g, tg); + data[i + 2] = Math.min(b, tb); + break; + case 'lighten': + data[i] = Math.max(r, tr); + data[i + 1] = Math.max(g, tg); + data[i + 2] = Math.max(b, tb); + break; } } @@ -21709,7 +21712,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot return; } - if (e.keyCode in this._keysMap) { + if (e.keyCode in this._keysMap && e.charCode === 0) { this[this._keysMap[e.keyCode]](e); } else if ((e.keyCode in this._ctrlKeysMap) && (e.ctrlKey || e.metaKey)) { @@ -21801,7 +21804,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot * @param {Event} e Event object */ onKeyPress: function(e) { - if (!this.isEditing || e.metaKey || e.ctrlKey || e.keyCode in this._keysMap) { + if (!this.isEditing || e.metaKey || e.ctrlKey || ( e.keyCode in this._keysMap && e.charCode === 0 )) { return; } diff --git a/dist/fabric.min.js b/dist/fabric.min.js index 64fa156d..4c075d87 100644 --- a/dist/fabric.min.js +++ b/dist/fabric.min.js @@ -1,7 +1,7 @@ -/* build: `node build.js modules=ALL exclude=gestures,cufon,json minifier=uglifyjs` *//*! Fabric.js Copyright 2008-2014, Printio (Juriy Zaytsev, Maxim Chernyak) */var fabric=fabric||{version:"1.4.10"};typeof exports!="undefined"&&(exports.fabric=fabric),typeof document!="undefined"&&typeof window!="undefined"?(fabric.document=document,fabric.window=window):(fabric.document=require("jsdom").jsdom("
"),fabric.window=fabric.document.createWindow()),fabric.isTouchSupported="ontouchstart"in fabric.document.documentElement,fabric.isLikelyNode=typeof Buffer!="undefined"&&typeof window=="undefined",fabric.SHARED_ATTRIBUTES=["display","transform","fill","fill-opacity","fill-rule","opacity","stroke","stroke-dasharray","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width"],fabric.DPI=96,function(){function e(e,t){if(!this.__eventListeners[e])return;t?fabric.util.removeFromArray(this.__eventListeners[e],t):this.__eventListeners[e].length=0}function t(e,t){this.__eventListeners||(this.__eventListeners={});if(arguments.length===1)for(var n in e)this.on(n,e[n]);else this.__eventListeners[e]||(this.__eventListeners[e]=[]),this.__eventListeners[e].push(t);return this}function n(t,n){if(!this.__eventListeners)return;if(arguments.length===0)this.__eventListeners={};else if(arguments.length===1&&typeof arguments[0]=="object")for(var r in t)e.call(this,r,t[r]);else e.call(this,t,n);return this}function r(e,t){if(!this.__eventListeners)return;var n=this.__eventListeners[e];if(!n)return;for(var r=0,i=n.length;r-1},complexity:function(){return this.getObjects().reduce(function(e,t){return e+=t.complexity?t.complexity():0,e},0)}},function(e){var t=Math.sqrt,n=Math.atan2,r=Math.PI/180;fabric.util={removeFromArray:function(e,t){var n=e.indexOf(t);return n!==-1&&e.splice(n,1),e},getRandomInt:function(e,t){return Math.floor(Math.random()*(t-e+1))+e},degreesToRadians:function(e){return e*r},radiansToDegrees:function(e){return e/r},rotatePoint:function(e,t,n){var r=Math.sin(n),i=Math.cos(n);e.subtractEquals(t);var s=e.x*i-e.y*r,o=e.x*r+e.y*i;return(new fabric.Point(s,o)).addEquals(t)},transformPoint:function(e,t,n){return n?new fabric.Point(t[0]*e.x+t[1]*e.y,t[2]*e.x+t[3]*e.y):new fabric.Point(t[0]*e.x+t[1]*e.y+t[4],t[2]*e.x+t[3]*e.y+t[5])},invertTransform:function(e){var t=e.slice(),n=1/(e[0]*e[3]-e[1]*e[2]);t=[n*e[3],-n*e[1],-n*e[2],n*e[0],0,0];var r=fabric.util.transformPoint({x:e[4],y:e[5]},t);return t[4]=-r.x,t[5]=-r.y,t},toFixed:function(e,t){return parseFloat(Number(e).toFixed(t))},parseUnit:function(e){var t=/\D{0,2}$/.exec(e),n=parseFloat(e);switch(t[0]){case"mm":return n*fabric.DPI/25.4;case"cm":return n*fabric.DPI/2.54;case"in":return n*fabric.DPI;case"pt":return n*fabric.DPI/72;case"pc":return n*fabric.DPI/72*12;default:return n}},falseFunction:function(){return!1},getKlass:function(e,t){return e=fabric.util.string.camelize(e.charAt(0).toUpperCase()+e.slice(1)),fabric.util.resolveNamespace(t)[e]},resolveNamespace:function(t){if(!t)return fabric;var n=t.split("."),r=n.length,i=e||fabric.window;for(var s=0;s