mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-04-21 22:44:42 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
7111e6f2cc
56 changed files with 1855 additions and 1478 deletions
|
|
@ -1,6 +1,6 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.10.29"
|
||||
script: 'npm run-script build && npm test'
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
|
|
|
|||
992
dist/fabric.js
vendored
992
dist/fabric.js
vendored
File diff suppressed because it is too large
Load diff
14
dist/fabric.min.js
vendored
14
dist/fabric.min.js
vendored
File diff suppressed because one or more lines are too long
BIN
dist/fabric.min.js.gz
vendored
BIN
dist/fabric.min.js.gz
vendored
Binary file not shown.
992
dist/fabric.require.js
vendored
992
dist/fabric.require.js
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -71,7 +71,9 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
|
|||
* @private
|
||||
*/
|
||||
_setShadow: function() {
|
||||
if (!this.shadow) return;
|
||||
if (!this.shadow) {
|
||||
return;
|
||||
}
|
||||
|
||||
var ctx = this.canvas.contextTop;
|
||||
|
||||
|
|
|
|||
|
|
@ -339,7 +339,9 @@
|
|||
* @param {fabric.Object} target
|
||||
*/
|
||||
_shouldCenterTransform: function (e, target) {
|
||||
if (!target) return;
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
var t = this._currentTransform,
|
||||
centerTransform;
|
||||
|
|
@ -403,7 +405,9 @@
|
|||
* @param {fabric.Object} target
|
||||
*/
|
||||
_setupCurrentTransform: function (e, target) {
|
||||
if (!target) return;
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pointer = this.getPointer(e),
|
||||
corner = target._findTargetCorner(this.getPointer(e, true)),
|
||||
|
|
@ -470,9 +474,12 @@
|
|||
var t = this._currentTransform,
|
||||
target = t.target,
|
||||
lockScalingX = target.get('lockScalingX'),
|
||||
lockScalingY = target.get('lockScalingY');
|
||||
lockScalingY = target.get('lockScalingY'),
|
||||
lockScalingFlip = target.get('lockScalingFlip');
|
||||
|
||||
if (lockScalingX && lockScalingY) return;
|
||||
if (lockScalingX && lockScalingY) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the constraint point
|
||||
var constraintPosition = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY),
|
||||
|
|
@ -481,7 +488,7 @@
|
|||
this._setLocalMouse(localMouse, t);
|
||||
|
||||
// Actually scale the object
|
||||
this._setObjectScale(localMouse, t, lockScalingX, lockScalingY, by);
|
||||
this._setObjectScale(localMouse, t, lockScalingX, lockScalingY, by, lockScalingFlip);
|
||||
|
||||
// Make sure the constraints apply
|
||||
target.setPositionByOrigin(constraintPosition, t.originX, t.originY);
|
||||
|
|
@ -490,32 +497,36 @@
|
|||
/**
|
||||
* @private
|
||||
*/
|
||||
_setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by) {
|
||||
var target = transform.target;
|
||||
_setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip) {
|
||||
var target = transform.target, forbidScalingX = false, forbidScalingY = false;
|
||||
|
||||
transform.newScaleX = target.scaleX;
|
||||
transform.newScaleY = target.scaleY;
|
||||
transform.newScaleX = localMouse.x / (target.width + target.strokeWidth);
|
||||
transform.newScaleY = localMouse.y / (target.height + target.strokeWidth);
|
||||
|
||||
if (lockScalingFlip && transform.newScaleX <= 0 && transform.newScaleX < target.scaleX) {
|
||||
forbidScalingX = true;
|
||||
}
|
||||
|
||||
if (lockScalingFlip && transform.newScaleY <= 0 && transform.newScaleY < target.scaleY) {
|
||||
forbidScalingY = true;
|
||||
}
|
||||
|
||||
if (by === 'equally' && !lockScalingX && !lockScalingY) {
|
||||
this._scaleObjectEqually(localMouse, target, transform);
|
||||
forbidScalingX || forbidScalingY || this._scaleObjectEqually(localMouse, target, transform);
|
||||
}
|
||||
else if (!by) {
|
||||
transform.newScaleX = localMouse.x / (target.width + target.strokeWidth);
|
||||
transform.newScaleY = localMouse.y / (target.height + target.strokeWidth);
|
||||
|
||||
lockScalingX || target.set('scaleX', transform.newScaleX);
|
||||
lockScalingY || target.set('scaleY', transform.newScaleY);
|
||||
forbidScalingX || lockScalingX || target.set('scaleX', transform.newScaleX);
|
||||
forbidScalingY || lockScalingY || target.set('scaleY', transform.newScaleY);
|
||||
}
|
||||
else if (by === 'x' && !target.get('lockUniScaling')) {
|
||||
transform.newScaleX = localMouse.x / (target.width + target.strokeWidth);
|
||||
lockScalingX || target.set('scaleX', transform.newScaleX);
|
||||
forbidScalingX || lockScalingX || target.set('scaleX', transform.newScaleX);
|
||||
}
|
||||
else if (by === 'y' && !target.get('lockUniScaling')) {
|
||||
transform.newScaleY = localMouse.y / (target.height + target.strokeWidth);
|
||||
lockScalingY || target.set('scaleY', transform.newScaleY);
|
||||
forbidScalingY || lockScalingY || target.set('scaleY', transform.newScaleY);
|
||||
}
|
||||
|
||||
this._flipObject(transform);
|
||||
forbidScalingX || forbidScalingY || this._flipObject(transform);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -623,7 +634,9 @@
|
|||
|
||||
var t = this._currentTransform;
|
||||
|
||||
if (t.target.get('lockRotation')) return;
|
||||
if (t.target.get('lockRotation')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var lastAngle = atan2(t.ey - t.top, t.ex - t.left),
|
||||
curAngle = atan2(y - t.top, x - t.left),
|
||||
|
|
@ -722,7 +735,9 @@
|
|||
* @param {Boolean} skipGroup when true, group is skipped and only objects are traversed through
|
||||
*/
|
||||
findTarget: function (e, skipGroup) {
|
||||
if (this.skipTargetFind) return;
|
||||
if (this.skipTargetFind) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._isLastRenderedObject(e)) {
|
||||
return this.lastRenderedObjectWithControlsAboveOverlay;
|
||||
|
|
@ -1102,7 +1117,9 @@
|
|||
*/
|
||||
_drawObjectsControls: function(ctx) {
|
||||
for (var i = 0, len = this._objects.length; i < len; ++i) {
|
||||
if (!this._objects[i] || !this._objects[i].active) continue;
|
||||
if (!this._objects[i] || !this._objects[i].active) {
|
||||
continue;
|
||||
}
|
||||
this._objects[i]._renderControls(ctx);
|
||||
this.lastRenderedObjectWithControlsAboveOverlay = this._objects[i];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -394,7 +394,9 @@
|
|||
*/
|
||||
fabric.Color.sourceFromHsl = function(color) {
|
||||
var match = color.match(Color.reHSLa);
|
||||
if (!match) return;
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
|
||||
var h = (((parseFloat(match[1]) % 360) + 360) % 360) / 360,
|
||||
s = parseFloat(match[2]) / (/%$/.test(match[2]) ? 100 : 1),
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ fabric.ElementsParser.prototype._createObject = function(klass, el, index) {
|
|||
}
|
||||
else {
|
||||
var obj = klass.fromElement(el, this.options);
|
||||
this.resolveGradient(obj, 'fill');
|
||||
this.resolveGradient(obj, 'stroke');
|
||||
this.reviver && this.reviver(el, obj);
|
||||
this.instances[index] = obj;
|
||||
this.checkIfDone();
|
||||
|
|
@ -52,18 +54,32 @@ fabric.ElementsParser.prototype._createObject = function(klass, el, index) {
|
|||
fabric.ElementsParser.prototype.createCallback = function(index, el) {
|
||||
var _this = this;
|
||||
return function(obj) {
|
||||
_this.resolveGradient(obj, 'fill');
|
||||
_this.resolveGradient(obj, 'stroke');
|
||||
_this.reviver && _this.reviver(el, obj);
|
||||
_this.instances[index] = obj;
|
||||
_this.checkIfDone();
|
||||
};
|
||||
};
|
||||
|
||||
fabric.ElementsParser.prototype.resolveGradient = function(obj, property) {
|
||||
|
||||
var instanceFillValue = obj.get(property);
|
||||
if (!(/^url\(/).test(instanceFillValue)) {
|
||||
return;
|
||||
}
|
||||
var gradientId = instanceFillValue.slice(5, instanceFillValue.length - 1);
|
||||
if (fabric.gradientDefs[gradientId]) {
|
||||
obj.set(property,
|
||||
fabric.Gradient.fromElement(fabric.gradientDefs[gradientId], obj));
|
||||
}
|
||||
};
|
||||
|
||||
fabric.ElementsParser.prototype.checkIfDone = function() {
|
||||
if (--this.numElements === 0) {
|
||||
this.instances = this.instances.filter(function(el) {
|
||||
return el != null;
|
||||
});
|
||||
fabric.resolveGradients(this.instances);
|
||||
this.callback(this.instances);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,12 +38,12 @@
|
|||
var context = canvasEl.getContext('2d'),
|
||||
imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
|
||||
data = imageData.data,
|
||||
tr, tg, tb,
|
||||
r, g, b,
|
||||
source,
|
||||
tr, tg, tb,
|
||||
r, g, b,
|
||||
source,
|
||||
isImage = false;
|
||||
|
||||
if(this.image){
|
||||
if (this.image) {
|
||||
// Blend images
|
||||
isImage = true;
|
||||
|
||||
|
|
@ -51,12 +51,13 @@
|
|||
_el.width = this.image.width;
|
||||
_el.height = this.image.height;
|
||||
|
||||
var _tmp_canvas = new fabric.StaticCanvas(_el);
|
||||
_tmp_canvas.add(this.image);
|
||||
var context2 = _tmp_canvas.getContext('2d');
|
||||
source = context2.getImageData(0, 0, _tmp_canvas.width, _tmp_canvas.height).data;
|
||||
} else {
|
||||
// Blend color
|
||||
var tmpCanvas = new fabric.StaticCanvas(_el);
|
||||
tmpCanvas.add(this.image);
|
||||
var context2 = tmpCanvas.getContext('2d');
|
||||
source = context2.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height).data;
|
||||
}
|
||||
else {
|
||||
// Blend color
|
||||
source = new fabric.Color(this.color).getSource();
|
||||
|
||||
tr = source[0] * this.alpha;
|
||||
|
|
@ -70,22 +71,22 @@
|
|||
g = data[i + 1];
|
||||
b = data[i + 2];
|
||||
|
||||
if(isImage){
|
||||
if (isImage) {
|
||||
tr = source[i] * this.alpha;
|
||||
tg = source[i + 1] * this.alpha;
|
||||
tb = source[i + 2] * this.alpha;
|
||||
}
|
||||
|
||||
switch(this.mode){
|
||||
switch (this.mode) {
|
||||
case 'multiply':
|
||||
data[i] = r * tr / 255;
|
||||
data[i + 1] = g * tg / 255;
|
||||
data[i + 2] = b * tb / 255;
|
||||
break;
|
||||
case 'screen':
|
||||
data[i] = 1 - (1-r) * (1-tr);
|
||||
data[i + 1] = 1 - (1-g) * (1-tg);
|
||||
data[i + 2] = 1 - (1-b) * (1-tb);
|
||||
data[i] = 1 - (1 - r) * (1 - tr);
|
||||
data[i + 1] = 1 - (1 - g) * (1 - tg);
|
||||
data[i + 2] = 1 - (1 - b) * (1 - tb);
|
||||
break;
|
||||
case 'add':
|
||||
data[i] = Math.min(255, r + tr);
|
||||
|
|
|
|||
|
|
@ -125,7 +125,9 @@
|
|||
scx = sx + cx - halfSide;
|
||||
|
||||
/* jshint maxdepth:5 */
|
||||
if (scy < 0 || scy > sh || scx < 0 || scx > sw) continue;
|
||||
if (scy < 0 || scy > sh || scx < 0 || scx > sw) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var srcOff = (scy * sw + scx) * 4,
|
||||
wt = weights[cy * side + cx];
|
||||
|
|
|
|||
|
|
@ -41,7 +41,9 @@
|
|||
* @param {Object} canvasEl Canvas element to apply filter to
|
||||
*/
|
||||
applyTo: function(canvasEl) {
|
||||
if (!this.mask) return;
|
||||
if (!this.mask) {
|
||||
return;
|
||||
}
|
||||
|
||||
var context = canvasEl.getContext('2d'),
|
||||
imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
function getColorStop(el) {
|
||||
var style = el.getAttribute('style'),
|
||||
offset = el.getAttribute('offset'),
|
||||
color, opacity;
|
||||
color, colorAlpha, opacity;
|
||||
|
||||
// convert percents to absolute values
|
||||
offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1);
|
||||
|
|
@ -38,13 +38,15 @@
|
|||
opacity = el.getAttribute('stop-opacity');
|
||||
}
|
||||
|
||||
// convert rgba color to rgb color - alpha value has no affect in svg
|
||||
color = new fabric.Color(color).toRgb();
|
||||
color = new fabric.Color(color);
|
||||
colorAlpha = color.getAlpha();
|
||||
opacity = isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity);
|
||||
opacity *= colorAlpha;
|
||||
|
||||
return {
|
||||
offset: offset,
|
||||
color: color,
|
||||
opacity: isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity)
|
||||
color: color.toRgb(),
|
||||
opacity: opacity
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +78,19 @@
|
|||
* @see {@link fabric.Gradient#initialize} for constructor definition
|
||||
*/
|
||||
fabric.Gradient = fabric.util.createClass(/** @lends fabric.Gradient.prototype */ {
|
||||
/*
|
||||
* Stores the original position of the gradient when we convert from % to fixed values, for objectBoundingBox case.
|
||||
* @type Number
|
||||
* @default 0
|
||||
*/
|
||||
origX: 0,
|
||||
|
||||
/*
|
||||
* Stores the original position of the gradient when we convert from % to fixed values, for objectBoundingBox case.
|
||||
* @type Number
|
||||
* @default 0
|
||||
*/
|
||||
origY: 0,
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
|
@ -105,6 +120,11 @@
|
|||
this.coords = coords;
|
||||
this.gradientUnits = options.gradientUnits || 'objectBoundingBox';
|
||||
this.colorStops = options.colorStops.slice();
|
||||
if (options.gradientTransform) {
|
||||
this.gradientTransform = options.gradientTransform;
|
||||
}
|
||||
this.origX = options.left || this.origX;
|
||||
this.origY = options.top || this.origY;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -146,7 +166,7 @@
|
|||
*/
|
||||
toSVG: function(object, normalize) {
|
||||
var coords = fabric.util.object.clone(this.coords),
|
||||
markup;
|
||||
markup, commonAttributes;
|
||||
|
||||
// colorStops must be sorted ascending
|
||||
this.colorStops.sort(function(a, b) {
|
||||
|
|
@ -162,44 +182,52 @@
|
|||
else if (this.gradientUnits === 'objectBoundingBox') {
|
||||
_convertValuesToPercentUnits(object, coords);
|
||||
}
|
||||
|
||||
commonAttributes = 'id="SVGID_' + this.id +
|
||||
'" gradientUnits="' + this.gradientUnits + '"';
|
||||
if (this.gradientTransform) {
|
||||
commonAttributes += ' gradientTransform="matrix(' + this.gradientTransform.join(' ') + ')" ';
|
||||
}
|
||||
if (this.type === 'linear') {
|
||||
markup = [
|
||||
//jscs:disable validateIndentation
|
||||
'<linearGradient ',
|
||||
'id="SVGID_', this.id,
|
||||
'" gradientUnits="', this.gradientUnits,
|
||||
'" x1="', coords.x1,
|
||||
commonAttributes,
|
||||
' x1="', coords.x1,
|
||||
'" y1="', coords.y1,
|
||||
'" x2="', coords.x2,
|
||||
'" y2="', coords.y2,
|
||||
'">'
|
||||
'">\n'
|
||||
//jscs:enable validateIndentation
|
||||
];
|
||||
}
|
||||
else if (this.type === 'radial') {
|
||||
markup = [
|
||||
//jscs:disable validateIndentation
|
||||
'<radialGradient ',
|
||||
'id="SVGID_', this.id,
|
||||
'" gradientUnits="', this.gradientUnits,
|
||||
'" cx="', coords.x2,
|
||||
commonAttributes,
|
||||
' cx="', coords.x2,
|
||||
'" cy="', coords.y2,
|
||||
'" r="', coords.r2,
|
||||
'" fx="', coords.x1,
|
||||
'" fy="', coords.y1,
|
||||
'">'
|
||||
'">\n'
|
||||
//jscs:enable validateIndentation
|
||||
];
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.colorStops.length; i++) {
|
||||
markup.push(
|
||||
//jscs:disable validateIndentation
|
||||
'<stop ',
|
||||
'offset="', (this.colorStops[i].offset * 100) + '%',
|
||||
'" style="stop-color:', this.colorStops[i].color,
|
||||
(this.colorStops[i].opacity ? ';stop-opacity: ' + this.colorStops[i].opacity : ';'),
|
||||
'"/>'
|
||||
(this.colorStops[i].opacity != null ? ';stop-opacity: ' + this.colorStops[i].opacity : ';'),
|
||||
'"/>\n'
|
||||
//jscs:enable validateIndentation
|
||||
);
|
||||
}
|
||||
|
||||
markup.push((this.type === 'linear' ? '</linearGradient>' : '</radialGradient>'));
|
||||
markup.push((this.type === 'linear' ? '</linearGradient>\n' : '</radialGradient>\n'));
|
||||
|
||||
return markup.join('');
|
||||
},
|
||||
|
|
@ -213,7 +241,9 @@
|
|||
toLive: function(ctx) {
|
||||
var gradient;
|
||||
|
||||
if (!this.type) return;
|
||||
if (!this.type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.type === 'linear') {
|
||||
gradient = ctx.createLinearGradient(
|
||||
|
|
@ -290,6 +320,7 @@
|
|||
var colorStopEls = el.getElementsByTagName('stop'),
|
||||
type = (el.nodeName === 'linearGradient' ? 'linear' : 'radial'),
|
||||
gradientUnits = el.getAttribute('gradientUnits') || 'objectBoundingBox',
|
||||
gradientTransform = el.getAttribute('gradientTransform'),
|
||||
colorStops = [],
|
||||
coords = { };
|
||||
|
||||
|
|
@ -306,12 +337,18 @@
|
|||
|
||||
_convertPercentUnitsToValues(instance, coords);
|
||||
|
||||
return new fabric.Gradient({
|
||||
var gradient = new fabric.Gradient({
|
||||
type: type,
|
||||
coords: coords,
|
||||
gradientUnits: gradientUnits,
|
||||
colorStops: colorStops
|
||||
});
|
||||
|
||||
if (gradientTransform) {
|
||||
gradient.gradientTransform = fabric.parseTransformAttribute(gradientTransform);
|
||||
}
|
||||
|
||||
return gradient;
|
||||
},
|
||||
/* _FROM_SVG_END_ */
|
||||
|
||||
|
|
@ -337,23 +374,12 @@
|
|||
if (typeof options[prop] === 'string' && /^\d+%$/.test(options[prop])) {
|
||||
var percents = parseFloat(options[prop], 10);
|
||||
if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
|
||||
options[prop] = fabric.util.toFixed(object.width * percents / 100, 2);
|
||||
options[prop] = fabric.util.toFixed(object.width * percents / 100, 2) + object.left;
|
||||
}
|
||||
else if (prop === 'y1' || prop === 'y2') {
|
||||
options[prop] = fabric.util.toFixed(object.height * percents / 100, 2);
|
||||
options[prop] = fabric.util.toFixed(object.height * percents / 100, 2) + object.top;
|
||||
}
|
||||
}
|
||||
normalize(options, prop, object);
|
||||
}
|
||||
}
|
||||
|
||||
// normalize rendering point (should be from top/left corner rather than center of the shape)
|
||||
function normalize(options, prop, object) {
|
||||
if (prop === 'x1' || prop === 'x2') {
|
||||
options[prop] -= fabric.util.toFixed(object.width / 2, 2);
|
||||
}
|
||||
else if (prop === 'y1' || prop === 'y2') {
|
||||
options[prop] -= fabric.util.toFixed(object.height / 2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -363,15 +389,12 @@
|
|||
*/
|
||||
function _convertValuesToPercentUnits(object, options) {
|
||||
for (var prop in options) {
|
||||
|
||||
normalize(options, prop, object);
|
||||
|
||||
// convert to percent units
|
||||
//convert to percent units
|
||||
if (prop === 'x1' || prop === 'x2' || prop === 'r2') {
|
||||
options[prop] = fabric.util.toFixed(options[prop] / object.width * 100, 2) + '%';
|
||||
options[prop] = fabric.util.toFixed((options[prop] - object.fill.origX) / object.width * 100, 2) + '%';
|
||||
}
|
||||
else if (prop === 'y1' || prop === 'y2') {
|
||||
options[prop] = fabric.util.toFixed(options[prop] / object.height * 100, 2) + '%';
|
||||
options[prop] = fabric.util.toFixed((options[prop] - object.fill.origY) / object.height * 100, 2) + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
/**
|
||||
* Wrapper around `console.log` (when available)
|
||||
* @param {Any} values Values to log
|
||||
* @param {Any} [values] Values to log
|
||||
*/
|
||||
fabric.log = function() { };
|
||||
|
||||
/**
|
||||
* Wrapper around `console.warn` (when available)
|
||||
* @param {Any} Values to log as a warning
|
||||
* @param {Any} [values] Values to log as a warning
|
||||
*/
|
||||
fabric.warn = function() { };
|
||||
|
||||
|
|
|
|||
|
|
@ -119,8 +119,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|||
fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
|
||||
/**
|
||||
* Animates object's properties
|
||||
* @param {String|Object} property to animate (if string) or properties to animate (if object)
|
||||
* @param {Number|Object} value to animate property to (if string was given first) or options object
|
||||
* @param {String|Object} property Property to animate (if string) or properties to animate (if object)
|
||||
* @param {Number|Object} value Value to animate property to (if string was given first) or options object
|
||||
* @return {fabric.Object} thisArg
|
||||
* @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#animation}
|
||||
* @chainable
|
||||
|
|
@ -208,11 +208,15 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|||
else {
|
||||
_this.set(property, value);
|
||||
}
|
||||
if (skipCallbacks) return;
|
||||
if (skipCallbacks) {
|
||||
return;
|
||||
}
|
||||
options.onChange && options.onChange();
|
||||
},
|
||||
onComplete: function() {
|
||||
if (skipCallbacks) return;
|
||||
if (skipCallbacks) {
|
||||
return;
|
||||
}
|
||||
|
||||
_this.setCoords();
|
||||
options.onComplete && options.onComplete();
|
||||
|
|
|
|||
|
|
@ -379,7 +379,9 @@
|
|||
|
||||
// accept only left clicks
|
||||
var isLeftClick = 'which' in e ? e.which === 1 : e.button === 1;
|
||||
if (!isLeftClick && !fabric.isTouchSupported) return;
|
||||
if (!isLeftClick && !fabric.isTouchSupported) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isDrawingMode) {
|
||||
this._onMouseDownInDrawingMode(e);
|
||||
|
|
@ -387,7 +389,9 @@
|
|||
}
|
||||
|
||||
// ignore if some object is being transformed at this moment
|
||||
if (this._currentTransform) return;
|
||||
if (this._currentTransform) {
|
||||
return;
|
||||
}
|
||||
|
||||
var target = this.findTarget(e),
|
||||
pointer = this.getPointer(e, true);
|
||||
|
|
|
|||
|
|
@ -70,7 +70,9 @@
|
|||
lockScalingX = target.get('lockScalingX'),
|
||||
lockScalingY = target.get('lockScalingY');
|
||||
|
||||
if (lockScalingX && lockScalingY) return;
|
||||
if (lockScalingX && lockScalingY) {
|
||||
return;
|
||||
}
|
||||
|
||||
target._scaling = true;
|
||||
|
||||
|
|
@ -97,7 +99,9 @@
|
|||
_rotateObjectByAngle: function(curAngle) {
|
||||
var t = this._currentTransform;
|
||||
|
||||
if (t.target.get('lockRotation')) return;
|
||||
if (t.target.get('lockRotation')) {
|
||||
return;
|
||||
}
|
||||
t.target.angle = radiansToDegrees(degreesToRadians(curAngle) + t.theta);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -156,7 +156,9 @@
|
|||
for (var i = this._objects.length; i--; ) {
|
||||
currentObject = this._objects[i];
|
||||
|
||||
if (!currentObject || !currentObject.selectable || !currentObject.visible) continue;
|
||||
if (!currentObject || !currentObject.selectable || !currentObject.visible) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2) ||
|
||||
currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2) ||
|
||||
|
|
@ -167,7 +169,9 @@
|
|||
group.push(currentObject);
|
||||
|
||||
// only add one object if it's a click
|
||||
if (isClick) break;
|
||||
if (isClick) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
|
|||
* });
|
||||
*/
|
||||
loadFromJSON: function (json, callback, reviver) {
|
||||
if (!json) return;
|
||||
if (!json) {
|
||||
return;
|
||||
}
|
||||
|
||||
// serialize if it wasn't already
|
||||
var serialized = (typeof json === 'string')
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
*/
|
||||
_createTextCharBg: function(styleDecl, lineLeftOffset, lineTopOffset, heightOfLine, charWidth, charOffset) {
|
||||
return [
|
||||
//jscs:disable validateIndentation
|
||||
'<rect fill="', styleDecl.textBackgroundColor,
|
||||
'" transform="translate(',
|
||||
-this.width / 2, ' ',
|
||||
|
|
@ -80,6 +81,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
'" width="', charWidth,
|
||||
'" height="', heightOfLine,
|
||||
'"></rect>'
|
||||
//jscs:enable validateIndentation
|
||||
].join('');
|
||||
},
|
||||
|
||||
|
|
@ -96,6 +98,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
}, styleDecl));
|
||||
|
||||
return [
|
||||
//jscs:disable validateIndentation
|
||||
'<tspan x="', lineLeftOffset + charOffset, '" ',
|
||||
yProp, '="', lineTopOffset, '" ',
|
||||
|
||||
|
|
@ -108,6 +111,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
fabric.util.string.escapeXml(_char),
|
||||
'</tspan>'
|
||||
//jscs:enable validateIndentation
|
||||
].join('');
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -61,11 +61,12 @@
|
|||
* @private
|
||||
*/
|
||||
_tick: function() {
|
||||
if (this._abortCursorAnimation) {
|
||||
return;
|
||||
}
|
||||
|
||||
var _this = this;
|
||||
|
||||
if (this._abortCursorAnimation) return;
|
||||
|
||||
this.animate('_currentCursorOpacity', 1, {
|
||||
|
||||
duration: this.cursorDuration,
|
||||
|
|
@ -88,7 +89,9 @@
|
|||
* @private
|
||||
*/
|
||||
_onTickComplete: function() {
|
||||
if (this._abortCursorAnimation) return;
|
||||
if (this._abortCursorAnimation) {
|
||||
return;
|
||||
}
|
||||
|
||||
var _this = this;
|
||||
if (this._cursorTimeout1) {
|
||||
|
|
@ -315,7 +318,9 @@
|
|||
* @chainable
|
||||
*/
|
||||
enterEditing: function() {
|
||||
if (this.isEditing || !this.editable) return;
|
||||
if (this.isEditing || !this.editable) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.exitEditingOnOthers();
|
||||
|
||||
|
|
@ -364,7 +369,9 @@
|
|||
* @private
|
||||
*/
|
||||
_updateTextarea: function() {
|
||||
if (!this.hiddenTextarea) return;
|
||||
if (!this.hiddenTextarea) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hiddenTextarea.value = this.text;
|
||||
this.hiddenTextarea.selectionStart = this.selectionStart;
|
||||
|
|
@ -389,7 +396,9 @@
|
|||
* @private
|
||||
*/
|
||||
_restoreEditingProps: function() {
|
||||
if (!this._savedProps) return;
|
||||
if (!this._savedProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.hoverCursor = this._savedProps.overCursor;
|
||||
this.hasControls = this._savedProps.hasControls;
|
||||
|
|
@ -575,7 +584,9 @@
|
|||
insertStyleObjects: function(_chars, isEndOfLine, styles) {
|
||||
|
||||
// short-circuit
|
||||
if (this.isEmptyStyles()) return;
|
||||
if (this.isEmptyStyles()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var cursorLocation = this.get2DCursorLocation(),
|
||||
lineIndex = cursorLocation.lineIndex,
|
||||
|
|
|
|||
|
|
@ -112,7 +112,9 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
*/
|
||||
initMousemoveHandler: function() {
|
||||
this.on('mousemove', function(options) {
|
||||
if (!this.__isMousedown || !this.isEditing) return;
|
||||
if (!this.__isMousedown || !this.isEditing) {
|
||||
return;
|
||||
}
|
||||
|
||||
var newSelectionStart = this.getSelectionStartFromPointer(options.e);
|
||||
|
||||
|
|
@ -143,7 +145,9 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
initMouseupHandler: function() {
|
||||
this.on('mouseup', function(options) {
|
||||
this.__isMousedown = false;
|
||||
if (this._isObjectMoved(options.e)) return;
|
||||
if (this._isObjectMoved(options.e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.__lastSelected) {
|
||||
this.enterEditing();
|
||||
|
|
|
|||
|
|
@ -53,7 +53,9 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
* @param {Event} e Event object
|
||||
*/
|
||||
onKeyDown: function(e) {
|
||||
if (!this.isEditing) return;
|
||||
if (!this.isEditing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.keyCode in this._keysMap) {
|
||||
this[this._keysMap[e.keyCode]](e);
|
||||
|
|
@ -442,7 +444,9 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
* @param {Event} e Event object
|
||||
*/
|
||||
moveCursorLeft: function(e) {
|
||||
if (this.selectionStart === 0 && this.selectionEnd === 0) return;
|
||||
if (this.selectionStart === 0 && this.selectionEnd === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.abortCursorAnimation();
|
||||
this._currentCursorOpacity = 1;
|
||||
|
|
@ -528,7 +532,9 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
* @param {Event} e Event object
|
||||
*/
|
||||
moveCursorRight: function(e) {
|
||||
if (this.selectionStart >= this.text.length && this.selectionEnd >= this.text.length) return;
|
||||
if (this.selectionStart >= this.text.length && this.selectionEnd >= this.text.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.abortCursorAnimation();
|
||||
this._currentCursorOpacity = 1;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|||
var fill = this.fill
|
||||
? (this.fill.toLive ? 'url(#SVGID_' + this.fill.id + ')' : this.fill)
|
||||
: 'none',
|
||||
|
||||
fillRule = (this.fillRule === 'destination-over' ? 'evenodd' : this.fillRule),
|
||||
stroke = this.stroke
|
||||
? (this.stroke.toLive ? 'url(#SVGID_' + this.stroke.id + ')' : this.stroke)
|
||||
: 'none',
|
||||
|
|
@ -33,6 +33,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|||
'stroke-linejoin: ', strokeLineJoin, '; ',
|
||||
'stroke-miterlimit: ', strokeMiterLimit, '; ',
|
||||
'fill: ', fill, '; ',
|
||||
'fill-rule: ', fillRule, '; ',
|
||||
'opacity: ', opacity, ';',
|
||||
filter,
|
||||
visibility
|
||||
|
|
@ -44,6 +45,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|||
* @return {String}
|
||||
*/
|
||||
getSvgTransform: function() {
|
||||
if (this.group) return '';
|
||||
var toFixed = fabric.util.toFixed,
|
||||
angle = this.getAngle(),
|
||||
vpt = this.getViewportTransform(),
|
||||
|
|
@ -51,7 +53,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|||
|
||||
NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,
|
||||
|
||||
translatePart = 'translate(' +
|
||||
translatePart = this.type === 'path-group' ? '' : 'translate(' +
|
||||
toFixed(center.x, NUM_FRACTION_DIGITS) +
|
||||
' ' +
|
||||
toFixed(center.y, NUM_FRACTION_DIGITS) +
|
||||
|
|
@ -68,16 +70,24 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
|
|||
' ' +
|
||||
toFixed(this.scaleY * vpt[3], NUM_FRACTION_DIGITS) +
|
||||
')'),
|
||||
|
||||
flipXPart = this.flipX ? 'matrix(-1 0 0 1 0 0) ' : '',
|
||||
|
||||
flipYPart = this.flipY ? 'matrix(1 0 0 -1 0 0)' : '';
|
||||
addTranslateX = this.type === 'path-group' ? this.width * vpt[0] : 0,
|
||||
flipXPart = this.flipX ? ' matrix(-1 0 0 1 ' + addTranslateX + ' 0) ' : '',
|
||||
addTranslateY = this.type === 'path-group' ? this.height * vpt[3] : 0,
|
||||
flipYPart = this.flipY ? ' matrix(1 0 0 -1 0 ' + addTranslateY + ')' : '';
|
||||
|
||||
return [
|
||||
translatePart, anglePart, scalePart, flipXPart, flipYPart
|
||||
].join('');
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns transform-string for svg-export from the transform matrix of single elements
|
||||
* @return {String}
|
||||
*/
|
||||
getSvgTransformMatrix: function() {
|
||||
return this.transformMatrix ? ' matrix(' + this.transformMatrix.join(' ') + ')' : '';
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
(function(){
|
||||
|
||||
var degreesToRadians = fabric.util.degreesToRadians,
|
||||
//jscs:disable requireCamelCaseOrUpperCaseIdentifiers
|
||||
isVML = function() { return typeof G_vmlCanvasManager !== 'undefined'; };
|
||||
//jscs:enable requireCamelCaseOrUpperCaseIdentifiers
|
||||
|
||||
fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {
|
||||
|
||||
|
|
@ -262,7 +264,9 @@
|
|||
* @chainable
|
||||
*/
|
||||
drawBorders: function(ctx) {
|
||||
if (!this.hasBorders) return this;
|
||||
if (!this.hasBorders) {
|
||||
return this;
|
||||
}
|
||||
|
||||
var padding = this.padding,
|
||||
padding2 = padding * 2,
|
||||
|
|
@ -337,7 +341,9 @@
|
|||
* @chainable
|
||||
*/
|
||||
drawControls: function(ctx) {
|
||||
if (!this.hasControls) return this;
|
||||
if (!this.hasControls) {
|
||||
return this;
|
||||
}
|
||||
|
||||
var size = this.cornerSize,
|
||||
size2 = size / 2,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
* @param {Function} handler
|
||||
*/
|
||||
function _removeEventListener(eventName, handler) {
|
||||
if (!this.__eventListeners[eventName]) return;
|
||||
if (!this.__eventListeners[eventName]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
fabric.util.removeFromArray(this.__eventListeners[eventName], handler);
|
||||
|
|
@ -57,7 +59,9 @@
|
|||
* @chainable
|
||||
*/
|
||||
function stopObserving(eventName, handler) {
|
||||
if (!this.__eventListeners) return;
|
||||
if (!this.__eventListeners) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove all key/value pairs (event name -> event handler)
|
||||
if (arguments.length === 0) {
|
||||
|
|
@ -86,10 +90,15 @@
|
|||
* @chainable
|
||||
*/
|
||||
function fire(eventName, options) {
|
||||
if (!this.__eventListeners) return;
|
||||
if (!this.__eventListeners) {
|
||||
return;
|
||||
}
|
||||
|
||||
var listenersForEvent = this.__eventListeners[eventName];
|
||||
if (!listenersForEvent) return;
|
||||
if (!listenersForEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0, len = listenersForEvent.length; i < len; i++) {
|
||||
// avoiding try/catch for perf. reasons
|
||||
listenersForEvent[i].call(this, options || { });
|
||||
|
|
|
|||
108
src/parser.js
108
src/parser.js
|
|
@ -101,9 +101,13 @@
|
|||
function _setStrokeFillOpacity(attributes) {
|
||||
for (var attr in colorAttributes) {
|
||||
|
||||
if (!attributes[attr] || typeof attributes[colorAttributes[attr]] === 'undefined') continue;
|
||||
if (!attributes[attr] || typeof attributes[colorAttributes[attr]] === 'undefined') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (attributes[attr].indexOf('url(') === 0) continue;
|
||||
if (attributes[attr].indexOf('url(') === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var color = new fabric.Color(attributes[attr]);
|
||||
attributes[attr] = color.setAlpha(toFixed(color.getAlpha() * attributes[colorAttributes[attr]], 2)).toRgba();
|
||||
|
|
@ -271,7 +275,9 @@
|
|||
// TODO: support non-px font size
|
||||
var match = value.match(/(normal|italic)?\s*(normal|small-caps)?\s*(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\s*(\d+)px(?:\/(normal|[\d\.]+))?\s+(.*)/);
|
||||
|
||||
if (!match) return;
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
|
||||
var fontStyle = match[1],
|
||||
// font variant is not used
|
||||
|
|
@ -324,7 +330,9 @@
|
|||
function parseStyleObject(style, oStyle) {
|
||||
var attr, value;
|
||||
for (var prop in style) {
|
||||
if (typeof style[prop] === 'undefined') continue;
|
||||
if (typeof style[prop] === 'undefined') {
|
||||
continue;
|
||||
}
|
||||
|
||||
attr = normalizeAttr(prop.toLowerCase());
|
||||
value = normalizeValue(attr, style[prop]);
|
||||
|
|
@ -343,7 +351,7 @@
|
|||
*/
|
||||
function getGlobalStylesForElement(element) {
|
||||
var styles = { };
|
||||
|
||||
|
||||
for (var rule in fabric.cssRules) {
|
||||
if (elementMatchesRule(element, rule.split(' '))) {
|
||||
for (var property in fabric.cssRules[rule]) {
|
||||
|
|
@ -419,7 +427,9 @@
|
|||
|
||||
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') continue;
|
||||
if (attr.nodeName === 'x' || attr.nodeName === 'y' || attr.nodeName === 'xlink:href') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (attr.nodeName === 'transform') {
|
||||
currentTrans = currentTrans + ' ' + attr.nodeValue;
|
||||
|
|
@ -441,7 +451,9 @@
|
|||
*/
|
||||
function addSvgTransform(doc, matrix) {
|
||||
matrix[3] = matrix[0] = (matrix[0] > matrix[3] ? matrix[3] : matrix[0]);
|
||||
if (!(matrix[0] !== 1 || matrix[3] !== 1 || matrix[4] !== 0 || matrix[5] !== 0)) return;
|
||||
if (!(matrix[0] !== 1 || matrix[3] !== 1 || matrix[4] !== 0 || matrix[5] !== 0)) {
|
||||
return;
|
||||
}
|
||||
// default is to preserve aspect ratio
|
||||
// preserveAspectRatio attribute to be implemented
|
||||
var el = doc.ownerDocument.createElement('g');
|
||||
|
|
@ -490,14 +502,16 @@
|
|||
}
|
||||
|
||||
return function(doc, callback, reviver) {
|
||||
if (!doc) return;
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
var startTime = new Date();
|
||||
|
||||
parseUseDirectives(doc);
|
||||
|
||||
var viewBoxAttr = doc.getAttribute('viewBox'),
|
||||
widthAttr = parseFloat(doc.getAttribute('width')),
|
||||
heightAttr = parseFloat(doc.getAttribute('height')),
|
||||
widthAttr = parseUnit(doc.getAttribute('width')),
|
||||
heightAttr = parseUnit(doc.getAttribute('height')),
|
||||
viewBoxWidth,
|
||||
viewBoxHeight;
|
||||
|
||||
|
|
@ -513,7 +527,7 @@
|
|||
if (heightAttr && heightAttr !== viewBoxHeight) {
|
||||
scaleY = heightAttr / viewBoxHeight;
|
||||
}
|
||||
addSvgTransform(doc, [scaleX, 0, 0, scaleY, -minX, -minY]);
|
||||
addSvgTransform(doc, [scaleX, 0, 0, scaleY, scaleX * -minX, scaleY * -minY]);
|
||||
}
|
||||
|
||||
var descendants = fabric.util.toArray(doc.getElementsByTagName('*'));
|
||||
|
|
@ -618,25 +632,6 @@
|
|||
|
||||
extend(fabric, {
|
||||
|
||||
/**
|
||||
* Initializes gradients on instances, according to gradients parsed from a document
|
||||
* @param {Array} instances
|
||||
*/
|
||||
resolveGradients: function(instances) {
|
||||
for (var i = instances.length; i--; ) {
|
||||
var instanceFillValue = instances[i].get('fill');
|
||||
|
||||
if (!(/^url\(/).test(instanceFillValue)) continue;
|
||||
|
||||
var gradientId = instanceFillValue.slice(5, instanceFillValue.length - 1);
|
||||
|
||||
if (fabric.gradientDefs[gradientId]) {
|
||||
instances[i].set('fill',
|
||||
fabric.Gradient.fromElement(fabric.gradientDefs[gradientId], instances[i]));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses an SVG document, returning all of the gradient declarations found in it
|
||||
* @static
|
||||
|
|
@ -648,21 +643,36 @@
|
|||
getGradientDefs: function(doc) {
|
||||
var linearGradientEls = doc.getElementsByTagName('linearGradient'),
|
||||
radialGradientEls = doc.getElementsByTagName('radialGradient'),
|
||||
el, i,
|
||||
gradientDefs = { };
|
||||
el, i, j = 0, id, xlink, elList = [ ],
|
||||
gradientDefs = { }, idsToXlinkMap = { };
|
||||
|
||||
elList.length = linearGradientEls.length + radialGradientEls.length;
|
||||
i = linearGradientEls.length;
|
||||
for (; i--; ) {
|
||||
el = linearGradientEls[i];
|
||||
gradientDefs[el.getAttribute('id')] = el;
|
||||
while (i--) {
|
||||
elList[j++] = linearGradientEls[i];
|
||||
}
|
||||
|
||||
i = radialGradientEls.length;
|
||||
for (; i--; ) {
|
||||
el = radialGradientEls[i];
|
||||
gradientDefs[el.getAttribute('id')] = el;
|
||||
while (i--) {
|
||||
elList[j++] = radialGradientEls[i];
|
||||
}
|
||||
|
||||
while (j--) {
|
||||
el = elList[j];
|
||||
xlink = el.getAttribute('xlink:href');
|
||||
id = el.getAttribute('id');
|
||||
if (xlink) {
|
||||
idsToXlinkMap[id] = xlink.substr(1);
|
||||
}
|
||||
gradientDefs[id] = el;
|
||||
}
|
||||
|
||||
for (id in idsToXlinkMap) {
|
||||
var el2 = gradientDefs[idsToXlinkMap[id]].cloneNode(true);
|
||||
el = gradientDefs[id];
|
||||
while (el2.firstChild) {
|
||||
el.appendChild(el2.firstChild);
|
||||
}
|
||||
}
|
||||
return gradientDefs;
|
||||
},
|
||||
|
||||
|
|
@ -684,8 +694,8 @@
|
|||
var value,
|
||||
parentAttributes = { };
|
||||
|
||||
// if there's a parent container (`g` node), parse its attributes recursively upwards
|
||||
if (element.parentNode && /^[g|a]$/i.test(element.parentNode.nodeName)) {
|
||||
// if there's a parent container (`g` or `a` or `symbol` node), parse its attributes recursively upwards
|
||||
if (element.parentNode && /^symbol|[g|a]$/i.test(element.parentNode.nodeName)) {
|
||||
parentAttributes = fabric.parseAttributes(element.parentNode, attributes);
|
||||
}
|
||||
|
||||
|
|
@ -756,7 +766,9 @@
|
|||
parsePointsAttribute: function(points) {
|
||||
|
||||
// points attribute is required and must not be empty
|
||||
if (!points) return null;
|
||||
if (!points) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// replace commas with whitespace and remove bookending whitespace
|
||||
points = points.replace(/,/g, ' ').trim();
|
||||
|
|
@ -858,7 +870,9 @@
|
|||
//IE chokes on DOCTYPE
|
||||
xml.loadXML(r.responseText.replace(/<!DOCTYPE[\s\S]*?(\[[\s\S]*\])*?>/i,''));
|
||||
}
|
||||
if (!xml || !xml.documentElement) return;
|
||||
if (!xml || !xml.documentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
fabric.parseSVGDocument(xml.documentElement, function (results, options) {
|
||||
svgCache.set(url, {
|
||||
|
|
@ -907,23 +921,29 @@
|
|||
var markup = '';
|
||||
|
||||
for (var i = 0, len = objects.length; i < len; i++) {
|
||||
if (objects[i].type !== 'text' || !objects[i].path) continue;
|
||||
if (objects[i].type !== 'text' || !objects[i].path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
markup += [
|
||||
//jscs:disable validateIndentation
|
||||
'@font-face {',
|
||||
'font-family: ', objects[i].fontFamily, '; ',
|
||||
'src: url(\'', objects[i].path, '\')',
|
||||
'}'
|
||||
//jscs:enable validateIndentation
|
||||
].join('');
|
||||
}
|
||||
|
||||
if (markup) {
|
||||
markup = [
|
||||
//jscs:disable validateIndentation
|
||||
'<style type="text/css">',
|
||||
'<![CDATA[',
|
||||
markup,
|
||||
']]>',
|
||||
'</style>'
|
||||
//jscs:enable validateIndentation
|
||||
].join('');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,15 +79,19 @@
|
|||
* @return {String} svg representation of an instance
|
||||
*/
|
||||
toSVG: function(reviver) {
|
||||
var markup = this._createBaseSVGMarkup();
|
||||
|
||||
var markup = this._createBaseSVGMarkup(), x = 0, y = 0;
|
||||
if (this.group) {
|
||||
x = this.left + this.radius;
|
||||
y = this.top + this.radius;
|
||||
}
|
||||
markup.push(
|
||||
'<circle ',
|
||||
'cx="0" cy="0" ',
|
||||
'cx="' + x + '" cy="' + y + '" ',
|
||||
'r="', this.radius,
|
||||
'" style="', this.getSvgStyles(),
|
||||
'" transform="', this.getSvgTransform(),
|
||||
'"/>'
|
||||
' ', this.getSvgTransformMatrix(),
|
||||
'"/>\n'
|
||||
);
|
||||
|
||||
return reviver ? reviver(markup.join('')) : markup.join('');
|
||||
|
|
@ -101,11 +105,9 @@
|
|||
*/
|
||||
_render: function(ctx, noTransform) {
|
||||
ctx.beginPath();
|
||||
// multiply by currently set alpha (the one that was set by path group where this object is contained, for example)
|
||||
ctx.globalAlpha = this.group ? (ctx.globalAlpha * this.opacity) : this.opacity;
|
||||
ctx.arc(noTransform ? this.left : 0, noTransform ? this.top : 0, this.radius, 0, piBy2, false);
|
||||
ctx.arc(noTransform ? this.left + this.radius : 0, noTransform ? this.top + this.radius : 0, this.radius, 0, piBy2, false);
|
||||
this._renderFill(ctx);
|
||||
this.stroke && this._renderStroke(ctx);
|
||||
this._renderStroke(ctx);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -169,22 +171,13 @@
|
|||
throw new Error('value of `r` attribute is required and can not be negative');
|
||||
}
|
||||
|
||||
if (!('left' in parsedAttributes)) {
|
||||
parsedAttributes.left = 0;
|
||||
}
|
||||
if (!('top' in parsedAttributes)) {
|
||||
parsedAttributes.top = 0;
|
||||
}
|
||||
if (!('transformMatrix' in parsedAttributes)) {
|
||||
parsedAttributes.left -= options.width ? (options.width / 2) : 0;
|
||||
parsedAttributes.top -= options.height ? (options.height / 2) : 0;
|
||||
}
|
||||
parsedAttributes.left = parsedAttributes.left || 0;
|
||||
parsedAttributes.top = parsedAttributes.top || 0;
|
||||
|
||||
var obj = new fabric.Circle(extend(parsedAttributes, options));
|
||||
|
||||
obj.cx = parseFloat(element.getAttribute('cx')) || 0;
|
||||
obj.cy = parseFloat(element.getAttribute('cy')) || 0;
|
||||
|
||||
obj.left -= obj.radius;
|
||||
obj.top -= obj.radius;
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -77,32 +77,26 @@
|
|||
* @return {String} svg representation of an instance
|
||||
*/
|
||||
toSVG: function(reviver) {
|
||||
var markup = this._createBaseSVGMarkup();
|
||||
|
||||
var markup = this._createBaseSVGMarkup(), x = 0, y = 0;
|
||||
if (this.group) {
|
||||
x = this.left + this.rx;
|
||||
y = this.top + this.ry;
|
||||
}
|
||||
markup.push(
|
||||
'<ellipse ',
|
||||
'rx="', this.get('rx'),
|
||||
'" ry="', this.get('ry'),
|
||||
'cx="', x, '" cy="', y, '" ',
|
||||
'rx="', this.rx,
|
||||
'" ry="', this.ry,
|
||||
'" style="', this.getSvgStyles(),
|
||||
'" transform="', this.getSvgTransform(),
|
||||
'"/>'
|
||||
this.getSvgTransformMatrix(),
|
||||
'"/>\n'
|
||||
);
|
||||
|
||||
return reviver ? reviver(markup.join('')) : markup.join('');
|
||||
},
|
||||
/* _TO_SVG_END_ */
|
||||
|
||||
/**
|
||||
* Renders this instance on a given context
|
||||
* @param {CanvasRenderingContext2D} ctx context to render on
|
||||
* @param {Boolean} [noTransform] When true, context is not transformed
|
||||
*/
|
||||
render: function(ctx, noTransform) {
|
||||
// do not use `get` for perf. reasons
|
||||
if (this.rx === 0 || this.ry === 0) return;
|
||||
return this.callSuper('render', ctx, noTransform);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx context to render on
|
||||
|
|
@ -110,10 +104,9 @@
|
|||
*/
|
||||
_render: function(ctx, noTransform) {
|
||||
ctx.beginPath();
|
||||
ctx.globalAlpha = this.group ? (ctx.globalAlpha * this.opacity) : this.opacity;
|
||||
ctx.save();
|
||||
ctx.transform(1, 0, 0, this.ry/this.rx, 0, 0);
|
||||
ctx.arc(noTransform ? this.left : 0, noTransform ? this.top * this.rx/this.ry : 0, this.rx, 0, piBy2, false);
|
||||
ctx.arc(noTransform ? this.left + this.rx : 0, noTransform ? (this.top + this.ry) * this.rx/this.ry : 0, this.rx, 0, piBy2, false);
|
||||
ctx.restore();
|
||||
this._renderFill(ctx);
|
||||
this._renderStroke(ctx);
|
||||
|
|
@ -150,21 +143,13 @@
|
|||
|
||||
var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES);
|
||||
|
||||
if (!('left' in parsedAttributes)) {
|
||||
parsedAttributes.left = 0;
|
||||
}
|
||||
if (!('top' in parsedAttributes)) {
|
||||
parsedAttributes.top = 0;
|
||||
}
|
||||
if (!('transformMatrix' in parsedAttributes)) {
|
||||
parsedAttributes.left -= options.width ? (options.width / 2) : 0;
|
||||
parsedAttributes.top -= options.height ? (options.height / 2) : 0;
|
||||
}
|
||||
parsedAttributes.left = parsedAttributes.left || 0;
|
||||
parsedAttributes.top = parsedAttributes.top || 0;
|
||||
|
||||
var ellipse = new fabric.Ellipse(extend(parsedAttributes, options));
|
||||
|
||||
ellipse.cx = parseFloat(element.getAttribute('cx')) || 0;
|
||||
ellipse.cy = parseFloat(element.getAttribute('cy')) || 0;
|
||||
|
||||
ellipse.top -= ellipse.ry;
|
||||
ellipse.left -= ellipse.rx;
|
||||
return ellipse;
|
||||
};
|
||||
/* _FROM_SVG_END_ */
|
||||
|
|
|
|||
|
|
@ -115,8 +115,8 @@
|
|||
addWithUpdate: function(object) {
|
||||
this._restoreObjectsState();
|
||||
if (object) {
|
||||
this._objects.push(object);
|
||||
object.group = this;
|
||||
this._objects.push(object);
|
||||
object.group = this;
|
||||
}
|
||||
// since _restoreObjectsState set objects inactive
|
||||
this.forEachObject(this._setObjectActive, this);
|
||||
|
|
@ -218,7 +218,9 @@
|
|||
*/
|
||||
render: function(ctx) {
|
||||
// do not render if object is not visible
|
||||
if (!this.visible) return;
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
this.clipTo && fabric.util.clipContext(this, ctx);
|
||||
|
|
@ -252,7 +254,9 @@
|
|||
var originalHasRotatingPoint = object.hasRotatingPoint;
|
||||
|
||||
// do not render if object is not visible
|
||||
if (!object.visible) return;
|
||||
if (!object.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
object.hasRotatingPoint = false;
|
||||
|
||||
|
|
@ -475,16 +479,18 @@
|
|||
*/
|
||||
toSVG: function(reviver) {
|
||||
var markup = [
|
||||
//jscs:disable validateIndentation
|
||||
'<g ',
|
||||
'transform="', this.getSvgTransform(),
|
||||
'">'
|
||||
'">\n'
|
||||
//jscs:enable validateIndentation
|
||||
];
|
||||
|
||||
for (var i = 0, len = this._objects.length; i < len; i++) {
|
||||
markup.push(this._objects[i].toSVG(reviver));
|
||||
}
|
||||
|
||||
markup.push('</g>');
|
||||
markup.push('</g>\n');
|
||||
|
||||
return reviver ? reviver(markup.join('')) : markup.join('');
|
||||
},
|
||||
|
|
|
|||
|
|
@ -112,44 +112,6 @@
|
|||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders image on a specified context
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
* @param {Boolean} [noTransform] When true, context is not transformed
|
||||
*/
|
||||
render: function(ctx, noTransform) {
|
||||
// do not render if object is not visible
|
||||
if (!this.visible) return;
|
||||
|
||||
ctx.save();
|
||||
var m = this.transformMatrix,
|
||||
isInPathGroup = this.group && this.group.type === 'path-group';
|
||||
|
||||
// this._resetWidthHeight();
|
||||
if (isInPathGroup) {
|
||||
ctx.translate(-this.group.width/2, -this.group.height/2);
|
||||
}
|
||||
if (m) {
|
||||
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||
}
|
||||
if (!noTransform) {
|
||||
this.transform(ctx);
|
||||
}
|
||||
if (isInPathGroup) {
|
||||
ctx.translate(this.width/2, this.height/2);
|
||||
}
|
||||
|
||||
this._setShadow(ctx);
|
||||
this.clipTo && fabric.util.clipContext(this, ctx);
|
||||
this._render(ctx);
|
||||
if (this.shadow && !this.shadow.affectStroke) {
|
||||
this._removeShadow(ctx);
|
||||
}
|
||||
this._renderStroke(ctx);
|
||||
this.clipTo && ctx.restore();
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
|
|
@ -207,20 +169,23 @@
|
|||
* @return {String} svg representation of an instance
|
||||
*/
|
||||
toSVG: function(reviver) {
|
||||
var markup = [];
|
||||
|
||||
var markup = [], x = -this.width / 2, y = -this.height / 2;
|
||||
if (this.group) {
|
||||
x = this.left;
|
||||
y = this.top;
|
||||
}
|
||||
markup.push(
|
||||
'<g transform="', this.getSvgTransform(), '">',
|
||||
'<g transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '">\n',
|
||||
'<image xlink:href="', this.getSvgSrc(),
|
||||
'" x="', x, '" y="', y,
|
||||
'" style="', this.getSvgStyles(),
|
||||
// we're essentially moving origin of transformation from top/left corner to the center of the shape
|
||||
// by wrapping it in container <g> element with actual transformation, then offsetting object to the top/left
|
||||
// so that object's center aligns with container's left/top
|
||||
'" transform="translate(' + (-this.width/2) + ' ' + (-this.height/2) + ')',
|
||||
'" width="', this.width,
|
||||
'" height="', this.height,
|
||||
'" preserveAspectRatio="none"',
|
||||
'></image>'
|
||||
'></image>\n'
|
||||
);
|
||||
|
||||
if (this.stroke || this.strokeDashArray) {
|
||||
|
|
@ -228,15 +193,15 @@
|
|||
this.fill = null;
|
||||
markup.push(
|
||||
'<rect ',
|
||||
'x="', (-1 * this.width / 2), '" y="', (-1 * this.height / 2),
|
||||
'x="', x, '" y="', y,
|
||||
'" width="', this.width, '" height="', this.height,
|
||||
'" style="', this.getSvgStyles(),
|
||||
'"/>'
|
||||
'"/>\n'
|
||||
);
|
||||
this.fill = origFill;
|
||||
}
|
||||
|
||||
markup.push('</g>');
|
||||
markup.push('</g>\n');
|
||||
|
||||
return reviver ? reviver(markup.join('')) : markup.join('');
|
||||
},
|
||||
|
|
@ -330,15 +295,16 @@
|
|||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_render: function(ctx) {
|
||||
_render: function(ctx, noTransform) {
|
||||
this._element &&
|
||||
ctx.drawImage(
|
||||
this._element,
|
||||
-this.width / 2,
|
||||
-this.height / 2,
|
||||
noTransform ? this.left : -this.width/2,
|
||||
noTransform ? this.top : -this.height/2,
|
||||
this.width,
|
||||
this.height
|
||||
);
|
||||
this._renderStroke(ctx);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -201,7 +201,9 @@
|
|||
* Returns true if object has no styling
|
||||
*/
|
||||
isEmptyStyles: function() {
|
||||
if (!this.styles) return true;
|
||||
if (!this.styles) {
|
||||
return true;
|
||||
}
|
||||
var obj = this.styles;
|
||||
|
||||
for (var p1 in obj) {
|
||||
|
|
@ -313,7 +315,9 @@
|
|||
* Renders cursor or selection (depending on what exists)
|
||||
*/
|
||||
renderCursorOrSelection: function() {
|
||||
if (!this.active) return;
|
||||
if (!this.active) {
|
||||
return;
|
||||
}
|
||||
|
||||
var chars = this.text.split(''),
|
||||
boundaries;
|
||||
|
|
@ -729,7 +733,9 @@
|
|||
|
||||
fontSize = (styleDeclaration ? styleDeclaration.fontSize : null) || this.fontSize;
|
||||
|
||||
if (!textDecoration) return;
|
||||
if (!textDecoration) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (textDecoration.indexOf('underline') > -1) {
|
||||
this._renderCharDecorationAtOffset(
|
||||
|
|
@ -800,7 +806,9 @@
|
|||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextLinesBackground: function(ctx, textLines) {
|
||||
if (!this.textBackgroundColor && !this.styles) return;
|
||||
if (!this.textBackgroundColor && !this.styles) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
|
||||
|
|
@ -1101,7 +1109,9 @@
|
|||
* @private
|
||||
*/
|
||||
_renderTextBoxBackground: function(ctx) {
|
||||
if (!this.backgroundColor) return;
|
||||
if (!this.backgroundColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
ctx.fillStyle = this.backgroundColor;
|
||||
|
|
|
|||
|
|
@ -150,11 +150,10 @@
|
|||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_render: function(ctx) {
|
||||
_render: function(ctx, noTransform) {
|
||||
ctx.beginPath();
|
||||
|
||||
var isInPathGroup = this.group && this.group.type === 'path-group';
|
||||
if (isInPathGroup) {
|
||||
if (noTransform) {
|
||||
// Line coords are distances from left-top of canvas to origin of line.
|
||||
//
|
||||
// To render line in a path-group, we need to translate them to
|
||||
|
|
@ -164,7 +163,6 @@
|
|||
cp.x,
|
||||
cp.y
|
||||
);
|
||||
if (!this.transformMatrix) ctx.translate(-this.group.width / 2, -this.group.height / 2);
|
||||
}
|
||||
|
||||
if (!this.strokeDashArray || this.strokeDashArray && supportsLineDash) {
|
||||
|
|
@ -232,16 +230,22 @@
|
|||
* @return {String} svg representation of an instance
|
||||
*/
|
||||
toSVG: function(reviver) {
|
||||
var markup = this._createBaseSVGMarkup();
|
||||
|
||||
var markup = this._createBaseSVGMarkup(), addTranslate = '';
|
||||
if (!this.group) {
|
||||
var x = - this.width / 2 - (this.x1 > this.x2 ? this.x2 : this.x1),
|
||||
y = - this.height / 2 - (this.y1 > this.y2 ? this.y2 : this.y1);
|
||||
addTranslate = 'translate(' + x + ', ' + y + ') ';
|
||||
}
|
||||
markup.push(
|
||||
'<line ',
|
||||
'x1="', this.get('x1'),
|
||||
'" y1="', this.get('y1'),
|
||||
'" x2="', this.get('x2'),
|
||||
'" y2="', this.get('y2'),
|
||||
'x1="', this.x1,
|
||||
'" y1="', this.y1,
|
||||
'" x2="', this.x2,
|
||||
'" y2="', this.y2,
|
||||
'" style="', this.getSvgStyles(),
|
||||
'"/>'
|
||||
'" transform="', this.getSvgTransform(), addTranslate,
|
||||
this.getSvgTransformMatrix(),
|
||||
'"/>\n'
|
||||
);
|
||||
|
||||
return reviver ? reviver(markup.join('')) : markup.join('');
|
||||
|
|
|
|||
|
|
@ -658,6 +658,13 @@
|
|||
*/
|
||||
lockUniScaling: false,
|
||||
|
||||
/**
|
||||
* When `true`, object cannot be flipped by scaling into negative values
|
||||
* @type Boolean
|
||||
* @default
|
||||
*/
|
||||
|
||||
lockScalingFlip: false,
|
||||
/**
|
||||
* List of properties to consider when checking if state
|
||||
* of an object is changed (fabric.Object#hasStateChanged)
|
||||
|
|
@ -708,7 +715,9 @@
|
|||
* @param {Object} [options] Options object
|
||||
*/
|
||||
_initClipping: function(options) {
|
||||
if (!options.clipTo || typeof options.clipTo !== 'string') return;
|
||||
if (!options.clipTo || typeof options.clipTo !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
var functionBody = fabric.util.getFunctionBody(options.clipTo);
|
||||
if (typeof functionBody !== 'undefined') {
|
||||
|
|
@ -932,8 +941,9 @@
|
|||
* @return {Boolean} flipY value // TODO
|
||||
*/
|
||||
getViewportTransform: function() {
|
||||
if (this.canvas && this.canvas.viewportTransform)
|
||||
if (this.canvas && this.canvas.viewportTransform) {
|
||||
return this.canvas.viewportTransform;
|
||||
}
|
||||
return [1, 0, 0, 1, 0, 0];
|
||||
},
|
||||
|
||||
|
|
@ -944,7 +954,9 @@
|
|||
*/
|
||||
render: function(ctx, noTransform) {
|
||||
// do not render if width/height are zeros or object is not visible
|
||||
if (this.width === 0 || this.height === 0 || !this.visible) return;
|
||||
if (this.width === 0 || this.height === 0 || !this.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
|
||||
|
|
@ -955,12 +967,14 @@
|
|||
this._setStrokeStyles(ctx);
|
||||
this._setFillStyles(ctx);
|
||||
|
||||
var m = this.transformMatrix;
|
||||
if (m && this.group) {
|
||||
if (this.group && this.group.type === 'path-group') {
|
||||
ctx.translate(-this.group.width/2, -this.group.height/2);
|
||||
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||
var m = this.transformMatrix;
|
||||
if (m) {
|
||||
ctx.transform.apply(ctx, m);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.globalAlpha = this.group ? (ctx.globalAlpha * this.opacity) : this.opacity;
|
||||
this._setShadow(ctx);
|
||||
this.clipTo && fabric.util.clipContext(this, ctx);
|
||||
this._render(ctx, noTransform);
|
||||
|
|
@ -975,7 +989,7 @@
|
|||
var m = this.transformMatrix;
|
||||
|
||||
if (m && !this.group) {
|
||||
ctx.setTransform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||
ctx.setTransform.apply(ctx, m);
|
||||
}
|
||||
if (!noTransform) {
|
||||
this.transform(ctx);
|
||||
|
|
@ -1036,7 +1050,9 @@
|
|||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_setShadow: function(ctx) {
|
||||
if (!this.shadow) return;
|
||||
if (!this.shadow) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.shadowColor = this.shadow.color;
|
||||
ctx.shadowBlur = this.shadow.blur;
|
||||
|
|
@ -1049,7 +1065,9 @@
|
|||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_removeShadow: function(ctx) {
|
||||
if (!this.shadow) return;
|
||||
if (!this.shadow) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.shadowColor = '';
|
||||
ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;
|
||||
|
|
@ -1060,23 +1078,27 @@
|
|||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderFill: function(ctx) {
|
||||
if (!this.fill) return;
|
||||
if (!this.fill) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
if (this.fill.toLive) {
|
||||
ctx.save();
|
||||
ctx.translate(
|
||||
-this.width / 2 + this.fill.offsetX || 0,
|
||||
-this.height / 2 + this.fill.offsetY || 0);
|
||||
}
|
||||
if (this.fill.gradientTransform) {
|
||||
var g = this.fill.gradientTransform;
|
||||
ctx.transform.apply(ctx, g);
|
||||
}
|
||||
if (this.fillRule === 'destination-over') {
|
||||
ctx.fill('evenodd');
|
||||
}
|
||||
else {
|
||||
ctx.fill();
|
||||
}
|
||||
if (this.fill.toLive) {
|
||||
ctx.restore();
|
||||
}
|
||||
ctx.restore();
|
||||
if (this.shadow && !this.shadow.affectStroke) {
|
||||
this._removeShadow(ctx);
|
||||
}
|
||||
|
|
@ -1087,7 +1109,9 @@
|
|||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderStroke: function(ctx) {
|
||||
if (!this.stroke || this.strokeWidth === 0) return;
|
||||
if (!this.stroke || this.strokeWidth === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
if (this.strokeDashArray) {
|
||||
|
|
@ -1106,6 +1130,10 @@
|
|||
ctx.stroke();
|
||||
}
|
||||
else {
|
||||
if (this.stroke.gradientTransform) {
|
||||
var g = this.stroke.gradientTransform;
|
||||
ctx.transform.apply(ctx, g);
|
||||
}
|
||||
this._stroke ? this._stroke(ctx) : ctx.stroke();
|
||||
}
|
||||
this._removeShadow(ctx);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,9 @@
|
|||
// one of commands (m,M,l,L,q,Q,c,C,etc.) followed by non-command characters (i.e. command values)
|
||||
: path.match && path.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi);
|
||||
|
||||
if (!this.path) return;
|
||||
if (!this.path) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fromArray) {
|
||||
this.path = this._parsePath();
|
||||
|
|
@ -455,12 +457,14 @@
|
|||
*/
|
||||
render: function(ctx, noTransform) {
|
||||
// do not render if object is not visible
|
||||
if (!this.visible) return;
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
if (noTransform) {
|
||||
ctx.translate(-this.width/2, -this.height/2);
|
||||
}
|
||||
ctx.translate(-this.width/2, -this.height/2);
|
||||
}
|
||||
var m = this.transformMatrix;
|
||||
|
||||
if (m) {
|
||||
|
|
@ -541,14 +545,14 @@
|
|||
var path = chunks.join(' ');
|
||||
|
||||
markup.push(
|
||||
'<g transform="', (this.group ? '' : this.getSvgTransform()), '">',
|
||||
'<path ',
|
||||
'd="', path,
|
||||
'" style="', this.getSvgStyles(),
|
||||
'" transform="translate(', (-this.width / 2), ' ', (-this.height/2), ')',
|
||||
'" stroke-linecap="round" ',
|
||||
'/>',
|
||||
'</g>'
|
||||
//jscs:disable validateIndentation
|
||||
'<path ',
|
||||
'd="', path,
|
||||
'" style="', this.getSvgStyles(),
|
||||
'" transform="', this.getSvgTransform(),
|
||||
this.getSvgTransformMatrix(), '" stroke-linecap="round" ',
|
||||
'/>\n'
|
||||
//jscs:enable validateIndentation
|
||||
);
|
||||
|
||||
return reviver ? reviver(markup.join('')) : markup.join('');
|
||||
|
|
|
|||
|
|
@ -72,7 +72,9 @@
|
|||
*/
|
||||
render: function(ctx) {
|
||||
// do not render if object is not visible
|
||||
if (!this.visible) return;
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
|
||||
|
|
@ -147,17 +149,20 @@
|
|||
*/
|
||||
toSVG: function(reviver) {
|
||||
var objects = this.getObjects(),
|
||||
translatePart = 'translate(' + this.left + ' ' + this.top + ')',
|
||||
markup = [
|
||||
//jscs:disable validateIndentation
|
||||
'<g ',
|
||||
'style="', this.getSvgStyles(), '" ',
|
||||
'transform="', this.getSvgTransform(), '" ',
|
||||
'>'
|
||||
'transform="', translatePart, this.getSvgTransform(), '" ',
|
||||
'>\n'
|
||||
//jscs:enable validateIndentation
|
||||
];
|
||||
|
||||
for (var i = 0, len = objects.length; i < len; i++) {
|
||||
markup.push(objects[i].toSVG(reviver));
|
||||
}
|
||||
markup.push('</g>');
|
||||
markup.push('</g>\n');
|
||||
|
||||
return reviver ? reviver(markup.join('')) : markup.join('');
|
||||
},
|
||||
|
|
|
|||
|
|
@ -67,7 +67,9 @@
|
|||
this.minX = minX;
|
||||
this.minY = minY;
|
||||
|
||||
if (skipOffset) return;
|
||||
if (skipOffset) {
|
||||
return;
|
||||
}
|
||||
|
||||
var halfWidth = this.width / 2 + this.minX,
|
||||
halfHeight = this.height / 2 + this.minY;
|
||||
|
|
@ -109,7 +111,8 @@
|
|||
'points="', points.join(''),
|
||||
'" style="', this.getSvgStyles(),
|
||||
'" transform="', this.getSvgTransform(),
|
||||
'"/>'
|
||||
' ', this.getSvgTransformMatrix(),
|
||||
'"/>\n'
|
||||
);
|
||||
|
||||
return reviver ? reviver(markup.join('')) : markup.join('');
|
||||
|
|
@ -123,7 +126,6 @@
|
|||
_render: function(ctx) {
|
||||
var point;
|
||||
ctx.beginPath();
|
||||
ctx.globalAlpha = this.group ? (ctx.globalAlpha * this.opacity) : this.opacity;
|
||||
ctx.moveTo(this.points[0].x, this.points[0].y);
|
||||
for (var i = 0, len = this.points.length; i < len; i++) {
|
||||
point = this.points[i];
|
||||
|
|
@ -182,14 +184,16 @@
|
|||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
|
||||
options || (options = { });
|
||||
|
||||
var points = fabric.parsePointsAttribute(element.getAttribute('points')),
|
||||
parsedAttributes = fabric.parseAttributes(element, fabric.Polygon.ATTRIBUTE_NAMES);
|
||||
|
||||
if (!('transformMatrix' in parsedAttributes)) {
|
||||
fabric.util.normalizePoints(points, options);
|
||||
if (points === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new fabric.Polygon(points, extend(parsedAttributes, options), true);
|
||||
};
|
||||
/* _FROM_SVG_END_ */
|
||||
|
|
|
|||
|
|
@ -95,7 +95,8 @@
|
|||
'points="', points.join(''),
|
||||
'" style="', this.getSvgStyles(),
|
||||
'" transform="', this.getSvgTransform(),
|
||||
'"/>'
|
||||
' ', this.getSvgTransformMatrix(),
|
||||
'"/>\n'
|
||||
);
|
||||
|
||||
return reviver ? reviver(markup.join('')) : markup.join('');
|
||||
|
|
@ -169,9 +170,10 @@
|
|||
var points = fabric.parsePointsAttribute(element.getAttribute('points')),
|
||||
parsedAttributes = fabric.parseAttributes(element, fabric.Polyline.ATTRIBUTE_NAMES);
|
||||
|
||||
if (!('transformMatrix' in parsedAttributes)) {
|
||||
fabric.util.normalizePoints(points, options);
|
||||
if (points === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new fabric.Polyline(points, fabric.util.object.extend(parsedAttributes, options), true);
|
||||
};
|
||||
/* _FROM_SVG_END_ */
|
||||
|
|
|
|||
|
|
@ -50,17 +50,6 @@
|
|||
*/
|
||||
ry: 0,
|
||||
|
||||
/**
|
||||
* @type Number
|
||||
* @default
|
||||
*/
|
||||
x: 0,
|
||||
|
||||
/**
|
||||
* @type Number
|
||||
* @default
|
||||
*/
|
||||
y: 0,
|
||||
|
||||
/**
|
||||
* Used to specify dash pattern for stroke on this object
|
||||
|
|
@ -79,8 +68,6 @@
|
|||
this.callSuper('initialize', options);
|
||||
this._initRxRy();
|
||||
|
||||
this.x = options.x || 0;
|
||||
this.y = options.y || 0;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -100,7 +87,7 @@
|
|||
* @private
|
||||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_render: function(ctx) {
|
||||
_render: function(ctx, noTransform) {
|
||||
|
||||
// optimize 1x1 case (used in spray brush)
|
||||
if (this.width === 1 && this.height === 1) {
|
||||
|
|
@ -112,24 +99,15 @@
|
|||
ry = this.ry ? Math.min(this.ry, this.height / 2) : 0,
|
||||
w = this.width,
|
||||
h = this.height,
|
||||
x = -w / 2,
|
||||
y = -h / 2,
|
||||
isInPathGroup = this.group && this.group.type === 'path-group',
|
||||
x = noTransform ? this.left : 0,
|
||||
y = noTransform ? this.top : 0,
|
||||
isRounded = rx !== 0 || ry !== 0,
|
||||
k = 1 - 0.5522847498 /* "magic number" for bezier approximations of arcs (http://itc.ktu.lt/itc354/Riskus354.pdf) */;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.globalAlpha = isInPathGroup ? (ctx.globalAlpha * this.opacity) : this.opacity;
|
||||
|
||||
if (this.transformMatrix && isInPathGroup) {
|
||||
ctx.translate(
|
||||
this.width / 2 + this.x,
|
||||
this.height / 2 + this.y);
|
||||
}
|
||||
if (!this.transformMatrix && isInPathGroup) {
|
||||
ctx.translate(
|
||||
-this.group.width / 2 + this.width / 2 + this.x,
|
||||
-this.group.height / 2 + this.height / 2 + this.y);
|
||||
if (!noTransform) {
|
||||
ctx.translate(-this.width / 2, -this.height / 2);
|
||||
}
|
||||
|
||||
ctx.moveTo(x + rx, y);
|
||||
|
|
@ -170,22 +148,6 @@
|
|||
ctx.closePath();
|
||||
},
|
||||
|
||||
/**
|
||||
* Since coordinate system differs from that of SVG
|
||||
* @private
|
||||
*/
|
||||
_normalizeLeftTopProperties: function(parsedAttributes) {
|
||||
if ('left' in parsedAttributes) {
|
||||
this.set('left', parsedAttributes.left + this.getWidth() / 2);
|
||||
}
|
||||
this.set('x', parsedAttributes.left || 0);
|
||||
if ('top' in parsedAttributes) {
|
||||
this.set('top', parsedAttributes.top + this.getHeight() / 2);
|
||||
}
|
||||
this.set('y', parsedAttributes.top || 0);
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns object representation of an instance
|
||||
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
||||
|
|
@ -194,9 +156,7 @@
|
|||
toObject: function(propertiesToInclude) {
|
||||
var object = extend(this.callSuper('toObject', propertiesToInclude), {
|
||||
rx: this.get('rx') || 0,
|
||||
ry: this.get('ry') || 0,
|
||||
x: this.get('x'),
|
||||
y: this.get('y')
|
||||
ry: this.get('ry') || 0
|
||||
});
|
||||
if (!this.includeDefaultValues) {
|
||||
this._removeDefaultValues(object);
|
||||
|
|
@ -211,16 +171,20 @@
|
|||
* @return {String} svg representation of an instance
|
||||
*/
|
||||
toSVG: function(reviver) {
|
||||
var markup = this._createBaseSVGMarkup();
|
||||
|
||||
var markup = this._createBaseSVGMarkup(), x = this.left, y = this.top;
|
||||
if (!this.group) {
|
||||
x = -this.width / 2;
|
||||
y = -this.height / 2;
|
||||
}
|
||||
markup.push(
|
||||
'<rect ',
|
||||
'x="', (-1 * this.width / 2), '" y="', (-1 * this.height / 2),
|
||||
'x="', x, '" y="', y,
|
||||
'" rx="', this.get('rx'), '" ry="', this.get('ry'),
|
||||
'" width="', this.width, '" height="', this.height,
|
||||
'" style="', this.getSvgStyles(),
|
||||
'" transform="', this.getSvgTransform(),
|
||||
'"/>');
|
||||
this.getSvgTransformMatrix(),
|
||||
'"/>\n');
|
||||
|
||||
return reviver ? reviver(markup.join('')) : markup.join('');
|
||||
},
|
||||
|
|
@ -244,15 +208,6 @@
|
|||
*/
|
||||
fabric.Rect.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x y rx ry width height'.split(' '));
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function _setDefaultLeftTopValues(attributes) {
|
||||
attributes.left = attributes.left || 0;
|
||||
attributes.top = attributes.top || 0;
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link fabric.Rect} instance from an SVG element
|
||||
* @static
|
||||
|
|
@ -265,14 +220,14 @@
|
|||
if (!element) {
|
||||
return null;
|
||||
}
|
||||
|
||||
options = options || { };
|
||||
|
||||
var parsedAttributes = fabric.parseAttributes(element, fabric.Rect.ATTRIBUTE_NAMES);
|
||||
parsedAttributes = _setDefaultLeftTopValues(parsedAttributes);
|
||||
|
||||
var rect = new fabric.Rect(extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));
|
||||
rect._normalizeLeftTopProperties(parsedAttributes);
|
||||
|
||||
return rect;
|
||||
|
||||
parsedAttributes.left = parsedAttributes.left || 0;
|
||||
parsedAttributes.top = parsedAttributes.top || 0;
|
||||
|
||||
return new fabric.Rect(extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));
|
||||
};
|
||||
/* _FROM_SVG_END_ */
|
||||
|
||||
|
|
|
|||
|
|
@ -326,7 +326,9 @@
|
|||
* @private
|
||||
*/
|
||||
_initDimensions: function() {
|
||||
if (this.__skipDimension) return;
|
||||
if (this.__skipDimension) {
|
||||
return;
|
||||
}
|
||||
var canvasEl = fabric.util.createCanvasElement();
|
||||
this._render(canvasEl.getContext('2d'));
|
||||
},
|
||||
|
|
@ -550,7 +552,9 @@
|
|||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextFill: function(ctx, textLines) {
|
||||
if (!this.fill && !this._skipFillStrokeCheck) return;
|
||||
if (!this.fill && !this._skipFillStrokeCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._boundaries = [ ];
|
||||
var lineHeights = 0;
|
||||
|
|
@ -576,7 +580,9 @@
|
|||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextStroke: function(ctx, textLines) {
|
||||
if ((!this.stroke || this.strokeWidth === 0) && !this._skipFillStrokeCheck) return;
|
||||
if ((!this.stroke || this.strokeWidth === 0) && !this._skipFillStrokeCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
var lineHeights = 0;
|
||||
|
||||
|
|
@ -626,7 +632,9 @@
|
|||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderTextBoxBackground: function(ctx) {
|
||||
if (!this.backgroundColor) return;
|
||||
if (!this.backgroundColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
ctx.fillStyle = this.backgroundColor;
|
||||
|
|
@ -647,7 +655,9 @@
|
|||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextLinesBackground: function(ctx, textLines) {
|
||||
if (!this.textBackgroundColor) return;
|
||||
if (!this.textBackgroundColor) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
ctx.fillStyle = this.textBackgroundColor;
|
||||
|
|
@ -703,7 +713,9 @@
|
|||
* @param {Array} textLines Array of all text lines
|
||||
*/
|
||||
_renderTextDecoration: function(ctx, textLines) {
|
||||
if (!this.textDecoration) return;
|
||||
if (!this.textDecoration) {
|
||||
return;
|
||||
}
|
||||
|
||||
// var halfOfVerticalBox = this.originY === 'top' ? 0 : this._getTextHeight(ctx, textLines) / 2;
|
||||
var halfOfVerticalBox = this._getTextHeight(ctx, textLines) / 2,
|
||||
|
|
@ -754,13 +766,16 @@
|
|||
*/
|
||||
render: function(ctx, noTransform) {
|
||||
// do not render if object is not visible
|
||||
if (!this.visible) return;
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
this._transform(ctx, noTransform);
|
||||
|
||||
var m = this.transformMatrix;
|
||||
var isInPathGroup = this.group && this.group.type === 'path-group';
|
||||
var m = this.transformMatrix,
|
||||
isInPathGroup = this.group && this.group.type === 'path-group';
|
||||
|
||||
if (isInPathGroup) {
|
||||
ctx.translate(-this.group.width/2, -this.group.height/2);
|
||||
}
|
||||
|
|
@ -834,8 +849,8 @@
|
|||
: (this.height/2) - (textLines.length * this.fontSize) - this._totalLineHeight;
|
||||
|
||||
return {
|
||||
textLeft: textLeft,
|
||||
textTop: textTop,
|
||||
textLeft: textLeft + (this.group ? this.left : 0),
|
||||
textTop: textTop + (this.group ? this.top : 0),
|
||||
lineTop: lineTop
|
||||
};
|
||||
},
|
||||
|
|
@ -845,7 +860,7 @@
|
|||
*/
|
||||
_wrapSVGTextAndBg: function(markup, textAndBg, shadowSpans, offsets) {
|
||||
markup.push(
|
||||
'<g transform="', this.getSvgTransform(), '">',
|
||||
'<g transform="', this.getSvgTransform(), this.getSvgTransformMatrix(), '">\n',
|
||||
textAndBg.textBgRects.join(''),
|
||||
'<text ',
|
||||
(this.fontFamily ? 'font-family="' + this.fontFamily.replace(/"/g,'\'') + '" ': ''),
|
||||
|
|
@ -858,8 +873,8 @@
|
|||
'transform="translate(', toFixed(offsets.textLeft, 2), ' ', toFixed(offsets.textTop, 2), ')">',
|
||||
shadowSpans.join(''),
|
||||
textAndBg.textSpans.join(''),
|
||||
'</text>',
|
||||
'</g>'
|
||||
'</text>\n',
|
||||
'</g>\n'
|
||||
);
|
||||
},
|
||||
|
||||
|
|
@ -931,7 +946,9 @@
|
|||
lineTopOffsetMultiplier++;
|
||||
}
|
||||
|
||||
if (!this.textBackgroundColor || !this._boundaries) continue;
|
||||
if (!this.textBackgroundColor || !this._boundaries) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this._setSVGTextLineBg(textBgRects, i, textLeftOffset, lineHeight);
|
||||
}
|
||||
|
|
@ -975,7 +992,7 @@
|
|||
toFixed(this._boundaries[i].width, 2),
|
||||
'" height="',
|
||||
toFixed(this._boundaries[i].height, 2),
|
||||
'"></rect>');
|
||||
'"></rect>\n');
|
||||
},
|
||||
|
||||
_setSVGBg: function(textBgRects) {
|
||||
|
|
@ -1087,14 +1104,14 @@
|
|||
options.originX = 'left';
|
||||
}
|
||||
|
||||
var text = new fabric.Text(element.textContent, options);
|
||||
var text = new fabric.Text(element.textContent, options),
|
||||
/*
|
||||
Adjust positioning:
|
||||
x/y attributes in SVG correspond to the bottom-left corner of text bounding box
|
||||
top/left properties in Fabric correspond to center point of text bounding box
|
||||
*/
|
||||
offX = 0;
|
||||
|
||||
/*
|
||||
Adjust positioning:
|
||||
x/y attributes in SVG correspond to the bottom-left corner of text bounding box
|
||||
top/left properties in Fabric correspond to center point of text bounding box
|
||||
*/
|
||||
var offX = 0;
|
||||
if (text.originX === 'left') {
|
||||
offX = text.getWidth() / 2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,9 +59,11 @@ fabric.util.object.extend(fabric.Text.prototype, {
|
|||
// Cufon doesn't play nice with textDecoration=underline if element doesn't have a parent
|
||||
container.appendChild(el);
|
||||
|
||||
//jscs:disable requireCamelCaseOrUpperCaseIdentifiers
|
||||
if (typeof G_vmlCanvasManager === 'undefined') {
|
||||
el.innerHTML = this.text;
|
||||
}
|
||||
//jscs:enable requireCamelCaseOrUpperCaseIdentifiers
|
||||
else {
|
||||
// IE 7 & 8 drop newlines and white space on text nodes
|
||||
// see: http://web.student.tuwien.ac.at/~e0226430/innerHtmlQuirk.html
|
||||
|
|
|
|||
|
|
@ -421,7 +421,9 @@
|
|||
this.width = this.width || parseInt(this.lowerCanvasEl.width, 10) || 0;
|
||||
this.height = this.height || parseInt(this.lowerCanvasEl.height, 10) || 0;
|
||||
|
||||
if (!this.lowerCanvasEl.style) return;
|
||||
if (!this.lowerCanvasEl.style) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lowerCanvasEl.width = this.width;
|
||||
this.lowerCanvasEl.height = this.height;
|
||||
|
|
@ -468,7 +470,7 @@
|
|||
|
||||
/**
|
||||
* Sets width of this canvas instance
|
||||
* @param {Number|String} width value to set width to
|
||||
* @param {Number|String} value Value to set width to
|
||||
* @param {Object} [options] Options object
|
||||
* @param {Boolean} [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions
|
||||
* @param {Boolean} [options.cssOnly=false] Set the given dimensions only as css dimensions
|
||||
|
|
@ -481,7 +483,7 @@
|
|||
|
||||
/**
|
||||
* Sets height of this canvas instance
|
||||
* @param {Number|String} height value to set height to
|
||||
* @param {Number|String} value Value to set height to
|
||||
* @param {Object} [options] Options object
|
||||
* @param {Boolean} [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions
|
||||
* @param {Boolean} [options.cssOnly=false] Set the given dimensions only as css dimensions
|
||||
|
|
@ -693,14 +695,18 @@
|
|||
* @private
|
||||
*/
|
||||
_draw: function (ctx, object) {
|
||||
if (!object) return;
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.save();
|
||||
var v = this.viewportTransform;
|
||||
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
|
||||
object.render(ctx);
|
||||
ctx.restore();
|
||||
if (!this.controlsAboveOverlay) object._renderControls(ctx);
|
||||
if (!this.controlsAboveOverlay) {
|
||||
object._renderControls(ctx);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
207
src/util/arc.js
207
src/util/arc.js
|
|
@ -2,132 +2,107 @@
|
|||
|
||||
var arcToSegmentsCache = { },
|
||||
segmentToBezierCache = { },
|
||||
_join = Array.prototype.join,
|
||||
argsString;
|
||||
|
||||
// Generous contribution by Raph Levien, from libsvg-0.1.0.tar.gz
|
||||
function arcToSegments(x, y, rx, ry, large, sweep, rotateX, ox, oy) {
|
||||
|
||||
argsString = _join.call(arguments);
|
||||
_join = Array.prototype.join;
|
||||
|
||||
/* Adapted from http://dxr.mozilla.org/mozilla-central/source/content/svg/content/src/nsSVGPathDataParser.cpp
|
||||
* by Andrea Bogazzi code is under MPL. if you don't have a copy of the license you can take it here
|
||||
* http://mozilla.org/MPL/2.0/
|
||||
*/
|
||||
function arcToSegments(toX, toY, rx, ry, large, sweep, rotateX) {
|
||||
var argsString = _join.call(arguments);
|
||||
if (arcToSegmentsCache[argsString]) {
|
||||
return arcToSegmentsCache[argsString];
|
||||
}
|
||||
|
||||
var coords = getXYCoords(rotateX, rx, ry, ox, oy, x, y),
|
||||
|
||||
d = (coords.x1 - coords.x0) * (coords.x1 - coords.x0) +
|
||||
(coords.y1 - coords.y0) * (coords.y1 - coords.y0),
|
||||
|
||||
sfactorSq = 1 / d - 0.25;
|
||||
|
||||
if (sfactorSq < 0) {
|
||||
sfactorSq = 0;
|
||||
}
|
||||
|
||||
var sfactor = Math.sqrt(sfactorSq);
|
||||
if (sweep === large) {
|
||||
sfactor = -sfactor;
|
||||
}
|
||||
|
||||
var xc = 0.5 * (coords.x0 + coords.x1) - sfactor * (coords.y1 - coords.y0),
|
||||
yc = 0.5 * (coords.y0 + coords.y1) + sfactor * (coords.x1 - coords.x0),
|
||||
th0 = Math.atan2(coords.y0 - yc, coords.x0 - xc),
|
||||
th1 = Math.atan2(coords.y1 - yc, coords.x1 - xc),
|
||||
thArc = th1 - th0;
|
||||
|
||||
if (thArc < 0 && sweep === 1) {
|
||||
thArc += 2 * Math.PI;
|
||||
}
|
||||
else if (thArc > 0 && sweep === 0) {
|
||||
thArc -= 2 * Math.PI;
|
||||
}
|
||||
|
||||
var segments = Math.ceil(Math.abs(thArc / (Math.PI * 0.5 + 0.001))),
|
||||
result = [];
|
||||
|
||||
for (var i = 0; i < segments; i++) {
|
||||
var th2 = th0 + i * thArc / segments,
|
||||
th3 = th0 + (i + 1) * thArc / segments;
|
||||
|
||||
result[i] = [xc, yc, th2, th3, rx, ry, coords.sinTh, coords.cosTh];
|
||||
}
|
||||
|
||||
arcToSegmentsCache[argsString] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
function getXYCoords(rotateX, rx, ry, ox, oy, x, y) {
|
||||
|
||||
var th = rotateX * (Math.PI / 180),
|
||||
var PI = Math.PI, th = rotateX * (PI / 180),
|
||||
sinTh = Math.sin(th),
|
||||
cosTh = Math.cos(th);
|
||||
cosTh = Math.cos(th),
|
||||
fromX = 0, fromY = 0;
|
||||
|
||||
rx = Math.abs(rx);
|
||||
ry = Math.abs(ry);
|
||||
|
||||
var px = cosTh * (ox - x) + sinTh * (oy - y),
|
||||
py = cosTh * (oy - y) - sinTh * (ox - x),
|
||||
pl = (px * px) / (rx * rx) + (py * py) / (ry * ry);
|
||||
var px = -cosTh * toX - sinTh * toY,
|
||||
py = -cosTh * toY + sinTh * toX,
|
||||
rx2 = rx * rx, ry2 = ry * ry, py2 = py * py, px2 = px * px,
|
||||
pl = 4 * rx2 * ry2 - rx2 * py2 - ry2 * px2,
|
||||
root = 0;
|
||||
|
||||
pl *= 0.25;
|
||||
|
||||
if (pl > 1) {
|
||||
pl = Math.sqrt(pl);
|
||||
rx *= pl;
|
||||
ry *= pl;
|
||||
if (pl < 0) {
|
||||
var s = Math.sqrt(1 - 0.25 * pl/(rx2 * ry2));
|
||||
rx *= s;
|
||||
ry *= s;
|
||||
} else {
|
||||
root = (large === sweep ? -0.5 : 0.5) *
|
||||
Math.sqrt( pl /(rx2 * py2 + ry2 * px2));
|
||||
}
|
||||
|
||||
var a00 = cosTh / rx,
|
||||
a01 = sinTh / rx,
|
||||
a10 = (-sinTh) / ry,
|
||||
a11 = (cosTh) / ry;
|
||||
var cx = root * rx * py / ry,
|
||||
cy = -root * ry * px / rx,
|
||||
cx1 = cosTh * cx - sinTh * cy + toX / 2,
|
||||
cy1 = sinTh * cx + cosTh * cy + toY / 2,
|
||||
mTheta = calcVectorAngle(1, 0, (px - cx) / rx, (py - cy) / ry),
|
||||
dtheta = calcVectorAngle((px - cx) / rx, (py - cy) / ry, (-px -cx) / rx, (-py -cy) / ry);
|
||||
|
||||
return {
|
||||
x0: a00 * ox + a01 * oy,
|
||||
y0: a10 * ox + a11 * oy,
|
||||
x1: a00 * x + a01 * y,
|
||||
y1: a10 * x + a11 * y,
|
||||
sinTh: sinTh,
|
||||
cosTh: cosTh
|
||||
};
|
||||
if (sweep === 0 && dtheta > 0) {
|
||||
dtheta -= 2 * PI;
|
||||
} else if (sweep === 1 && dtheta < 0) {
|
||||
dtheta += 2 * PI;
|
||||
}
|
||||
|
||||
// Convert into cubic bezier segments <= 90deg
|
||||
var segments = Math.ceil(Math.abs(dtheta / (PI * 0.5))),
|
||||
result = [], mDelta = dtheta / segments,
|
||||
mT = 8 / 3 * Math.sin(mDelta / 4) * Math.sin(mDelta / 4) / Math.sin(mDelta / 2),
|
||||
th3 = mTheta + mDelta;
|
||||
|
||||
for (var i = 0; i < segments; i++) {
|
||||
result[i] = segmentToBezier(mTheta, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY);
|
||||
fromX = result[i][4];
|
||||
fromY = result[i][5];
|
||||
mTheta += mDelta;
|
||||
th3 += mDelta;
|
||||
}
|
||||
arcToSegmentsCache[argsString] = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
function segmentToBezier(cx, cy, th0, th1, rx, ry, sinTh, cosTh) {
|
||||
argsString = _join.call(arguments);
|
||||
|
||||
if (segmentToBezierCache[argsString]) {
|
||||
return segmentToBezierCache[argsString];
|
||||
function segmentToBezier(th2, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY) {
|
||||
var argsString2 = _join.call(arguments);
|
||||
if (segmentToBezierCache[argsString2]) {
|
||||
return segmentToBezierCache[argsString2];
|
||||
}
|
||||
|
||||
var costh2 = Math.cos(th2),
|
||||
sinth2 = Math.sin(th2),
|
||||
costh3 = Math.cos(th3),
|
||||
sinth3 = Math.sin(th3),
|
||||
toX = cosTh * rx * costh3 - sinTh * ry * sinth3 + cx1,
|
||||
toY = sinTh * rx * costh3 + cosTh * ry * sinth3 + cy1,
|
||||
cp1X = fromX + mT * ( - cosTh * rx * sinth2 - sinTh * ry * costh2),
|
||||
cp1Y = fromY + mT * ( - sinTh * rx * sinth2 + cosTh * ry * costh2),
|
||||
cp2X = toX + mT * ( cosTh * rx * sinth3 + sinTh * ry * costh3),
|
||||
cp2Y = toY + mT * ( sinTh * rx * sinth3 - cosTh * ry * costh3);
|
||||
|
||||
var sinTh0 = Math.sin(th0),
|
||||
cosTh0 = Math.cos(th0),
|
||||
sinTh1 = Math.sin(th1),
|
||||
cosTh1 = Math.cos(th1),
|
||||
|
||||
a00 = cosTh * rx,
|
||||
a01 = -sinTh * ry,
|
||||
a10 = sinTh * rx,
|
||||
a11 = cosTh * ry,
|
||||
thHalf = 0.25 * (th1 - th0),
|
||||
|
||||
t = (8 / 3) * Math.sin(thHalf) *
|
||||
Math.sin(thHalf) / Math.sin(thHalf * 2),
|
||||
|
||||
x1 = cx + cosTh0 - t * sinTh0,
|
||||
y1 = cy + sinTh0 + t * cosTh0,
|
||||
x3 = cx + cosTh1,
|
||||
y3 = cy + sinTh1,
|
||||
x2 = x3 + t * sinTh1,
|
||||
y2 = y3 - t * cosTh1;
|
||||
|
||||
segmentToBezierCache[argsString] = [
|
||||
a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
|
||||
a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
|
||||
a00 * x3 + a01 * y3, a10 * x3 + a11 * y3
|
||||
segmentToBezierCache[argsString2] = [
|
||||
cp1X, cp1Y,
|
||||
cp2X, cp2Y,
|
||||
toX, toY
|
||||
];
|
||||
return segmentToBezierCache[argsString2];
|
||||
}
|
||||
|
||||
return segmentToBezierCache[argsString];
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
function calcVectorAngle(ux, uy, vx, vy) {
|
||||
var ta = Math.atan2(uy, ux),
|
||||
tb = Math.atan2(vy, vx);
|
||||
if (tb >= ta) {
|
||||
return tb - ta;
|
||||
} else {
|
||||
return 2 * Math.PI - (ta - tb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -137,18 +112,24 @@
|
|||
* @param {Number} y
|
||||
* @param {Array} coords
|
||||
*/
|
||||
fabric.util.drawArc = function(ctx, x, y, coords) {
|
||||
fabric.util.drawArc = function(ctx, fx, fy, coords) {
|
||||
var rx = coords[0],
|
||||
ry = coords[1],
|
||||
rot = coords[2],
|
||||
large = coords[3],
|
||||
sweep = coords[4],
|
||||
ex = coords[5],
|
||||
ey = coords[6],
|
||||
segs = arcToSegments(ex, ey, rx, ry, large, sweep, rot, x, y);
|
||||
for (var i = 0; i < segs.length; i++) {
|
||||
var bez = segmentToBezier.apply(this, segs[i]);
|
||||
ctx.bezierCurveTo.apply(ctx, bez);
|
||||
tx = coords[5],
|
||||
ty = coords[6],
|
||||
segs = [[ ], [ ], [ ], [ ]],
|
||||
segs_norm = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot);
|
||||
for (var i = 0; i < segs_norm.length; i++) {
|
||||
segs[i][0] = segs_norm[i][0] + fx;
|
||||
segs[i][1] = segs_norm[i][1] + fy;
|
||||
segs[i][2] = segs_norm[i][2] + fx;
|
||||
segs[i][3] = segs_norm[i][3] + fy;
|
||||
segs[i][4] = segs_norm[i][4] + fx;
|
||||
segs[i][5] = segs_norm[i][5] + fy;
|
||||
ctx.bezierCurveTo.apply(ctx, segs[i]);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -276,7 +276,9 @@
|
|||
if (loading) {
|
||||
if (typeof this.readyState === 'string' &&
|
||||
this.readyState !== 'loaded' &&
|
||||
this.readyState !== 'complete') return;
|
||||
this.readyState !== 'complete') {
|
||||
return;
|
||||
}
|
||||
loading = false;
|
||||
callback(e || fabric.window.event);
|
||||
scriptEl = scriptEl.onload = scriptEl.onreadystatechange = null;
|
||||
|
|
|
|||
|
|
@ -215,7 +215,9 @@
|
|||
* @private
|
||||
*/
|
||||
function find(array, byProperty, condition) {
|
||||
if (!array || array.length === 0) return;
|
||||
if (!array || array.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var i = array.length - 1,
|
||||
result = byProperty ? array[i][byProperty] : array[i];
|
||||
|
|
|
|||
|
|
@ -387,9 +387,11 @@
|
|||
*/
|
||||
createCanvasElement: function(canvasEl) {
|
||||
canvasEl || (canvasEl = fabric.document.createElement('canvas'));
|
||||
//jscs:disable requireCamelCaseOrUpperCaseIdentifiers
|
||||
if (!canvasEl.getContext && typeof G_vmlCanvasManager !== 'undefined') {
|
||||
G_vmlCanvasManager.initElement(canvasEl);
|
||||
}
|
||||
//jscs:enable requireCamelCaseOrUpperCaseIdentifiers
|
||||
return canvasEl;
|
||||
},
|
||||
|
||||
|
|
@ -503,26 +505,6 @@
|
|||
return (String(fn).match(/function[^{]*\{([\s\S]*)\}/) || {})[1];
|
||||
},
|
||||
|
||||
/**
|
||||
* Normalizes polygon/polyline points according to their dimensions
|
||||
* @param {Array} points
|
||||
* @param {Object} options
|
||||
*/
|
||||
normalizePoints: function(points, options) {
|
||||
var minX = fabric.util.array.min(points, 'x'),
|
||||
minY = fabric.util.array.min(points, 'y');
|
||||
|
||||
minX = minX < 0 ? minX : 0;
|
||||
minY = minX < 0 ? minY : 0;
|
||||
|
||||
for (var i = 0, len = points.length; i < len; i++) {
|
||||
// normalize coordinates, according to containing box
|
||||
// (dimensions of which are passed via `options`)
|
||||
points[i].x -= (options.width / 2 + minX) || 0;
|
||||
points[i].y -= (options.height / 2 + minY) || 0;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if context has transparent pixel
|
||||
* at specified location (taking tolerance into account)
|
||||
|
|
@ -557,7 +539,9 @@
|
|||
for (var i = 3, l = imageData.data.length; i < l; i += 4) {
|
||||
var temp = imageData.data[i];
|
||||
_isTransparent = temp <= 0;
|
||||
if (_isTransparent === false) break; // Stop if colour found
|
||||
if (_isTransparent === false) {
|
||||
break; // Stop if colour found
|
||||
}
|
||||
}
|
||||
|
||||
imageData = null;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
var RECT_JSON = '{"objects":[{"type":"rect","originX":"left","originY":"top","left":0,"top":0,"width":10,"height":10,"fill":"rgb(0,0,0)",'+
|
||||
'"stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,'+
|
||||
'"shadow":null,'+
|
||||
'"visible":true,"clipTo":null,"backgroundColor":"","rx":0,"ry":0,"x":0,"y":0}],"background":"#ff5555","overlay":"rgba(0,0,0,0.2)"}';
|
||||
'"visible":true,"clipTo":null,"backgroundColor":"","rx":0,"ry":0}],"background":"#ff5555","overlay":"rgba(0,0,0,0.2)"}';
|
||||
|
||||
var el = fabric.document.createElement('canvas');
|
||||
el.width = 600; el.height = 600;
|
||||
|
|
|
|||
|
|
@ -33,12 +33,12 @@
|
|||
var RECT_JSON = '{"objects":[{"type":"rect","originX":"left","originY":"top","left":0,"top":0,"width":10,"height":10,"fill":"rgb(0,0,0)",'+
|
||||
'"stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,'+
|
||||
'"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,'+
|
||||
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","rx":0,"ry":0,"x":0,"y":0}],"background":"#ff5555","overlay":"rgba(0,0,0,0.2)"}';
|
||||
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","rx":0,"ry":0}],"background":"#ff5555","overlay":"rgba(0,0,0,0.2)"}';
|
||||
|
||||
var RECT_JSON_WITH_PADDING = '{"objects":[{"type":"rect","originX":"left","originY":"top","left":0,"top":0,"width":10,"height":20,"fill":"rgb(0,0,0)",'+
|
||||
'"stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeLineJoin":"miter","strokeMiterLimit":10,'+
|
||||
'"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,'+
|
||||
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","padding":123,"foo":"bar","rx":0,"ry":0,"x":0,"y":0}],"background":""}';
|
||||
'"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","padding":123,"foo":"bar","rx":0,"ry":0}],"background":""}';
|
||||
|
||||
function getAbsolutePath(path) {
|
||||
var isAbsolute = /^https?:/.test(path);
|
||||
|
|
|
|||
|
|
@ -152,8 +152,8 @@
|
|||
ok(oCircle instanceof fabric.Circle);
|
||||
|
||||
equal(oCircle.get('radius'), radius);
|
||||
equal(oCircle.get('left'), left);
|
||||
equal(oCircle.get('top'), top);
|
||||
equal(oCircle.get('left'), left - radius);
|
||||
equal(oCircle.get('top'), top - radius);
|
||||
equal(oCircle.get('fill'), fill);
|
||||
equal(oCircle.get('opacity'), opacity);
|
||||
equal(oCircle.get('strokeWidth'), strokeWidth);
|
||||
|
|
|
|||
|
|
@ -111,8 +111,8 @@
|
|||
|
||||
equal(oEllipse.get('rx'), rx);
|
||||
equal(oEllipse.get('ry'), ry);
|
||||
equal(oEllipse.get('left'), left);
|
||||
equal(oEllipse.get('top'), top);
|
||||
equal(oEllipse.get('left'), left - rx);
|
||||
equal(oEllipse.get('top'), top - ry);
|
||||
equal(oEllipse.get('fill'), fill);
|
||||
equal(oEllipse.get('opacity'), opacity);
|
||||
equal(oEllipse.get('strokeWidth'), strokeWidth);
|
||||
|
|
|
|||
|
|
@ -162,8 +162,8 @@
|
|||
|
||||
// TODO: need to double check these values
|
||||
|
||||
equal(gradient.coords.x1, 0);
|
||||
equal(gradient.coords.y1, 0);
|
||||
equal(gradient.coords.x1, 50);
|
||||
equal(gradient.coords.y1, 50);
|
||||
|
||||
//equal(gradient.coords.x2, 100);
|
||||
//equal(gradient.coords.y2, 100);
|
||||
|
|
@ -200,8 +200,8 @@
|
|||
|
||||
// TODO: need to double check these values
|
||||
|
||||
equal(gradient.coords.x1, 0);
|
||||
equal(gradient.coords.y1, 0);
|
||||
equal(gradient.coords.x1, 50);
|
||||
equal(gradient.coords.y1, 50);
|
||||
|
||||
//equal(gradient.coords.x2, 100);
|
||||
//equal(gradient.coords.y2, 100);
|
||||
|
|
@ -213,6 +213,43 @@
|
|||
equal(gradient.colorStops[1].color, 'rgb(255,255,255)');
|
||||
});
|
||||
|
||||
test('fromElement radialGradient with transform', function() {
|
||||
ok(typeof fabric.Gradient.fromElement == 'function');
|
||||
|
||||
var element = fabric.document.createElement('radialGradient');
|
||||
var stop1 = fabric.document.createElement('stop');
|
||||
var stop2 = fabric.document.createElement('stop');
|
||||
|
||||
stop1.setAttribute('offset', '0%');
|
||||
stop1.setAttribute('stop-color', 'white');
|
||||
|
||||
stop2.setAttribute('offset', '100%');
|
||||
stop2.setAttribute('stop-color', 'black');
|
||||
|
||||
element.appendChild(stop1);
|
||||
element.appendChild(stop2);
|
||||
element.setAttribute('gradientTransform', 'matrix(3.321 -0.6998 0.4077 1.9347 -440.9168 -408.0598)');
|
||||
var object = new fabric.Object({ width: 100, height: 100 });
|
||||
var gradient = fabric.Gradient.fromElement(element, object);
|
||||
|
||||
ok(gradient instanceof fabric.Gradient);
|
||||
|
||||
// TODO: need to double check these values
|
||||
|
||||
equal(gradient.coords.x1, 50);
|
||||
equal(gradient.coords.y1, 50);
|
||||
|
||||
//equal(gradient.coords.x2, 100);
|
||||
//equal(gradient.coords.y2, 100);
|
||||
|
||||
equal(gradient.colorStops[0].offset, 1);
|
||||
equal(gradient.colorStops[1].offset, 0);
|
||||
|
||||
equal(gradient.colorStops[0].color, 'rgb(0,0,0)');
|
||||
equal(gradient.colorStops[1].color, 'rgb(255,255,255)');
|
||||
deepEqual(gradient.gradientTransform, [ 3.321, -0.6998, 0.4077, 1.9347, -440.9168, -408.0598 ]);
|
||||
})
|
||||
|
||||
test('fromElement linearGradient colorStop attributes/styles', function() {
|
||||
ok(typeof fabric.Gradient.fromElement == 'function');
|
||||
|
||||
|
|
@ -251,8 +288,8 @@
|
|||
|
||||
// TODO: need to double check these values
|
||||
|
||||
equal(gradient.coords.x1, 0);
|
||||
equal(gradient.coords.y1, 0);
|
||||
equal(gradient.coords.x1, 50);
|
||||
equal(gradient.coords.y1, 50);
|
||||
|
||||
//equal(gradient.coords.x2, 100);
|
||||
//equal(gradient.coords.y2, 100);
|
||||
|
|
@ -311,8 +348,8 @@
|
|||
|
||||
// TODO: need to double check these values
|
||||
|
||||
equal(gradient.coords.x1, 0);
|
||||
equal(gradient.coords.y1, 0);
|
||||
equal(gradient.coords.x1, 50);
|
||||
equal(gradient.coords.y1, 50);
|
||||
|
||||
//equal(gradient.coords.x2, 100);
|
||||
//equal(gradient.coords.y2, 100);
|
||||
|
|
|
|||
|
|
@ -384,7 +384,7 @@ test('toObject without default values', function() {
|
|||
var group = makeGroupWith2Objects();
|
||||
ok(typeof group.toSVG == 'function');
|
||||
|
||||
var expectedSVG = '<g transform="translate(130 160)"><rect x="-15" y="-5" rx="0" ry="0" width="30" height="10" 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(25 -25)"/><rect x="-5" y="-20" rx="0" ry="0" width="10" height="40" 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(-35 10)"/></g>';
|
||||
var expectedSVG = '<g transform="translate(130 160)">\n<rect x="10" y="-30" rx="0" ry="0" width="30" height="10" style="stroke: none; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: source-over; opacity: 1;" transform=""/>\n<rect x="-40" y="-10" rx="0" ry="0" width="10" height="40" style="stroke: none; stroke-width: 1; stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: source-over; opacity: 1;" transform=""/>\n</g>\n';
|
||||
equal(group.toSVG(), expectedSVG);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -128,14 +128,12 @@
|
|||
|
||||
var elPolygonWithoutPoints = fabric.document.createElement('polygon');
|
||||
|
||||
var error;
|
||||
try {
|
||||
fabric.Polygon.fromElement(elPolygonWithoutPoints);
|
||||
}
|
||||
catch(err) {
|
||||
error = err;
|
||||
}
|
||||
ok(error, 'missing points attribute should result in error');
|
||||
equal(fabric.Polygon.fromElement(elPolygonWithoutPoints), null);
|
||||
|
||||
var elPolygonWithEmptyPoints = fabric.document.createElement('polygon');
|
||||
elPolygonWithEmptyPoints.setAttribute('points', '');
|
||||
|
||||
equal(fabric.Polygon.fromElement(elPolygonWithEmptyPoints), null);
|
||||
|
||||
equal(fabric.Polygon.fromElement(), null);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -116,16 +116,13 @@
|
|||
deepEqual(polylineWithAttrs.get('transformMatrix'), [ 2, 0, 0, 2, -10, -20 ]);
|
||||
|
||||
var elPolylineWithoutPoints = fabric.document.createElement('polyline');
|
||||
equal(fabric.Polyline.fromElement(elPolylineWithoutPoints), null);
|
||||
|
||||
var error;
|
||||
try {
|
||||
fabric.Polyline.fromElement(elPolylineWithoutPoints);
|
||||
}
|
||||
catch(err) {
|
||||
error = err;
|
||||
}
|
||||
var elPolylineWithEmptyPoints = fabric.document.createElement('polyline');
|
||||
elPolylineWithEmptyPoints.setAttribute('points', '');
|
||||
|
||||
ok(typeof error !== 'undefined', 'missing points attribute should result in error');
|
||||
equal(fabric.Polyline.fromElement(), null);
|
||||
equal(fabric.Polyline.fromElement(elPolylineWithEmptyPoints), null);
|
||||
|
||||
equal(fabric.Polyline.fromElement(), null);
|
||||
});
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@
|
|||
'clipTo': null,
|
||||
'rx': 0,
|
||||
'ry': 0,
|
||||
'x': 0,
|
||||
'y': 0
|
||||
};
|
||||
|
||||
QUnit.module('fabric.Rect');
|
||||
|
|
@ -99,8 +97,8 @@
|
|||
ok(rectWithAttrs instanceof fabric.Rect);
|
||||
|
||||
var expectedObject = fabric.util.object.extend(REFERENCE_RECT, {
|
||||
left: 121,
|
||||
top: 186.5,
|
||||
left: 10,
|
||||
top: 20,
|
||||
width: 222,
|
||||
height: 333,
|
||||
fill: 'rgb(255,255,255)',
|
||||
|
|
@ -112,9 +110,7 @@
|
|||
strokeLineJoin: 'bevil',
|
||||
strokeMiterLimit: 5,
|
||||
rx: 11,
|
||||
ry: 12,
|
||||
x: 10,
|
||||
y: 20
|
||||
ry: 12
|
||||
});
|
||||
deepEqual(rectWithAttrs.toObject(), expectedObject);
|
||||
});
|
||||
|
|
@ -135,7 +131,7 @@
|
|||
var rect = new fabric.Rect({ width: 100, height: 100, rx: 20, ry: 30 });
|
||||
var svg = rect.toSVG();
|
||||
|
||||
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(50 50)"/>');
|
||||
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); fill-rule: source-over; opacity: 1;" transform="translate(50 50)"/>\n');
|
||||
});
|
||||
|
||||
test('toObject without default values', function() {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
'useNative': true
|
||||
};
|
||||
|
||||
var TEXT_SVG = '<g transform="translate(10 26)"><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(-10 39)"><tspan x="0" y="-26" fill="rgb(0,0,0)">x</tspan></text></g>';
|
||||
var TEXT_SVG = '<g transform="translate(10 26)">\n<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: source-over; opacity: 1;" transform="translate(-10 39)"><tspan x="0" y="-26" fill="rgb(0,0,0)">x</tspan></text>\n</g>\n';
|
||||
|
||||
test('constructor', function() {
|
||||
ok(fabric.Text);
|
||||
|
|
|
|||
Loading…
Reference in a new issue