mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-05-10 14:54:42 +00:00
Merge pull request #646 from Kienz/parseSVGOpacity
Parse SVG stroke-opacity and fill-opacity. Add hsl/hsla support.
This commit is contained in:
commit
13326cde52
16 changed files with 649 additions and 290 deletions
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {String|Array} color Color value to parse
|
||||
*/
|
||||
_tryParsingColor: function(color) {
|
||||
var source;
|
||||
|
|
@ -46,11 +47,58 @@
|
|||
if (!source) {
|
||||
source = Color.sourceFromRgb(color);
|
||||
}
|
||||
if (!source) {
|
||||
source = Color.sourceFromHsl(color);
|
||||
}
|
||||
if (source) {
|
||||
this.setSource(source);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adapted from <a href="https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html">https://github.com/mjijackson</a>
|
||||
* @private
|
||||
* @param {Number} r Red color value
|
||||
* @param {Number} g Green color value
|
||||
* @param {Number} b Blue color value
|
||||
* @return {Array} Hsl color
|
||||
*/
|
||||
_rgbToHsl: function(r, g, b) {
|
||||
r /= 255, g /= 255, b /= 255;
|
||||
|
||||
var h, s, l,
|
||||
max = fabric.util.array.max([r, g, b]),
|
||||
min = fabric.util.array.min([r, g, b]);
|
||||
|
||||
l = (max + min) / 2;
|
||||
|
||||
if (max === min) {
|
||||
h = s = 0; // achromatic
|
||||
}
|
||||
else {
|
||||
var d = max - min;
|
||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
||||
switch (max) {
|
||||
case r:
|
||||
h = (g - b) / d + (g < b ? 6 : 0);
|
||||
break;
|
||||
case g:
|
||||
h = (b - r) / d + 2;
|
||||
break;
|
||||
case b:
|
||||
h = (r - g) / d + 4;
|
||||
break;
|
||||
}
|
||||
h /= 6;
|
||||
}
|
||||
|
||||
return [
|
||||
Math.round(h * 360),
|
||||
Math.round(s * 100),
|
||||
Math.round(l * 100)
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1])
|
||||
* @return {Array}
|
||||
|
|
@ -85,6 +133,28 @@
|
|||
return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')';
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns color represenation in HSL format
|
||||
* @return {String} ex: hsl(0-360,0%-100%,0%-100%)
|
||||
*/
|
||||
toHsl: function() {
|
||||
var source = this.getSource(),
|
||||
hsl = this._rgbToHsl(source[0], source[1], source[2]);
|
||||
|
||||
return 'hsl(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%)';
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns color represenation in HSLA format
|
||||
* @return {String} ex: hsla(0-360,0%-100%,0%-100%,0-1)
|
||||
*/
|
||||
toHsla: function() {
|
||||
var source = this.getSource(),
|
||||
hsl = this._rgbToHsl(source[0], source[1], source[2]);
|
||||
|
||||
return 'hsla(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%,' + source[3] + ')';
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns color represenation in HEX format
|
||||
* @return {String} ex: FF5555
|
||||
|
|
@ -114,7 +184,7 @@
|
|||
|
||||
/**
|
||||
* Sets value of alpha channel for this color
|
||||
* @param {Number} 0-1
|
||||
* @param {Number} alpha 0-1
|
||||
* @return {fabric.Color} thisArg
|
||||
*/
|
||||
setAlpha: function(alpha) {
|
||||
|
|
@ -138,6 +208,7 @@
|
|||
|
||||
/**
|
||||
* Transforms color to its black and white representation
|
||||
* @param {Number} threshold
|
||||
* @return {fabric.Color} thisArg
|
||||
*/
|
||||
toBlackWhite: function(threshold) {
|
||||
|
|
@ -179,11 +250,18 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* Regex matching color in RGB or RGBA formats (ex: rgb(0, 0, 0), rgb(255, 100, 10, 0.5), rgb(1,1,1))
|
||||
* Regex matching color in RGB or RGBA formats (ex: rgb(0, 0, 0), rgba(255, 100, 10, 0.5), rgba( 255 , 100 , 10 , 0.5 ), rgb(1,1,1), rgba(100%, 60%, 10%, 0.5))
|
||||
* @static
|
||||
* @field
|
||||
*/
|
||||
fabric.Color.reRGBa = /^rgba?\((\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(\d+(?:\.\d+)?))?\)$/;
|
||||
fabric.Color.reRGBa = /^rgba?\(\s*(\d{1,3}\%?)\s*,\s*(\d{1,3}\%?)\s*,\s*(\d{1,3}\%?)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/;
|
||||
|
||||
/**
|
||||
* Regex matching color in HSL or HSLA formats (ex: hsl(200, 80%, 10%), hsla(300, 50%, 80%, 0.5), hsla( 300 , 50% , 80% , 0.5 ))
|
||||
* @static
|
||||
* @field
|
||||
*/
|
||||
fabric.Color.reHSLa = /^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3}\%)\s*,\s*(\d{1,3}\%)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/;
|
||||
|
||||
/**
|
||||
* Regex matching color in HEX format (ex: #FF5555, 010155, aff)
|
||||
|
|
@ -216,6 +294,22 @@
|
|||
'yellow': '#FFFF00'
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Number} p
|
||||
* @param {Number} q
|
||||
* @param {Number} t
|
||||
* @return {Number}
|
||||
*/
|
||||
function hue2rgb(p, q, t){
|
||||
if(t < 0) t += 1;
|
||||
if(t > 1) t -= 1;
|
||||
if(t < 1/6) return p + (q - p) * 6 * t;
|
||||
if(t < 1/2) return q;
|
||||
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns new color object, when given a color in RGB format
|
||||
* @param {String} color ex: rgb(0-255,0-255,0-255)
|
||||
|
|
@ -227,16 +321,20 @@
|
|||
|
||||
/**
|
||||
* Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format
|
||||
* @param {String} color ex: rgb(0-255,0-255,0-255)
|
||||
* @param {String} color ex: rgb(0-255,0-255,0-255), rgb(0%-100%,0%-100%,0%-100%)
|
||||
* @return {Array} source
|
||||
*/
|
||||
fabric.Color.sourceFromRgb = function(color) {
|
||||
var match = color.match(Color.reRGBa);
|
||||
if (match) {
|
||||
var r = parseInt(match[1], 10) / (/%$/.test(match[1]) ? 100 : 1) * (/%$/.test(match[1]) ? 255 : 1),
|
||||
g = parseInt(match[2], 10) / (/%$/.test(match[2]) ? 100 : 1) * (/%$/.test(match[2]) ? 255 : 1),
|
||||
b = parseInt(match[3], 10) / (/%$/.test(match[3]) ? 100 : 1) * (/%$/.test(match[3]) ? 255 : 1);
|
||||
|
||||
return [
|
||||
parseInt(match[1], 10),
|
||||
parseInt(match[2], 10),
|
||||
parseInt(match[3], 10),
|
||||
parseInt(r, 10),
|
||||
parseInt(g, 10),
|
||||
parseInt(b, 10),
|
||||
match[4] ? parseFloat(match[4]) : 1
|
||||
];
|
||||
}
|
||||
|
|
@ -251,6 +349,60 @@
|
|||
*/
|
||||
fabric.Color.fromRgba = Color.fromRgb;
|
||||
|
||||
/**
|
||||
* Returns new color object, when given a color in HSL format
|
||||
* @param {String} color ex: hsl(0-260,0%-100%,0%-100%)
|
||||
* @return {fabric.Color}
|
||||
*/
|
||||
fabric.Color.fromHsl = function(color) {
|
||||
return Color.fromSource(Color.sourceFromHsl(color));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns array represenatation (ex: [100, 100, 200, 1]) of a color that's in HSL or HSLA format.
|
||||
* Adapted from <a href="https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html">https://github.com/mjijackson</a>
|
||||
* @param {String} color ex: hsl(0-360,0%-100%,0%-100%) or hsla(0-360,0%-100%,0%-100%, 0-1)
|
||||
* @return {Array} source
|
||||
* @see http://http://www.w3.org/TR/css3-color/#hsl-color
|
||||
*/
|
||||
fabric.Color.sourceFromHsl = function(color) {
|
||||
var match = color.match(Color.reHSLa);
|
||||
if (!match) return;
|
||||
|
||||
var h = (((parseFloat(match[1]) % 360) + 360) % 360) / 360,
|
||||
s = parseFloat(match[2]) / (/%$/.test(match[2]) ? 100 : 1),
|
||||
l = parseFloat(match[3]) / (/%$/.test(match[3]) ? 100 : 1),
|
||||
r, g, b;
|
||||
|
||||
if (s === 0) {
|
||||
r = g = b = l;
|
||||
}
|
||||
else {
|
||||
var q = l <= 0.5 ? l * (s + 1) : l + s - l * s;
|
||||
var p = l * 2 - q;
|
||||
|
||||
r = hue2rgb(p, q, h + 1/3);
|
||||
g = hue2rgb(p, q, h);
|
||||
b = hue2rgb(p, q, h - 1/3);
|
||||
}
|
||||
|
||||
return [
|
||||
Math.round(r * 255),
|
||||
Math.round(g * 255),
|
||||
Math.round(b * 255),
|
||||
match[4] ? parseFloat(match[4]) : 1
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns new color object, when given a color in HSLA format
|
||||
* @static
|
||||
* @function
|
||||
* @param {String} color
|
||||
* @return {fabric.Color}
|
||||
*/
|
||||
fabric.Color.fromHsla = Color.fromHsl;
|
||||
|
||||
/**
|
||||
* Returns new color object, when given a color in HEX format
|
||||
* @static
|
||||
|
|
@ -286,6 +438,7 @@
|
|||
/**
|
||||
* Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5])
|
||||
* @static
|
||||
* @param {Array} source
|
||||
* @return {fabric.Color}
|
||||
*/
|
||||
fabric.Color.fromSource = function(source) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
* Constructor
|
||||
* @param {HTMLImageElement | String} element Image element
|
||||
* @param {Object} [options] Options object
|
||||
* @return {fabric.Image}
|
||||
* @return {fabric.Image} thisArg
|
||||
*/
|
||||
initialize: function(element, options) {
|
||||
options || (options = { });
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
|
||||
/**
|
||||
* Returns image element which this instance if based on
|
||||
* @return {HTMLImageElement} image element
|
||||
* @return {HTMLImageElement} Image element
|
||||
*/
|
||||
getElement: function() {
|
||||
return this._element;
|
||||
|
|
@ -136,9 +136,10 @@
|
|||
ctx.strokeStyle = this.stroke.toLive
|
||||
? this.stroke.toLive(ctx)
|
||||
: this.stroke;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.strokeRect(-this.width / 2, -this.height / 2, this.width, this.height);
|
||||
ctx.beginPath();
|
||||
ctx.closePath();
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
|
|
@ -152,6 +153,7 @@
|
|||
w = this.width,
|
||||
h = this.height;
|
||||
|
||||
ctx.save();
|
||||
ctx.lineWidth = this.strokeWidth;
|
||||
ctx.lineCap = this.strokeLineCap;
|
||||
ctx.lineJoin = this.strokeLineJoin;
|
||||
|
|
@ -159,12 +161,14 @@
|
|||
ctx.strokeStyle = this.stroke.toLive
|
||||
? this.stroke.toLive(ctx)
|
||||
: this.stroke;
|
||||
|
||||
ctx.beginPath();
|
||||
fabric.util.drawDashedLine(ctx, x, y, x+w, y, this.strokeDashArray);
|
||||
fabric.util.drawDashedLine(ctx, x+w, y, x+w, y+h, this.strokeDashArray);
|
||||
fabric.util.drawDashedLine(ctx, x+w, y+h, x, y+h, this.strokeDashArray);
|
||||
fabric.util.drawDashedLine(ctx, x, y+h, x, y, this.strokeDashArray);
|
||||
ctx.closePath();
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -372,7 +376,7 @@
|
|||
|
||||
/**
|
||||
* Returns complexity of an instance
|
||||
* @return {Number} complexity
|
||||
* @return {Number} complexity of this instance
|
||||
*/
|
||||
complexity: function() {
|
||||
return 1;
|
||||
|
|
@ -455,7 +459,7 @@
|
|||
* @param {SVGElement} element Element to parse
|
||||
* @param {Function} callback Callback to execute when fabric.Image object is created
|
||||
* @param {Object} [options] Options object
|
||||
* @return {fabric.Image}
|
||||
* @return {fabric.Image} Instance of fabric.Image
|
||||
*/
|
||||
fabric.Image.fromElement = function(element, callback, options) {
|
||||
var parsedAttributes = fabric.parseAttributes(element, fabric.Image.ATTRIBUTE_NAMES);
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@
|
|||
overlayFill: null,
|
||||
|
||||
/**
|
||||
* When `true`, an object is rendered via stroke and this property specifies its color
|
||||
* When defined, an object is rendered via stroke and this property specifies its color
|
||||
* @type String
|
||||
* @default
|
||||
*/
|
||||
|
|
@ -413,7 +413,7 @@
|
|||
/**
|
||||
* Transforms context when rendering an object
|
||||
* @param {CanvasRenderingContext2D} ctx Context
|
||||
* @param {Boolean} when true, context is transformed to object's top/left corner. This is used when rendering text on Node
|
||||
* @param {Boolean} fromLeft When true, context is transformed to object's top/left corner. This is used when rendering text on Node
|
||||
*/
|
||||
transform: function(ctx, fromLeft) {
|
||||
ctx.globalAlpha = this.opacity;
|
||||
|
|
@ -429,8 +429,8 @@
|
|||
|
||||
/**
|
||||
* Returns an object representation of an instance
|
||||
* @param {Array} propertiesToInclude
|
||||
* @return {Object} object representation of an instance
|
||||
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
||||
* @return {Object} Object representation of an instance
|
||||
*/
|
||||
toObject: function(propertiesToInclude) {
|
||||
|
||||
|
|
@ -478,8 +478,8 @@
|
|||
|
||||
/**
|
||||
* Returns (dataless) object representation of an instance
|
||||
* @param {Array} [propertiesToInclude]
|
||||
* @return {Object} object representation of an instance
|
||||
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
||||
* @return {Object} Object representation of an instance
|
||||
*/
|
||||
toDatalessObject: function(propertiesToInclude) {
|
||||
// will be overwritten by subclasses
|
||||
|
|
@ -540,6 +540,7 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} object
|
||||
*/
|
||||
_removeDefaultValues: function(object) {
|
||||
var defaultOptions = fabric.Object.prototype.options;
|
||||
|
|
@ -572,7 +573,7 @@
|
|||
|
||||
/**
|
||||
* Sets property to a given value. When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls. If you need to update those, call `setCoords()`.
|
||||
* @param {String} name
|
||||
* @param {String|Object} key (if object, iterate over the object properties)
|
||||
* @param {Object|Function} value (if function, the value is passed into it and its return value is used as a new one)
|
||||
* @return {fabric.Object} thisArg
|
||||
* @chainable
|
||||
|
|
@ -596,8 +597,9 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param key
|
||||
* @param value
|
||||
* @param {String} key
|
||||
* @param {Any} value
|
||||
* @return {fabric.Object} thisArg
|
||||
*/
|
||||
_set: function(key, value) {
|
||||
var shouldConstrainValue = (key === 'scaleX' || key === 'scaleY');
|
||||
|
|
@ -667,7 +669,6 @@
|
|||
this.transform(ctx);
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
if (this.stroke) {
|
||||
ctx.lineWidth = this.strokeWidth;
|
||||
ctx.lineCap = this.strokeLineCap;
|
||||
|
|
@ -697,7 +698,6 @@
|
|||
this._render(ctx, noTransform);
|
||||
this.clipTo && ctx.restore();
|
||||
this._removeShadow(ctx);
|
||||
ctx.restore();
|
||||
|
||||
if (this.active && !noTransform) {
|
||||
this.drawBorders(ctx);
|
||||
|
|
@ -757,6 +757,7 @@
|
|||
_renderStroke: function(ctx) {
|
||||
if (!this.stroke) return;
|
||||
|
||||
ctx.save();
|
||||
if (this.strokeDashArray) {
|
||||
// Spec requires the concatenation of two copies the dash list when the number of elements is odd
|
||||
if (1 & this.strokeDashArray.length) {
|
||||
|
|
@ -776,12 +777,13 @@
|
|||
this._stroke ? this._stroke(ctx) : ctx.stroke();
|
||||
}
|
||||
this._removeShadow(ctx);
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* Clones an instance
|
||||
* @param {Function} callback Callback is invoked with a clone as a first argument
|
||||
* @param {Array} propertiesToInclude
|
||||
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the outpu
|
||||
* @return {fabric.Object} clone of an instance
|
||||
*/
|
||||
clone: function(callback, propertiesToInclude) {
|
||||
|
|
@ -808,7 +810,7 @@
|
|||
|
||||
/**
|
||||
* Converts an object into a data-url-like string
|
||||
* @param {Object} options
|
||||
* @param {Object} options Options object
|
||||
*
|
||||
* `format` the format of the output image. Either "jpeg" or "png".
|
||||
* `quality` quality level (0..1)
|
||||
|
|
@ -876,7 +878,7 @@
|
|||
|
||||
/**
|
||||
* Returns complexity of an instance
|
||||
* @return {Number} complexity
|
||||
* @return {Number} complexity of this instance
|
||||
*/
|
||||
complexity: function() {
|
||||
return 0;
|
||||
|
|
@ -884,7 +886,7 @@
|
|||
|
||||
/**
|
||||
* Returns a JSON representation of an instance
|
||||
* @param {Array} propertiesToInclude Any properties that you might want to additionally include in the output
|
||||
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
||||
* @return {Object} JSON
|
||||
*/
|
||||
toJSON: function(propertiesToInclude) {
|
||||
|
|
|
|||
|
|
@ -11,34 +11,41 @@
|
|||
extend = fabric.util.object.extend,
|
||||
capitalize = fabric.util.string.capitalize,
|
||||
clone = fabric.util.object.clone,
|
||||
toFixed = fabric.util.toFixed,
|
||||
multiplyTransformMatrices = fabric.util.multiplyTransformMatrices;
|
||||
|
||||
fabric.SHARED_ATTRIBUTES = [
|
||||
"transform",
|
||||
"fill", "fill-rule", "fill-opacity",
|
||||
"fill", "fill-opacity", "fill-rule",
|
||||
"opacity",
|
||||
"stroke", "stroke-dasharray", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-width"
|
||||
"stroke", "stroke-dasharray", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width"
|
||||
];
|
||||
|
||||
var attributesMap = {
|
||||
'fill-opacity': 'fillOpacity',
|
||||
'fill-rule': 'fillRule',
|
||||
'font-family': 'fontFamily',
|
||||
'font-size': 'fontSize',
|
||||
'font-style': 'fontStyle',
|
||||
'font-weight': 'fontWeight',
|
||||
'cx': 'left',
|
||||
'x': 'left',
|
||||
'cy': 'top',
|
||||
'y': 'top',
|
||||
'r': 'radius',
|
||||
'fill-opacity': 'opacity',
|
||||
'fill-rule': 'fillRule',
|
||||
'stroke-width': 'strokeWidth',
|
||||
'stroke-dasharray': 'strokeDashArray',
|
||||
'stroke-linecap': 'strokeLineCap',
|
||||
'stroke-linejoin': 'strokeLineJoin',
|
||||
'stroke-miterlimit':'strokeMiterLimit',
|
||||
'transform': 'transformMatrix',
|
||||
'stroke-opacity': 'strokeOpacity',
|
||||
'stroke-width': 'strokeWidth',
|
||||
'text-decoration': 'textDecoration',
|
||||
'font-size': 'fontSize',
|
||||
'font-weight': 'fontWeight',
|
||||
'font-style': 'fontStyle',
|
||||
'font-family': 'fontFamily'
|
||||
'cy': 'top',
|
||||
'y': 'top',
|
||||
'transform': 'transformMatrix'
|
||||
};
|
||||
|
||||
var colorAttributes = {
|
||||
'stroke': 'strokeOpacity',
|
||||
'fill': 'fillOpacity'
|
||||
};
|
||||
|
||||
function normalizeAttr(attr) {
|
||||
|
|
@ -77,6 +84,22 @@
|
|||
return (!isArray && isNaN(parsed) ? value : parsed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} attributes Array of attributes to parse
|
||||
*/
|
||||
function _setStrokeFillOpacity(attributes) {
|
||||
for (var attr in colorAttributes) {
|
||||
if (!attributes[attr] || typeof attributes[colorAttributes[attr]] === 'undefined') continue;
|
||||
|
||||
var color = new fabric.Color(attributes[attr]);
|
||||
attributes[attr] = color.setAlpha(toFixed(color.getAlpha() * attributes[colorAttributes[attr]], 2)).toRgba();
|
||||
|
||||
delete attributes[colorAttributes[attr]];
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object of attributes' name/value, given element and an array of attribute names;
|
||||
* Parses parent "g" nodes recursively upwards.
|
||||
|
|
@ -116,7 +139,7 @@
|
|||
|
||||
ownAttributes = extend(ownAttributes,
|
||||
extend(getGlobalStylesForElement(element), fabric.parseStyleAttribute(element)));
|
||||
return extend(parentAttributes, ownAttributes);
|
||||
return _setStrokeFillOpacity(extend(parentAttributes, ownAttributes));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@
|
|||
* Constructor
|
||||
* @param {Array|String} path Path data (sequence of coordinates and corresponding "command" tokens)
|
||||
* @param {Object} [options] Options object
|
||||
* @return {fabric.Path} thisArg
|
||||
*/
|
||||
initialize: function(path, options) {
|
||||
options = options || { };
|
||||
|
|
@ -203,6 +204,7 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} [options] Options object
|
||||
*/
|
||||
_initializePath: function (options) {
|
||||
var isWidthSet = 'width' in options,
|
||||
|
|
@ -232,6 +234,7 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {Boolean} positionSet When false, path offset is returned otherwise 0
|
||||
*/
|
||||
_calculatePathOffset: function (positionSet) {
|
||||
return {
|
||||
|
|
@ -242,6 +245,7 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx context to render path on
|
||||
*/
|
||||
_render: function(ctx) {
|
||||
var current, // current instruction
|
||||
|
|
@ -540,7 +544,6 @@
|
|||
}
|
||||
// ctx.globalCompositeOperation = this.fillRule;
|
||||
|
||||
ctx.save();
|
||||
if (this.overlayFill) {
|
||||
ctx.fillStyle = this.overlayFill;
|
||||
}
|
||||
|
|
@ -569,7 +572,6 @@
|
|||
this._renderStroke(ctx);
|
||||
this.clipTo && ctx.restore();
|
||||
this._removeShadow(ctx);
|
||||
ctx.restore();
|
||||
|
||||
if (!noTransform && this.active) {
|
||||
this.drawBorders(ctx);
|
||||
|
|
@ -589,7 +591,7 @@
|
|||
|
||||
/**
|
||||
* Returns object representation of an instance
|
||||
* @param {Array} propertiesToInclude
|
||||
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
||||
* @return {Object} object representation of an instance
|
||||
*/
|
||||
toObject: function(propertiesToInclude) {
|
||||
|
|
@ -607,7 +609,7 @@
|
|||
|
||||
/**
|
||||
* Returns dataless object representation of an instance
|
||||
* @param {Array} propertiesToInclude
|
||||
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
||||
* @return {Object} object representation of an instance
|
||||
*/
|
||||
toDatalessObject: function(propertiesToInclude) {
|
||||
|
|
@ -657,7 +659,7 @@
|
|||
|
||||
/**
|
||||
* Returns number representation of an instance complexity
|
||||
* @return {Number} complexity
|
||||
* @return {Number} complexity of this instance
|
||||
*/
|
||||
complexity: function() {
|
||||
return this.path.length;
|
||||
|
|
|
|||
|
|
@ -37,8 +37,6 @@
|
|||
'textAlign',
|
||||
'fontStyle',
|
||||
'lineHeight',
|
||||
'stroke',
|
||||
'strokeWidth',
|
||||
'backgroundColor',
|
||||
'textBackgroundColor',
|
||||
'useNative'
|
||||
|
|
@ -52,6 +50,14 @@
|
|||
*/
|
||||
fabric.Text = fabric.util.createClass(fabric.Object, /** @lends fabric.Text.prototype */ {
|
||||
|
||||
|
||||
/**
|
||||
* Type of an object
|
||||
* @type String
|
||||
* @default
|
||||
*/
|
||||
type: 'text',
|
||||
|
||||
/**
|
||||
* Font size (in pixels)
|
||||
* @type Number
|
||||
|
|
@ -74,7 +80,7 @@
|
|||
fontFamily: 'Times New Roman',
|
||||
|
||||
/**
|
||||
* Text decoration (e.g. underline, overline)
|
||||
* Text decoration Possible values: "", "underline", "overline" or "line-through".
|
||||
* @type String
|
||||
* @default
|
||||
*/
|
||||
|
|
@ -95,7 +101,7 @@
|
|||
textAlign: 'left',
|
||||
|
||||
/**
|
||||
* Font style (e.g. italic)
|
||||
* Font style . Possible values: "", "normal", "italic" or "oblique".
|
||||
* @type String
|
||||
* @default
|
||||
*/
|
||||
|
|
@ -108,20 +114,6 @@
|
|||
*/
|
||||
lineHeight: 1.3,
|
||||
|
||||
/**
|
||||
* Stroke style. When specified, text is rendered with stroke
|
||||
* @type String
|
||||
* @default
|
||||
*/
|
||||
stroke: '',
|
||||
|
||||
/**
|
||||
* Stroke width
|
||||
* @type Number
|
||||
* @default
|
||||
*/
|
||||
strokeWidth: 1,
|
||||
|
||||
/**
|
||||
* Background color of an entire text box
|
||||
* @type String
|
||||
|
|
@ -143,13 +135,6 @@
|
|||
*/
|
||||
path: null,
|
||||
|
||||
/**
|
||||
* Type of an object
|
||||
* @type String
|
||||
* @default
|
||||
*/
|
||||
type: 'text',
|
||||
|
||||
/**
|
||||
* Indicates whether canvas native text methods should be used to render text (otherwise, Cufon is used)
|
||||
* @type Boolean
|
||||
|
|
@ -166,8 +151,8 @@
|
|||
|
||||
/**
|
||||
* Constructor
|
||||
* @param {String} text
|
||||
* @param {Object} [options]
|
||||
* @param {String} text Text string
|
||||
* @param {Object} [options] Options object
|
||||
* @return {fabric.Text} thisArg
|
||||
*/
|
||||
initialize: function(text, options) {
|
||||
|
|
@ -224,6 +209,7 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderViaCufon: function(ctx) {
|
||||
var o = Cufon.textOptions || (Cufon.textOptions = { });
|
||||
|
|
@ -316,6 +302,8 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_setBoundaries: function(ctx, textLines) {
|
||||
this._boundaries = [ ];
|
||||
|
|
@ -335,6 +323,7 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_setTextStyles: function(ctx) {
|
||||
if (this.fill) {
|
||||
|
|
@ -358,6 +347,9 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
* @return {Number} Height of fabric.Text object
|
||||
*/
|
||||
_getTextHeight: function(ctx, textLines) {
|
||||
return this.fontSize * textLines.length * this.lineHeight;
|
||||
|
|
@ -365,6 +357,9 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
* @return {Number} Maximum width of fabric.Text object
|
||||
*/
|
||||
_getTextWidth: function(ctx, textLines) {
|
||||
var maxWidth = ctx.measureText(textLines[0]).width;
|
||||
|
|
@ -380,46 +375,46 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_setTextShadow: function(ctx) {
|
||||
if (this.textShadow) {
|
||||
if (!this.textShadow) return;
|
||||
|
||||
// "rgba(0,0,0,0.2) 2px 2px 10px"
|
||||
// "rgb(0, 100, 0) 0 0 5px"
|
||||
// "red 2px 2px 1px"
|
||||
// "#f55 123 345 567"
|
||||
var reOffsetsAndBlur = /\s+(-?\d+)(?:px)?\s+(-?\d+)(?:px)?\s+(\d+)(?:px)?\s*/;
|
||||
// "rgba(0,0,0,0.2) 2px 2px 10px"
|
||||
// "rgb(0, 100, 0) 0 0 5px"
|
||||
// "red 2px 2px 1px"
|
||||
// "#f55 123 345 567"
|
||||
var reOffsetsAndBlur = /\s+(-?\d+)(?:px)?\s+(-?\d+)(?:px)?\s+(\d+)(?:px)?\s*/;
|
||||
|
||||
var shadowDeclaration = this.textShadow;
|
||||
var offsetsAndBlur = reOffsetsAndBlur.exec(this.textShadow);
|
||||
var shadowColor = shadowDeclaration.replace(reOffsetsAndBlur, '');
|
||||
var shadowDeclaration = this.textShadow;
|
||||
var offsetsAndBlur = reOffsetsAndBlur.exec(this.textShadow);
|
||||
var shadowColor = shadowDeclaration.replace(reOffsetsAndBlur, '');
|
||||
|
||||
ctx.save();
|
||||
ctx.shadowColor = shadowColor;
|
||||
ctx.shadowOffsetX = parseInt(offsetsAndBlur[1], 10);
|
||||
ctx.shadowOffsetY = parseInt(offsetsAndBlur[2], 10);
|
||||
ctx.shadowBlur = parseInt(offsetsAndBlur[3], 10);
|
||||
ctx.save();
|
||||
ctx.shadowColor = shadowColor;
|
||||
ctx.shadowOffsetX = parseInt(offsetsAndBlur[1], 10);
|
||||
ctx.shadowOffsetY = parseInt(offsetsAndBlur[2], 10);
|
||||
ctx.shadowBlur = parseInt(offsetsAndBlur[3], 10);
|
||||
|
||||
this._shadows = [{
|
||||
blur: ctx.shadowBlur,
|
||||
color: ctx.shadowColor,
|
||||
offX: ctx.shadowOffsetX,
|
||||
offY: ctx.shadowOffsetY
|
||||
}];
|
||||
this._shadows = [{
|
||||
blur: ctx.shadowBlur,
|
||||
color: ctx.shadowColor,
|
||||
offX: ctx.shadowOffsetX,
|
||||
offY: ctx.shadowOffsetY
|
||||
}];
|
||||
|
||||
this._shadowOffsets = [[
|
||||
parseInt(ctx.shadowOffsetX, 10), parseInt(ctx.shadowOffsetY, 10)
|
||||
]];
|
||||
}
|
||||
this._shadowOffsets = [[
|
||||
parseInt(ctx.shadowOffsetX, 10), parseInt(ctx.shadowOffsetY, 10)
|
||||
]];
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param method
|
||||
* @param ctx
|
||||
* @param line
|
||||
* @param left
|
||||
* param top
|
||||
* @param {String} method Method name ("fillText" or "strokeText")
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {String} line Text to render
|
||||
* @param {Number} left Left position of text
|
||||
* @param {Number} top Top position of text
|
||||
*/
|
||||
_drawTextLine: function(method, ctx, line, left, top) {
|
||||
|
||||
|
|
@ -452,6 +447,10 @@
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {Number} Left offset
|
||||
*/
|
||||
_getLeftOffset: function() {
|
||||
if (fabric.isLikelyNode && (this.originX === 'left' || this.originX === 'center')) {
|
||||
return 0;
|
||||
|
|
@ -459,6 +458,10 @@
|
|||
return -this.width / 2;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {Number} Top offset
|
||||
*/
|
||||
_getTopOffset: function() {
|
||||
if (fabric.isLikelyNode && (this.originY === 'top' || this.originY === 'center')) {
|
||||
return 0;
|
||||
|
|
@ -468,51 +471,59 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextFill: function(ctx, textLines) {
|
||||
if (this.fill) {
|
||||
this._boundaries = [ ];
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
this._drawTextLine(
|
||||
'fillText',
|
||||
ctx,
|
||||
textLines[i],
|
||||
this._getLeftOffset(),
|
||||
this._getTopOffset() + ((i + 1) * this.fontSize * this.lineHeight)
|
||||
);
|
||||
}
|
||||
if (!this.fill) return;
|
||||
|
||||
this._boundaries = [ ];
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
this._drawTextLine(
|
||||
'fillText',
|
||||
ctx,
|
||||
textLines[i],
|
||||
this._getLeftOffset(),
|
||||
this._getTopOffset() + ((i + 1) * this.fontSize * this.lineHeight)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextStroke: function(ctx, textLines) {
|
||||
if (this.stroke) {
|
||||
if (this.strokeDashArray) {
|
||||
// Spec requires the concatenation of two copies the dash list when the number of elements is odd
|
||||
if (1 & this.strokeDashArray.length) {
|
||||
this.strokeDashArray.push.apply(this.strokeDashArray, this.strokeDashArray);
|
||||
}
|
||||
supportsLineDash && ctx.setLineDash(this.strokeDashArray);
|
||||
}
|
||||
if (!this.stroke) return;
|
||||
|
||||
ctx.beginPath();
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
this._drawTextLine(
|
||||
'strokeText',
|
||||
ctx,
|
||||
textLines[i],
|
||||
this._getLeftOffset(),
|
||||
this._getTopOffset() + ((i + 1) * this.fontSize * this.lineHeight)
|
||||
);
|
||||
ctx.save();
|
||||
if (this.strokeDashArray) {
|
||||
// Spec requires the concatenation of two copies the dash list when the number of elements is odd
|
||||
if (1 & this.strokeDashArray.length) {
|
||||
this.strokeDashArray.push.apply(this.strokeDashArray, this.strokeDashArray);
|
||||
}
|
||||
ctx.closePath();
|
||||
supportsLineDash && ctx.setLineDash(this.strokeDashArray);
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
this._drawTextLine(
|
||||
'strokeText',
|
||||
ctx,
|
||||
textLines[i],
|
||||
this._getLeftOffset(),
|
||||
this._getTopOffset() + ((i + 1) * this.fontSize * this.lineHeight)
|
||||
);
|
||||
}
|
||||
ctx.closePath();
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextBackground: function(ctx, textLines) {
|
||||
this._renderTextBoxBackground(ctx);
|
||||
|
|
@ -521,52 +532,57 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderTextBoxBackground: function(ctx) {
|
||||
if (this.backgroundColor) {
|
||||
ctx.save();
|
||||
ctx.fillStyle = this.backgroundColor;
|
||||
if (!this.backgroundColor) return;
|
||||
|
||||
ctx.fillRect(
|
||||
this._getLeftOffset(),
|
||||
this._getTopOffset(),
|
||||
this.width,
|
||||
this.height
|
||||
);
|
||||
ctx.save();
|
||||
ctx.fillStyle = this.backgroundColor;
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
ctx.fillRect(
|
||||
this._getLeftOffset(),
|
||||
this._getTopOffset(),
|
||||
this.width,
|
||||
this.height
|
||||
);
|
||||
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextLinesBackground: function(ctx, textLines) {
|
||||
if (this.textBackgroundColor) {
|
||||
ctx.save();
|
||||
ctx.fillStyle = this.textBackgroundColor;
|
||||
if (!this.textBackgroundColor) return;
|
||||
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
ctx.save();
|
||||
ctx.fillStyle = this.textBackgroundColor;
|
||||
|
||||
if (textLines[i] !== '') {
|
||||
for (var i = 0, len = textLines.length; i < len; i++) {
|
||||
|
||||
var lineWidth = this._getLineWidth(ctx, textLines[i]);
|
||||
var lineLeftOffset = this._getLineLeftOffset(lineWidth);
|
||||
if (textLines[i] !== '') {
|
||||
|
||||
ctx.fillRect(
|
||||
this._getLeftOffset() + lineLeftOffset,
|
||||
this._getTopOffset() + (i * this.fontSize * this.lineHeight),
|
||||
lineWidth,
|
||||
this.fontSize * this.lineHeight
|
||||
);
|
||||
}
|
||||
var lineWidth = this._getLineWidth(ctx, textLines[i]);
|
||||
var lineLeftOffset = this._getLineLeftOffset(lineWidth);
|
||||
|
||||
ctx.fillRect(
|
||||
this._getLeftOffset() + lineLeftOffset,
|
||||
this._getTopOffset() + (i * this.fontSize * this.lineHeight),
|
||||
lineWidth,
|
||||
this.fontSize * this.lineHeight
|
||||
);
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Number} lineWidth Width of text line
|
||||
* @return {Number} Line left offset
|
||||
*/
|
||||
_getLineLeftOffset: function(lineWidth) {
|
||||
if (this.textAlign === 'center') {
|
||||
|
|
@ -580,8 +596,9 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param ctx
|
||||
* @param line
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {String} line Text line
|
||||
* @return {Number} Line width
|
||||
*/
|
||||
_getLineWidth: function(ctx, line) {
|
||||
return this.textAlign === 'justify'
|
||||
|
|
@ -591,8 +608,11 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextDecoration: function(ctx, textLines) {
|
||||
if (!this.textDecoration) return;
|
||||
|
||||
var halfOfVerticalBox = this.originY === 'top' ? 0 : this._getTextHeight(ctx, textLines) / 2;
|
||||
var _this = this;
|
||||
|
|
@ -664,7 +684,7 @@
|
|||
|
||||
/**
|
||||
* Renders text instance on a specified context
|
||||
* @param ctx {CanvasRenderingContext2D} context to render on
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Boolean} [noTransform] When true, context is not transformed
|
||||
*/
|
||||
render: function(ctx, noTransform) {
|
||||
|
|
@ -682,8 +702,8 @@
|
|||
|
||||
/**
|
||||
* Returns object representation of an instance
|
||||
* @param {Array} propertiesToInclude
|
||||
* @return {Object} object representation of an instance
|
||||
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
||||
* @return {Object} Object representation of an instance
|
||||
*/
|
||||
toObject: function(propertiesToInclude) {
|
||||
return extend(this.callSuper('toObject', propertiesToInclude), {
|
||||
|
|
@ -697,8 +717,6 @@
|
|||
textShadow: this.textShadow,
|
||||
textAlign: this.textAlign,
|
||||
path: this.path,
|
||||
stroke: this.stroke,
|
||||
strokeWidth: this.strokeWidth,
|
||||
backgroundColor: this.backgroundColor,
|
||||
textBackgroundColor: this.textBackgroundColor,
|
||||
useNative: this.useNative
|
||||
|
|
@ -749,6 +767,9 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {Number} lineTopOffset Line top offset
|
||||
* @param {Array} textLines Array of all text lines
|
||||
* @return {Array}
|
||||
*/
|
||||
_getSVGShadows: function(lineTopOffset, textLines) {
|
||||
var shadowSpans = [], j, i, jlen, ilen, lineTopOffsetMultiplier = 1;
|
||||
|
|
@ -785,6 +806,10 @@
|
|||
|
||||
/**
|
||||
* @private
|
||||
* @param {Number} lineTopOffset Line top offset
|
||||
* @param {Number} textLeftOffset Text left offset
|
||||
* @param {Array} textLines Array of all text lines
|
||||
* @return {Object}
|
||||
*/
|
||||
_getSVGTextAndBg: function(lineTopOffset, textLeftOffset, textLines) {
|
||||
var textSpans = [ ], textBgRects = [ ], i, lineLeftOffset, len, lineTopOffsetMultiplier = 1;
|
||||
|
|
@ -854,6 +879,8 @@
|
|||
* we work around it by "moving" alpha channel into opacity attribute and setting fill's alpha to 1
|
||||
*
|
||||
* @private
|
||||
* @param {Any} value
|
||||
* @return {String}
|
||||
*/
|
||||
_getFillAttributes: function(value) {
|
||||
var fillColor = (value && typeof value === 'string') ? new fabric.Color(value) : '';
|
||||
|
|
@ -921,8 +948,8 @@
|
|||
/**
|
||||
* Returns fabric.Text instance from an object representation
|
||||
* @static
|
||||
* @param {Object} object to create an instance from
|
||||
* @return {fabric.Text} an instance
|
||||
* @param object {Object} object Object to create an instance from
|
||||
* @return {fabric.Text} Instance of fabric.Text
|
||||
*/
|
||||
fabric.Text.fromObject = function(object) {
|
||||
return new fabric.Text(object.text, clone(object));
|
||||
|
|
@ -931,9 +958,9 @@
|
|||
/**
|
||||
* Returns fabric.Text instance from an SVG element (<b>not yet implemented</b>)
|
||||
* @static
|
||||
* @param element
|
||||
* @param options
|
||||
* @return {fabric.Text} an instance
|
||||
* @param {SVGElement} element Element to parse
|
||||
* @param {Object} [options] Options object
|
||||
* @return {fabric.Text} Instance of fabric.Text
|
||||
*/
|
||||
fabric.Text.fromElement = function(element, options) {
|
||||
|
||||
|
|
|
|||
|
|
@ -44,11 +44,11 @@
|
|||
ok(typeof circle.setRadius == 'function');
|
||||
circle.setRadius(20);
|
||||
|
||||
equal(20, circle.getRadiusX());
|
||||
equal(20, circle.getRadiusY());
|
||||
equal(circle.getRadiusX(), 20);
|
||||
equal(circle.getRadiusY(), 20);
|
||||
|
||||
equal(40, circle.getWidth());
|
||||
equal(40, circle.getHeight());
|
||||
equal(circle.getWidth(), 40);
|
||||
equal(circle.getHeight(), 40);
|
||||
});
|
||||
|
||||
test('complexity', function() {
|
||||
|
|
@ -97,8 +97,8 @@
|
|||
circle.set('left', 100).set('top', 200).set('radius', 15);
|
||||
|
||||
var augmentedProperties = fabric.util.object.extend(fabric.util.object.clone(defaultProperties), {
|
||||
left: 100,
|
||||
top: 200,
|
||||
left: 100,
|
||||
top: 200,
|
||||
radius: 15
|
||||
});
|
||||
|
||||
|
|
@ -113,7 +113,7 @@
|
|||
left = 12,
|
||||
top = 15,
|
||||
fill = 'ff5555',
|
||||
fillOpacity = 0.5,
|
||||
opacity = 0.5,
|
||||
strokeWidth = 2,
|
||||
strokeDashArray = [5, 2],
|
||||
strokeLineCap = 'round',
|
||||
|
|
@ -125,7 +125,7 @@
|
|||
elCircle.setAttribute('cx', left);
|
||||
elCircle.setAttribute('cy', top);
|
||||
elCircle.setAttribute('fill', fill);
|
||||
elCircle.setAttribute('fill-opacity', fillOpacity);
|
||||
elCircle.setAttribute('opacity', opacity);
|
||||
elCircle.setAttribute('stroke-width', strokeWidth);
|
||||
elCircle.setAttribute('stroke-dasharray', '5, 2');
|
||||
elCircle.setAttribute('stroke-linecap', strokeLineCap);
|
||||
|
|
@ -139,7 +139,7 @@
|
|||
equal(oCircle.get('left'), left);
|
||||
equal(oCircle.get('top'), top);
|
||||
equal(oCircle.get('fill'), fill);
|
||||
equal(oCircle.get('opacity'), fillOpacity);
|
||||
equal(oCircle.get('opacity'), opacity);
|
||||
equal(oCircle.get('strokeWidth'), strokeWidth);
|
||||
deepEqual(oCircle.get('strokeDashArray'), strokeDashArray);
|
||||
equal(oCircle.get('strokeLineCap'), strokeLineCap);
|
||||
|
|
@ -193,7 +193,7 @@
|
|||
var expected = circle.toObject();
|
||||
var actual = fabric.Circle.fromObject(expected).toObject();
|
||||
|
||||
deepEqual(expected, actual);
|
||||
deepEqual(actual, expected);
|
||||
});
|
||||
|
||||
test('cloning and radius, width, height', function() {
|
||||
|
|
@ -202,9 +202,9 @@
|
|||
|
||||
var clone = circle.clone();
|
||||
|
||||
equal(40, clone.getWidth());
|
||||
equal(40, clone.getHeight());
|
||||
equal(clone.getWidth(), 40);
|
||||
equal(clone.getHeight(), 40);
|
||||
|
||||
equal(10, clone.radius);
|
||||
equal(clone.radius, 10);
|
||||
});
|
||||
})();
|
||||
|
|
@ -12,6 +12,16 @@
|
|||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toRgb(), 'rgb(100,100,100)');
|
||||
|
||||
var oColor = new fabric.Color('rgba(100,100,100, 0.5)');
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toRgba(), 'rgba(100,100,100,0.5)');
|
||||
|
||||
var oColor = new fabric.Color('hsl(262,80%,12%)');
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toHsl(), 'hsl(262,80%,12%)');
|
||||
});
|
||||
|
||||
test('getSource', function() {
|
||||
|
|
@ -43,6 +53,22 @@
|
|||
equal(oColor.toRgba(), 'rgba(0,0,0,0.5)');
|
||||
});
|
||||
|
||||
test('toHsl', function() {
|
||||
var oColor = new fabric.Color('ffffff');
|
||||
ok(typeof oColor.toHsl == 'function');
|
||||
equal(oColor.toHsl(), 'hsl(0,0%,100%)');
|
||||
oColor.setSource([0,0,0,0.5]);
|
||||
equal(oColor.toHsl(), 'hsl(0,0%,0%)');
|
||||
});
|
||||
|
||||
test('toHsla', function() {
|
||||
var oColor = new fabric.Color('ffffff');
|
||||
ok(typeof oColor.toHsla == 'function');
|
||||
equal(oColor.toHsla(), 'hsla(0,0%,100%,1)');
|
||||
oColor.setSource([0,0,0,0.5]);
|
||||
equal(oColor.toHsla(), 'hsla(0,0%,0%,0.5)');
|
||||
});
|
||||
|
||||
test('toHex', function() {
|
||||
var oColor = new fabric.Color('ffffff');
|
||||
ok(typeof oColor.toHex == 'function');
|
||||
|
|
@ -100,6 +126,36 @@
|
|||
equal(oColor.toHex(), 'FFFFFF');
|
||||
});
|
||||
|
||||
test('fromRgb (with whitespaces)', function() {
|
||||
ok(typeof fabric.Color.fromRgb == 'function');
|
||||
var originalRgb = 'rgb( 255 , 255 , 255 )';
|
||||
var oColor = fabric.Color.fromRgb(originalRgb);
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toRgb(), 'rgb(255,255,255)');
|
||||
equal(oColor.toHex(), 'FFFFFF');
|
||||
});
|
||||
|
||||
test('fromRgb (percentage values)', function() {
|
||||
ok(typeof fabric.Color.fromRgb == 'function');
|
||||
var originalRgb = 'rgb(100%,100%,100%)';
|
||||
var oColor = fabric.Color.fromRgb(originalRgb);
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toRgb(), 'rgb(255,255,255)');
|
||||
equal(oColor.toHex(), 'FFFFFF');
|
||||
});
|
||||
|
||||
test('fromRgb (percentage values with whitespaces)', function() {
|
||||
ok(typeof fabric.Color.fromRgb == 'function');
|
||||
var originalRgb = 'rgb( 100% , 100% , 100% )';
|
||||
var oColor = fabric.Color.fromRgb(originalRgb);
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toRgb(), 'rgb(255,255,255)');
|
||||
equal(oColor.toHex(), 'FFFFFF');
|
||||
});
|
||||
|
||||
test('fromRgba', function() {
|
||||
ok(typeof fabric.Color.fromRgba == 'function');
|
||||
var originalRgba = 'rgba(255,255,255,0.5)';
|
||||
|
|
@ -111,6 +167,78 @@
|
|||
equal(oColor.getAlpha(), 0.5, 'alpha should be set properly');
|
||||
});
|
||||
|
||||
test('fromRgba (with whitespaces)', function() {
|
||||
var originalRgba = 'rgba( 255 , 255 , 255 , 0.5 )';
|
||||
oColor = fabric.Color.fromRgba(originalRgba);
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toRgba(), 'rgba(255,255,255,0.5)');
|
||||
equal(oColor.toHex(), 'FFFFFF');
|
||||
equal(oColor.getAlpha(), 0.5, 'alpha should be set properly');
|
||||
});
|
||||
|
||||
test('fromRgba (percentage values)', function() {
|
||||
var originalRgba = 'rgba(100%,100%,100%,0.5)';
|
||||
oColor = fabric.Color.fromRgba(originalRgba);
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toRgba(), 'rgba(255,255,255,0.5)');
|
||||
equal(oColor.toHex(), 'FFFFFF');
|
||||
equal(oColor.getAlpha(), 0.5, 'alpha should be set properly');
|
||||
});
|
||||
|
||||
test('fromRgba (percentage values with whitespaces)', function() {
|
||||
var originalRgba = 'rgba( 100% , 100% , 100% , 0.5 )';
|
||||
oColor = fabric.Color.fromRgba(originalRgba);
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toRgba(), 'rgba(255,255,255,0.5)');
|
||||
equal(oColor.toHex(), 'FFFFFF');
|
||||
equal(oColor.getAlpha(), 0.5, 'alpha should be set properly');
|
||||
});
|
||||
|
||||
test('fromHsl', function() {
|
||||
ok(typeof fabric.Color.fromHsl == 'function');
|
||||
var originalHsl = 'hsl(262,80%,12%)';
|
||||
var oColor = fabric.Color.fromHsl(originalHsl);
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toHsl(), originalHsl);
|
||||
equal(oColor.toHex(), '180637');
|
||||
});
|
||||
|
||||
test('fromHsl (with whitespaces)', function() {
|
||||
ok(typeof fabric.Color.fromHsl == 'function');
|
||||
var originalHsl = 'hsl( 262 , 80% , 12% )';
|
||||
var oColor = fabric.Color.fromHsl(originalHsl);
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toHsl(), 'hsl(262,80%,12%)');
|
||||
equal(oColor.toHex(), '180637');
|
||||
});
|
||||
|
||||
test('fromHsla', function() {
|
||||
ok(typeof fabric.Color.fromHsla == 'function');
|
||||
var originalHsla = 'hsla(262,80%,12%,0.2)';
|
||||
var oColor = fabric.Color.fromHsla(originalHsla);
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toHsla(), originalHsla);
|
||||
equal(oColor.toHex(), '180637');
|
||||
equal(oColor.getAlpha(), 0.2, 'alpha should be set properly');
|
||||
});
|
||||
|
||||
test('fromHsla (with whitespaces)', function() {
|
||||
ok(typeof fabric.Color.fromHsla == 'function');
|
||||
var originalHsla = 'hsla( 262 , 80% , 12% , 0.2 )';
|
||||
var oColor = fabric.Color.fromHsla(originalHsla);
|
||||
ok(oColor);
|
||||
ok(oColor instanceof fabric.Color);
|
||||
equal(oColor.toHsla(), 'hsla(262,80%,12%,0.2)');
|
||||
equal(oColor.toHex(), '180637');
|
||||
equal(oColor.getAlpha(), 0.2, 'alpha should be set properly');
|
||||
});
|
||||
|
||||
test('fromHex', function() {
|
||||
ok(typeof fabric.Color.fromHex == 'function');
|
||||
var originalHex = 'FF5555';
|
||||
|
|
@ -123,24 +251,30 @@
|
|||
|
||||
test('sourceFromRgb', function() {
|
||||
ok(typeof fabric.Color.sourceFromRgb == 'function');
|
||||
deepEqual([255,255,255,1], fabric.Color.sourceFromRgb('rgb(255,255,255)'));
|
||||
deepEqual([100,150,200,1], fabric.Color.sourceFromRgb('rgb(100,150,200)'));
|
||||
deepEqual(fabric.Color.sourceFromRgb('rgb(255,255,255)'), [255,255,255,1]);
|
||||
deepEqual(fabric.Color.sourceFromRgb('rgb(100,150,200)'), [100,150,200,1]);
|
||||
});
|
||||
|
||||
test('sourceFromHsl', function() {
|
||||
ok(typeof fabric.Color.sourceFromHsl == 'function');
|
||||
deepEqual(fabric.Color.sourceFromHsl('hsl(360,100%,100%)'), [255,255,255,1]);
|
||||
deepEqual(fabric.Color.sourceFromHsl('hsl(180,50%,40%)'), [51,153,153,1]);
|
||||
});
|
||||
|
||||
test('sourceFromHex', function() {
|
||||
ok(typeof fabric.Color.sourceFromHex == 'function');
|
||||
|
||||
// uppercase
|
||||
deepEqual([255,255,255,1], fabric.Color.sourceFromHex('FFFFFF'));
|
||||
deepEqual([255,255,255,1], fabric.Color.sourceFromHex('FFF'));
|
||||
deepEqual([255,255,255,1], fabric.Color.sourceFromHex('#FFFFFF'));
|
||||
deepEqual([255,255,255,1], fabric.Color.sourceFromHex('#FFF'));
|
||||
deepEqual(fabric.Color.sourceFromHex('FFFFFF'), [255,255,255,1]);
|
||||
deepEqual(fabric.Color.sourceFromHex('FFF'), [255,255,255,1]);
|
||||
deepEqual(fabric.Color.sourceFromHex('#FFFFFF'), [255,255,255,1]);
|
||||
deepEqual(fabric.Color.sourceFromHex('#FFF'), [255,255,255,1]);
|
||||
|
||||
// lowercase
|
||||
deepEqual([255,255,255,1], fabric.Color.sourceFromHex('#ffffff'));
|
||||
deepEqual([255,255,255,1], fabric.Color.sourceFromHex('#fff'));
|
||||
deepEqual([255,255,255,1], fabric.Color.sourceFromHex('ffffff'));
|
||||
deepEqual([255,255,255,1], fabric.Color.sourceFromHex('fff'));
|
||||
deepEqual(fabric.Color.sourceFromHex('#ffffff'), [255,255,255,1]);
|
||||
deepEqual(fabric.Color.sourceFromHex('#fff'), [255,255,255,1]);
|
||||
deepEqual(fabric.Color.sourceFromHex('ffffff'), [255,255,255,1]);
|
||||
deepEqual(fabric.Color.sourceFromHex('fff'), [255,255,255,1]);
|
||||
});
|
||||
|
||||
test('fromSource', function() {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
'visible': true
|
||||
};
|
||||
ok(typeof ellipse.toObject == 'function');
|
||||
deepEqual(defaultProperties, ellipse.toObject());
|
||||
deepEqual(ellipse.toObject(), defaultProperties);
|
||||
|
||||
ellipse.set('left', 100).set('top', 200).set('rx', 15).set('ry', 25);
|
||||
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
ry: 25
|
||||
});
|
||||
|
||||
deepEqual(augmentedProperties, ellipse.toObject());
|
||||
deepEqual(ellipse.toObject(), augmentedProperties);
|
||||
});
|
||||
|
||||
test('render', function() {
|
||||
|
|
@ -92,7 +92,7 @@
|
|||
left = 12,
|
||||
top = 15,
|
||||
fill = 'ff5555',
|
||||
fillOpacity = 0.5,
|
||||
opacity = 0.5,
|
||||
strokeWidth = 2,
|
||||
strokeDashArray = [5, 2],
|
||||
strokeLineCap = 'round',
|
||||
|
|
@ -104,7 +104,7 @@
|
|||
elEllipse.setAttribute('cx', left);
|
||||
elEllipse.setAttribute('cy', top);
|
||||
elEllipse.setAttribute('fill', fill);
|
||||
elEllipse.setAttribute('fill-opacity', fillOpacity);
|
||||
elEllipse.setAttribute('opacity', opacity);
|
||||
elEllipse.setAttribute('stroke-width', strokeWidth);
|
||||
elEllipse.setAttribute('stroke-dasharray', '5, 2');
|
||||
elEllipse.setAttribute('stroke-linecap', strokeLineCap);
|
||||
|
|
@ -119,7 +119,7 @@
|
|||
equal(oEllipse.get('left'), left);
|
||||
equal(oEllipse.get('top'), top);
|
||||
equal(oEllipse.get('fill'), fill);
|
||||
equal(oEllipse.get('opacity'), fillOpacity);
|
||||
equal(oEllipse.get('opacity'), opacity);
|
||||
equal(oEllipse.get('strokeWidth'), strokeWidth);
|
||||
deepEqual(oEllipse.get('strokeDashArray'), strokeDashArray);
|
||||
equal(oEllipse.get('strokeLineCap'), strokeLineCap);
|
||||
|
|
@ -150,6 +150,6 @@
|
|||
var expected = ellipse.toObject();
|
||||
var actual = fabric.Ellipse.fromObject(expected).toObject();
|
||||
|
||||
deepEqual(expected, actual);
|
||||
deepEqual(actual, expected);
|
||||
});
|
||||
})();
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
'cy': 103,
|
||||
'y': 104,
|
||||
'r': 105,
|
||||
'fill-opacity': 0.45,
|
||||
'opacity': 0.45,
|
||||
'fill-rule': 'foo',
|
||||
'stroke-width': 4
|
||||
};
|
||||
|
|
@ -26,17 +26,17 @@
|
|||
ok(fabric.parseAttributes);
|
||||
|
||||
var element = makeElement();
|
||||
var attributeNames = 'cx cy x y r fill-opacity fill-rule stroke-width transform fill fill-rule'.split(' ');
|
||||
var attributeNames = 'cx cy x y r opacity fill-rule stroke-width transform fill fill-rule'.split(' ');
|
||||
var parsedAttributes = fabric.parseAttributes(element, attributeNames);
|
||||
|
||||
deepEqual({
|
||||
deepEqual(parsedAttributes, {
|
||||
left: 102,
|
||||
top: 104,
|
||||
radius: 105,
|
||||
opacity: 0.45,
|
||||
fillRule: 'foo',
|
||||
strokeWidth: 4
|
||||
}, parsedAttributes);
|
||||
});
|
||||
});
|
||||
|
||||
test('parseAttributesNoneValues', function() {
|
||||
|
|
@ -44,27 +44,27 @@
|
|||
element.setAttribute('fill', 'none');
|
||||
element.setAttribute('stroke', 'none');
|
||||
|
||||
deepEqual({ fill: '', stroke: '' }, fabric.parseAttributes(element, 'fill stroke'.split(' ')));
|
||||
deepEqual(fabric.parseAttributes(element, 'fill stroke'.split(' ')), { fill: '', stroke: '' });
|
||||
});
|
||||
|
||||
test('parseAttributesFillRule', function() {
|
||||
var element = fabric.document.createElement('path');
|
||||
element.setAttribute('fill-rule', 'evenodd');
|
||||
|
||||
deepEqual({ fillRule: 'destination-over' }, fabric.parseAttributes(element, ['fill-rule']));
|
||||
deepEqual(fabric.parseAttributes(element, ['fill-rule']), { fillRule: 'destination-over' });
|
||||
});
|
||||
|
||||
test('parseAttributesFillRuleWithoutTransformation', function() {
|
||||
var element = fabric.document.createElement('path');
|
||||
element.setAttribute('fill-rule', 'inherit');
|
||||
|
||||
deepEqual({ fillRule: 'inherit' }, fabric.parseAttributes(element, ['fill-rule']));
|
||||
deepEqual(fabric.parseAttributes(element, ['fill-rule']), { fillRule: 'inherit' });
|
||||
});
|
||||
|
||||
test('parseAttributesTransform', function() {
|
||||
var element = fabric.document.createElement('path');
|
||||
element.setAttribute('transform', 'translate(5, 10)');
|
||||
deepEqual({ transformMatrix: [1, 0, 0, 1, 5, 10] }, fabric.parseAttributes(element, ['transform']));
|
||||
deepEqual(fabric.parseAttributes(element, ['transform']), { transformMatrix: [1, 0, 0, 1, 5, 10] });
|
||||
});
|
||||
|
||||
test('parseAttributesWithParent', function() {
|
||||
|
|
@ -79,8 +79,8 @@
|
|||
parent.setAttribute('y', '200');
|
||||
grandParent.setAttribute('fill', 'red');
|
||||
|
||||
deepEqual({ fill: 'red', left: 100, top: 200 },
|
||||
fabric.parseAttributes(element, 'x y fill'.split(' ')));
|
||||
deepEqual(fabric.parseAttributes(element, 'x y fill'.split(' ')),
|
||||
{ fill: 'red', left: 100, top: 200 });
|
||||
});
|
||||
|
||||
asyncTest('parseElements', function() {
|
||||
|
|
@ -132,7 +132,7 @@
|
|||
'width': 103.45,
|
||||
'height': 20
|
||||
};
|
||||
deepEqual(expectedObject, fabric.parseStyleAttribute(element));
|
||||
deepEqual(fabric.parseStyleAttribute(element), expectedObject);
|
||||
});
|
||||
|
||||
test('parseStyleAttribute with one pair', function() {
|
||||
|
|
@ -142,7 +142,7 @@
|
|||
var expectedObject = {
|
||||
'left': 10
|
||||
};
|
||||
deepEqual(expectedObject, fabric.parseStyleAttribute(element));
|
||||
deepEqual(fabric.parseStyleAttribute(element), expectedObject);
|
||||
});
|
||||
|
||||
test('parseStyleAttribute with value normalization', function() {
|
||||
|
|
@ -152,7 +152,7 @@
|
|||
var expectedObject = {
|
||||
'fill': ''
|
||||
};
|
||||
deepEqual(expectedObject, fabric.parseStyleAttribute(element));
|
||||
deepEqual(fabric.parseStyleAttribute(element), expectedObject);
|
||||
});
|
||||
|
||||
test('parseStyleAttribute with short font declaration', function() {
|
||||
|
|
@ -164,7 +164,7 @@
|
|||
'fontStyle': 'italic',
|
||||
'fontFamily': 'Arial,Helvetica,sans-serif'
|
||||
};
|
||||
deepEqual(expectedObject, fabric.parseStyleAttribute(element));
|
||||
deepEqual(fabric.parseStyleAttribute(element), expectedObject);
|
||||
});
|
||||
|
||||
test('parseAttributes (style to have higher priority than attribute)', function() {
|
||||
|
|
@ -175,7 +175,21 @@
|
|||
var expectedObject = {
|
||||
'fill': 'red'
|
||||
};
|
||||
deepEqual(expectedObject, fabric.parseAttributes(element, ['path']));
|
||||
deepEqual(fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES), expectedObject);
|
||||
});
|
||||
|
||||
test('parseAttributes stroke-opacity and fill-opacity', function() {
|
||||
var element = fabric.document.createElement('path');
|
||||
element.setAttribute('style', 'fill:rgb(100,200,50);fill-opacity:0.2;');
|
||||
element.setAttribute('stroke', 'green');
|
||||
element.setAttribute('stroke-opacity', '0.5');
|
||||
element.setAttribute('fill', 'green');
|
||||
|
||||
var expectedObject = {
|
||||
'fill': 'rgba(100,200,50,0.2)',
|
||||
'stroke': 'rgba(0,128,0,0.5)'
|
||||
};
|
||||
deepEqual(fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES), expectedObject);
|
||||
});
|
||||
|
||||
test('parsePointsAttribute', function() {
|
||||
|
|
@ -210,44 +224,44 @@
|
|||
|
||||
element.setAttribute('transform', 'translate(5,10)');
|
||||
var parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform'));
|
||||
deepEqual([1,0,0,1,5,10], parsedValue);
|
||||
deepEqual(parsedValue, [1,0,0,1,5,10]);
|
||||
|
||||
element.setAttribute('transform', 'translate(-10,-20)');
|
||||
var parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform'));
|
||||
deepEqual([1,0,0,1,-10,-20], parsedValue);
|
||||
deepEqual(parsedValue, [1,0,0,1,-10,-20]);
|
||||
|
||||
var ANGLE = 90;
|
||||
element.setAttribute('transform', 'rotate(' + ANGLE + ')');
|
||||
var parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform'));
|
||||
deepEqual([Math.cos(ANGLE), Math.sin(ANGLE), -Math.sin(ANGLE), Math.cos(ANGLE), 0, 0], parsedValue);
|
||||
deepEqual(parsedValue, [Math.cos(ANGLE), Math.sin(ANGLE), -Math.sin(ANGLE), Math.cos(ANGLE), 0, 0]);
|
||||
|
||||
element.setAttribute('transform', 'scale(3.5)');
|
||||
var parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform'));
|
||||
deepEqual([3.5,0,0,3.5,0,0], parsedValue);
|
||||
deepEqual(parsedValue, [3.5,0,0,3.5,0,0]);
|
||||
|
||||
element.setAttribute('transform', 'scale(2 13)');
|
||||
var parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform'));
|
||||
deepEqual([2,0,0,13,0,0], parsedValue);
|
||||
deepEqual(parsedValue, [2,0,0,13,0,0]);
|
||||
|
||||
element.setAttribute('transform', 'skewX(2)');
|
||||
var parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform'));
|
||||
deepEqual([1,0,2,1,0,0], parsedValue);
|
||||
deepEqual(parsedValue, [1,0,2,1,0,0]);
|
||||
|
||||
element.setAttribute('transform', 'skewY(234.111)');
|
||||
var parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform'));
|
||||
deepEqual([1,234.111,0,1,0,0], parsedValue);
|
||||
deepEqual(parsedValue, [1,234.111,0,1,0,0]);
|
||||
|
||||
element.setAttribute('transform', 'matrix(1,2,3,4,5,6)');
|
||||
var parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform'));
|
||||
deepEqual([1,2,3,4,5,6], parsedValue);
|
||||
deepEqual(parsedValue, [1,2,3,4,5,6]);
|
||||
|
||||
element.setAttribute('transform', 'translate(21,31) translate(11,22)');
|
||||
var parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform'));
|
||||
deepEqual([1,0,0,1,32,53], parsedValue);
|
||||
deepEqual(parsedValue, [1,0,0,1,32,53]);
|
||||
|
||||
element.setAttribute('transform', 'scale(2 13) translate(5,15) skewX(11.22)');
|
||||
var parsedValue = fabric.parseTransformAttribute(element.getAttribute('transform'));
|
||||
deepEqual([2,0,22.44,13,10,195], parsedValue);
|
||||
deepEqual(parsedValue, [2,0,22.44,13,10,195]);
|
||||
|
||||
});
|
||||
|
||||
|
|
@ -321,7 +335,7 @@
|
|||
el.setAttribute('opacity', opacityValue);
|
||||
var obj = fabric.Rect.fromElement(el);
|
||||
|
||||
equal(parseFloat(opacityValue), obj.opacity,
|
||||
equal(obj.opacity, parseFloat(opacityValue),
|
||||
'opacity should be parsed correctly from "opacity" attribute of ' + tagNames[i] + ' element');
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -78,25 +78,25 @@
|
|||
test('toString', function() {
|
||||
var path = makePathObject();
|
||||
ok(typeof path.toString == 'function');
|
||||
equal('#<fabric.Path (4): { "top": 200, "left": 200 }>', path.toString());
|
||||
equal(path.toString(), '#<fabric.Path (4): { "top": 200, "left": 200 }>');
|
||||
});
|
||||
|
||||
test('toObject', function() {
|
||||
var path = makePathObject();
|
||||
ok(typeof path.toObject == 'function');
|
||||
deepEqual(REFERENCE_PATH_OBJECT, path.toObject());
|
||||
deepEqual(path.toObject(), REFERENCE_PATH_OBJECT);
|
||||
});
|
||||
|
||||
test('toDatalessObject', function() {
|
||||
var path = makePathObject();
|
||||
ok(typeof path.toDatalessObject == 'function');
|
||||
deepEqual(REFERENCE_PATH_OBJECT, path.toDatalessObject());
|
||||
deepEqual(path.toDatalessObject(), REFERENCE_PATH_OBJECT);
|
||||
|
||||
var src = 'http://example.com/';
|
||||
path.setSourcePath(src);
|
||||
deepEqual(fabric.util.object.extend(fabric.util.object.clone(REFERENCE_PATH_OBJECT), {
|
||||
path: src
|
||||
}), path.toDatalessObject());
|
||||
deepEqual(path.toDatalessObject(), fabric.util.object.extend(fabric.util.object.clone(REFERENCE_PATH_OBJECT), {
|
||||
path: src
|
||||
}));
|
||||
});
|
||||
|
||||
test('complexity', function() {
|
||||
|
|
@ -108,7 +108,7 @@
|
|||
ok(typeof fabric.Path.fromObject == 'function');
|
||||
var path = fabric.Path.fromObject(REFERENCE_PATH_OBJECT);
|
||||
ok(path instanceof fabric.Path);
|
||||
deepEqual(REFERENCE_PATH_OBJECT, path.toObject());
|
||||
deepEqual(path.toObject(), REFERENCE_PATH_OBJECT);
|
||||
});
|
||||
|
||||
test('fromElement', function() {
|
||||
|
|
@ -117,7 +117,7 @@
|
|||
|
||||
elPath.setAttribute('d', 'M 100 100 L 300 100 L 200 300 z');
|
||||
elPath.setAttribute('fill', 'red');
|
||||
elPath.setAttribute('fill-opacity', '1');
|
||||
elPath.setAttribute('opacity', '1');
|
||||
elPath.setAttribute('stroke', 'blue');
|
||||
elPath.setAttribute('stroke-width', '1');
|
||||
elPath.setAttribute('stroke-dasharray', '5, 2');
|
||||
|
|
@ -132,13 +132,13 @@
|
|||
var path = fabric.Path.fromElement(elPath);
|
||||
ok(path instanceof fabric.Path);
|
||||
|
||||
deepEqual(fabric.util.object.extend(REFERENCE_PATH_OBJECT, {
|
||||
deepEqual(path.toObject(), fabric.util.object.extend(REFERENCE_PATH_OBJECT, {
|
||||
strokeDashArray: [5, 2],
|
||||
strokeLineCap: 'round',
|
||||
strokeLineJoin: 'bevil',
|
||||
strokeMiterLimit: 5,
|
||||
transformMatrix: [2, 0, 0, 2, 0, 0]
|
||||
}), path.toObject());
|
||||
}));
|
||||
|
||||
var ANGLE = 90;
|
||||
|
||||
|
|
@ -146,8 +146,8 @@
|
|||
path = fabric.Path.fromElement(elPath);
|
||||
|
||||
deepEqual(
|
||||
[ Math.cos(ANGLE), Math.sin(ANGLE), -Math.sin(ANGLE), Math.cos(ANGLE), 0, 0 ],
|
||||
path.get('transformMatrix')
|
||||
path.get('transformMatrix'),
|
||||
[ Math.cos(ANGLE), Math.sin(ANGLE), -Math.sin(ANGLE), Math.cos(ANGLE), 0, 0 ]
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -155,16 +155,16 @@
|
|||
var el = getPathElement('M100 100 l 200 200 300 300 400 -50 z');
|
||||
var obj = fabric.Path.fromElement(el);
|
||||
|
||||
deepEqual(['M', 100, 100], obj.path[0]);
|
||||
deepEqual(['l', 200, 200], obj.path[1]);
|
||||
deepEqual(['l', 300, 300], obj.path[2]);
|
||||
deepEqual(['l', 400, -50], obj.path[3]);
|
||||
deepEqual(obj.path[0], ['M', 100, 100]);
|
||||
deepEqual(obj.path[1], ['l', 200, 200]);
|
||||
deepEqual(obj.path[2], ['l', 300, 300]);
|
||||
deepEqual(obj.path[3], ['l', 400, -50]);
|
||||
|
||||
el = getPathElement('c 0,-53.25604 43.17254,-96.42858 96.42857,-96.42857 53.25603,0 96.42857,43.17254 96.42857,96.42857');
|
||||
obj = fabric.Path.fromElement(el);
|
||||
|
||||
deepEqual(['c', 0, -53.25604, 43.17254, -96.42858, 96.42857, -96.42857], obj.path[0]);
|
||||
deepEqual(['c', 53.25603, 0, 96.42857, 43.17254, 96.42857, 96.42857], obj.path[1]);
|
||||
deepEqual(obj.path[0], ['c', 0, -53.25604, 43.17254, -96.42858, 96.42857, -96.42857]);
|
||||
deepEqual(obj.path[1], ['c', 53.25603, 0, 96.42857, 43.17254, 96.42857, 96.42857]);
|
||||
});
|
||||
|
||||
test('compressed path commands', function() {
|
||||
|
|
@ -172,9 +172,9 @@
|
|||
var el = getPathElement('M56.224 84.12c-.047.132-.138.221-.322.215.046-.131.137-.221.322-.215z');
|
||||
var obj = fabric.Path.fromElement(el);
|
||||
|
||||
deepEqual(['M', 56.224, 84.12], obj.path[0]);
|
||||
deepEqual(['c', -0.047, 0.132, -0.138, 0.221, -0.322, 0.215], obj.path[1]);
|
||||
deepEqual(['c', 0.046, -0.131, 0.137, -0.221, 0.322, -0.215], obj.path[2]);
|
||||
deepEqual(['z'], obj.path[3]);
|
||||
deepEqual(obj.path[0], ['M', 56.224, 84.12]);
|
||||
deepEqual(obj.path[1], ['c', -0.047, 0.132, -0.138, 0.221, -0.322, 0.215]);
|
||||
deepEqual(obj.path[2], ['c', 0.046, -0.131, 0.137, -0.221, 0.322, -0.215]);
|
||||
deepEqual(obj.path[3], ['z']);
|
||||
});
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
el.setAttribute('d', path);
|
||||
el.setAttribute('fill', 'rgb(255,0,0)');
|
||||
el.setAttribute('stroke', 'blue');
|
||||
el.setAttribute('troke-width', 3);
|
||||
el.setAttribute('stroke-width', 3);
|
||||
return el;
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +77,7 @@
|
|||
paths[0].group = null;
|
||||
paths[1].group = null;
|
||||
|
||||
deepEqual(paths, pathGroup.getObjects());
|
||||
deepEqual(pathGroup.getObjects(), paths);
|
||||
});
|
||||
|
||||
test('toObject', function() {
|
||||
|
|
@ -115,7 +115,7 @@
|
|||
'paths': 'http://example.com/',
|
||||
'sourcePath': 'http://example.com/'
|
||||
});
|
||||
deepEqual(expectedObject, pathGroup.toDatalessObject());
|
||||
deepEqual(pathGroup.toDatalessObject(), expectedObject);
|
||||
});
|
||||
|
||||
test('toString', function() {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
ok(polygon instanceof fabric.Object);
|
||||
|
||||
equal(polygon.type, 'polygon');
|
||||
deepEqual([ { x: -5, y: -5 }, { x: 5, y: 5 } ], polygon.get('points'));
|
||||
deepEqual(polygon.get('points'), [ { x: -5, y: -5 }, { x: 5, y: 5 } ]);
|
||||
});
|
||||
|
||||
test('complexity', function() {
|
||||
|
|
@ -74,7 +74,7 @@
|
|||
ok(typeof fabric.Polygon.fromObject == 'function');
|
||||
var polygon = fabric.Polygon.fromObject(REFERENCE_OBJECT);
|
||||
ok(polygon instanceof fabric.Polygon);
|
||||
deepEqual(REFERENCE_OBJECT, polygon.toObject());
|
||||
deepEqual(polygon.toObject(), REFERENCE_OBJECT);
|
||||
});
|
||||
|
||||
test('fromElement', function() {
|
||||
|
|
@ -93,12 +93,12 @@
|
|||
points: [ { x: 10, y: 12 }, { x: 20, y: 22 } ]
|
||||
});
|
||||
|
||||
deepEqual(expected, polygon.toObject());
|
||||
deepEqual(polygon.toObject(), expected);
|
||||
|
||||
var elPolygonWithAttrs = fabric.document.createElement('polygon');
|
||||
elPolygonWithAttrs.setAttribute('points', '10,10 20,20 30,30 10,10');
|
||||
elPolygonWithAttrs.setAttribute('fill', 'rgb(255,255,255)');
|
||||
elPolygonWithAttrs.setAttribute('fill-opacity', '0.34');
|
||||
elPolygonWithAttrs.setAttribute('opacity', '0.34');
|
||||
elPolygonWithAttrs.setAttribute('stroke-width', '3');
|
||||
elPolygonWithAttrs.setAttribute('stroke', 'blue');
|
||||
elPolygonWithAttrs.setAttribute('transform', 'translate(-10,-20) scale(2)');
|
||||
|
|
@ -115,21 +115,21 @@
|
|||
{ x: 10, y: 10 }
|
||||
];
|
||||
|
||||
deepEqual(fabric.util.object.extend(REFERENCE_OBJECT, {
|
||||
'width': 20,
|
||||
'height': 20,
|
||||
'fill': 'rgb(255,255,255)',
|
||||
'stroke': 'blue',
|
||||
'strokeWidth': 3,
|
||||
'strokeDashArray': [5, 2],
|
||||
'strokeLineCap': 'round',
|
||||
'strokeLineJoin': 'bevil',
|
||||
deepEqual(polygonWithAttrs.toObject(), fabric.util.object.extend(REFERENCE_OBJECT, {
|
||||
'width': 20,
|
||||
'height': 20,
|
||||
'fill': 'rgb(255,255,255)',
|
||||
'stroke': 'blue',
|
||||
'strokeWidth': 3,
|
||||
'strokeDashArray': [5, 2],
|
||||
'strokeLineCap': 'round',
|
||||
'strokeLineJoin': 'bevil',
|
||||
'strokeMiterLimit': 5,
|
||||
'opacity': 0.34,
|
||||
'points': expectedPoints
|
||||
}), polygonWithAttrs.toObject());
|
||||
'opacity': 0.34,
|
||||
'points': expectedPoints
|
||||
}));
|
||||
|
||||
deepEqual([ 2, 0, 0, 2, -10, -20 ], polygonWithAttrs.get('transformMatrix'));
|
||||
deepEqual(polygonWithAttrs.get('transformMatrix'), [ 2, 0, 0, 2, -10, -20 ]);
|
||||
|
||||
var elPolygonWithoutPoints = fabric.document.createElement('polygon');
|
||||
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@
|
|||
var elPolylineWithAttrs = fabric.document.createElement('polyline');
|
||||
elPolylineWithAttrs.setAttribute('points', '10,10 20,20 30,30 10,10');
|
||||
elPolylineWithAttrs.setAttribute('fill', 'rgb(255,255,255)');
|
||||
elPolylineWithAttrs.setAttribute('fill-opacity', '0.34');
|
||||
elPolylineWithAttrs.setAttribute('opacity', '0.34');
|
||||
elPolylineWithAttrs.setAttribute('stroke-width', '3');
|
||||
elPolylineWithAttrs.setAttribute('stroke', 'blue');
|
||||
elPolylineWithAttrs.setAttribute('transform', 'translate(-10,-20) scale(2)');
|
||||
|
|
@ -118,7 +118,7 @@
|
|||
'points': expectedPoints
|
||||
}));
|
||||
|
||||
deepEqual([ 2, 0, 0, 2, -10, -20 ], polylineWithAttrs.get('transformMatrix'));
|
||||
deepEqual(polylineWithAttrs.get('transformMatrix'), [ 2, 0, 0, 2, -10, -20 ]);
|
||||
|
||||
var elPolylineWithoutPoints = fabric.document.createElement('polyline');
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@
|
|||
elRectWithAttrs.setAttribute('rx', 11);
|
||||
elRectWithAttrs.setAttribute('ry', 12);
|
||||
elRectWithAttrs.setAttribute('fill', 'rgb(255,255,255)');
|
||||
elRectWithAttrs.setAttribute('fill-opacity', 0.45);
|
||||
elRectWithAttrs.setAttribute('opacity', 0.45);
|
||||
elRectWithAttrs.setAttribute('stroke', 'blue');
|
||||
elRectWithAttrs.setAttribute('stroke-width', 3);
|
||||
elRectWithAttrs.setAttribute('stroke-dasharray', '5, 2');
|
||||
|
|
@ -102,20 +102,20 @@
|
|||
ok(rectWithAttrs instanceof fabric.Rect);
|
||||
|
||||
var expectedObject = fabric.util.object.extend(REFERENCE_RECT, {
|
||||
left: 121,
|
||||
top: 186.5,
|
||||
width: 222,
|
||||
height: 333,
|
||||
fill: 'rgb(255,255,255)',
|
||||
opacity: 0.45,
|
||||
stroke: 'blue',
|
||||
strokeWidth: 3,
|
||||
strokeDashArray: [5, 2],
|
||||
strokeLineCap: 'round',
|
||||
strokeLineJoin: 'bevil',
|
||||
left: 121,
|
||||
top: 186.5,
|
||||
width: 222,
|
||||
height: 333,
|
||||
fill: 'rgb(255,255,255)',
|
||||
opacity: 0.45,
|
||||
stroke: 'blue',
|
||||
strokeWidth: 3,
|
||||
strokeDashArray: [5, 2],
|
||||
strokeLineCap: 'round',
|
||||
strokeLineJoin: 'bevil',
|
||||
strokeMiterLimit: 5,
|
||||
rx: 11,
|
||||
ry: 12
|
||||
rx: 11,
|
||||
ry: 12
|
||||
});
|
||||
deepEqual(rectWithAttrs.toObject(), expectedObject);
|
||||
});
|
||||
|
|
@ -136,6 +136,6 @@
|
|||
var rect = new fabric.Rect({ width: 100, height: 100, rx: 20, ry: 30 });
|
||||
var svg = rect.toSVG();
|
||||
|
||||
equal('<rect x="-50" y="-50" rx="20" ry="30" width="100" height="100" 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(0 0)"/>', svg);
|
||||
equal(svg, '<rect x="-50" y="-50" rx="20" ry="30" width="100" height="100" 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(0 0)"/>');
|
||||
});
|
||||
})();
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
'height': 52,
|
||||
'fill': 'rgb(0,0,0)',
|
||||
'overlayFill': null,
|
||||
'stroke': '',
|
||||
'stroke': null,
|
||||
'strokeWidth': 1,
|
||||
'strokeDashArray': null,
|
||||
'strokeLineCap': 'butt',
|
||||
|
|
@ -98,9 +98,9 @@
|
|||
|
||||
text.set({ opacity: 0.123, fill: 'red', fontFamily: 'blah' });
|
||||
|
||||
equal(0.123, text.getOpacity());
|
||||
equal('red', text.getFill());
|
||||
equal('blah', text.get('fontFamily'));
|
||||
equal(text.getOpacity(), 0.123);
|
||||
equal(text.getFill(), 'red');
|
||||
equal(text.get('fontFamily'), 'blah');
|
||||
});
|
||||
|
||||
test('setColor', function(){
|
||||
|
|
@ -166,7 +166,7 @@
|
|||
elTextWithAttrs.setAttribute('x', 10);
|
||||
elTextWithAttrs.setAttribute('y', 20);
|
||||
elTextWithAttrs.setAttribute('fill', 'rgb(255,255,255)');
|
||||
elTextWithAttrs.setAttribute('fill-opacity', 0.45);
|
||||
elTextWithAttrs.setAttribute('opacity', 0.45);
|
||||
elTextWithAttrs.setAttribute('stroke', 'blue');
|
||||
elTextWithAttrs.setAttribute('stroke-width', 3);
|
||||
elTextWithAttrs.setAttribute('stroke-dasharray', '5, 2');
|
||||
|
|
@ -215,10 +215,10 @@
|
|||
|
||||
test('dimensions after text change', function() {
|
||||
var text = new fabric.Text('x');
|
||||
equal(20, text.width);
|
||||
equal(text.width, 20);
|
||||
|
||||
text.setText('xx');
|
||||
equal(40, text.width);
|
||||
equal(text.width, 40);
|
||||
});
|
||||
|
||||
test('setting fontFamily', function() {
|
||||
|
|
@ -226,7 +226,7 @@
|
|||
text.path = 'foobar.js';
|
||||
|
||||
text.set('fontFamily', 'foobar');
|
||||
equal('foobar', text.get('fontFamily'));
|
||||
equal(text.get('fontFamily'), 'foobar');
|
||||
});
|
||||
|
||||
})();
|
||||
|
|
|
|||
Loading…
Reference in a new issue