This commit is contained in:
Andrea Bogazzi 2018-02-05 00:05:12 +01:00 committed by GitHub
parent dea22aca70
commit 58f2488fc7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 253 additions and 149 deletions

View file

@ -1,4 +1,14 @@
**Version 2.0.0**
- final
- fix dataurl and svg export on retina and rounding [#4674](https://github.com/kangax/fabric.js/pull/4674)
- avoid error if iText is removed on mousedown [#4650](https://github.com/kangax/fabric.js/pull/4650)
- fix calcOffset when text enter editing [#4649](https://github.com/kangax/fabric.js/pull/4649)
- Gradient fix parsing floats [#4637](https://github.com/kangax/fabric.js/pull/4637)
- Add CrossOrigin managment to fabric.Pattern [#4618](https://github.com/kangax/fabric.js/pull/4618)
- Add patternTransform toObject saving [#4626](https://github.com/kangax/fabric.js/pull/4626)
- normalize brushes render [#4613](https://github.com/kangax/fabric.js/pull/4613)
- avoid charspacing shortcut [#4594](https://github.com/kangax/fabric.js/pull/4594)
- Fix color toHexa() [#4579](https://github.com/kangax/fabric.js/pull/4579)
- rc3 and rc4
- more fixes to transformMatrix memoization
- Canvas.selectionFullyContained allows you to select objects just when full grabbed by the selections. [#4508](https://github.com/kangax/fabric.js/pull/4508)

View file

@ -11,7 +11,7 @@
To get your questions answered, please ask/search on [Fabric's google group], [StackOverflow] or on Fabric's IRC channel (irc://irc.freenode.net/#fabric.js).
Please do not open an issue if you're not sure it's a bug or if it's not a feature/suggestion.
For news about Fabric you can follow [@fabric.js], [@kangax], or [@kienzle_s] on Twitter.
For news about Fabric you can follow [@fabric.js], [@AndreaBogazzi], [@kangax], or [@kienzle_s] on Twitter.
Demos and examples can be found on [jsfiddle], [codepen.io] and [fabricjs.com].
## Issue tracker
@ -61,10 +61,12 @@ Here are a few notes you should take into account:
[Fabric's google group]: https://groups.google.com/forum/#!forum/fabricjs
[stackoverflow]: http://stackoverflow.com/questions/tagged/fabricjs
[@fabric.js]: https://twitter.com/fabricjs
[@AndreaBogazzi]: https://twitter.com/AndreaBogazzi
[@kangax]: https://twitter.com/kangax
[@kienzle_s]: https://twitter.com/kienzle_s
[jsfiddle]: http://jsfiddle.net/user/fabricjs/fiddles
[codepen.io]: http://codepen.io/tag/fabricjs
[fabricjs.com]: http://fabricjs.com/demos
[fabricjs.com/docs]: http://fabricjs.com/docs
[JSDoc 3]: http://usejsdoc.org/
[issue]: https://github.com/kangax/fabric.js/issues

View file

@ -1,6 +1,6 @@
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
var fabric = fabric || { version: '2.0.0-rc.4' };
var fabric = fabric || { version: '2.0.0' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}

View file

@ -43,7 +43,7 @@ Fabric.js allows you to easily create simple shapes like rectangles, circles, tr
### Goals
- Unit tested (4600+ assertion, 940+ tests at the moment, 75%+ coverage)
- Unit tested (4800+ assertion, 1050+ tests at the moment, 76%+ coverage)
- Modular (~60 small ["classes", modules, mixins](http://fabricjs.com/docs/))
- Cross-browser
- [Fast](https://github.com/kangax/fabric.js/wiki/Focus-on-speed)
@ -130,13 +130,9 @@ To install Fabric.js using npm, you must first manually [install Cairo](http://c
//# sourceMappingURL=fabric.min.js.map
6. Lint source code (prerequisite: `npm -g install jshint`)
6. Ensure code guidelines are met (prerequisite: `npm -g install eslint`)
$ npm run lint_tests
7. Ensure code guidelines are met (prerequisite: `npm -g install jscs`)
$ npm run lint
$ npm run lint && npm run lint_tests
<h3 id="fabric-building">Testing</h3>
@ -239,7 +235,7 @@ For example:
### Staying in touch
Follow [@fabric.js](http://twitter.com/fabricjs), [@kangax](http://twitter.com/kangax) or or [@AndreaBogazzi](http://twitter.com/AndreaBogazzi) on twitter.
Follow [@fabric.js](http://twitter.com/fabricjs), [@kangax](http://twitter.com/kangax) or [@AndreaBogazzi](http://twitter.com/AndreaBogazzi) on twitter.
Questions, suggestions — [fabric.js on Google Groups](http://groups.google.com/group/fabricjs).
@ -258,7 +254,7 @@ Get help in Fabric's IRC channel — irc://irc.freenode.net/#fabric.js
- [Maxim "hakunin" Chernyak](http://twitter.com/hakunin) for ideas, and help with various parts of the library throughout its life
- [Sergey Nisnevich](http://nisnya.com) for help with geometry logic
- [Stefan Kienzle](https://twitter.com/kienzle_s) for help with bugs, features, documentation, GitHub issues
- [Shutterstock](http://www.shutterstock.com) for the time and resources invested in using and improving fabric.js
- [Shutterstock](http://www.shutterstock.com/jobs) for the time and resources invested in using and improving fabric.js
- [And all the other GitHub contributors](https://github.com/kangax/fabric.js/graphs/contributors)
### MIT License

218
dist/fabric.js vendored
View file

@ -5028,7 +5028,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
toHexa: function() {
var source = this.getSource(), a;
a = source[3] * 255;
a = Math.round(source[3] * 255);
a = a.toString(16);
a = (a.length === 1) ? ('0' + a) : a;
@ -5888,7 +5888,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
options[prop] = 0;
}
propValue = parseFloat(options[prop], 10);
if (typeof options[prop] === 'string' && /^\d+%$/.test(options[prop])) {
if (typeof options[prop] === 'string' && /^(\d+\.\d+)%|(\d+)%$/.test(options[prop])) {
multFactor = 0.01;
}
else {
@ -5961,6 +5961,21 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
*/
offsetY: 0,
/**
* crossOrigin value (one of "", "anonymous", "use-credentials")
* @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes
* @type String
* @default
*/
crossOrigin: '',
/**
* transform matrix to change the pattern, imported from svgs.
* @type Array
* @default
*/
patternTransform: null,
/**
* Constructor
* @param {Object} [options] Options object
@ -5988,7 +6003,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
fabric.util.loadImage(options.source, function(img) {
_this.source = img;
callback && callback(_this);
});
}, null, this.crossOrigin);
}
},
@ -6018,8 +6033,10 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
type: 'pattern',
source: source,
repeat: this.repeat,
crossOrigin: this.crossOrigin,
offsetX: toFixed(this.offsetX, NUM_FRACTION_DIGITS),
offsetY: toFixed(this.offsetY, NUM_FRACTION_DIGITS),
patternTransform: this.patternTransform ? this.patternTransform.concat() : null
};
fabric.util.populateWithProperties(this, object, propertiesToInclude);
@ -8146,6 +8163,17 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
}
},
/**
* Sets the transformation on given context
* @param {RenderingContext2d} ctx context to render on
* @private
*/
_saveAndTransform: function(ctx) {
var v = this.canvas.viewportTransform;
ctx.save();
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
},
/**
* Sets brush shadow styles
* @private
@ -8278,12 +8306,10 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype
*/
_render: function() {
var ctx = this.canvas.contextTop, i, len,
v = this.canvas.viewportTransform,
p1 = this._points[0],
p2 = this._points[1];
ctx.save();
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
this._saveAndTransform(ctx);
ctx.beginPath();
//if we only have 2 points in the path and they are the same
//it means that the user only clicked the canvas without moving the mouse
@ -8442,11 +8468,8 @@ fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric
*/
drawDot: function(pointer) {
var point = this.addPoint(pointer),
ctx = this.canvas.contextTop,
v = this.canvas.viewportTransform;
ctx.save();
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
ctx = this.canvas.contextTop;
this._saveAndTransform(ctx);
ctx.fillStyle = point.fill;
ctx.beginPath();
ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false);
@ -8466,6 +8489,25 @@ fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric
this.drawDot(pointer);
},
/**
* Render the full state of the brush
* @private
*/
_render: function() {
var ctx = this.canvas.contextTop, i, len,
points = this.points, point;
this._saveAndTransform(ctx);
for (i = 0, len = points.length; i < len; i++) {
point = points[i];
ctx.fillStyle = point.fill;
ctx.beginPath();
ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
}
ctx.restore();
},
/**
* Invoked on mouse move
* @param {Object} pointer
@ -8602,7 +8644,7 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
this._setShadow();
this.addSprayChunk(pointer);
this.render();
this.render(this.sprayChunkPoints);
},
/**
@ -8611,7 +8653,7 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
*/
onMouseMove: function(pointer) {
this.addSprayChunk(pointer);
this.render();
this.render(this.sprayChunkPoints);
},
/**
@ -8637,8 +8679,6 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
originY: 'center',
fill: this.color
});
this.shadow && rect.setShadow(this.shadow);
rects.push(rect);
}
}
@ -8648,8 +8688,7 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
}
var group = new fabric.Group(rects, { originX: 'center', originY: 'center' });
group.canvas = this.canvas;
this.shadow && group.setShadow(this.shadow);
this.canvas.add(group);
this.canvas.fire('path:created', { path: group });
@ -8683,18 +8722,16 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
},
/**
* Renders brush
* Render new chunk of spray brush
*/
render: function() {
var ctx = this.canvas.contextTop;
render: function(sprayChunk) {
var ctx = this.canvas.contextTop, i, len;
ctx.fillStyle = this.color;
var v = this.canvas.viewportTransform, i, len;
ctx.save();
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
this._saveAndTransform(ctx);
for (i = 0, len = this.sprayChunkPoints.length; i < len; i++) {
var point = this.sprayChunkPoints[i];
for (i = 0, len = sprayChunk.length; i < len; i++) {
var point = sprayChunk[i];
if (typeof point.opacity !== 'undefined') {
ctx.globalAlpha = point.opacity;
}
@ -8703,6 +8740,21 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric
ctx.restore();
},
/**
* Render all spray chunks
*/
_render: function() {
var ctx = this.canvas.contextTop, i, ilen;
ctx.fillStyle = this.color;
this._saveAndTransform(ctx);
for (i = 0, ilen = this.sprayChunks.length; i < ilen; i++) {
this.render(this.sprayChunks[i]);
}
ctx.restore();
},
/**
* @param {Object} pointer
*/
@ -10922,7 +10974,9 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
*/
_onMouseDownInDrawingMode: function(e) {
this._isCurrentlyDrawing = true;
this.discardActiveObject(e).requestRenderAll();
if (this.getActiveObject()) {
this.discardActiveObject(e).requestRenderAll();
}
if (this.clipTo) {
fabric.util.clipContext(this, this.contextTop);
}
@ -11543,11 +11597,12 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
* @param {Object} [options] Options object
* @param {String} [options.format=png] The format of the output image. Either "jpeg" or "png"
* @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.
* @param {Number} [options.multiplier=1] Multiplier to scale by
* @param {Number} [options.multiplier=1] Multiplier to scale by, to have consistent
* @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14
* @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14
* @param {Number} [options.width] Cropping width. Introduced in v1.2.14
* @param {Number} [options.height] Cropping height. Introduced in v1.2.14
* @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 2.0.0
* @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format
* @see {@link http://jsfiddle.net/fabricjs/NfZVb/|jsFiddle demo}
* @example <caption>Generate jpeg dataURL with lower quality</caption>
@ -11574,7 +11629,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
var format = options.format || 'png',
quality = options.quality || 1,
multiplier = options.multiplier || 1,
multiplier = options.multiplier || options.enableRetinaScaling ? 1 : 1 / this.getRetinaScaling(),
cropping = {
left: options.left || 0,
top: options.top || 0,
@ -13292,7 +13347,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14
* @param {Number} [options.width] Cropping width. Introduced in v1.2.14
* @param {Number} [options.height] Cropping height. Introduced in v1.2.14
* @param {Boolean} [options.enableRetina] Enable retina scaling for clone image. Introduce in 1.6.4
* @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 1.6.4
* @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format
*/
toDataURL: function(options) {
@ -13304,7 +13359,11 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
el.width = boundingRect.width;
el.height = boundingRect.height;
fabric.util.wrapElement(el, 'div');
var canvas = new fabric.StaticCanvas(el, { enableRetinaScaling: options.enableRetinaScaling });
var canvas = new fabric.StaticCanvas(el, {
enableRetinaScaling: options.enableRetinaScaling,
renderOnAddRemove: false,
skipOffscreen: false,
});
// to avoid common confusion https://github.com/kangax/fabric.js/issues/806
if (options.format === 'jpg') {
options.format = 'jpeg';
@ -13324,10 +13383,12 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
var originalCanvas = this.canvas;
canvas.add(this);
var data = canvas.toDataURL(options);
this.set(origParams).setCoords();
this.canvas = originalCanvas;
// canvas.dispose will call image.dispose that will nullify the elements
// since this canvas is a simple element for the process, we remove references
// to objects in this way in order to avoid object trashing.
canvas._objects = [];
canvas.dispose();
canvas = null;
@ -14588,8 +14649,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
/* _TO_SVG_START_ */
(function() {
var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
function getSvgColorString(prop, value) {
if (!value) {
return prop + ': none; ';
@ -14656,7 +14715,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
var term = '; ',
strokeWidth = style.strokeWidth ? 'stroke-width: ' + style.strokeWidth + term : '',
fontFamily = style.fontFamily ? 'font-family: ' + style.fontFamily.replace(/"/g, '\'') + term : '',
fontSize = style.fontSize ? 'font-size: ' + style.fontSize + term : '',
fontSize = style.fontSize ? 'font-size: ' + style.fontSize + 'px' + term : '',
fontStyle = style.fontStyle ? 'font-style: ' + style.fontStyle + term : '',
fontWeight = style.fontWeight ? 'font-weight: ' + style.fontWeight + term : '',
fill = style.fill ? getSvgColorString('fill', style.fill) : '',
@ -14755,6 +14814,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
_setSVGBg: function(textBgRects) {
if (this.backgroundColor) {
var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
textBgRects.push(
'\t\t<rect ',
this._getFillAttributes(this.backgroundColor),
@ -15894,8 +15954,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
'use strict';
var fabric = global.fabric || (global.fabric = { }),
pi = Math.PI,
extend = fabric.util.object.extend;
pi = Math.PI;
if (fabric.Circle) {
fabric.warn('fabric.Circle is already defined.');
@ -16065,13 +16124,11 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @static
* @memberOf fabric.Circle
* @param {SVGElement} element Element to parse
* @param {Object} [options] Options object
* @param {Function} [callback] Options callback invoked after parsing is finished
* @param {Object} [options] Options object
* @throws {Error} If value of `r` attribute is missing or invalid
*/
fabric.Circle.fromElement = function(element, callback, options) {
options || (options = { });
fabric.Circle.fromElement = function(element, callback) {
var parsedAttributes = fabric.parseAttributes(element, fabric.Circle.ATTRIBUTE_NAMES);
if (!isValidRadius(parsedAttributes)) {
@ -16080,7 +16137,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
parsedAttributes.left = (parsedAttributes.left || 0) - parsedAttributes.radius;
parsedAttributes.top = (parsedAttributes.top || 0) - parsedAttributes.radius;
callback(new fabric.Circle(extend(parsedAttributes, options)));
callback(new fabric.Circle(parsedAttributes));
};
/**
@ -16229,8 +16286,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
'use strict';
var fabric = global.fabric || (global.fabric = { }),
piBy2 = Math.PI * 2,
extend = fabric.util.object.extend;
piBy2 = Math.PI * 2;
if (fabric.Ellipse) {
fabric.warn('fabric.Ellipse is already defined.');
@ -16387,18 +16443,16 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
* @static
* @memberOf fabric.Ellipse
* @param {SVGElement} element Element to parse
* @param {Object} [options] Options object
* @param {Function} [callback] Options callback invoked after parsing is finished
* @return {fabric.Ellipse}
*/
fabric.Ellipse.fromElement = function(element, callback, options) {
options || (options = { });
fabric.Ellipse.fromElement = function(element, callback) {
var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES);
parsedAttributes.left = (parsedAttributes.left || 0) - parsedAttributes.rx;
parsedAttributes.top = (parsedAttributes.top || 0) - parsedAttributes.ry;
callback(new fabric.Ellipse(extend(parsedAttributes, options)));
callback(new fabric.Ellipse(parsedAttributes));
};
/* _FROM_SVG_END_ */
@ -16639,8 +16693,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
extend = fabric.util.object.extend,
min = fabric.util.array.min,
max = fabric.util.array.max,
toFixed = fabric.util.toFixed,
NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
toFixed = fabric.util.toFixed;
if (fabric.Polyline) {
fabric.warn('fabric.Polyline is already defined');
@ -16756,7 +16809,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
*/
toSVG: function(reviver) {
var points = [], diffX = this.pathOffset.x, diffY = this.pathOffset.y,
markup = this._createBaseSVGMarkup();
markup = this._createBaseSVGMarkup(),
NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
for (var i = 0, len = this.points.length; i < len; i++) {
points.push(
@ -24349,7 +24403,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
charBox,
boxWidth = 0,
timeToRender,
shortCut = !isJustify && this.isEmptyStyles(lineIndex);
shortCut = !isJustify && this.charSpacing === 0 && this.isEmptyStyles(lineIndex);
ctx.save();
top -= lineHeight * this._fontSizeFraction / this.lineHeight;
@ -25992,6 +26046,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
}
if (this.canvas) {
this.canvas.calcOffset();
this.exitEditingOnOthers(this.canvas);
}
@ -26638,32 +26693,40 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
});
},
/**
* Default event handler for the basic functionalities needed on _mouseDown
* can be overridden to do something different.
* Scope of this implementation is: find the click position, set selectionStart
* find selectionEnd, initialize the drawing of either cursor or selection area
*/
_mouseDownHandler: function(options) {
if (!this.canvas || !this.editable || (options.e.button && options.e.button !== 1)) {
return;
}
var pointer = this.canvas.getPointer(options.e);
this.__mousedownX = pointer.x;
this.__mousedownY = pointer.y;
this.__isMousedown = true;
if (this.selected) {
this.setCursorByClick(options.e);
}
if (this.isEditing) {
this.__selectionStartOnMouseDown = this.selectionStart;
if (this.selectionStart === this.selectionEnd) {
this.abortCursorAnimation();
}
this.renderCursorOrSelection();
}
},
/**
* Initializes "mousedown" event handler
*/
initMousedownHandler: function() {
this.on('mousedown', function(options) {
if (!this.editable || (options.e.button && options.e.button !== 1)) {
return;
}
var pointer = this.canvas.getPointer(options.e);
this.__mousedownX = pointer.x;
this.__mousedownY = pointer.y;
this.__isMousedown = true;
if (this.selected) {
this.setCursorByClick(options.e);
}
if (this.isEditing) {
this.__selectionStartOnMouseDown = this.selectionStart;
if (this.selectionStart === this.selectionEnd) {
this.abortCursorAnimation();
}
this.renderCursorOrSelection();
}
});
this.on('mousedown', this._mouseDownHandler);
},
/**
@ -27437,8 +27500,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
/* _TO_SVG_START_ */
(function() {
var toFixed = fabric.util.toFixed,
NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
var toFixed = fabric.util.toFixed;
fabric.util.object.extend(fabric.Text.prototype, /** @lends fabric.Text.prototype */ {
@ -27525,7 +27587,8 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
*/
_createTextCharSpan: function(_char, styleDecl, left, top) {
var styleProps = this.getSvgSpanStyles(styleDecl, _char !== _char.trim()),
fillStyles = styleProps ? 'style="' + styleProps + '"' : '';
fillStyles = styleProps ? 'style="' + styleProps + '"' : '',
NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
return [
'<tspan x="', toFixed(left, NUM_FRACTION_DIGITS), '" y="',
@ -27583,6 +27646,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
},
_pushTextBgRect: function(textBgRects, color, left, top, width, height) {
var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
textBgRects.push(
'\t\t<rect ',
this._getFillAttributes(color),

2
dist/fabric.min.js vendored

File diff suppressed because one or more lines are too long

BIN
dist/fabric.min.js.gz vendored

Binary file not shown.

148
dist/fabric.require.js vendored
View file

@ -2723,7 +2723,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
},
toHexa: function() {
var source = this.getSource(), a;
a = source[3] * 255;
a = Math.round(source[3] * 255);
a = a.toString(16);
a = a.length === 1 ? "0" + a : a;
return this.toHex() + a.toUpperCase();
@ -3195,7 +3195,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
options[prop] = 0;
}
propValue = parseFloat(options[prop], 10);
if (typeof options[prop] === "string" && /^\d+%$/.test(options[prop])) {
if (typeof options[prop] === "string" && /^(\d+\.\d+)%|(\d+)%$/.test(options[prop])) {
multFactor = .01;
} else {
multFactor = 1;
@ -3230,6 +3230,8 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
repeat: "repeat",
offsetX: 0,
offsetY: 0,
crossOrigin: "",
patternTransform: null,
initialize: function(options, callback) {
options || (options = {});
this.id = fabric.Object.__uid++;
@ -3247,7 +3249,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
fabric.util.loadImage(options.source, function(img) {
_this.source = img;
callback && callback(_this);
});
}, null, this.crossOrigin);
}
},
toObject: function(propertiesToInclude) {
@ -3263,8 +3265,10 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
type: "pattern",
source: source,
repeat: this.repeat,
crossOrigin: this.crossOrigin,
offsetX: toFixed(this.offsetX, NUM_FRACTION_DIGITS),
offsetY: toFixed(this.offsetY, NUM_FRACTION_DIGITS)
offsetY: toFixed(this.offsetY, NUM_FRACTION_DIGITS),
patternTransform: this.patternTransform ? this.patternTransform.concat() : null
};
fabric.util.populateWithProperties(this, object, propertiesToInclude);
return object;
@ -4176,6 +4180,11 @@ fabric.BaseBrush = fabric.util.createClass({
ctx.setLineDash(this.strokeDashArray);
}
},
_saveAndTransform: function(ctx) {
var v = this.canvas.viewportTransform;
ctx.save();
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
},
_setShadow: function() {
if (!this.shadow) {
return;
@ -4234,9 +4243,8 @@ fabric.BaseBrush = fabric.util.createClass({
this._addPoint(pointerPoint);
},
_render: function() {
var ctx = this.canvas.contextTop, i, len, v = this.canvas.viewportTransform, p1 = this._points[0], p2 = this._points[1];
ctx.save();
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
var ctx = this.canvas.contextTop, i, len, p1 = this._points[0], p2 = this._points[1];
this._saveAndTransform(ctx);
ctx.beginPath();
if (this._points.length === 2 && p1.x === p2.x && p1.y === p2.y) {
var width = this.width / 1e3;
@ -4328,9 +4336,8 @@ fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, {
this.points = [];
},
drawDot: function(pointer) {
var point = this.addPoint(pointer), ctx = this.canvas.contextTop, v = this.canvas.viewportTransform;
ctx.save();
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
var point = this.addPoint(pointer), ctx = this.canvas.contextTop;
this._saveAndTransform(ctx);
ctx.fillStyle = point.fill;
ctx.beginPath();
ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false);
@ -4344,6 +4351,19 @@ fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, {
this._setShadow();
this.drawDot(pointer);
},
_render: function() {
var ctx = this.canvas.contextTop, i, len, points = this.points, point;
this._saveAndTransform(ctx);
for (i = 0, len = points.length; i < len; i++) {
point = points[i];
ctx.fillStyle = point.fill;
ctx.beginPath();
ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
}
ctx.restore();
},
onMouseMove: function(pointer) {
this.drawDot(pointer);
},
@ -4402,11 +4422,11 @@ fabric.SprayBrush = fabric.util.createClass(fabric.BaseBrush, {
this.canvas.clearContext(this.canvas.contextTop);
this._setShadow();
this.addSprayChunk(pointer);
this.render();
this.render(this.sprayChunkPoints);
},
onMouseMove: function(pointer) {
this.addSprayChunk(pointer);
this.render();
this.render(this.sprayChunkPoints);
},
onMouseUp: function() {
var originalRenderOnAddRemove = this.canvas.renderOnAddRemove;
@ -4424,7 +4444,6 @@ fabric.SprayBrush = fabric.util.createClass(fabric.BaseBrush, {
originY: "center",
fill: this.color
});
this.shadow && rect.setShadow(this.shadow);
rects.push(rect);
}
}
@ -4435,7 +4454,7 @@ fabric.SprayBrush = fabric.util.createClass(fabric.BaseBrush, {
originX: "center",
originY: "center"
});
group.canvas = this.canvas;
this.shadow && group.setShadow(this.shadow);
this.canvas.add(group);
this.canvas.fire("path:created", {
path: group
@ -4459,14 +4478,12 @@ fabric.SprayBrush = fabric.util.createClass(fabric.BaseBrush, {
}
return uniqueRectsArray;
},
render: function() {
var ctx = this.canvas.contextTop;
render: function(sprayChunk) {
var ctx = this.canvas.contextTop, i, len;
ctx.fillStyle = this.color;
var v = this.canvas.viewportTransform, i, len;
ctx.save();
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
for (i = 0, len = this.sprayChunkPoints.length; i < len; i++) {
var point = this.sprayChunkPoints[i];
this._saveAndTransform(ctx);
for (i = 0, len = sprayChunk.length; i < len; i++) {
var point = sprayChunk[i];
if (typeof point.opacity !== "undefined") {
ctx.globalAlpha = point.opacity;
}
@ -4474,6 +4491,15 @@ fabric.SprayBrush = fabric.util.createClass(fabric.BaseBrush, {
}
ctx.restore();
},
_render: function() {
var ctx = this.canvas.contextTop, i, ilen;
ctx.fillStyle = this.color;
this._saveAndTransform(ctx);
for (i = 0, ilen = this.sprayChunks.length; i < ilen; i++) {
this.render(this.sprayChunks[i]);
}
ctx.restore();
},
addSprayChunk: function(pointer) {
this.sprayChunkPoints = [];
var x, y, width, radius = this.width / 2, i;
@ -5626,7 +5652,9 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
},
_onMouseDownInDrawingMode: function(e) {
this._isCurrentlyDrawing = true;
this.discardActiveObject(e).requestRenderAll();
if (this.getActiveObject()) {
this.discardActiveObject(e).requestRenderAll();
}
if (this.clipTo) {
fabric.util.clipContext(this, this.contextTop);
}
@ -5991,7 +6019,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
fabric.util.object.extend(fabric.StaticCanvas.prototype, {
toDataURL: function(options) {
options || (options = {});
var format = options.format || "png", quality = options.quality || 1, multiplier = options.multiplier || 1, cropping = {
var format = options.format || "png", quality = options.quality || 1, multiplier = options.multiplier || options.enableRetinaScaling ? 1 : 1 / this.getRetinaScaling(), cropping = {
left: options.left || 0,
top: options.top || 0,
width: options.width || 0,
@ -6741,7 +6769,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
el.height = boundingRect.height;
fabric.util.wrapElement(el, "div");
var canvas = new fabric.StaticCanvas(el, {
enableRetinaScaling: options.enableRetinaScaling
enableRetinaScaling: options.enableRetinaScaling,
renderOnAddRemove: false,
skipOffscreen: false
});
if (options.format === "jpg") {
options.format = "jpeg";
@ -6759,6 +6789,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, {
var data = canvas.toDataURL(options);
this.set(origParams).setCoords();
this.canvas = originalCanvas;
canvas._objects = [];
canvas.dispose();
canvas = null;
return data;
@ -7322,7 +7353,6 @@ fabric.util.object.extend(fabric.Object.prototype, {
});
(function() {
var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
function getSvgColorString(prop, value) {
if (!value) {
return prop + ": none; ";
@ -7343,7 +7373,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
return [ stroke, "stroke-width: ", strokeWidth, "; ", "stroke-dasharray: ", strokeDashArray, "; ", "stroke-linecap: ", strokeLineCap, "; ", "stroke-linejoin: ", strokeLineJoin, "; ", "stroke-miterlimit: ", strokeMiterLimit, "; ", fill, "fill-rule: ", fillRule, "; ", "opacity: ", opacity, ";", filter, visibility ].join("");
},
getSvgSpanStyles: function(style, useWhiteSpace) {
var term = "; ", strokeWidth = style.strokeWidth ? "stroke-width: " + style.strokeWidth + term : "", fontFamily = style.fontFamily ? "font-family: " + style.fontFamily.replace(/"/g, "'") + term : "", fontSize = style.fontSize ? "font-size: " + style.fontSize + term : "", fontStyle = style.fontStyle ? "font-style: " + style.fontStyle + term : "", fontWeight = style.fontWeight ? "font-weight: " + style.fontWeight + term : "", fill = style.fill ? getSvgColorString("fill", style.fill) : "", stroke = style.stroke ? getSvgColorString("stroke", style.stroke) : "", textDecoration = this.getSvgTextDecoration(style);
var term = "; ", strokeWidth = style.strokeWidth ? "stroke-width: " + style.strokeWidth + term : "", fontFamily = style.fontFamily ? "font-family: " + style.fontFamily.replace(/"/g, "'") + term : "", fontSize = style.fontSize ? "font-size: " + style.fontSize + "px" + term : "", fontStyle = style.fontStyle ? "font-style: " + style.fontStyle + term : "", fontWeight = style.fontWeight ? "font-weight: " + style.fontWeight + term : "", fill = style.fill ? getSvgColorString("fill", style.fill) : "", stroke = style.stroke ? getSvgColorString("stroke", style.stroke) : "", textDecoration = this.getSvgTextDecoration(style);
if (textDecoration) {
textDecoration = "text-decoration: " + textDecoration + term;
}
@ -7370,6 +7400,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
},
_setSVGBg: function(textBgRects) {
if (this.backgroundColor) {
var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
textBgRects.push("\t\t<rect ", this._getFillAttributes(this.backgroundColor), ' x="', toFixed(-this.width / 2, NUM_FRACTION_DIGITS), '" y="', toFixed(-this.height / 2, NUM_FRACTION_DIGITS), '" width="', toFixed(this.width, NUM_FRACTION_DIGITS), '" height="', toFixed(this.height, NUM_FRACTION_DIGITS), '"></rect>\n');
}
},
@ -7923,7 +7954,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
(function(global) {
"use strict";
var fabric = global.fabric || (global.fabric = {}), pi = Math.PI, extend = fabric.util.object.extend;
var fabric = global.fabric || (global.fabric = {}), pi = Math.PI;
if (fabric.Circle) {
fabric.warn("fabric.Circle is already defined.");
return;
@ -7971,15 +8002,14 @@ fabric.util.object.extend(fabric.Object.prototype, {
}
});
fabric.Circle.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat("cx cy r".split(" "));
fabric.Circle.fromElement = function(element, callback, options) {
options || (options = {});
fabric.Circle.fromElement = function(element, callback) {
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");
}
parsedAttributes.left = (parsedAttributes.left || 0) - parsedAttributes.radius;
parsedAttributes.top = (parsedAttributes.top || 0) - parsedAttributes.radius;
callback(new fabric.Circle(extend(parsedAttributes, options)));
callback(new fabric.Circle(parsedAttributes));
};
function isValidRadius(attributes) {
return "radius" in attributes && attributes.radius >= 0;
@ -8030,7 +8060,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
(function(global) {
"use strict";
var fabric = global.fabric || (global.fabric = {}), piBy2 = Math.PI * 2, extend = fabric.util.object.extend;
var fabric = global.fabric || (global.fabric = {}), piBy2 = Math.PI * 2;
if (fabric.Ellipse) {
fabric.warn("fabric.Ellipse is already defined.");
return;
@ -8084,12 +8114,11 @@ fabric.util.object.extend(fabric.Object.prototype, {
}
});
fabric.Ellipse.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat("cx cy rx ry".split(" "));
fabric.Ellipse.fromElement = function(element, callback, options) {
options || (options = {});
fabric.Ellipse.fromElement = function(element, callback) {
var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES);
parsedAttributes.left = (parsedAttributes.left || 0) - parsedAttributes.rx;
parsedAttributes.top = (parsedAttributes.top || 0) - parsedAttributes.ry;
callback(new fabric.Ellipse(extend(parsedAttributes, options)));
callback(new fabric.Ellipse(parsedAttributes));
};
fabric.Ellipse.fromObject = function(object, callback) {
return fabric.Object._fromObject("Ellipse", object, callback);
@ -8177,7 +8206,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
(function(global) {
"use strict";
var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, min = fabric.util.array.min, max = fabric.util.array.max, toFixed = fabric.util.toFixed, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, min = fabric.util.array.min, max = fabric.util.array.max, toFixed = fabric.util.toFixed;
if (fabric.Polyline) {
fabric.warn("fabric.Polyline is already defined");
return;
@ -8219,7 +8248,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
});
},
toSVG: function(reviver) {
var points = [], diffX = this.pathOffset.x, diffY = this.pathOffset.y, markup = this._createBaseSVGMarkup();
var points = [], diffX = this.pathOffset.x, diffY = this.pathOffset.y, markup = this._createBaseSVGMarkup(), NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
for (var i = 0, len = this.points.length; i < len; i++) {
points.push(toFixed(this.points[i].x - diffX, NUM_FRACTION_DIGITS), ",", toFixed(this.points[i].y - diffY, NUM_FRACTION_DIGITS), " ");
}
@ -11646,7 +11675,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
ctx.restore();
},
_renderChars: function(method, ctx, line, left, top, lineIndex) {
var lineHeight = this.getHeightOfLine(lineIndex), isJustify = this.textAlign.indexOf("justify") !== -1, actualStyle, nextStyle, charsToRender = "", charBox, boxWidth = 0, timeToRender, shortCut = !isJustify && this.isEmptyStyles(lineIndex);
var lineHeight = this.getHeightOfLine(lineIndex), isJustify = this.textAlign.indexOf("justify") !== -1, actualStyle, nextStyle, charsToRender = "", charBox, boxWidth = 0, timeToRender, shortCut = !isJustify && this.charSpacing === 0 && this.isEmptyStyles(lineIndex);
ctx.save();
top -= lineHeight * this._fontSizeFraction / this.lineHeight;
if (shortCut) {
@ -12509,6 +12538,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
return;
}
if (this.canvas) {
this.canvas.calcOffset();
this.exitEditingOnOthers(this.canvas);
}
this.isEditing = true;
@ -12972,26 +13002,27 @@ fabric.util.object.extend(fabric.IText.prototype, {
this.selectLine(this.getSelectionStartFromPointer(options.e));
});
},
_mouseDownHandler: function(options) {
if (!this.canvas || !this.editable || options.e.button && options.e.button !== 1) {
return;
}
var pointer = this.canvas.getPointer(options.e);
this.__mousedownX = pointer.x;
this.__mousedownY = pointer.y;
this.__isMousedown = true;
if (this.selected) {
this.setCursorByClick(options.e);
}
if (this.isEditing) {
this.__selectionStartOnMouseDown = this.selectionStart;
if (this.selectionStart === this.selectionEnd) {
this.abortCursorAnimation();
}
this.renderCursorOrSelection();
}
},
initMousedownHandler: function() {
this.on("mousedown", function(options) {
if (!this.editable || options.e.button && options.e.button !== 1) {
return;
}
var pointer = this.canvas.getPointer(options.e);
this.__mousedownX = pointer.x;
this.__mousedownY = pointer.y;
this.__isMousedown = true;
if (this.selected) {
this.setCursorByClick(options.e);
}
if (this.isEditing) {
this.__selectionStartOnMouseDown = this.selectionStart;
if (this.selectionStart === this.selectionEnd) {
this.abortCursorAnimation();
}
this.renderCursorOrSelection();
}
});
this.on("mousedown", this._mouseDownHandler);
},
_isObjectMoved: function(e) {
var pointer = this.canvas.getPointer(e);
@ -13441,7 +13472,7 @@ fabric.util.object.extend(fabric.IText.prototype, {
});
(function() {
var toFixed = fabric.util.toFixed, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
var toFixed = fabric.util.toFixed;
fabric.util.object.extend(fabric.Text.prototype, {
toSVG: function(reviver) {
var markup = this._createBaseSVGMarkup(), offsets = this._getSVGLeftTopOffsets(), textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft);
@ -13476,7 +13507,7 @@ fabric.util.object.extend(fabric.IText.prototype, {
};
},
_createTextCharSpan: function(_char, styleDecl, left, top) {
var styleProps = this.getSvgSpanStyles(styleDecl, _char !== _char.trim()), fillStyles = styleProps ? 'style="' + styleProps + '"' : "";
var styleProps = this.getSvgSpanStyles(styleDecl, _char !== _char.trim()), fillStyles = styleProps ? 'style="' + styleProps + '"' : "", NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
return [ '<tspan x="', toFixed(left, NUM_FRACTION_DIGITS), '" y="', toFixed(top, NUM_FRACTION_DIGITS), '" ', fillStyles, ">", fabric.util.string.escapeXml(_char), "</tspan>" ].join("");
},
_setSVGTextLineText: function(textSpans, lineIndex, textLeftOffset, textTopOffset) {
@ -13513,6 +13544,7 @@ fabric.util.object.extend(fabric.IText.prototype, {
}
},
_pushTextBgRect: function(textBgRects, color, left, top, width, height) {
var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
textBgRects.push("\t\t<rect ", this._getFillAttributes(color), ' x="', toFixed(left, NUM_FRACTION_DIGITS), '" y="', toFixed(top, NUM_FRACTION_DIGITS), '" width="', toFixed(width, NUM_FRACTION_DIGITS), '" height="', toFixed(height, NUM_FRACTION_DIGITS), '"></rect>\n');
},
_setSVGTextLineBg: function(textBgRects, i, leftOffset, textTopOffset) {

View file

@ -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": "2.0.0-rc.4",
"version": "2.0.0",
"author": "Juriy Zaytsev <kangax@gmail.com>",
"contributors": [
{