//= require "object.class" (function(global) { var commandLengths = { m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7 }; function drawArc(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 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; var x0 = a00 * ox + a01 * oy; var y0 = a10 * ox + a11 * oy; var x1 = a00 * x + a01 * y; var y1 = a10 * x + a11 * y; var d = (x1-x0) * (x1-x0) + (y1-y0) * (y1-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 * (x0 + x1) - sfactor * (y1-y0); var yc = 0.5 * (y0 + y1) + sfactor * (x1-x0); var th0 = Math.atan2(y0-yc, x0-xc); var th1 = Math.atan2(y1-yc, 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'; }, /** * Returns object representation of an instance * @method toObject * @return {Object} */ toObject: function() { var o = extend(this.callSuper('toObject'), { path: this.path }); if (this.sourcePath) { o.sourcePath = this.sourcePath; } if (this.transformMatrix) { o.transformMatrix = this.transformMatrix; } return o; }, /** * Returns dataless object representation of an instance * @method toDatalessObject * @return {Object} */ toDatalessObject: function() { var o = this.toObject(); if (this.sourcePath) { o.path = this.sourcePath; } delete o.sourcePath; return o; }, /** * Returns svg representation of an instance * @method toSVG * @return {string} svg representation of an instance */ toSVG: function() { var chunks = []; for (var i = 0, len = this.path.length; i < len; i++) { chunks.push(this.path[i].join(' ')); } var path = chunks.join(' '); return [ '', '', '' ].join(''); }, /** * Returns number representation of an instance complexity * @method complexity * @return {Number} complexity */ complexity: function() { return this.path.length; }, /** * @private * @method _parsePath */ _parsePath: function() { var result = [ ], currentPath, chunks, parsed; for (var i = 0, j, chunksParsed, len = this.path.length; i < len; i++) { currentPath = this.path[i]; chunks = currentPath.slice(1).trim().replace(/(\d)-/g, '$1###-').split(/\s|,|###/); chunksParsed = [ currentPath.charAt(0) ]; for (var j = 0, jlen = chunks.length; j < jlen; j++) { parsed = parseFloat(chunks[j]); if (!isNaN(parsed)) { chunksParsed.push(parsed); } } var command = chunksParsed[0].toLowerCase(), commandLength = commandLengths[command]; if (chunksParsed.length - 1 > commandLength) { for (var k = 1, klen = chunksParsed.length; k < klen; k += commandLength) { result.push([ chunksParsed[0] ].concat(chunksParsed.slice(k, k + commandLength))); } } else { result.push(chunksParsed); } } return result; }, /** * @method _parseDimensions */ _parseDimensions: function() { var aX = [], aY = [], previousX, previousY, isLowerCase = false, x, y; this.path.forEach(function(item, i) { if (item[0] !== 'H') { previousX = (i === 0) ? getX(item) : getX(this.path[i-1]); } if (item[0] !== 'V') { previousY = (i === 0) ? getY(item) : getY(this.path[i-1]); } // lowercased letter denotes relative position; // transform to absolute if (item[0] === item[0].toLowerCase()) { isLowerCase = true; } // last 2 items in an array of coordinates are the actualy x/y (except H/V); // collect them // TODO (kangax): support relative h/v commands x = isLowerCase ? previousX + getX(item) : item[0] === 'V' ? previousX : getX(item); y = isLowerCase ? previousY + getY(item) : item[0] === 'H' ? previousY : getY(item); var val = parseInt(x, 10); if (!isNaN(val)) aX.push(val); val = parseInt(y, 10); if (!isNaN(val)) aY.push(val); }, this); var minX = min(aX), minY = min(aY), deltaX = 0, deltaY = 0; var o = { top: minY - deltaY, left: minX - deltaX, bottom: max(aY) - deltaY, right: max(aX) - deltaX }; o.width = o.right - o.left; o.height = o.bottom - o.top; return o; } }); /** * Creates an instance of fabric.Path from an object * @static * @method fabric.Path.fromObject * @return {fabric.Path} Instance of fabric.Path */ fabric.Path.fromObject = function(object) { return new fabric.Path(object.path, object); }; /** * List of attribute names to account for when parsing SVG element (used by `fabric.Path.fromElement`) * @static * @see http://www.w3.org/TR/SVG/paths.html#PathElement */ fabric.Path.ATTRIBUTE_NAMES = 'd fill fill-opacity opacity fill-rule stroke stroke-width transform'.split(' '); /** * Creates an instance of fabric.Path from an SVG element * @static * @method fabric.Path.fromElement * @param {SVGElement} element to parse * @param {Object} options object * @return {fabric.Path} Instance of fabric.Path */ fabric.Path.fromElement = function(element, options) { var parsedAttributes = fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES); return new fabric.Path(parsedAttributes.d, extend(parsedAttributes, options)); }; })(typeof exports != 'undefined' ? exports : this);