mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-05-11 15:23:10 +00:00
Merge remote-tracking branch 'upstream/master'
Conflicts: dist/fabric.min.js dist/fabric.min.js.gz dist/fabric.require.js src/canvas.class.js
This commit is contained in:
commit
a4129c31e8
34 changed files with 22281 additions and 16892 deletions
|
|
@ -7,8 +7,6 @@
|
|||
"requireParenthesesAroundIIFE": true,
|
||||
"requireSpacesInsideObjectBrackets": "all",
|
||||
"requireCommaBeforeLineBreak": true,
|
||||
"requireRightStickedOperators": ["!"],
|
||||
"requireLeftStickedOperators": [","],
|
||||
"requireCamelCaseOrUpperCaseIdentifiers": true,
|
||||
"requireKeywordsOnNewLine": ["else"],
|
||||
"requireLineFeedAtFileEnd": true,
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
- Fix `setAngle` for different originX/originY (!= 'center')
|
||||
- Change default/init noise/brightness value for `fabric.Image.filters.Noise` and `fabric.Image.filters.Brightness` from 100 to 0
|
||||
- Add `fabric.Canvas#imageSmoothingEnabled`
|
||||
- Add `copy/paste` support for iText (uses clipboardData)
|
||||
|
||||
**Version 1.4.0**
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*! Fabric.js Copyright 2008-2014, Printio (Juriy Zaytsev, Maxim Chernyak) */
|
||||
|
||||
var fabric = fabric || { version: "1.4.6" };
|
||||
var fabric = fabric || { version: "1.4.7" };
|
||||
if (typeof exports !== 'undefined') {
|
||||
exports.fabric = fabric;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
[](https://david-dm.org/kangax/fabric.js)
|
||||
[](https://david-dm.org/kangax/fabric.js#info=devDependencies)
|
||||
|
||||
[](https://www.bountysource.com/trackers/23217-fabric-js?utm_source=23217&utm_medium=shield&utm_campaign=TRACKER_BADGE)
|
||||
|
||||
|
||||
**Fabric.js** is a framework that makes it easy to work with HTML5 canvas element. It is an **interactive object model** on top of canvas element. It is also an **SVG-to-canvas parser**.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "fabric.js",
|
||||
"version": "1.4.6",
|
||||
"version": "1.4.7",
|
||||
"homepage": "http://fabricjs.com",
|
||||
"authors": [
|
||||
"kangax", "Kienz"
|
||||
|
|
|
|||
4464
dist/fabric.js
vendored
4464
dist/fabric.js
vendored
File diff suppressed because it is too large
Load diff
19
dist/fabric.min.js
vendored
19
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.
34311
dist/fabric.require.js
vendored
34311
dist/fabric.require.js
vendored
File diff suppressed because it is too large
Load diff
15
package.json
15
package.json
|
|
@ -2,7 +2,7 @@
|
|||
"name": "fabric",
|
||||
"description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.",
|
||||
"homepage": "http://fabricjs.com/",
|
||||
"version": "1.4.6",
|
||||
"version": "1.4.7",
|
||||
"author": "Juriy Zaytsev <kangax@gmail.com>",
|
||||
"keywords": [
|
||||
"canvas",
|
||||
|
|
@ -14,6 +14,11 @@
|
|||
"HTML5",
|
||||
"object model"
|
||||
],
|
||||
"browser" : {
|
||||
"canvas" : false,
|
||||
"jsdom": false,
|
||||
"xmldom": false
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/kangax/fabric.js"
|
||||
|
|
@ -27,17 +32,17 @@
|
|||
"test": "node test.js && jshint src"
|
||||
},
|
||||
"dependencies": {
|
||||
"canvas": "1.0.x",
|
||||
"jsdom": "0.10.x",
|
||||
"canvas": "1.1.x",
|
||||
"jsdom": "0.11.x",
|
||||
"xmldom": "0.1.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"execSync": "0.0.x",
|
||||
"uglify-js": "2.4.x",
|
||||
"jscs": "1.4.x",
|
||||
"jscs": "1.5.x",
|
||||
"jshint": "2.5.x",
|
||||
"qunit": "0.6.x",
|
||||
"istanbul": "0.2.6"
|
||||
"istanbul": "0.2.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0 && <1.0.0"
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@
|
|||
this.box = this.getPathBoundingBox(this._points);
|
||||
return this.convertPointsToSVGPath(
|
||||
this._points, this.box.minx, this.box.maxx, this.box.miny, this.box.maxy);
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns bounding box of a path based on given points
|
||||
|
|
|
|||
|
|
@ -787,9 +787,8 @@
|
|||
|
||||
// Cache all targets where their bounding box contains point.
|
||||
var target,
|
||||
pointer = this.getPointer(e, true);
|
||||
|
||||
var i = this._objects.length;
|
||||
pointer = this.getPointer(e, true),
|
||||
i = this._objects.length;
|
||||
|
||||
while (i--) {
|
||||
if (this._checkTarget(e, this._objects[i], pointer)){
|
||||
|
|
|
|||
|
|
@ -59,10 +59,9 @@
|
|||
source = new fabric.Color(this.color).getSource();
|
||||
|
||||
for (i = 0; i < iLen; i+=4) {
|
||||
data[i] *= source[0]/255;
|
||||
data[i + 1] *= source[1]/255;
|
||||
data[i + 2] *= source[2]/255;
|
||||
|
||||
data[i] *= source[0] / 255;
|
||||
data[i + 1] *= source[1] / 255;
|
||||
data[i + 2] *= source[2] / 255;
|
||||
}
|
||||
|
||||
context.putImageData(imageData, 0, 0);
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@
|
|||
|
||||
if (e.type === 'touchstart') {
|
||||
// Unbind mousedown to prevent double triggers from touch devices
|
||||
removeListener(this.upperCanvasEl, 'mousedown', this._onMouseDown);
|
||||
removeListener(this.upperCanvasEl, 'mousedown', this._onMouseDown);
|
||||
}
|
||||
else {
|
||||
addListener(fabric.document, 'mouseup', this._onMouseUp);
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
fabric.util.string.escapeXml(_char),
|
||||
'</tspan>'
|
||||
].join('');
|
||||
].join('');
|
||||
}
|
||||
});
|
||||
/* _TO_SVG_END_ */
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@
|
|||
selectAll: function() {
|
||||
this.selectionStart = 0;
|
||||
this.selectionEnd = this.text.length;
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -238,10 +238,10 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
mouseOffset, prevWidth, width, charIndex + i, jlen);
|
||||
}
|
||||
|
||||
if (mouseOffset.y < height) {
|
||||
return this._getNewSelectionStartFromOffset(
|
||||
mouseOffset, prevWidth, width, charIndex + i, jlen, j);
|
||||
}
|
||||
if (mouseOffset.y < height) {
|
||||
return this._getNewSelectionStartFromOffset(
|
||||
mouseOffset, prevWidth, width, charIndex + i, jlen, j);
|
||||
}
|
||||
}
|
||||
|
||||
// clicked somewhere after all chars, so set at the end
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
fabric.util.addListener(this.hiddenTextarea, 'keydown', this.onKeyDown.bind(this));
|
||||
fabric.util.addListener(this.hiddenTextarea, 'keypress', this.onKeyPress.bind(this));
|
||||
fabric.util.addListener(this.hiddenTextarea, 'copy', this.copy.bind(this));
|
||||
fabric.util.addListener(this.hiddenTextarea, 'paste', this.paste.bind(this));
|
||||
|
||||
if (!this._clickHandlerInitialized && this.canvas) {
|
||||
fabric.util.addListener(this.canvas.upperCanvasEl, 'click', this.onClick.bind(this));
|
||||
|
|
@ -38,8 +40,6 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
*/
|
||||
_ctrlKeysMap: {
|
||||
65: 'selectAll',
|
||||
67: 'copy',
|
||||
86: 'paste',
|
||||
88: 'cut'
|
||||
},
|
||||
|
||||
|
|
@ -65,7 +65,6 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
this.canvas && this.canvas.renderAll();
|
||||
|
|
@ -83,9 +82,17 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
/**
|
||||
* Copies selected text
|
||||
* @param {Event} e Event object
|
||||
*/
|
||||
copy: function() {
|
||||
var selectedText = this.getSelectedText();
|
||||
copy: function(e) {
|
||||
var selectedText = this.getSelectedText(),
|
||||
clipboardData = this._getClipboardData(e);
|
||||
|
||||
// Check for backward compatibility with old browsers
|
||||
if (clipboardData) {
|
||||
clipboardData.setData('text', selectedText);
|
||||
}
|
||||
|
||||
this.copiedText = selectedText;
|
||||
this.copiedStyles = this.getSelectionStyles(
|
||||
this.selectionStart,
|
||||
|
|
@ -94,21 +101,45 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
/**
|
||||
* Pastes text
|
||||
* @param {Event} e Event object
|
||||
*/
|
||||
paste: function() {
|
||||
if (this.copiedText) {
|
||||
this.insertChars(this.copiedText);
|
||||
paste: function(e) {
|
||||
var copiedText = null,
|
||||
clipboardData = this._getClipboardData(e);
|
||||
|
||||
// Check for backward compatibility with old browsers
|
||||
if (clipboardData) {
|
||||
copiedText = clipboardData.getData('text');
|
||||
} else {
|
||||
copiedText = this.copiedText;
|
||||
}
|
||||
|
||||
if (copiedText) {
|
||||
this.insertChars(copiedText);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Cuts text
|
||||
* @param {Event} e Event object
|
||||
*/
|
||||
cut: function(e) {
|
||||
if (this.selectionStart === this.selectionEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.copy();
|
||||
this.removeChars(e);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} e Event object
|
||||
*/
|
||||
_getClipboardData: function(e) {
|
||||
return e && (e.clipboardData || fabric.window.clipboardData);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles keypress event
|
||||
* @param {Event} e Event object
|
||||
|
|
@ -120,7 +151,6 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
this.insertChars(String.fromCharCode(e.which));
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@
|
|||
* @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found
|
||||
*/
|
||||
_findTargetCorner: function(pointer) {
|
||||
if (!this.hasControls || !this.active) return false;
|
||||
if (!this.hasControls || !this.active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var ex = pointer.x,
|
||||
ey = pointer.y,
|
||||
|
|
|
|||
103
src/parser.js
103
src/parser.js
|
|
@ -76,7 +76,7 @@
|
|||
else if (attr === 'visible') {
|
||||
value = (value === 'none' || value === 'hidden') ? false : true;
|
||||
// display=none on parent element always takes precedence over child element
|
||||
if (parentAttributes.visible === false) {
|
||||
if (parentAttributes && parentAttributes.visible === false) {
|
||||
value = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -354,13 +354,44 @@
|
|||
|
||||
if (ruleMatchesElement) {
|
||||
for (var property in fabric.cssRules[rule]) {
|
||||
styles[property] = fabric.cssRules[rule][property];
|
||||
var attr = normalizeAttr(property),
|
||||
value = normalizeValue(attr, fabric.cssRules[rule][property]);
|
||||
styles[attr] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function parseUseDirectives(doc) {
|
||||
var nodelist = doc.querySelectorAll("use");
|
||||
for (var i = 0; i < nodelist.length; i++) {
|
||||
var el = nodelist[i];
|
||||
var xlink = el.getAttribute('xlink:href').substr(1);
|
||||
var x = el.getAttribute('x') || 0;
|
||||
var y = el.getAttribute('y') || 0;
|
||||
var el2 = doc.getElementById(xlink).cloneNode(true);
|
||||
var currentTrans = (el.getAttribute('transform') || '') + ' translate(' + x + ', ' + y + ')';
|
||||
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') {
|
||||
if (attr.nodeName === 'transform') {
|
||||
currentTrans = currentTrans + ' ' + attr.nodeValue;
|
||||
} else {
|
||||
el2.setAttribute(attr.nodeName, attr.nodeValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
el2.setAttribute('transform', currentTrans);
|
||||
el2.removeAttribute('id');
|
||||
var pNode=el.parentNode;
|
||||
pNode.replaceChild(el2, el);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an SVG document, converts it to an array of corresponding fabric.* instances and passes them to a callback
|
||||
|
|
@ -401,9 +432,11 @@
|
|||
|
||||
return function(doc, callback, reviver) {
|
||||
if (!doc) return;
|
||||
|
||||
var startTime = new Date(),
|
||||
descendants = fabric.util.toArray(doc.getElementsByTagName('*'));
|
||||
var startTime = new Date();
|
||||
|
||||
parseUseDirectives(doc);
|
||||
|
||||
var descendants = fabric.util.toArray(doc.getElementsByTagName('*'));
|
||||
|
||||
if (descendants.length === 0 && fabric.isLikelyNode) {
|
||||
// we're likely in node, where "o3-xml" library fails to gEBTN("*")
|
||||
|
|
@ -462,7 +495,6 @@
|
|||
|
||||
fabric.gradientDefs = fabric.getGradientDefs(doc);
|
||||
fabric.cssRules = fabric.getCSSRules(doc);
|
||||
|
||||
// Precedence of rules: style > class > attribute
|
||||
|
||||
fabric.parseElements(elements, function(instances) {
|
||||
|
|
@ -478,46 +510,46 @@
|
|||
* Used for caching SVG documents (loaded via `fabric.Canvas#loadSVGFromURL`)
|
||||
* @namespace
|
||||
*/
|
||||
var svgCache = {
|
||||
var svgCache = {
|
||||
|
||||
/**
|
||||
* @param {String} name
|
||||
* @param {Function} callback
|
||||
*/
|
||||
has: function (name, callback) {
|
||||
callback(false);
|
||||
},
|
||||
/**
|
||||
* @param {String} name
|
||||
* @param {Function} callback
|
||||
*/
|
||||
has: function (name, callback) {
|
||||
callback(false);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} url
|
||||
* @param {Function} callback
|
||||
*/
|
||||
get: function () {
|
||||
/* NOOP */
|
||||
},
|
||||
/**
|
||||
* @param {String} url
|
||||
* @param {Function} callback
|
||||
*/
|
||||
get: function () {
|
||||
/* NOOP */
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {String} url
|
||||
* @param {Object} object
|
||||
*/
|
||||
set: function () {
|
||||
/* NOOP */
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @param {String} url
|
||||
* @param {Object} object
|
||||
*/
|
||||
set: function () {
|
||||
/* NOOP */
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function _enlivenCachedObject(cachedObject) {
|
||||
|
||||
var objects = cachedObject.objects,
|
||||
options = cachedObject.options;
|
||||
var objects = cachedObject.objects,
|
||||
options = cachedObject.options;
|
||||
|
||||
objects = objects.map(function (o) {
|
||||
return fabric[capitalize(o.type)].fromObject(o);
|
||||
});
|
||||
objects = objects.map(function (o) {
|
||||
return fabric[capitalize(o.type)].fromObject(o);
|
||||
});
|
||||
|
||||
return ({ objects: objects, options: options });
|
||||
return ({ objects: objects, options: options });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -774,7 +806,6 @@
|
|||
loadSVGFromURL: function(url, callback, reviver) {
|
||||
|
||||
url = url.replace(/^\n\s*/, '').trim();
|
||||
|
||||
svgCache.has(url, function (hasUrl) {
|
||||
if (hasUrl) {
|
||||
svgCache.get(url, function (value) {
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@
|
|||
* @return {fabric.Shadow} thisArg
|
||||
*/
|
||||
initialize: function(options) {
|
||||
|
||||
if (typeof options === 'string') {
|
||||
options = this._parseShadow(options);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,8 +103,6 @@
|
|||
// 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.closePath();
|
||||
|
||||
this._renderFill(ctx);
|
||||
this.stroke && this._renderStroke(ctx);
|
||||
},
|
||||
|
|
@ -163,16 +161,24 @@
|
|||
*/
|
||||
fabric.Circle.fromElement = function(element, options) {
|
||||
options || (options = { });
|
||||
|
||||
var parsedAttributes = fabric.parseAttributes(element, fabric.Circle.ATTRIBUTE_NAMES);
|
||||
|
||||
if (!isValidRadius(parsedAttributes)) {
|
||||
throw new Error('value of `r` attribute is required and can not be negative');
|
||||
}
|
||||
if ('left' in parsedAttributes) {
|
||||
parsedAttributes.left -= (options.width / 2) || 0;
|
||||
|
||||
if (!('left' in parsedAttributes)) {
|
||||
parsedAttributes.left = 0;
|
||||
}
|
||||
if ('top' in parsedAttributes) {
|
||||
parsedAttributes.top -= (options.height / 2) || 0;
|
||||
if (!('top' in parsedAttributes)) {
|
||||
parsedAttributes.top = 0
|
||||
}
|
||||
if (!('transformMatrix' in parsedAttributes)) {
|
||||
parsedAttributes.left -= (options.width / 2);
|
||||
parsedAttributes.top -= (options.height / 2);
|
||||
}
|
||||
|
||||
var obj = new fabric.Circle(extend(parsedAttributes, options));
|
||||
|
||||
obj.cx = parseFloat(element.getAttribute('cx')) || 0;
|
||||
|
|
|
|||
|
|
@ -111,15 +111,11 @@
|
|||
ctx.beginPath();
|
||||
ctx.save();
|
||||
ctx.globalAlpha = this.group ? (ctx.globalAlpha * this.opacity) : this.opacity;
|
||||
if (this.transformMatrix && this.group) {
|
||||
ctx.translate(this.cx, this.cy);
|
||||
}
|
||||
ctx.transform(1, 0, 0, this.ry/this.rx, 0, 0);
|
||||
ctx.arc(noTransform ? this.left : 0, noTransform ? this.top : 0, this.rx, 0, piBy2, false);
|
||||
ctx.restore();
|
||||
|
||||
ctx.arc(noTransform ? this.left : 0, noTransform ? this.top * this.rx/this.ry : 0, this.rx, 0, piBy2, false);
|
||||
this._renderFill(ctx);
|
||||
this._renderStroke(ctx);
|
||||
ctx.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -151,21 +147,22 @@
|
|||
fabric.Ellipse.fromElement = function(element, options) {
|
||||
options || (options = { });
|
||||
|
||||
var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES),
|
||||
cx = parsedAttributes.left,
|
||||
cy = parsedAttributes.top;
|
||||
var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES);
|
||||
|
||||
if ('left' in parsedAttributes) {
|
||||
parsedAttributes.left -= (options.width / 2) || 0;
|
||||
if (!('left' in parsedAttributes)) {
|
||||
parsedAttributes.left = 0;
|
||||
}
|
||||
if ('top' in parsedAttributes) {
|
||||
parsedAttributes.top -= (options.height / 2) || 0;
|
||||
if (!('top' in parsedAttributes)) {
|
||||
parsedAttributes.top = 0;
|
||||
}
|
||||
if (!('transformMatrix' in parsedAttributes)) {
|
||||
parsedAttributes.left -= (options.width / 2);
|
||||
parsedAttributes.top -= (options.height / 2);
|
||||
}
|
||||
|
||||
var ellipse = new fabric.Ellipse(extend(parsedAttributes, options));
|
||||
|
||||
ellipse.cx = cx || 0;
|
||||
ellipse.cy = cy || 0;
|
||||
ellipse.cx = parseFloat(element.getAttribute('cx')) || 0;
|
||||
ellipse.cy = parseFloat(element.getAttribute('cy')) || 0;
|
||||
|
||||
return ellipse;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -168,10 +168,10 @@
|
|||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_renderDashedStroke: function(ctx) {
|
||||
var x = -this.width/2,
|
||||
y = -this.height/2,
|
||||
w = this.width,
|
||||
h = this.height;
|
||||
var x = -this.width / 2,
|
||||
y = -this.height / 2,
|
||||
w = this.width,
|
||||
h = this.height;
|
||||
|
||||
ctx.save();
|
||||
this._setStrokeStyles(ctx);
|
||||
|
|
@ -331,13 +331,14 @@
|
|||
* @param {CanvasRenderingContext2D} ctx Context to render on
|
||||
*/
|
||||
_render: function(ctx) {
|
||||
this._element && ctx.drawImage(
|
||||
this._element,
|
||||
-this.width / 2,
|
||||
-this.height / 2,
|
||||
this.width,
|
||||
this.height
|
||||
);
|
||||
this._element &&
|
||||
ctx.drawImage(
|
||||
this._element,
|
||||
-this.width / 2,
|
||||
-this.height / 2,
|
||||
this.width,
|
||||
this.height
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
* @mixes fabric.Observable
|
||||
*
|
||||
* @fires changed ("text:changed" when observing canvas)
|
||||
* @fires selection:changed ("text:selection:changed" when observing canvas)
|
||||
* @fires editing:entered ("text:editing:entered" when observing canvas)
|
||||
* @fires editing:exited ("text:editing:exited" when observing canvas)
|
||||
*
|
||||
|
|
@ -219,6 +220,7 @@
|
|||
*/
|
||||
setSelectionStart: function(index) {
|
||||
if (this.selectionStart !== index) {
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
}
|
||||
this.selectionStart = index;
|
||||
|
|
@ -231,6 +233,7 @@
|
|||
*/
|
||||
setSelectionEnd: function(index) {
|
||||
if (this.selectionEnd !== index) {
|
||||
this.fire('selection:changed');
|
||||
this.canvas && this.canvas.fire('text:selection:changed', { target: this });
|
||||
}
|
||||
this.selectionEnd = index;
|
||||
|
|
@ -356,6 +359,8 @@
|
|||
textBackgroundColor: style && style.textBackgroundColor || this.textBackgroundColor,
|
||||
textDecoration: style && style.textDecoration || this.textDecoration,
|
||||
fontFamily: style && style.fontFamily || this.fontFamily,
|
||||
fontWeight: style && style.fontWeight || this.fontWeight,
|
||||
fontStyle: style && style.fontStyle || this.fontStyle,
|
||||
stroke: style && style.stroke || this.stroke,
|
||||
strokeWidth: style && style.strokeWidth || this.strokeWidth
|
||||
};
|
||||
|
|
@ -695,6 +700,8 @@
|
|||
prevStyle.textBackgroundColor !== thisStyle.textBackgroundColor ||
|
||||
prevStyle.textDecoration !== thisStyle.textDecoration ||
|
||||
prevStyle.fontFamily !== thisStyle.fontFamily ||
|
||||
prevStyle.fontWeight !== thisStyle.fontWeight ||
|
||||
prevStyle.fontStyle !== thisStyle.fontStyle ||
|
||||
prevStyle.stroke !== thisStyle.stroke ||
|
||||
prevStyle.strokeWidth !== thisStyle.strokeWidth
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1343,7 +1343,7 @@
|
|||
* canvas.renderAll();
|
||||
*/
|
||||
setShadow: function(options) {
|
||||
return this.set('shadow', new fabric.Shadow(options));
|
||||
return this.set('shadow', options ? new fabric.Shadow(options) : null);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -158,6 +158,8 @@
|
|||
_render: function(ctx) {
|
||||
var current, // current instruction
|
||||
previous = null,
|
||||
subpathStartX = 0,
|
||||
subpathStartY = 0,
|
||||
x = 0, // current x
|
||||
y = 0, // current y
|
||||
controlX = 0, // current control point x
|
||||
|
|
@ -167,8 +169,7 @@
|
|||
tempControlX,
|
||||
tempControlY,
|
||||
l = -((this.width / 2) + this.pathOffset.x),
|
||||
t = -((this.height / 2) + this.pathOffset.y),
|
||||
methodName;
|
||||
t = -((this.height / 2) + this.pathOffset.y);
|
||||
|
||||
for (var i = 0, len = this.path.length; i < len; ++i) {
|
||||
|
||||
|
|
@ -211,21 +212,17 @@
|
|||
case 'm': // moveTo, relative
|
||||
x += current[1];
|
||||
y += current[2];
|
||||
// draw a line if previous command was moveTo as well (otherwise, it will have no effect)
|
||||
methodName = (previous && (previous[0] === 'm' || previous[0] === 'M'))
|
||||
? 'lineTo'
|
||||
: 'moveTo';
|
||||
ctx[methodName](x + l, y + t);
|
||||
subpathStartX = x;
|
||||
subpathStartY = y;
|
||||
ctx.moveTo(x + l, y + t);
|
||||
break;
|
||||
|
||||
case 'M': // moveTo, absolute
|
||||
x = current[1];
|
||||
y = current[2];
|
||||
// draw a line if previous command was moveTo as well (otherwise, it will have no effect)
|
||||
methodName = (previous && (previous[0] === 'm' || previous[0] === 'M'))
|
||||
? 'lineTo'
|
||||
: 'moveTo';
|
||||
ctx[methodName](x + l, y + t);
|
||||
subpathStartX = x;
|
||||
subpathStartY = y;
|
||||
ctx.moveTo(x + l, y + t);
|
||||
break;
|
||||
|
||||
case 'c': // bezierCurveTo, relative
|
||||
|
|
@ -436,6 +433,8 @@
|
|||
|
||||
case 'z':
|
||||
case 'Z':
|
||||
x = subpathStartX;
|
||||
y = subpathStartY;
|
||||
ctx.closePath();
|
||||
break;
|
||||
}
|
||||
|
|
@ -466,7 +465,7 @@
|
|||
this._setShadow(ctx);
|
||||
this.clipTo && fabric.util.clipContext(this, ctx);
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.globalAlpha = this.group ? (ctx.globalAlpha * this.opacity) : this.opacity;
|
||||
this._render(ctx);
|
||||
this._renderFill(ctx);
|
||||
this._renderStroke(ctx);
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@
|
|||
_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];
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@
|
|||
* @private
|
||||
* @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundImage|backgroundImage}
|
||||
* or {@link fabric.StaticCanvas#overlayImage|overlayImage})
|
||||
* @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set background or overlay to
|
||||
* @param {(fabric.Image|String|null)} image fabric.Image instance, URL of an image or null to set background or overlay to
|
||||
* @param {Function} callback Callback to invoke when image is loaded and set as background or overlay
|
||||
* @param {Object} [options] Optional options to set for the {@link fabric.Image|image}.
|
||||
*/
|
||||
|
|
@ -359,11 +359,11 @@
|
|||
* @private
|
||||
* @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundColor|backgroundColor}
|
||||
* or {@link fabric.StaticCanvas#overlayColor|overlayColor})
|
||||
* @param {(Object|String)} color Object with pattern information or color value
|
||||
* @param {(Object|String|null)} color Object with pattern information, color value or null
|
||||
* @param {Function} [callback] Callback is invoked when color is set
|
||||
*/
|
||||
__setBgOverlayColor: function(property, color, callback) {
|
||||
if (color.source) {
|
||||
if (color && color.source) {
|
||||
var _this = this;
|
||||
fabric.util.loadImage(color.source, function(img) {
|
||||
_this[property] = new fabric.Pattern({
|
||||
|
|
@ -1022,7 +1022,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -66,10 +66,12 @@
|
|||
rx = Math.abs(rx);
|
||||
ry = Math.abs(ry);
|
||||
|
||||
var px = cosTh * (ox - x) * 0.5 + sinTh * (oy - y) * 0.5,
|
||||
py = cosTh * (oy - y) * 0.5 - sinTh * (ox - x) * 0.5,
|
||||
var px = cosTh * (ox - x) + sinTh * (oy - y),
|
||||
py = cosTh * (oy - y) - sinTh * (ox - x),
|
||||
pl = (px * px) / (rx * rx) + (py * py) / (ry * ry);
|
||||
|
||||
pl *= 0.25;
|
||||
|
||||
if (pl > 1) {
|
||||
pl = Math.sqrt(pl);
|
||||
rx *= pl;
|
||||
|
|
@ -98,20 +100,26 @@
|
|||
return segmentToBezierCache[argsString];
|
||||
}
|
||||
|
||||
var a00 = cosTh * rx,
|
||||
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.5 * (th1 - th0),
|
||||
t = (8 / 3) * Math.sin(thHalf * 0.5) *
|
||||
Math.sin(thHalf * 0.5) / Math.sin(thHalf),
|
||||
thHalf = 0.25 * (th1 - th0),
|
||||
|
||||
x1 = cx + Math.cos(th0) - t * Math.sin(th0),
|
||||
y1 = cy + Math.sin(th0) + t * Math.cos(th0),
|
||||
x3 = cx + Math.cos(th1),
|
||||
y3 = cy + Math.sin(th1),
|
||||
x2 = x3 + t * Math.sin(th1),
|
||||
y2 = y3 - t * Math.cos(th1);
|
||||
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,
|
||||
|
|
@ -138,7 +146,6 @@
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@
|
|||
t, i, len = methodNames.length;
|
||||
for (i = 0; i < len; i++) {
|
||||
t = typeof object[methodNames[i]];
|
||||
if (!(/^(?:function|object|unknown)$/).test(t)) return false;
|
||||
if (!(/^(?:function|object|unknown)$/).test(t)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
IS_DONTENUM_BUGGY = (function(){
|
||||
for (var p in { toString: 1 }) {
|
||||
if (p === 'toString') return false;
|
||||
if (p === 'toString') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})(),
|
||||
|
|
|
|||
|
|
@ -1075,6 +1075,11 @@ test('toDataURL & reference to canvas', function() {
|
|||
equal(object.shadow.blur, 10);
|
||||
equal(object.shadow.offsetX, 5);
|
||||
equal(object.shadow.offsetY, 15);
|
||||
|
||||
equal(object.setShadow(null), object, 'should be chainable');
|
||||
ok(!(object.shadow instanceof fabric.Shadow));
|
||||
equal(object.shadow, null);
|
||||
|
||||
});
|
||||
|
||||
test('set shadow', function() {
|
||||
|
|
|
|||
|
|
@ -224,6 +224,20 @@
|
|||
});
|
||||
});
|
||||
|
||||
asyncTest('multiple M/m commands preserved as M/m commands', function() {
|
||||
var el = getPathElement('M100 100 M 200 200 M150 50 m 300 300 m 400 -50 m 50 100');
|
||||
fabric.Path.fromElement(el, function(obj) {
|
||||
|
||||
deepEqual(obj.path[0], ['M', 100, 100]);
|
||||
deepEqual(obj.path[1], ['M', 200, 200]);
|
||||
deepEqual(obj.path[2], ['M', 150, 50]);
|
||||
deepEqual(obj.path[3], ['m', 300, 300]);
|
||||
deepEqual(obj.path[4], ['m', 400, -50]);
|
||||
deepEqual(obj.path[5], ['m', 50, 100]);
|
||||
start();
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest('compressed path commands', function() {
|
||||
var el = getPathElement('M56.224 84.12c-.047.132-.138.221-.322.215.046-.131.137-.221.322-.215z');
|
||||
fabric.Path.fromElement(el, function(obj) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue