Merge pull request #14 from kangax/master

update master
This commit is contained in:
Andrea Bogazzi 2015-05-18 22:55:40 +02:00
commit dd769a98cf
28 changed files with 924 additions and 675 deletions

821
dist/fabric.js vendored

File diff suppressed because it is too large Load diff

19
dist/fabric.min.js vendored

File diff suppressed because one or more lines are too long

BIN
dist/fabric.min.js.gz vendored

Binary file not shown.

443
dist/fabric.require.js vendored
View file

@ -1741,10 +1741,24 @@ if (typeof console !== "undefined") {
}
return selector.length === 0;
}
function elementById(doc, id) {
var el;
doc.getElementById && (el = doc.getElementById(id));
if (el) {
return el;
}
var node, i, idAttr, nodelist = doc.getElementsByTagName("*");
for (i = 0; i < nodelist.length; i++) {
node = nodelist[i];
if (idAttr === node.getAttribute("id")) {
return node;
}
}
}
function parseUseDirectives(doc) {
var nodelist = doc.getElementsByTagName("use");
while (nodelist.length) {
var el = nodelist[0], xlink = el.getAttribute("xlink:href").substr(1), x = el.getAttribute("x") || 0, y = el.getAttribute("y") || 0, el2 = doc.getElementById(xlink).cloneNode(true), currentTrans = (el2.getAttribute("transform") || "") + " translate(" + x + ", " + y + ")", parentNode;
var nodelist = doc.getElementsByTagName("use"), i = 0;
while (nodelist.length && i < nodelist.length) {
var el = nodelist[i], xlink = el.getAttribute("xlink:href").substr(1), x = el.getAttribute("x") || 0, y = el.getAttribute("y") || 0, el2 = elementById(doc, xlink).cloneNode(true), currentTrans = (el2.getAttribute("transform") || "") + " translate(" + x + ", " + y + ")", parentNode, oldLength = nodelist.length;
for (var j = 0, attrs = el.attributes, l = attrs.length; j < l; j++) {
var attr = attrs.item(j);
if (attr.nodeName === "x" || attr.nodeName === "y" || attr.nodeName === "xlink:href") {
@ -1761,6 +1775,9 @@ if (typeof console !== "undefined") {
el2.removeAttribute("id");
parentNode = el.parentNode;
parentNode.replaceChild(el2, el);
if (nodelist.length === oldLength) {
i++;
}
}
}
var reViewBoxAttrValue = new RegExp("^" + "\\s*(" + fabric.reNum + "+)\\s*,?" + "\\s*(" + fabric.reNum + "+)\\s*,?" + "\\s*(" + fabric.reNum + "+)\\s*,?" + "\\s*(" + fabric.reNum + "+)\\s*" + "$");
@ -1837,7 +1854,7 @@ if (typeof console !== "undefined") {
}
var elements = descendants.filter(function(el) {
reViewBoxTagNames.test(el.tagName) && addVBTransform(el, 0, 0);
return reAllowedSVGTagNames.test(el.tagName) && !hasAncestorWithNodeName(el, /^(?:pattern|defs|symbol)$/);
return reAllowedSVGTagNames.test(el.tagName) && !hasAncestorWithNodeName(el, /^(?:pattern|defs|symbol|metadata)$/);
});
if (!elements || elements && !elements.length) {
callback && callback([], {});
@ -2723,15 +2740,6 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
}
}
}
if (object.type === "text" || object.type === "i-text") {
for (prop in coords) {
if (prop === "x1" || prop === "x2") {
coords[prop] -= object.width / 2;
} else if (prop === "y1" || prop === "y2") {
coords[prop] -= object.height / 2;
}
}
}
if (this.type === "linear") {
gradient = ctx.createLinearGradient(coords.x1, coords.y1, coords.x2, coords.y2);
} else if (this.type === "radial") {
@ -3236,7 +3244,7 @@ fabric.Pattern = fabric.util.createClass({
},
_onObjectAdded: function(obj) {
this.stateful && obj.setupState();
obj.canvas = this;
obj._set("canvas", this);
obj.setCoords();
this.fire("object:added", {
target: obj
@ -3326,7 +3334,7 @@ fabric.Pattern = fabric.util.createClass({
sortedObjects.push(object);
}
});
activeGroup._set("objects", sortedObjects);
activeGroup._set("_objects", sortedObjects.reverse());
this._draw(ctx, activeGroup);
}
},
@ -4005,6 +4013,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
perPixelTargetFind: false,
targetFindTolerance: 0,
skipTargetFind: false,
isDrawingMode: false,
_initInteractive: function() {
this._currentTransform = null;
this._groupSelector = null;
@ -4168,9 +4177,9 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
target.setPositionByOrigin(constraintPosition, t.originX, t.originY);
},
_setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip) {
var target = transform.target, forbidScalingX = false, forbidScalingY = false, strokeWidth = target.stroke ? target.strokeWidth : 0;
transform.newScaleX = localMouse.x / (target.width + strokeWidth / 2);
transform.newScaleY = localMouse.y / (target.height + strokeWidth / 2);
var target = transform.target, forbidScalingX = false, forbidScalingY = false, vLine = target.type === "line" && target.width === 0, hLine = target.type === "line" && target.height === 0, strokeWidthX = hLine ? 0 : target.strokeWidth, strokeWidthY = vLine ? 0 : target.strokeWidth;
transform.newScaleX = localMouse.x / (target.width + strokeWidthX);
transform.newScaleY = localMouse.y / (target.height + strokeWidthY);
if (lockScalingFlip && transform.newScaleX <= 0 && transform.newScaleX < target.scaleX) {
forbidScalingX = true;
}
@ -4190,7 +4199,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
forbidScalingX || forbidScalingY || this._flipObject(transform, by);
},
_scaleObjectEqually: function(localMouse, target, transform) {
var dist = localMouse.y + localMouse.x, strokeWidth = target.stroke ? target.strokeWidth : 0, lastDist = (target.height + strokeWidth / 2) * transform.original.scaleY + (target.width + strokeWidth / 2) * transform.original.scaleX;
var dist = localMouse.y + localMouse.x, vLine = target.type === "line" && target.width === 0, hLine = target.type === "line" && target.height === 0, strokeWidthX = hLine ? 0 : target.strokeWidth, strokeWidthY = vLine ? 0 : target.strokeWidth, lastDist = (target.height + strokeWidthY) * transform.original.scaleY + (target.width + strokeWidthX) * transform.original.scaleX;
transform.newScaleX = transform.original.scaleX * dist / lastDist;
transform.newScaleY = transform.original.scaleY * dist / lastDist;
target.set("scaleX", transform.newScaleX);
@ -4302,27 +4311,30 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
return activeGroup;
}
var target = this._searchPossibleTargets(e);
this._fireOverOutEvents(target);
this._fireOverOutEvents(target, e);
return target;
},
_fireOverOutEvents: function(target) {
_fireOverOutEvents: function(target, e) {
if (target) {
if (this._hoveredTarget !== target) {
this.fire("mouse:over", {
target: target
});
target.fire("mouseover");
if (this._hoveredTarget) {
this.fire("mouse:out", {
target: this._hoveredTarget
target: this._hoveredTarget,
e: e
});
this._hoveredTarget.fire("mouseout");
}
this.fire("mouse:over", {
target: target,
e: e
});
target.fire("mouseover");
this._hoveredTarget = target;
}
} else if (this._hoveredTarget) {
this.fire("mouse:out", {
target: this._hoveredTarget
target: this._hoveredTarget,
e: e
});
this._hoveredTarget.fire("mouseout");
this._hoveredTarget = null;
@ -5394,6 +5406,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
if (options.fill && options.fill.colorStops && !(options.fill instanceof fabric.Gradient)) {
this.set("fill", new fabric.Gradient(options.fill));
}
if (options.stroke && options.stroke.colorStops && !(options.stroke instanceof fabric.Gradient)) {
this.set("stroke", new fabric.Gradient(options.stroke));
}
},
_initPattern: function(options) {
if (options.fill && options.fill.source && !(options.fill instanceof fabric.Pattern)) {
@ -5421,6 +5436,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
this._initClipping(options);
},
transform: function(ctx, fromLeft) {
if (this.group && this.canvas.preserveObjectStacking && this.group === this.canvas._activeGroup) {
this.group.transform(ctx);
}
var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint();
ctx.translate(center.x, center.y);
ctx.rotate(degreesToRadians(this.angle));
@ -5551,8 +5569,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
this.clipTo && fabric.util.clipContext(this, ctx);
this._render(ctx, noTransform);
this.clipTo && ctx.restore();
this._removeShadow(ctx);
this._restoreCompositeOperation(ctx);
ctx.restore();
},
_setOpacity: function(ctx) {
@ -5633,14 +5649,14 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
ctx.fill();
}
ctx.restore();
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}
},
_renderStroke: function(ctx) {
if (!this.stroke || this.strokeWidth === 0) {
return;
}
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}
ctx.save();
if (this.strokeDashArray) {
if (1 & this.strokeDashArray.length) {
@ -5660,7 +5676,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
}
this._stroke ? this._stroke(ctx) : ctx.stroke();
}
this._removeShadow(ctx);
ctx.restore();
},
clone: function(callback, propertiesToInclude) {
@ -5789,14 +5804,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
},
_setupCompositeOperation: function(ctx) {
if (this.globalCompositeOperation) {
this._prevGlobalCompositeOperation = ctx.globalCompositeOperation;
ctx.globalCompositeOperation = this.globalCompositeOperation;
}
},
_restoreCompositeOperation: function(ctx) {
if (this.globalCompositeOperation && this._prevGlobalCompositeOperation) {
ctx.globalCompositeOperation = this._prevGlobalCompositeOperation;
}
}
});
fabric.util.createAccessors(fabric.Object);
@ -5810,30 +5819,30 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
var degreesToRadians = fabric.util.degreesToRadians;
fabric.util.object.extend(fabric.Object.prototype, {
translateToCenterPoint: function(point, originX, originY) {
var cx = point.x, cy = point.y, strokeWidth = this.stroke ? this.strokeWidth : 0;
var cx = point.x, cy = point.y;
if (originX === "left") {
cx = point.x + (this.getWidth() + strokeWidth * this.scaleX) / 2;
cx = point.x + (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
} else if (originX === "right") {
cx = point.x - (this.getWidth() + strokeWidth * this.scaleX) / 2;
cx = point.x - (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
}
if (originY === "top") {
cy = point.y + (this.getHeight() + strokeWidth * this.scaleY) / 2;
cy = point.y + (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
} else if (originY === "bottom") {
cy = point.y - (this.getHeight() + strokeWidth * this.scaleY) / 2;
cy = point.y - (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
}
return fabric.util.rotatePoint(new fabric.Point(cx, cy), point, degreesToRadians(this.angle));
},
translateToOriginPoint: function(center, originX, originY) {
var x = center.x, y = center.y, strokeWidth = this.stroke ? this.strokeWidth : 0;
var x = center.x, y = center.y;
if (originX === "left") {
x = center.x - (this.getWidth() + strokeWidth * this.scaleX) / 2;
x = center.x - (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
} else if (originX === "right") {
x = center.x + (this.getWidth() + strokeWidth * this.scaleX) / 2;
x = center.x + (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
}
if (originY === "top") {
y = center.y - (this.getHeight() + strokeWidth * this.scaleY) / 2;
y = center.y - (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
} else if (originY === "bottom") {
y = center.y + (this.getHeight() + strokeWidth * this.scaleY) / 2;
y = center.y + (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
}
return fabric.util.rotatePoint(new fabric.Point(x, y), center, degreesToRadians(this.angle));
},
@ -5846,19 +5855,19 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
return this.translateToOriginPoint(center, originX, originY);
},
toLocalPoint: function(point, originX, originY) {
var center = this.getCenterPoint(), strokeWidth = this.stroke ? this.strokeWidth : 0, x, y;
var center = this.getCenterPoint(), x, y;
if (originX && originY) {
if (originX === "left") {
x = center.x - (this.getWidth() + strokeWidth * this.scaleX) / 2;
x = center.x - (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
} else if (originX === "right") {
x = center.x + (this.getWidth() + strokeWidth * this.scaleX) / 2;
x = center.x + (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
} else {
x = center.x;
}
if (originY === "top") {
y = center.y - (this.getHeight() + strokeWidth * this.scaleY) / 2;
y = center.y - (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
} else if (originY === "bottom") {
y = center.y + (this.getHeight() + strokeWidth * this.scaleY) / 2;
y = center.y + (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
} else {
y = center.y;
}
@ -5910,7 +5919,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
this._originalOriginY = null;
},
_getLeftTopCoords: function() {
return this.translateToOriginPoint(this.getCenterPoint(), "left", "center");
return this.translateToOriginPoint(this.getCenterPoint(), "left", "top");
}
});
})();
@ -7132,21 +7141,23 @@ fabric.util.object.extend(fabric.Object.prototype, {
if (!fromArray) {
this.path = this._parsePath();
}
this._setPositionDimensions();
this._setPositionDimensions(options);
if (options.sourcePath) {
this.setSourcePath(options.sourcePath);
}
},
_setPositionDimensions: function() {
_setPositionDimensions: function(options) {
var calcDim = this._parseDimensions();
this.minX = calcDim.left;
this.minY = calcDim.top;
this.width = calcDim.width;
this.height = calcDim.height;
calcDim.left += this.originX === "center" ? this.width / 2 : this.originX === "right" ? this.width : 0;
calcDim.top += this.originY === "center" ? this.height / 2 : this.originY === "bottom" ? this.height : 0;
this.top = this.top || calcDim.top;
this.left = this.left || calcDim.left;
if (typeof options.left === "undefined") {
this.left = calcDim.left + (this.originX === "center" ? this.width / 2 : this.originX === "right" ? this.width : 0);
}
if (typeof options.top === "undefined") {
this.top = calcDim.top + (this.originY === "center" ? this.height / 2 : this.originY === "bottom" ? this.height : 0);
}
this.pathOffset = this.pathOffset || {
x: this.minX + this.width / 2,
y: this.minY + this.height / 2
@ -7687,7 +7698,6 @@ fabric.util.object.extend(fabric.Object.prototype, {
this.paths[i].render(ctx, true);
}
this.clipTo && ctx.restore();
this._removeShadow(ctx);
ctx.restore();
},
_set: function(prop, value) {
@ -7775,6 +7785,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
};
fabric.Group = fabric.util.createClass(fabric.Object, fabric.Collection, {
type: "group",
strokeWidth: 0,
initialize: function(objects, options) {
options = options || {};
this._objects = objects || [];
@ -7782,7 +7793,6 @@ fabric.util.object.extend(fabric.Object.prototype, {
this._objects[i].group = this;
}
this.originalState = {};
this.callSuper("initialize");
if (options.originX) {
this.originX = options.originX;
}
@ -7818,6 +7828,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
if (object) {
this._objects.push(object);
object.group = this;
object._set("canvas", this.canvas);
}
this.forEachObject(this._setObjectActive, this);
this._calcBounds();
@ -7839,6 +7850,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
},
_onObjectAdded: function(object) {
object.group = this;
object._set("canvas", this.canvas);
},
_onObjectRemoved: function(object) {
delete object.group;
@ -7857,7 +7869,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
backgroundColor: true
},
_set: function(key, value) {
if (key in this.delegatedProperties) {
if (key in this.delegatedProperties || key === "canvas") {
var i = this._objects.length;
while (i--) {
this._objects[i].set(key, value);
@ -7875,8 +7887,11 @@ fabric.util.object.extend(fabric.Object.prototype, {
return;
}
ctx.save();
this.clipTo && fabric.util.clipContext(this, ctx);
if (this.transformMatrix) {
ctx.transform.apply(ctx, this.transformMatrix);
}
this.transform(ctx);
this.clipTo && fabric.util.clipContext(this, ctx);
for (var i = 0, len = this._objects.length; i < len; i++) {
this._renderObject(this._objects[i], ctx);
}
@ -7890,10 +7905,10 @@ fabric.util.object.extend(fabric.Object.prototype, {
}
},
_renderObject: function(object, ctx) {
var originalHasRotatingPoint = object.hasRotatingPoint;
if (!object.visible) {
return;
}
var originalHasRotatingPoint = object.hasRotatingPoint;
object.hasRotatingPoint = false;
object.render(ctx);
object.hasRotatingPoint = originalHasRotatingPoint;
@ -8079,11 +8094,6 @@ fabric.util.object.extend(fabric.Object.prototype, {
this.resizeFilters = [];
this.callSuper("initialize", options);
this._initElement(element, options);
this._initConfig(options);
if (options.filters) {
this.filters = options.filters;
this.applyFilters();
}
},
getElement: function() {
return this._element;
@ -8132,7 +8142,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
ctx.restore();
},
toObject: function(propertiesToInclude) {
return extend(this.callSuper("toObject", propertiesToInclude), {
var object = extend(this.callSuper("toObject", propertiesToInclude), {
src: this._originalElement.src || this._originalElement._src,
filters: this.filters.map(function(filterObj) {
return filterObj && filterObj.toObject();
@ -8142,6 +8152,12 @@ fabric.util.object.extend(fabric.Object.prototype, {
alignY: this.alignY,
meetOrSlice: this.meetOrSlice
});
if (this.resizeFilters.length > 0) {
object.resizeFilters = this.resizeFilters.map(function(filterObj) {
return filterObj && filterObj.toObject();
});
}
return object;
},
toSVG: function(reviver) {
var markup = [], x = -this.width / 2, y = -this.height / 2, preserveAspectRatio = "none";
@ -8284,9 +8300,9 @@ fabric.util.object.extend(fabric.Object.prototype, {
this._element.crossOrigin = this.crossOrigin;
}
},
_initFilters: function(object, callback) {
if (object.filters && object.filters.length) {
fabric.util.enlivenObjects(object.filters, function(enlivenedObjects) {
_initFilters: function(filters, callback) {
if (filters && filters.length) {
fabric.util.enlivenObjects(filters, function(enlivenedObjects) {
callback && callback(enlivenedObjects);
}, "fabric.Image.filters");
} else {
@ -8305,10 +8321,13 @@ fabric.util.object.extend(fabric.Object.prototype, {
fabric.Image.prototype.getSvgSrc = fabric.Image.prototype.getSrc;
fabric.Image.fromObject = function(object, callback) {
fabric.util.loadImage(object.src, function(img) {
fabric.Image.prototype._initFilters.call(object, object, function(filters) {
fabric.Image.prototype._initFilters.call(object, object.filters, function(filters) {
object.filters = filters || [];
var instance = new fabric.Image(img, object);
callback && callback(instance);
fabric.Image.prototype._initFilters.call(object, object.resizeFilters, function(resizeFilters) {
object.resizeFilters = resizeFilters || [];
var instance = new fabric.Image(img, object);
callback && callback(instance);
});
});
}, null, object.crossOrigin);
};
@ -9121,20 +9140,20 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
return {
type: this.type,
scaleX: this.scaleX,
scaley: this.scaleY,
scaleY: this.scaleY,
resizeType: this.resizeType,
lanczosLobes: this.lanczosLobes
};
}
});
fabric.Image.filters.Resize.fromObject = function() {
return new fabric.Image.filters.Resize();
fabric.Image.filters.Resize.fromObject = function(object) {
return new fabric.Image.filters.Resize(object);
};
})(typeof exports !== "undefined" ? exports : this);
(function(global) {
"use strict";
var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, clone = fabric.util.object.clone, toFixed = fabric.util.toFixed, supportsLineDash = fabric.StaticCanvas.supports("setLineDash");
var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, clone = fabric.util.object.clone, toFixed = fabric.util.toFixed, supportsLineDash = fabric.StaticCanvas.supports("setLineDash"), NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
if (fabric.Text) {
fabric.warn("fabric.Text is already defined");
return;
@ -9210,8 +9229,6 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
this._setupCompositeOperation(ctx);
this._renderTextFill(ctx);
this._renderTextStroke(ctx);
this._restoreCompositeOperation(ctx);
this._removeShadow(ctx);
ctx.restore();
},
_translateForTextAlign: function(ctx) {
@ -9240,7 +9257,17 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
return maxWidth;
},
_renderChars: function(method, ctx, chars, left, top) {
var shortM = method.slice(0, -4);
if (this[shortM].toLive) {
var offsetX = -this.width / 2 + this[shortM].offsetX || 0, offsetY = -this.height / 2 + this[shortM].offsetY || 0;
ctx.save();
ctx.translate(offsetX, offsetY);
left -= offsetX;
top -= offsetY;
}
console.log(ctx.strokeStyle);
ctx[method](chars, left, top);
this[shortM].toLive && ctx.restore();
},
_renderTextLine: function(method, ctx, line, left, top, lineIndex) {
top -= this.fontSize * this._fontSizeFraction;
@ -9278,15 +9305,15 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
this._renderTextLine("fillText", ctx, this._textLines[i], this._getLeftOffset(), this._getTopOffset() + lineHeights + maxHeight, i);
lineHeights += heightOfLine;
}
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}
},
_renderTextStroke: function(ctx) {
if ((!this.stroke || this.strokeWidth === 0) && !this._skipFillStrokeCheck) {
return;
}
var lineHeights = 0;
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}
ctx.save();
if (this.strokeDashArray) {
if (1 & this.strokeDashArray.length) {
@ -9470,14 +9497,14 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
},
_setSVGTextLineText: function(i, textSpans, height, textLeftOffset, textTopOffset) {
var yPos = this.fontSize * (this._fontSizeMult - this._fontSizeFraction) - textTopOffset + height - this.height / 2;
textSpans.push('<tspan x="', toFixed(textLeftOffset + this._getLineLeftOffset(this.__lineWidths[i]), 4), '" ', 'y="', toFixed(yPos, 4), '" ', this._getFillAttributes(this.fill), ">", fabric.util.string.escapeXml(this._textLines[i]), "</tspan>");
textSpans.push('<tspan x="', toFixed(textLeftOffset + this._getLineLeftOffset(this.__lineWidths[i]), NUM_FRACTION_DIGITS), '" ', 'y="', toFixed(yPos, NUM_FRACTION_DIGITS), '" ', this._getFillAttributes(this.fill), ">", fabric.util.string.escapeXml(this._textLines[i]), "</tspan>");
},
_setSVGTextLineBg: function(textBgRects, i, textLeftOffset, textTopOffset, height) {
textBgRects.push(" <rect ", this._getFillAttributes(this.textBackgroundColor), ' x="', toFixed(textLeftOffset + this._getLineLeftOffset(this.__lineWidths[i]), 4), '" y="', toFixed(height - this.height / 2, 4), '" width="', toFixed(this.__lineWidths[i], 4), '" height="', toFixed(this._getHeightOfLine(this.ctx, i) / this.lineHeight, 4), '"></rect>\n');
textBgRects.push(" <rect ", this._getFillAttributes(this.textBackgroundColor), ' x="', toFixed(textLeftOffset + this._getLineLeftOffset(this.__lineWidths[i]), NUM_FRACTION_DIGITS), '" y="', toFixed(height - this.height / 2, NUM_FRACTION_DIGITS), '" width="', toFixed(this.__lineWidths[i], NUM_FRACTION_DIGITS), '" height="', toFixed(this._getHeightOfLine(this.ctx, i) / this.lineHeight, NUM_FRACTION_DIGITS), '"></rect>\n');
},
_setSVGBg: function(textBgRects) {
if (this.backgroundColor) {
textBgRects.push(" <rect ", this._getFillAttributes(this.backgroundColor), ' x="', toFixed(-this.width / 2, 4), '" y="', toFixed(-this.height / 2, 4), '" width="', toFixed(this.width, 4), '" height="', toFixed(this.height, 4), '"></rect>\n');
textBgRects.push(" <rect ", this._getFillAttributes(this.backgroundColor), ' x="', toFixed(-this.width / 2, NUM_FRACTION_DIGITS), '" y="', toFixed(-this.height / 2, NUM_FRACTION_DIGITS), '" width="', toFixed(this.width, NUM_FRACTION_DIGITS), '" height="', toFixed(this.height, NUM_FRACTION_DIGITS), '"></rect>\n');
}
},
_getFillAttributes: function(value) {
@ -9657,6 +9684,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
ctx.save();
ctx.transform.apply(ctx, this.canvas.viewportTransform);
this.transform(ctx);
this.transformMatrix && ctx.transform.apply(ctx, this.transformMatrix);
} else {
ctx = this.ctx;
ctx.save();
@ -9674,10 +9702,19 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
if (typeof selectionStart === "undefined") {
selectionStart = this.selectionStart;
}
var textBeforeCursor = this.text.slice(0, selectionStart), linesBeforeCursor = textBeforeCursor.split(this._reNewline);
var len = this._textLines.length;
for (var i = 0; i < len; i++) {
if (selectionStart <= this._textLines[i].length) {
return {
lineIndex: i,
charIndex: selectionStart
};
}
selectionStart -= this._textLines[i].length + 1;
}
return {
lineIndex: linesBeforeCursor.length - 1,
charIndex: linesBeforeCursor[linesBeforeCursor.length - 1].length
lineIndex: i - 1,
charIndex: this._textLines[i - 1].length < selectionStart ? this._textLines[i - 1].length : selectionStart
};
},
getCurrentCharStyle: function(lineIndex, charIndex) {
@ -9773,11 +9810,11 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
}
this.skipTextAlign = true;
left -= this.textAlign === "center" ? this.width / 2 : this.textAlign === "right" ? this.width : 0;
var lineHeight = this._getHeightOfLine(ctx, lineIndex), lineLeftOffset = this._getCachedLineOffset(lineIndex), chars = line.split(""), prevStyle, charsToRender = "";
var lineHeight = this._getHeightOfLine(ctx, lineIndex), lineLeftOffset = this._getCachedLineOffset(lineIndex), prevStyle, charsToRender = "";
left += lineLeftOffset || 0;
ctx.save();
top -= lineHeight / this.lineHeight * this._fontSizeFraction;
for (var i = 0, len = chars.length; i <= len; i++) {
for (var i = 0, len = line.length; i <= len; i++) {
prevStyle = prevStyle || this.getCurrentCharStyle(lineIndex, i);
var thisStyle = this.getCurrentCharStyle(lineIndex, i + 1);
if (this._hasStyleChanged(prevStyle, thisStyle) || i === len) {
@ -9785,7 +9822,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
charsToRender = "";
prevStyle = thisStyle;
}
charsToRender += chars[i];
charsToRender += line[i];
}
ctx.restore();
},
@ -10212,8 +10249,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
},
getNumNewLinesInSelectedText: function() {
var selectedText = this.getSelectedText(), numNewLines = 0;
for (var i = 0, chars = selectedText.split(""), len = chars.length; i < len; i++) {
if (chars[i] === "\n") {
for (var i = 0, len = selectedText.length; i < len; i++) {
if (selectedText[i] === "\n") {
numNewLines++;
}
}
@ -10357,29 +10394,28 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
}
},
_removeCharsFromTo: function(start, end) {
var i = end;
while (i !== start) {
var prevIndex = this.get2DCursorLocation(i).charIndex;
i--;
var index = this.get2DCursorLocation(i).charIndex, isNewline = index > prevIndex;
if (isNewline) {
this.removeStyleObject(isNewline, i + 1);
} else {
this.removeStyleObject(this.get2DCursorLocation(i).charIndex === 0, i);
}
while (end !== start) {
this._removeSingleCharAndStyle(start + 1);
end--;
}
this.text = this.text.slice(0, start) + this.text.slice(end);
this._clearCache();
this.setSelectionStart(start);
},
_removeSingleCharAndStyle: function(index) {
var isBeginningOfLine = this.text[index - 1] === "\n", indexStyle = isBeginningOfLine ? index : index - 1;
this.removeStyleObject(isBeginningOfLine, indexStyle);
this.text = this.text.slice(0, index - 1) + this.text.slice(index);
this._textLines = this.text.split(this._reNewline);
},
insertChars: function(_chars, useCopiedStyle) {
var isEndOfLine = this.text.slice(this.selectionStart, this.selectionStart + 1) === "\n";
this.text = this.text.slice(0, this.selectionStart) + _chars + this.text.slice(this.selectionEnd);
if (this.selectionStart === this.selectionEnd) {
this.insertStyleObjects(_chars, isEndOfLine, useCopiedStyle);
if (this.selectionEnd - this.selectionStart > 1) {
this._removeCharsFromTo(this.selectionStart, this.selectionEnd);
this.setSelectionEnd(this.selectionStart);
}
var isEndOfLine = this.text[this.selectionStart] === "\n";
this.text = this.text.slice(0, this.selectionStart) + _chars + this.text.slice(this.selectionEnd);
this.insertStyleObjects(_chars, isEndOfLine, useCopiedStyle);
this.setSelectionStart(this.selectionStart + _chars.length);
this.setSelectionEnd(this.selectionStart);
this._clearCache();
this.canvas && this.canvas.renderAll();
this.setCoords();
this.fire("changed");
@ -10392,7 +10428,10 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
if (!this.styles[lineIndex + 1]) {
this.styles[lineIndex + 1] = {};
}
var currentCharStyle = this.styles[lineIndex][charIndex - 1], newLineStyles = {};
var currentCharStyle = {}, newLineStyles = {};
if (this.styles[lineIndex] && this.styles[lineIndex][charIndex - 1]) {
currentCharStyle = this.styles[lineIndex][charIndex - 1];
}
if (isEndOfLine) {
newLineStyles[0] = clone(currentCharStyle);
this.styles[lineIndex + 1] = newLineStyles;
@ -10448,6 +10487,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
var numericLine = parseInt(line, 10);
if (numericLine > lineIndex) {
this.styles[numericLine + offset] = clonedStyles[numericLine];
if (!clonedStyles[numericLine - offset]) {
delete this.styles[numericLine];
}
}
}
},
@ -10465,8 +10507,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({
} else {
var currentLineStyles = this.styles[lineIndex];
if (currentLineStyles) {
var offset = this.selectionStart === this.selectionEnd ? -1 : 0;
delete currentLineStyles[charIndex + offset];
delete currentLineStyles[charIndex];
}
var currentLineStylesCloned = clone(currentLineStyles);
for (var i in currentLineStylesCloned) {
@ -10587,7 +10628,7 @@ fabric.util.object.extend(fabric.IText.prototype, {
getSelectionStartFromPointer: function(e) {
var mouseOffset = this._getLocalRotatedPointer(e), prevWidth = 0, width = 0, height = 0, charIndex = 0, newSelectionStart, line;
for (var i = 0, len = this._textLines.length; i < len; i++) {
line = this._textLines[i].split("");
line = this._textLines[i];
height += this._getHeightOfLine(this.ctx, i) * this.scaleY;
var widthOfLine = this._getLineWidth(this.ctx, i), lineLeftOffset = this._getLineLeftOffset(widthOfLine);
width = lineLeftOffset * this.scaleX;
@ -10595,9 +10636,8 @@ fabric.util.object.extend(fabric.IText.prototype, {
this._textLines[i] = line.reverse().join("");
}
for (var j = 0, jlen = line.length; j < jlen; j++) {
var _char = line[j];
prevWidth = width;
width += this._getWidthOfChar(this.ctx, _char, i, this.flipX ? jlen - j : j) * this.scaleX;
width += this._getWidthOfChar(this.ctx, line[j], i, this.flipX ? jlen - j : j) * this.scaleX;
if (height <= mouseOffset.y || width <= mouseOffset.x) {
charIndex++;
continue;
@ -10721,13 +10761,13 @@ fabric.util.object.extend(fabric.IText.prototype, {
e.stopPropagation();
},
getDownCursorOffset: function(e, isRight) {
var selectionProp = isRight ? this.selectionEnd : this.selectionStart, _char, lineLeftOffset, textBeforeCursor = this.text.slice(0, selectionProp), textAfterCursor = this.text.slice(selectionProp), textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf("\n") + 1), textOnSameLineAfterCursor = textAfterCursor.match(/(.*)\n?/)[1], textOnNextLine = (textAfterCursor.match(/.*\n(.*)\n?/) || {})[1] || "", cursorLocation = this.get2DCursorLocation(selectionProp);
if (cursorLocation.lineIndex === this._textLines.length - 1 || e.metaKey || e.keyCode === 34) {
var selectionProp = isRight ? this.selectionEnd : this.selectionStart, cursorLocation = this.get2DCursorLocation(selectionProp), _char, lineLeftOffset, lineIndex = cursorLocation.lineIndex, textOnSameLineBeforeCursor = this._textLines[lineIndex].slice(0, cursorLocation.charIndex), textOnSameLineAfterCursor = this._textLines[lineIndex].slice(cursorLocation.charIndex), textOnNextLine = this._textLines[lineIndex + 1] || "";
if (lineIndex === this._textLines.length - 1 || e.metaKey || e.keyCode === 34) {
return this.text.length - selectionProp;
}
var widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, cursorLocation.lineIndex);
var widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, lineIndex);
lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor);
var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset, lineIndex = cursorLocation.lineIndex;
var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset;
for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) {
_char = textOnSameLineBeforeCursor[i];
widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i);
@ -10791,11 +10831,11 @@ fabric.util.object.extend(fabric.IText.prototype, {
}
},
getUpCursorOffset: function(e, isRight) {
var selectionProp = isRight ? this.selectionEnd : this.selectionStart, cursorLocation = this.get2DCursorLocation(selectionProp);
if (cursorLocation.lineIndex === 0 || e.metaKey || e.keyCode === 33) {
var selectionProp = isRight ? this.selectionEnd : this.selectionStart, cursorLocation = this.get2DCursorLocation(selectionProp), lineIndex = cursorLocation.lineIndex;
if (lineIndex === 0 || e.metaKey || e.keyCode === 33) {
return selectionProp;
}
var textBeforeCursor = this.text.slice(0, selectionProp), textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf("\n") + 1), textOnPreviousLine = (textBeforeCursor.match(/\n?(.*)\n.*$/) || {})[1] || "", _char, widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, cursorLocation.lineIndex), lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor), widthOfCharsOnSameLineBeforeCursor = lineLeftOffset, lineIndex = cursorLocation.lineIndex;
var textOnSameLineBeforeCursor = this._textLines[lineIndex].slice(0, cursorLocation.charIndex), textOnPreviousLine = this._textLines[lineIndex - 1] || "", _char, widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, cursorLocation.lineIndex), lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor), widthOfCharsOnSameLineBeforeCursor = lineLeftOffset;
for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) {
_char = textOnSameLineBeforeCursor[i];
widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i);
@ -10894,9 +10934,6 @@ fabric.util.object.extend(fabric.IText.prototype, {
} else {
this._selectionDirection = "left";
this._moveLeft(e, "selectionStart");
if (this.text.charAt(this.selectionStart) === "\n") {
this.setSelectionStart(this.selectionStart - 1);
}
}
},
moveCursorRight: function(e) {
@ -10918,9 +10955,6 @@ fabric.util.object.extend(fabric.IText.prototype, {
} else {
this._selectionDirection = "right";
this._moveRight(e, "selectionEnd");
if (this.text.charAt(this.selectionEnd - 1) === "\n") {
this.setSelectionEnd(this.selectionEnd + 1);
}
}
},
moveCursorRightWithoutShift: function(e) {
@ -10950,72 +10984,74 @@ fabric.util.object.extend(fabric.IText.prototype, {
});
},
_removeCharsNearCursor: function(e) {
if (this.selectionStart !== 0) {
if (e.metaKey) {
var leftLineBoundary = this.findLineBoundaryLeft(this.selectionStart);
this._removeCharsFromTo(leftLineBoundary, this.selectionStart);
this.setSelectionStart(leftLineBoundary);
} else if (e.altKey) {
var leftWordBoundary = this.findWordBoundaryLeft(this.selectionStart);
this._removeCharsFromTo(leftWordBoundary, this.selectionStart);
this.setSelectionStart(leftWordBoundary);
} else {
var isBeginningOfLine = this.text.slice(this.selectionStart - 1, this.selectionStart) === "\n";
this.removeStyleObject(isBeginningOfLine);
this.setSelectionStart(this.selectionStart - 1);
this.text = this.text.slice(0, this.selectionStart) + this.text.slice(this.selectionStart + 1);
}
if (this.selectionStart === 0) {
return;
}
if (e.metaKey) {
var leftLineBoundary = this.findLineBoundaryLeft(this.selectionStart);
this._removeCharsFromTo(leftLineBoundary, this.selectionStart);
this.setSelectionStart(leftLineBoundary);
} else if (e.altKey) {
var leftWordBoundary = this.findWordBoundaryLeft(this.selectionStart);
this._removeCharsFromTo(leftWordBoundary, this.selectionStart);
this.setSelectionStart(leftWordBoundary);
} else {
this._removeSingleCharAndStyle(this.selectionStart);
this.setSelectionStart(this.selectionStart - 1);
}
}
});
fabric.util.object.extend(fabric.IText.prototype, {
_setSVGTextLineText: function(lineIndex, textSpans, height, textLeftOffset, textTopOffset, textBgRects) {
if (!this.styles[lineIndex]) {
this.callSuper("_setSVGTextLineText", lineIndex, textSpans, height, textLeftOffset, textTopOffset);
} else {
this._setSVGTextLineChars(lineIndex, textSpans, height, textLeftOffset, textBgRects);
}
},
_setSVGTextLineChars: function(lineIndex, textSpans, height, textLeftOffset, textBgRects) {
var chars = this._textLines[lineIndex].split(""), charOffset = 0, lineLeftOffset = this._getSVGLineLeftOffset(lineIndex) - this.width / 2, lineOffset = this._getSVGLineTopOffset(lineIndex), heightOfLine = this._getHeightOfLine(this.ctx, lineIndex);
for (var i = 0, len = chars.length; i < len; i++) {
var styleDecl = this.styles[lineIndex][i] || {};
textSpans.push(this._createTextCharSpan(chars[i], styleDecl, lineLeftOffset, lineOffset.lineTop + lineOffset.offset, charOffset));
var charWidth = this._getWidthOfChar(this.ctx, chars[i], lineIndex, i);
if (styleDecl.textBackgroundColor) {
textBgRects.push(this._createTextCharBg(styleDecl, lineLeftOffset, lineOffset.lineTop, heightOfLine, charWidth, charOffset));
(function() {
var toFixed = fabric.util.toFixed, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
fabric.util.object.extend(fabric.IText.prototype, {
_setSVGTextLineText: function(lineIndex, textSpans, height, textLeftOffset, textTopOffset, textBgRects) {
if (!this.styles[lineIndex]) {
this.callSuper("_setSVGTextLineText", lineIndex, textSpans, height, textLeftOffset, textTopOffset);
} else {
this._setSVGTextLineChars(lineIndex, textSpans, height, textLeftOffset, textBgRects);
}
charOffset += charWidth;
},
_setSVGTextLineChars: function(lineIndex, textSpans, height, textLeftOffset, textBgRects) {
var chars = this._textLines[lineIndex], charOffset = 0, lineLeftOffset = this._getSVGLineLeftOffset(lineIndex) - this.width / 2, lineOffset = this._getSVGLineTopOffset(lineIndex), heightOfLine = this._getHeightOfLine(this.ctx, lineIndex);
for (var i = 0, len = chars.length; i < len; i++) {
var styleDecl = this.styles[lineIndex][i] || {};
textSpans.push(this._createTextCharSpan(chars[i], styleDecl, lineLeftOffset, lineOffset.lineTop + lineOffset.offset, charOffset));
var charWidth = this._getWidthOfChar(this.ctx, chars[i], lineIndex, i);
if (styleDecl.textBackgroundColor) {
textBgRects.push(this._createTextCharBg(styleDecl, lineLeftOffset, lineOffset.lineTop, heightOfLine, charWidth, charOffset));
}
charOffset += charWidth;
}
},
_getSVGLineLeftOffset: function(lineIndex) {
return fabric.util.toFixed(this._getLineLeftOffset(this.__lineWidths[lineIndex]), 2);
},
_getSVGLineTopOffset: function(lineIndex) {
var lineTopOffset = 0, lastHeight = 0;
for (var j = 0; j < lineIndex; j++) {
lineTopOffset += this._getHeightOfLine(this.ctx, j);
}
lastHeight = this._getHeightOfLine(this.ctx, j);
return {
lineTop: lineTopOffset,
offset: (this._fontSizeMult - this._fontSizeFraction) * lastHeight / (this.lineHeight * this._fontSizeMult)
};
},
_createTextCharBg: function(styleDecl, lineLeftOffset, lineTopOffset, heightOfLine, charWidth, charOffset) {
return [ '<rect fill="', styleDecl.textBackgroundColor, '" x="', toFixed(lineLeftOffset + charOffset, NUM_FRACTION_DIGITS), '" y="', toFixed(lineTopOffset - this.height / 2, NUM_FRACTION_DIGITS), '" width="', toFixed(charWidth, NUM_FRACTION_DIGITS), '" height="', toFixed(heightOfLine / this.lineHeight, NUM_FRACTION_DIGITS), '"></rect>' ].join("");
},
_createTextCharSpan: function(_char, styleDecl, lineLeftOffset, lineTopOffset, charOffset) {
var fillStyles = this.getSvgStyles.call(fabric.util.object.extend({
visible: true,
fill: this.fill,
stroke: this.stroke,
type: "text"
}, styleDecl));
return [ '<tspan x="', lineLeftOffset + charOffset, '" y="', lineTopOffset - this.height / 2, '" ', styleDecl.fontFamily ? 'font-family="' + styleDecl.fontFamily.replace(/"/g, "'") + '" ' : "", styleDecl.fontSize ? 'font-size="' + styleDecl.fontSize + '" ' : "", styleDecl.fontStyle ? 'font-style="' + styleDecl.fontStyle + '" ' : "", styleDecl.fontWeight ? 'font-weight="' + styleDecl.fontWeight + '" ' : "", styleDecl.textDecoration ? 'text-decoration="' + styleDecl.textDecoration + '" ' : "", 'style="', fillStyles, '">', fabric.util.string.escapeXml(_char), "</tspan>" ].join("");
}
},
_getSVGLineLeftOffset: function(lineIndex) {
return fabric.util.toFixed(this._getLineLeftOffset(this.__lineWidths[lineIndex]), 2);
},
_getSVGLineTopOffset: function(lineIndex) {
var lineTopOffset = 0, lastHeight = 0;
for (var j = 0; j < lineIndex; j++) {
lineTopOffset += this._getHeightOfLine(this.ctx, j);
}
lastHeight = this._getHeightOfLine(this.ctx, j);
return {
lineTop: lineTopOffset,
offset: (this._fontSizeMult - this._fontSizeFraction) * lastHeight / (this.lineHeight * this._fontSizeMult)
};
},
_createTextCharBg: function(styleDecl, lineLeftOffset, lineTopOffset, heightOfLine, charWidth, charOffset) {
return [ '<rect fill="', styleDecl.textBackgroundColor, '" x="', lineLeftOffset + charOffset, '" y="', lineTopOffset - this.height / 2, '" width="', charWidth, '" height="', heightOfLine / this.lineHeight, '"></rect>' ].join("");
},
_createTextCharSpan: function(_char, styleDecl, lineLeftOffset, lineTopOffset, charOffset) {
var fillStyles = this.getSvgStyles.call(fabric.util.object.extend({
visible: true,
fill: this.fill,
stroke: this.stroke,
type: "text"
}, styleDecl));
return [ '<tspan x="', lineLeftOffset + charOffset, '" y="', lineTopOffset - this.height / 2, '" ', styleDecl.fontFamily ? 'font-family="' + styleDecl.fontFamily.replace(/"/g, "'") + '" ' : "", styleDecl.fontSize ? 'font-size="' + styleDecl.fontSize + '" ' : "", styleDecl.fontStyle ? 'font-style="' + styleDecl.fontStyle + '" ' : "", styleDecl.fontWeight ? 'font-weight="' + styleDecl.fontWeight + '" ' : "", styleDecl.textDecoration ? 'text-decoration="' + styleDecl.textDecoration + '" ' : "", 'style="', fillStyles, '">', fabric.util.string.escapeXml(_char), "</tspan>" ].join("");
}
});
});
})();
(function() {
if (typeof document !== "undefined" && typeof window !== "undefined") {
@ -11052,6 +11088,7 @@ fabric.util.object.extend(fabric.IText.prototype, {
} else {
fabric.log(err.message);
}
callback(null);
});
req.end();
}
@ -11068,9 +11105,14 @@ fabric.util.object.extend(fabric.IText.prototype, {
}
fabric.util.loadImage = function(url, callback, context) {
function createImageAndCallBack(data) {
img.src = new Buffer(data, "binary");
img._src = url;
callback && callback.call(context, img);
if (data) {
img.src = new Buffer(data, "binary");
img._src = url;
callback && callback.call(context, img);
} else {
img = null;
callback && callback.call(context, null, true);
}
}
var img = new Image();
if (url && (url instanceof Buffer || url.indexOf("data") === 0)) {
@ -11112,9 +11154,12 @@ fabric.util.object.extend(fabric.IText.prototype, {
fabric.util.loadImage(object.src, function(img) {
var oImg = new fabric.Image(img);
oImg._initConfig(object);
oImg._initFilters(object, function(filters) {
oImg._initFilters(object.filters, function(filters) {
oImg.filters = filters || [];
callback && callback(oImg);
oImg._initFilters(object.resizeFilters, function(resizeFilters) {
oImg.resizeFilters = resizeFilters || [];
callback && callback(oImg);
});
});
});
};

View file

@ -181,6 +181,16 @@
*/
skipTargetFind: false,
/**
* When true, mouse events on canvas (mousedown/mousemove/mouseup) result in free drawing.
* After mousedown, mousemove creates a shape,
* and then mouseup finalizes it and adds an instance of `fabric.Path` onto canvas.
* @tutorial {@link http://fabricjs.com/fabric-intro-part-4/#free_drawing}
* @type Boolean
* @default
*/
isDrawingMode: false,
/**
* @private
*/
@ -499,13 +509,10 @@
*/
_setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip) {
var target = transform.target, forbidScalingX = false, forbidScalingY = false,
vLine = target.type === 'line' && target.width === 0,
hLine = target.type === 'line' && target.height === 0,
strokeWidthX = hLine ? 0 : target.strokeWidth,
strokeWidthY = vLine ? 0 : target.strokeWidth;
dim = target._getNonTransformedDimensions();
transform.newScaleX = localMouse.x / (target.width + strokeWidthX);
transform.newScaleY = localMouse.y / (target.height + strokeWidthY);
transform.newScaleX = localMouse.x / dim.x;
transform.newScaleY = localMouse.y / dim.y;
if (lockScalingFlip && transform.newScaleX <= 0 && transform.newScaleX < target.scaleX) {
forbidScalingX = true;
@ -539,12 +546,9 @@
_scaleObjectEqually: function(localMouse, target, transform) {
var dist = localMouse.y + localMouse.x,
vLine = target.type === 'line' && target.width === 0,
hLine = target.type === 'line' && target.height === 0,
strokeWidthX = hLine ? 0 : target.strokeWidth,
strokeWidthY = vLine ? 0 : target.strokeWidth,
lastDist = (target.height + strokeWidthY) * transform.original.scaleY +
(target.width + strokeWidthX) * transform.original.scaleX;
dim = target._getNonTransformedDimensions(),
lastDist = dim.y * transform.original.scaleY +
dim.x * transform.original.scaleX;
// We use transform.scaleX/Y instead of target.scaleX/Y
// because the object may have a min scale and we'll loose the proportions

View file

@ -258,17 +258,6 @@
}
}
if (object.type === 'text' || object.type === 'i-text') {
for (prop in coords) {
if (prop === 'x1' || prop === 'x2') {
coords[prop] -= object.width / 2;
}
else if (prop === 'y1' || prop === 'y2') {
coords[prop] -= object.height / 2;
}
}
}
if (this.type === 'linear') {
gradient = ctx.createLinearGradient(
coords.x1, coords.y1, coords.x2, coords.y2);

View file

@ -65,6 +65,7 @@
this.renderAll();
t.action = 'drag';
},
/**
* Method that defines actions when an Event.js drag is detected.
*
@ -76,6 +77,7 @@
e: e, self: self
});
},
/**
* Method that defines actions when an Event.js orientation event is detected.
*
@ -87,6 +89,7 @@
e: e, self: self
});
},
/**
* Method that defines actions when an Event.js shake event is detected.
*
@ -98,6 +101,7 @@
e: e, self: self
});
},
/**
* Method that defines actions when an Event.js longpress event is detected.
*
@ -109,6 +113,7 @@
e: e, self: self
});
},
/**
* Scales an object by a factor
* @param {Number} s The scale factor to apply to the current scale level
@ -127,19 +132,16 @@
target._scaling = true;
var constraintPosition = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY),
vLine = target.type === 'line' && target.width === 0,
hLine = target.type === 'line' && target.height === 0,
strokeWidthX = hLine ? 0 : target.strokeWidth,
strokeWidthY = vLine ? 0 : target.strokeWidth;
dim = target._getNonTransformedDimensions();
this._setObjectScale(new fabric.Point((t.scaleX * s * (target.width + strokeWidthX)),
(t.scaleY * s * (target.height + strokeWidthY))),
this._setObjectScale(new fabric.Point(t.scaleX * s * dim.x, t.scaleY * s * dim.y),
t, lockScalingX, lockScalingY, null, target.get('lockScalingFlip'));
target.setPositionByOrigin(constraintPosition, t.originX, t.originY);
this._fire('scaling', target, e);
},
/**
* Rotates object by an angle
* @param {Number} curAngle The angle of rotation in degrees

View file

@ -557,9 +557,13 @@
this.styles[lineIndex + 1] = { };
}
var currentCharStyle = this.styles[lineIndex][charIndex - 1],
var currentCharStyle = { },
newLineStyles = { };
if (this.styles[lineIndex] && this.styles[lineIndex][charIndex - 1]) {
currentCharStyle = this.styles[lineIndex][charIndex - 1];
}
// if there's nothing after cursor,
// we clone current char style onto the next (otherwise empty) line
if (isEndOfLine) {
@ -578,7 +582,7 @@
}
this.styles[lineIndex + 1] = newLineStyles;
}
this._clearCache();
this._forceClearCache = true;
},
/**
@ -608,7 +612,7 @@
this.styles[lineIndex][charIndex] =
style || clone(currentLineStyles[charIndex - 1]);
this._clearCache();
this._forceClearCache = true;
},
/**
@ -668,6 +672,9 @@
var numericLine = parseInt(line, 10);
if (numericLine > lineIndex) {
this.styles[numericLine + offset] = clonedStyles[numericLine];
if (!clonedStyles[numericLine - offset]) {
delete this.styles[numericLine];
}
}
}
//TODO: evaluate if delete old style lines with offset -1

View file

@ -579,7 +579,6 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
this._removeExtraneousStyles();
this._clearCache();
this.canvas && this.canvas.renderAll();
this.setCoords();

View file

@ -16,7 +16,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
: 'none',
strokeWidth = this.strokeWidth ? this.strokeWidth : '0',
strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : '',
strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : 'none',
strokeLineCap = this.strokeLineCap ? this.strokeLineCap : 'butt',
strokeLineJoin = this.strokeLineJoin ? this.strokeLineJoin : 'miter',
strokeMiterLimit = this.strokeMiterLimit ? this.strokeMiterLimit : '4',

View file

@ -371,6 +371,11 @@
this._setCornerCoords && this._setCornerCoords();
return this;
},
_calcDimensionsTransformMatrix: function() {
// introduce skew matrix here later
return [this.scaleX, 0, 0, this.scaleY, 0, 0];
}
});
})();

View file

@ -106,9 +106,12 @@
}
},
_calculateCurrentDimensions: function(shouldTransform) {
var vpt = this.getViewportTransform(),
strokeWidth = this.strokeWidth,
/*
* Calculate object dimensions from its properties
* @private
*/
_getNonTransformedDimensions: function() {
var strokeWidth = this.strokeWidth,
w = this.width,
h = this.height,
capped = this.strokeLineCap === 'round' || this.strokeLineCap === 'square',
@ -130,9 +133,30 @@
if (strokeH) {
h += (h < 0 ? -strokeWidth : strokeWidth);
}
return { x: w, y: h };
},
w = w * this.scaleX + 2 * this.padding;
h = h * this.scaleY + 2 * this.padding;
/*
* @private
*/
_getTransformedDimensions: function(dimensions) {
if (!dimensions) {
dimensions = this._getNonTransformedDimensions();
}
var transformMatrix = this._calcDimensionsTransformMatrix();
return fabric.util.transformPoint(dimensions, transformMatrix, true);
},
/*
* private
*/
_calculateCurrentDimensions: function(shouldTransform) {
var vpt = this.getViewportTransform(),
dim = this._getTransformedDimensions(),
w = dim.x, h = dim.y;
w += 2 * this.padding;
h += 2 * this.padding;
if (shouldTransform) {
return fabric.util.transformPoint(new fabric.Point(w, h), vpt, true);

View file

@ -15,18 +15,21 @@
var cx = point.x,
cy = point.y;
if (originX !== 'center' || originY !== 'center') {
dim = this._getTransformedDimensions();
}
if (originX === 'left') {
cx = point.x + (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
cx = point.x + dim.x / 2;
}
else if (originX === 'right') {
cx = point.x - (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
cx = point.x - dim.x / 2;
}
if (originY === 'top') {
cy = point.y + (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
cy = point.y + dim.y / 2;
}
else if (originY === 'bottom') {
cy = point.y - (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
cy = point.y - dim.y / 2;
}
// Apply the reverse rotation to the point (it's already scaled properly)
@ -44,18 +47,21 @@
var x = center.x,
y = center.y;
if (originX !== 'center' || originY !== 'center') {
dim = this._getTransformedDimensions();
}
// Get the point coordinates
if (originX === 'left') {
x = center.x - (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
x = center.x - dim.x / 2;
}
else if (originX === 'right') {
x = center.x + (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
x = center.x + dim.x / 2;
}
if (originY === 'top') {
y = center.y - (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
y = center.y - dim.y / 2;
}
else if (originY === 'bottom') {
y = center.y + (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
y = center.y + dim.y / 2;
}
// Apply the rotation to the point (it's already scaled properly)
@ -103,21 +109,24 @@
x, y;
if (originX && originY) {
if (originX !== 'center' || originY !== 'center') {
dim = this._getTransformedDimensions();
}
if (originX === 'left') {
x = center.x - (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
x = center.x - dim.x / 2;
}
else if (originX === 'right') {
x = center.x + (this.getWidth() + this.strokeWidth * this.scaleX) / 2;
x = center.x + dim.x / 2;
}
else {
x = center.x;
}
if (originY === 'top') {
y = center.y - (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
y = center.y - dim.y / 2;
}
else if (originY === 'bottom') {
y = center.y + (this.getHeight() + this.strokeWidth * this.scaleY) / 2;
y = center.y + dim.y / 2;
}
else {
y = center.y;

View file

@ -50,6 +50,7 @@
else {
fabric.log(err.message);
}
callback(null);
});
req.end();
@ -71,10 +72,16 @@
fabric.util.loadImage = function(url, callback, context) {
function createImageAndCallBack(data) {
img.src = new Buffer(data, 'binary');
// preserving original url, which seems to be lost in node-canvas
img._src = url;
callback && callback.call(context, img);
if (data) {
img.src = new Buffer(data, 'binary');
// preserving original url, which seems to be lost in node-canvas
img._src = url;
callback && callback.call(context, img);
}
else {
img = null;
callback && callback.call(context, null, true);
}
}
var img = new Image();
if (url && (url instanceof Buffer || url.indexOf('data') === 0)) {

View file

@ -367,19 +367,38 @@
return selector.length === 0;
}
/**
* @private
* to support IE8 missing getElementById on SVGdocument
*/
function elementById(doc, id) {
var el;
doc.getElementById && (el = doc.getElementById(id));
if (el) {
return el;
}
var node, i, idAttr, nodelist = doc.getElementsByTagName('*');
for (i = 0; i < nodelist.length; i++) {
node = nodelist[i];
if (idAttr === node.getAttribute('id')) {
return node;
}
}
}
/**
* @private
*/
function parseUseDirectives(doc) {
var nodelist = doc.getElementsByTagName('use');
while (nodelist.length) {
var el = nodelist[0],
var nodelist = doc.getElementsByTagName('use'), i = 0;
while (nodelist.length && i < nodelist.length) {
var el = nodelist[i],
xlink = el.getAttribute('xlink:href').substr(1),
x = el.getAttribute('x') || 0,
y = el.getAttribute('y') || 0,
el2 = doc.getElementById(xlink).cloneNode(true),
el2 = elementById(doc, xlink).cloneNode(true),
currentTrans = (el2.getAttribute('transform') || '') + ' translate(' + x + ', ' + y + ')',
parentNode;
parentNode, oldLength = nodelist.length;
for (var j = 0, attrs = el.attributes, l = attrs.length; j < l; j++) {
var attr = attrs.item(j);
@ -400,6 +419,10 @@
el2.removeAttribute('id');
parentNode = el.parentNode;
parentNode.replaceChild(el2, el);
// some browsers do not shorten nodelist after replaceChild (IE8)
if (nodelist.length === oldLength) {
i++;
}
}
}

View file

@ -57,6 +57,7 @@
this.callSuper('initialize', options);
this.set('radius', options.radius || 0);
this.startAngle = options.startAngle || this.startAngle;
this.endAngle = options.endAngle || this.endAngle;
},
@ -171,11 +172,11 @@
/**
* Sets radius of an object (and updates width accordingly)
* @return {Number}
* @return {fabric.Circle} thisArg
*/
setRadius: function(value) {
this.radius = value;
this.set('width', value * 2).set('height', value * 2);
return this.set('width', value * 2).set('height', value * 2);
},
/**

View file

@ -283,7 +283,7 @@
}
}
/* not included in _extendStyles to avoid clearing cache more than once */
this._clearCache();
this._forceClearCache = true;
return this;
},

View file

@ -699,6 +699,9 @@
if (options.fill && options.fill.colorStops && !(options.fill instanceof fabric.Gradient)) {
this.set('fill', new fabric.Gradient(options.fill));
}
if (options.stroke && options.stroke.colorStops && !(options.stroke instanceof fabric.Gradient)) {
this.set('stroke', new fabric.Gradient(options.stroke));
}
},
/**
@ -1111,7 +1114,7 @@
return;
}
if (!this.shadow.affectStroke) {
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}

View file

@ -434,7 +434,19 @@
* @param {Number} top Top position of text
*/
_renderChars: function(method, ctx, chars, left, top) {
// remove Text word from method var
var shortM = method.slice(0, -4);
if (this[shortM].toLive) {
var offsetX = -this.width / 2 + this[shortM].offsetX || 0,
offsetY = -this.height / 2 + this[shortM].offsetY || 0;
ctx.save();
ctx.translate(offsetX, offsetY);
left -= offsetX;
top -= offsetY;
}
console.log(ctx.strokeStyle);
ctx[method](chars, left, top);
this[shortM].toLive && ctx.restore();
},
/**
@ -540,7 +552,7 @@
var lineHeights = 0;
if (!this.shadow.affectStroke) {
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}
@ -670,6 +682,10 @@
*/
_shouldClearCache: function() {
var shouldClear = false;
if (this._forceClearCache) {
this._forceClearCache = false;
return true;
}
for (var prop in this._dimensionAffectingProps) {
if (this['__' + prop] !== this[prop]) {
this['__' + prop] = this[prop];

View file

@ -49,7 +49,7 @@
equal(circle.getWidth(), 20);
equal(circle.getHeight(), 20);
circle.setRadius(20);
equal(circle, circle.setRadius(20));
equal(circle.getRadiusX(), 20);
equal(circle.getRadiusY(), 20);

View file

@ -389,7 +389,7 @@ test('toObject without default values', function() {
var group = makeGroupWith2Objects();
ok(typeof group.toSVG == 'function');
var expectedSVG = '<g transform="translate(90 130)">\n<rect x="-15" y="-5" rx="0" ry="0" width="30" height="10" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform="translate(25 -25)"/>\n<rect x="-5" y="-20" rx="0" ry="0" width="10" height="40" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform="translate(-35 10)"/>\n</g>\n';
var expectedSVG = '<g transform="translate(90 130)">\n<rect x="-15" y="-5" rx="0" ry="0" width="30" height="10" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform="translate(25 -25)"/>\n<rect x="-5" y="-20" rx="0" ry="0" width="10" height="40" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform="translate(-35 10)"/>\n</g>\n';
equal(group.toSVG(), expectedSVG);
});

View file

@ -274,6 +274,51 @@
equal(iText.text, 't\nt');
});
test('insertNewlineStyleObject', function() {
var iText = new fabric.IText('test\n');
equal(typeof iText.insertNewlineStyleObject, 'function');
iText.insertNewlineStyleObject(0, 4, true);
deepEqual(iText.styles, { '1': { '0': { } } });
});
test('shiftLineStyles', function() {
var iText = new fabric.IText('test\ntest\ntest', {
styles: {
'1': {
'0': { 'fill': 'red' },
'1': { 'fill': 'red' },
'2': { 'fill': 'red' },
'3': { 'fill': 'red' }
}
}
});
equal(typeof iText.shiftLineStyles, 'function');
iText.shiftLineStyles(0, +1);
deepEqual(iText.styles, {
'2': {
'0': { 'fill': 'red' },
'1': { 'fill': 'red' },
'2': { 'fill': 'red' },
'3': { 'fill': 'red' }
}
});
iText.shiftLineStyles(0, -1);
deepEqual(iText.styles, {
'1': {
'0': { 'fill': 'red' },
'1': { 'fill': 'red' },
'2': { 'fill': 'red' },
'3': { 'fill': 'red' }
}
});
});
test('selectWord', function() {
var iText = new fabric.IText('test foo bar-baz\nqux');
@ -530,7 +575,7 @@
// because translate values differ
if (!fabric.isLikelyNode) {
equal(iText.toSVG(), '<g transform="translate(124.38 52)"><text font-family="Times New Roman" font-size="40" font-weight="normal" style="stroke: none; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); opacity: 1;" transform="translate(-124.38 39)"><tspan x="0" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #112233; opacity: 1;">t</tspan><tspan x="11.11328125" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">e</tspan><tspan x="28.8671875" y="0" style="stroke: #223344; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">s</tspan><tspan x="44.43359375" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">t</tspan><tspan x="55.546875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;"> </tspan><tspan x="65.546875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">f</tspan><tspan x="78.8671875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">o</tspan><tspan x="98.8671875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">o</tspan><tspan x="118.8671875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;"> </tspan><tspan x="128.8671875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">b</tspan><tspan x="148.8671875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">a</tspan><tspan x="166.62109375" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">r</tspan><tspan x="179.94140625" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">-</tspan><tspan x="193.26171875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">b</tspan><tspan x="213.26171875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">a</tspan><tspan x="231.015625" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">z</tspan><tspan x="0" y="0" fill="rgb(0,0,0)">qux</tspan></text></g>');
equal(iText.toSVG(), '<g transform="translate(124.38 52)"><text font-family="Times New Roman" font-size="40" font-weight="normal" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); opacity: 1;" transform="translate(-124.38 39)"><tspan x="0" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: #112233; opacity: 1;">t</tspan><tspan x="11.11328125" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">e</tspan><tspan x="28.8671875" y="0" style="stroke: #223344; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">s</tspan><tspan x="44.43359375" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">t</tspan><tspan x="55.546875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;"> </tspan><tspan x="65.546875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">f</tspan><tspan x="78.8671875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">o</tspan><tspan x="98.8671875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">o</tspan><tspan x="118.8671875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;"> </tspan><tspan x="128.8671875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">b</tspan><tspan x="148.8671875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">a</tspan><tspan x="166.62109375" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">r</tspan><tspan x="179.94140625" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">-</tspan><tspan x="193.26171875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">b</tspan><tspan x="213.26171875" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">a</tspan><tspan x="231.015625" y="0" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); opacity: 1;">z</tspan><tspan x="0" y="0" fill="rgb(0,0,0)">qux</tspan></text></g>');
}
// TODO: more SVG tests here?

View file

@ -102,7 +102,7 @@
asyncTest('toSVG', function() {
makePathObject(function(path) {
ok(typeof path.toObject == 'function');
deepEqual(path.toSVG(), '<path d="M 100 100 L 300 100 L 200 300 z" style="stroke: blue; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: red; fill-rule: nonzero; opacity: 1;" transform="translate(200.5 200.5) translate(-200, -200) " stroke-linecap="round" />\n');
deepEqual(path.toSVG(), '<path d="M 100 100 L 300 100 L 200 300 z" style="stroke: blue; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: red; fill-rule: nonzero; opacity: 1;" transform="translate(200.5 200.5) translate(-200, -200) " stroke-linecap="round" />\n');
start();
});
});

View file

@ -30,14 +30,14 @@
'paths': getPathObjects()
};
var REFERENCE_PATH_GROUP_SVG = '<g style="stroke: none; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(0 0)" >\n' +
'<path d="M 100 100 L 300 100 L 200 300 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
'<path d="M 200 200 L 100 200 L 400 50 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
var REFERENCE_PATH_GROUP_SVG = '<g style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform="translate(0 0)" >\n' +
'<path d="M 100 100 L 300 100 L 200 300 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
'<path d="M 200 200 L 100 200 L 400 50 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
'</g>\n';
var REFERENCE_PATH_GROUP_SVG_WITH_MATRIX = '<g style="stroke: none; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform=" matrix(1 2 3 4 5 6) translate(0 0)" >\n' +
'<path d="M 100 100 L 300 100 L 200 300 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
'<path d="M 200 200 L 100 200 L 400 50 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
var REFERENCE_PATH_GROUP_SVG_WITH_MATRIX = '<g style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;" transform=" matrix(1 2 3 4 5 6) translate(0 0)" >\n' +
'<path d="M 100 100 L 300 100 L 200 300 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
'<path d="M 200 200 L 100 200 L 400 50 z" style="stroke: blue; stroke-width: 3; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" transform="" stroke-linecap="round" />\n' +
'</g>\n';
function getPathElement(path) {

View file

@ -57,7 +57,7 @@
// node-canvas doesn't give <img> "src"
if (img.src) {
equal(object.source, '../fixtures/greyfloral.png');
ok(object.source.indexOf('fixtures/greyfloral.png') > -1);
}
equal(object.repeat, 'repeat');
equal(object.offsetX, 0);

View file

@ -64,6 +64,13 @@
var rect = fabric.Rect.fromObject(REFERENCE_RECT);
ok(rect instanceof fabric.Rect);
deepEqual(rect.toObject(), REFERENCE_RECT);
var expectedObject = fabric.util.object.extend({ }, REFERENCE_RECT);
expectedObject.fill = {"type":"linear","coords":{"x1":0,"y1":0,"x2":200,"y2":0},"colorStops":[{"offset":"0","color":"rgb(255,0,0)","opacity":1},{"offset":"1","color":"rgb(0,0,255)","opacity":1}],"offsetX":0,"offsetY":0};
expectedObject.stroke = {"type":"linear","coords":{"x1":0,"y1":0,"x2":200,"y2":0},"colorStops":[{"offset":"0","color":"rgb(255,0,0)","opacity":1},{"offset":"1","color":"rgb(0,0,255)","opacity":1}],"offsetX":0,"offsetY":0};
rect = fabric.Rect.fromObject(expectedObject);
ok(rect.fill instanceof fabric.Gradient);
ok(rect.stroke instanceof fabric.Gradient);
});
test('fabric.Rect.fromElement', function() {
@ -134,7 +141,7 @@
var rect = new fabric.Rect({ width: 100, height: 100, rx: 20, ry: 30, strokeWidth: 0 });
var svg = rect.toSVG();
equal(svg, '<rect x="-50" y="-50" rx="20" ry="30" width="100" height="100" style="stroke: none; stroke-width: 0; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform="translate(50 50)"/>\n');
equal(svg, '<rect x="-50" y="-50" rx="20" ry="30" width="100" height="100" style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform="translate(50 50)"/>\n');
});
test('toObject without default values', function() {

View file

@ -46,7 +46,7 @@
'globalCompositeOperation': 'source-over'
};
var TEXT_SVG = '\t<g transform="translate(10.5 26.72)">\n\t\t<text font-family="Times New Roman" font-size="40" font-weight="normal" style="stroke: none; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" ><tspan x="-10" y="8.98" fill="rgb(0,0,0)">x</tspan></text>\n\t</g>\n';
var TEXT_SVG = '\t<g transform="translate(10.5 26.72)">\n\t\t<text font-family="Times New Roman" font-size="40" font-weight="normal" style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" ><tspan x="-10" y="8.98" fill="rgb(0,0,0)">x</tspan></text>\n\t</g>\n';
test('constructor', function() {
ok(fabric.Text);

View file

@ -24,6 +24,8 @@
? require("path").join(__dirname, '../fixtures/', 'very_large_image.jpg')
: getAbsolutePath('../fixtures/very_large_image.jpg');
var IMG_URL_NON_EXISTING = 'http://www.google.com/non-existing';
test('fabric.util.toFixed', function(){
ok(typeof fabric.util.toFixed == 'function');
@ -459,6 +461,23 @@
}, 1000);
});
asyncTest('fabric.util.loadImage with url for a non exsiting image', function() {
var callbackInvoked = false;
var hadError = false;
fabric.util.loadImage(IMG_URL_NON_EXISTING, function(img, error) {
callbackInvoked = true;
hadError = error;
});
setTimeout(function() {
ok(callbackInvoked, 'callback should be invoked');
equal(hadError, true, 'callback should be invoked with error set to true');
start();
}, 1000);
});
var SVG_WITH_1_ELEMENT = '<?xml version="1.0"?>\
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">\