diff --git a/.eslintrc.json b/.eslintrc.json index 4bbe62198e3..f3d848c6348 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,7 +3,7 @@ "browser": true }, "globals": { - "ActiveXObject": true, + "Promise": true, "define": true, "eventjs": true, "exports": true, diff --git a/src/filters/base_filter.class.js b/src/filters/base_filter.class.js index dfcf5bab46c..bb55d5d439a 100644 --- a/src/filters/base_filter.class.js +++ b/src/filters/base_filter.class.js @@ -355,8 +355,12 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag } }); -fabric.Image.filters.BaseFilter.fromObject = function(object, callback) { - var filter = new fabric.Image.filters[object.type](object); - callback && callback(filter); - return filter; +/** + * Create filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @returns {Promise} + */ +fabric.Image.filters.BaseFilter.fromObject = function(object) { + return Promise.resolve(new fabric.Image.filters[object.type](object)); }; diff --git a/src/filters/blendcolor_filter.class.js b/src/filters/blendcolor_filter.class.js index 37eb5bfabfb..7379b665f19 100644 --- a/src/filters/blendcolor_filter.class.js +++ b/src/filters/blendcolor_filter.class.js @@ -240,11 +240,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.BlendColor} Instance of fabric.Image.filters.BlendColor + * @returns {Promise} */ fabric.Image.filters.BlendColor.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/blendimage_filter.class.js b/src/filters/blendimage_filter.class.js index 1c0c906ea78..5ff2d480da5 100644 --- a/src/filters/blendimage_filter.class.js +++ b/src/filters/blendimage_filter.class.js @@ -230,17 +230,16 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {function} callback to be invoked after filter creation - * @return {fabric.Image.filters.BlendImage} Instance of fabric.Image.filters.BlendImage + * @returns {Promise} */ - fabric.Image.filters.BlendImage.fromObject = function(object, callback) { - fabric.Image.fromObject(object.image, function(image) { + fabric.Image.filters.BlendImage.fromObject = function(object) { + return fabric.Image.fromObject(object.image).then(function(image) { var options = fabric.util.object.clone(object); options.image = image; - callback(new fabric.Image.filters.BlendImage(options)); + return new fabric.Image.filters.BlendImage(options); }); }; diff --git a/src/filters/blur_filter.class.js b/src/filters/blur_filter.class.js index 11d3150222a..d99e3f275cd 100644 --- a/src/filters/blur_filter.class.js +++ b/src/filters/blur_filter.class.js @@ -210,7 +210,10 @@ }); /** - * Deserialize a JSON definition of a BlurFilter into a concrete instance. + * Create filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @returns {Promise} */ filters.Blur.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/brightness_filter.class.js b/src/filters/brightness_filter.class.js index 2838741a39b..4749cb93d0e 100644 --- a/src/filters/brightness_filter.class.js +++ b/src/filters/brightness_filter.class.js @@ -102,11 +102,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.Brightness} Instance of fabric.Image.filters.Brightness + * @returns {Promise} */ fabric.Image.filters.Brightness.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/colormatrix_filter.class.js b/src/filters/colormatrix_filter.class.js index 091f1bab4d1..045cab5ef76 100644 --- a/src/filters/colormatrix_filter.class.js +++ b/src/filters/colormatrix_filter.class.js @@ -149,11 +149,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {function} [callback] function to invoke after filter creation - * @return {fabric.Image.filters.ColorMatrix} Instance of fabric.Image.filters.ColorMatrix + * @returns {Promise} */ fabric.Image.filters.ColorMatrix.fromObject = fabric.Image.filters.BaseFilter.fromObject; })(typeof exports !== 'undefined' ? exports : this); diff --git a/src/filters/composed_filter.class.js b/src/filters/composed_filter.class.js index c03d962aa4d..dc42aa71f04 100644 --- a/src/filters/composed_filter.class.js +++ b/src/filters/composed_filter.class.js @@ -60,13 +60,12 @@ /** * Deserialize a JSON definition of a ComposedFilter into a concrete instance. */ - fabric.Image.filters.Composed.fromObject = function(object, callback) { - var filters = object.subFilters || [], - subFilters = filters.map(function(filter) { - return new fabric.Image.filters[filter.type](filter); - }), - instance = new fabric.Image.filters.Composed({ subFilters: subFilters }); - callback && callback(instance); - return instance; + fabric.Image.filters.Composed.fromObject = function(object) { + var filters = object.subFilters || []; + return Promise.all(filters.map(function(filter) { + return fabric.Image.filters[filter.type].fromObject(filter); + })).then(function(enlivedFilters) { + return new fabric.Image.filters.Composed({ subFilters: enlivedFilters }); + }); }; })(typeof exports !== 'undefined' ? exports : this); diff --git a/src/filters/contrast_filter.class.js b/src/filters/contrast_filter.class.js index f8f37b8b828..fd5d1833592 100644 --- a/src/filters/contrast_filter.class.js +++ b/src/filters/contrast_filter.class.js @@ -102,11 +102,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.Contrast} Instance of fabric.Image.filters.Contrast + * @returns {Promise} */ fabric.Image.filters.Contrast.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/convolute_filter.class.js b/src/filters/convolute_filter.class.js index 2cd6cfc2545..2941208206e 100644 --- a/src/filters/convolute_filter.class.js +++ b/src/filters/convolute_filter.class.js @@ -341,11 +341,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.Convolute} Instance of fabric.Image.filters.Convolute + * @returns {Promise} */ fabric.Image.filters.Convolute.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/filter_boilerplate.js b/src/filters/filter_boilerplate.js index 6cecad85274..c1de87cc2e7 100644 --- a/src/filters/filter_boilerplate.js +++ b/src/filters/filter_boilerplate.js @@ -100,11 +100,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.MyFilter} Instance of fabric.Image.filters.MyFilter + * @returns {Promise} */ fabric.Image.filters.MyFilter.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/gamma_filter.class.js b/src/filters/gamma_filter.class.js index 7b39c7c27e8..5bd67be32fd 100644 --- a/src/filters/gamma_filter.class.js +++ b/src/filters/gamma_filter.class.js @@ -125,11 +125,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.Gamma} Instance of fabric.Image.filters.Gamma + * @returns {Promise} */ fabric.Image.filters.Gamma.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/grayscale_filter.class.js b/src/filters/grayscale_filter.class.js index 414b96d880f..992b02ed27f 100644 --- a/src/filters/grayscale_filter.class.js +++ b/src/filters/grayscale_filter.class.js @@ -143,11 +143,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.Grayscale} Instance of fabric.Image.filters.Grayscale + * @returns {Promise} */ fabric.Image.filters.Grayscale.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/hue_rotation.class.js b/src/filters/hue_rotation.class.js index 5c3e6ec4dc4..7339a28c092 100644 --- a/src/filters/hue_rotation.class.js +++ b/src/filters/hue_rotation.class.js @@ -96,11 +96,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.HueRotation} Instance of fabric.Image.filters.HueRotation + * @returns {Promise} */ fabric.Image.filters.HueRotation.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/invert_filter.class.js b/src/filters/invert_filter.class.js index 6490b2248d1..7d5c6bbfc67 100644 --- a/src/filters/invert_filter.class.js +++ b/src/filters/invert_filter.class.js @@ -99,11 +99,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.Invert} Instance of fabric.Image.filters.Invert + * @returns {Promise} */ fabric.Image.filters.Invert.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/noise_filter.class.js b/src/filters/noise_filter.class.js index 20a85eb84ca..9cb2a0faf6f 100644 --- a/src/filters/noise_filter.class.js +++ b/src/filters/noise_filter.class.js @@ -123,11 +123,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {Function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.Noise} Instance of fabric.Image.filters.Noise + * @returns {Promise} */ fabric.Image.filters.Noise.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/pixelate_filter.class.js b/src/filters/pixelate_filter.class.js index ee7d04bf8c7..5e3eef21d9a 100644 --- a/src/filters/pixelate_filter.class.js +++ b/src/filters/pixelate_filter.class.js @@ -126,11 +126,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {Function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.Pixelate} Instance of fabric.Image.filters.Pixelate + * @returns {Promise} */ fabric.Image.filters.Pixelate.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/removecolor_filter.class.js b/src/filters/removecolor_filter.class.js index 091ec80959d..c36feabbc9f 100644 --- a/src/filters/removecolor_filter.class.js +++ b/src/filters/removecolor_filter.class.js @@ -162,11 +162,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {Function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.RemoveColor} Instance of fabric.Image.filters.RemoveWhite + * @returns {Promise} */ fabric.Image.filters.RemoveColor.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/resize_filter.class.js b/src/filters/resize_filter.class.js index c04f36ff5c3..f5abcf35ba0 100644 --- a/src/filters/resize_filter.class.js +++ b/src/filters/resize_filter.class.js @@ -479,11 +479,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {Function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.Resize} Instance of fabric.Image.filters.Resize + * @returns {Promise} */ fabric.Image.filters.Resize.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/saturate_filter.class.js b/src/filters/saturate_filter.class.js index 99bde576a08..b85b108679f 100644 --- a/src/filters/saturate_filter.class.js +++ b/src/filters/saturate_filter.class.js @@ -47,7 +47,7 @@ * Saturation value, from -1 to 1. * Increases/decreases the color saturation. * A value of 0 has no effect. - * + * * @param {Number} saturation * @default */ @@ -108,11 +108,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {Function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.Saturation} Instance of fabric.Image.filters.Saturate + * @returns {Promise} */ fabric.Image.filters.Saturation.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/filters/vibrance_filter.class.js b/src/filters/vibrance_filter.class.js index 094681079d7..235c6c26f7d 100644 --- a/src/filters/vibrance_filter.class.js +++ b/src/filters/vibrance_filter.class.js @@ -48,7 +48,7 @@ * Vibrance value, from -1 to 1. * Increases/decreases the saturation of more muted colors with less effect on saturated colors. * A value of 0 has no effect. - * + * * @param {Number} vibrance * @default */ @@ -111,11 +111,10 @@ }); /** - * Returns filter instance from an object representation + * Create filter instance from an object representation * @static * @param {Object} object Object to create an instance from - * @param {Function} [callback] to be invoked after filter creation - * @return {fabric.Image.filters.Vibrance} Instance of fabric.Image.filters.Vibrance + * @returns {Promise} */ fabric.Image.filters.Vibrance.fromObject = fabric.Image.filters.BaseFilter.fromObject; diff --git a/src/mixins/canvas_serialization.mixin.js b/src/mixins/canvas_serialization.mixin.js index 4f7f0fe356e..e82d665b090 100644 --- a/src/mixins/canvas_serialization.mixin.js +++ b/src/mixins/canvas_serialization.mixin.js @@ -3,24 +3,23 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati * Populates canvas with data from the specified JSON. * JSON format must conform to the one of {@link fabric.Canvas#toJSON} * @param {String|Object} json JSON string or object - * @param {Function} callback Callback, invoked when json is parsed - * and corresponding objects (e.g: {@link fabric.Image}) - * are initialized * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created. - * @return {fabric.Canvas} instance + * @return {Promise} instance * @chainable * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#deserialization} * @see {@link http://jsfiddle.net/fabricjs/fmgXt/|jsFiddle demo} * @example loadFromJSON - * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas)); + * canvas.loadFromJSON(json).then((canvas) => canvas.requestRenderAll()); * @example loadFromJSON with reviver - * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), function(o, object) { + * canvas.loadFromJSON(json, function(o, object) { * // `o` = json object * // `object` = fabric.Object instance * // ... do some stuff ... + * }).then((canvas) => { + * ... canvas is restored, add your code. * }); */ - loadFromJSON: function (json, callback, reviver) { + loadFromJSON: function (json, reviver) { if (!json) { return; } @@ -31,38 +30,35 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati : fabric.util.object.clone(json); var _this = this, - clipPath = serialized.clipPath, renderOnAddRemove = this.renderOnAddRemove; this.renderOnAddRemove = false; - delete serialized.clipPath; - - this._enlivenObjects(serialized.objects, function (enlivenedObjects) { - _this.clear(); - _this._setBgOverlay(serialized, function () { - if (clipPath) { - _this._enlivenObjects([clipPath], function (enlivenedCanvasClip) { - _this.clipPath = enlivenedCanvasClip[0]; - _this.__setupCanvas.call(_this, serialized, enlivenedObjects, renderOnAddRemove, callback); + return fabric.util.enlivenObjects(serialized.objects || [], '', reviver) + .then(function(enlived) { + _this.clear(); + return fabric.util.enlivenObjectEnlivables({ + backgroundImage: serialized.backgroundImage, + backgroundColor: serialized.background, + overlayImage: serialized.overlayImage, + overlayColor: serialized.overlay, + clipPath: serialized.clipPath, + }) + .then(function(enlivedMap) { + _this.__setupCanvas(serialized, enlived, renderOnAddRemove); + _this.set(enlivedMap); + return _this; }); - } - else { - _this.__setupCanvas.call(_this, serialized, enlivenedObjects, renderOnAddRemove, callback); - } }); - }, reviver); - return this; }, /** * @private * @param {Object} serialized Object with background and overlay information - * @param {Array} restored canvas objects - * @param {Function} cached renderOnAddRemove callback - * @param {Function} callback Invoked after all background and overlay images/patterns loaded + * @param {Array} enlivenedObjects canvas objects + * @param {boolean} renderOnAddRemove renderOnAddRemove setting for the canvas */ - __setupCanvas: function(serialized, enlivenedObjects, renderOnAddRemove, callback) { + __setupCanvas: function(serialized, enlivenedObjects, renderOnAddRemove) { var _this = this; enlivenedObjects.forEach(function(obj, index) { // we splice the array just in case some custom classes restored from JSON @@ -81,122 +77,17 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati // create the Object instance. Here the Canvas is // already an instance and we are just loading things over it this._setOptions(serialized); - this.renderAll(); - callback && callback(); - }, - - /** - * @private - * @param {Object} serialized Object with background and overlay information - * @param {Function} callback Invoked after all background and overlay images/patterns loaded - */ - _setBgOverlay: function(serialized, callback) { - var loaded = { - backgroundColor: false, - overlayColor: false, - backgroundImage: false, - overlayImage: false - }; - - if (!serialized.backgroundImage && !serialized.overlayImage && !serialized.background && !serialized.overlay) { - callback && callback(); - return; - } - - var cbIfLoaded = function () { - if (loaded.backgroundImage && loaded.overlayImage && loaded.backgroundColor && loaded.overlayColor) { - callback && callback(); - } - }; - - this.__setBgOverlay('backgroundImage', serialized.backgroundImage, loaded, cbIfLoaded); - this.__setBgOverlay('overlayImage', serialized.overlayImage, loaded, cbIfLoaded); - this.__setBgOverlay('backgroundColor', serialized.background, loaded, cbIfLoaded); - this.__setBgOverlay('overlayColor', serialized.overlay, loaded, cbIfLoaded); - }, - - /** - * @private - * @param {String} property Property to set (backgroundImage, overlayImage, backgroundColor, overlayColor) - * @param {(Object|String)} value Value to set - * @param {Object} loaded Set loaded property to true if property is set - * @param {Object} callback Callback function to invoke after property is set - */ - __setBgOverlay: function(property, value, loaded, callback) { - var _this = this; - - if (!value) { - loaded[property] = true; - callback && callback(); - return; - } - - if (property === 'backgroundImage' || property === 'overlayImage') { - fabric.util.enlivenObjects([value], function(enlivedObject){ - _this[property] = enlivedObject[0]; - loaded[property] = true; - callback && callback(); - }); - } - else { - this['set' + fabric.util.string.capitalize(property, true)](value, function() { - loaded[property] = true; - callback && callback(); - }); - } - }, - - /** - * @private - * @param {Array} objects - * @param {Function} callback - * @param {Function} [reviver] - */ - _enlivenObjects: function (objects, callback, reviver) { - if (!objects || objects.length === 0) { - callback && callback([]); - return; - } - - fabric.util.enlivenObjects(objects, function(enlivenedObjects) { - callback && callback(enlivenedObjects); - }, null, reviver); - }, - - /** - * @private - * @param {String} format - * @param {Function} callback - */ - _toDataURL: function (format, callback) { - this.clone(function (clone) { - callback(clone.toDataURL(format)); - }); - }, - - /** - * @private - * @param {String} format - * @param {Number} multiplier - * @param {Function} callback - */ - _toDataURLWithMultiplier: function (format, multiplier, callback) { - this.clone(function (clone) { - callback(clone.toDataURLWithMultiplier(format, multiplier)); - }); }, /** * Clones canvas instance - * @param {Object} [callback] Receives cloned instance as a first argument * @param {Array} [properties] Array of properties to include in the cloned canvas and children + * @returns {Promise} */ - clone: function (callback, properties) { + clone: function (properties) { var data = JSON.stringify(this.toJSON(properties)); - this.cloneWithoutData(function(clone) { - clone.loadFromJSON(data, function() { - callback && callback(clone); - }); + return this.cloneWithoutData().then(function(clone) { + return clone.loadFromJSON(data); }); }, @@ -204,25 +95,22 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati * Clones canvas instance without cloning existing data. * This essentially copies canvas dimensions, clipping properties, etc. * but leaves data empty (so that you can populate it with your own) - * @param {Object} [callback] Receives cloned instance as a first argument + * @returns {Promise} */ - cloneWithoutData: function(callback) { + cloneWithoutData: function() { var el = fabric.util.createCanvasElement(); el.width = this.width; el.height = this.height; - + // this seems wrong. either Canvas or StaticCanvas var clone = new fabric.Canvas(el); + var data = {}; if (this.backgroundImage) { - clone.setBackgroundImage(this.backgroundImage.src, function() { - clone.renderAll(); - callback && callback(clone); - }); - clone.backgroundImageOpacity = this.backgroundImageOpacity; - clone.backgroundImageStretch = this.backgroundImageStretch; + data.backgroundImage = this.backgroundImage.toObject(); } - else { - callback && callback(clone); + if (this.backgroundColor) { + data.background = this.backgroundColor.toObject ? this.backgroundColor.toObject() : this.backgroundColor; } + return clone.loadFromJSON(data); } }); diff --git a/src/mixins/eraser_brush.mixin.js b/src/mixins/eraser_brush.mixin.js index 9294c937248..376c4fa8647 100644 --- a/src/mixins/eraser_brush.mixin.js +++ b/src/mixins/eraser_brush.mixin.js @@ -1,11 +1,6 @@ (function () { /** ERASER_START */ - /** - * add `eraser` to enlivened props - */ - fabric.Object.ENLIVEN_PROPS.push('eraser'); - var __drawClipPath = fabric.Object.prototype._drawClipPath; var _needsItsOwnCache = fabric.Object.prototype.needsItsOwnCache; var _toObject = fabric.Object.prototype.toObject; @@ -131,53 +126,57 @@ /** * @private * @param {fabric.Path} path + * @returns {Promise} */ _addEraserPathToObjects: function (path) { - this._objects.forEach(function (object) { - fabric.EraserBrush.prototype._addPathToObjectEraser.call( + return Promise.all(this._objects.map(function (object) { + return fabric.EraserBrush.prototype._addPathToObjectEraser.call( fabric.EraserBrush.prototype, object, path ); - }); + })); }, /** * Applies the group's eraser to its objects * @tutorial {@link http://fabricjs.com/erasing#erasable_property} + * @returns {Promise} */ applyEraserToObjects: function () { var _this = this, eraser = this.eraser; - if (eraser) { - delete this.eraser; - var transform = _this.calcTransformMatrix(); - eraser.clone(function (eraser) { - var clipPath = _this.clipPath; - eraser.getObjects('path') - .forEach(function (path) { - // first we transform the path from the group's coordinate system to the canvas' - var originalTransform = fabric.util.multiplyTransformMatrices( - transform, - path.calcTransformMatrix() - ); - fabric.util.applyTransformToObject(path, originalTransform); - if (clipPath) { - clipPath.clone(function (_clipPath) { - var eraserPath = fabric.EraserBrush.prototype.applyClipPathToPath.call( - fabric.EraserBrush.prototype, - path, - _clipPath, - transform - ); - _this._addEraserPathToObjects(eraserPath); - }, ['absolutePositioned', 'inverted']); - } - else { - _this._addEraserPathToObjects(path); - } - }); + return Promise.resolve() + .then(function () { + if (eraser) { + delete _this.eraser; + var transform = _this.calcTransformMatrix(); + return eraser.clone() + .then(function (eraser) { + var clipPath = _this.clipPath; + return Promise.all(eraser.getObjects('path') + .map(function (path) { + // first we transform the path from the group's coordinate system to the canvas' + var originalTransform = fabric.util.multiplyTransformMatrices( + transform, + path.calcTransformMatrix() + ); + fabric.util.applyTransformToObject(path, originalTransform); + return clipPath ? + clipPath.clone() + .then(function (_clipPath) { + var eraserPath = fabric.EraserBrush.prototype.applyClipPathToPath.call( + fabric.EraserBrush.prototype, + path, + _clipPath, + transform + ); + return _this._addEraserPathToObjects(eraserPath); + }, ['absolutePositioned', 'inverted']) : + _this._addEraserPathToObjects(path); + })); + }); + } }); - } }, /** @@ -262,20 +261,21 @@ }); /** - * Returns {@link fabric.Eraser} instance from an object representation + * Returns instance from an object representation * @static * @memberOf fabric.Eraser * @param {Object} object Object to create an Eraser from - * @param {Function} [callback] Callback to invoke when an eraser instance is created + * @returns {Promise} */ - fabric.Eraser.fromObject = function (object, callback) { - var objects = object.objects; - fabric.util.enlivenObjects(objects, function (enlivenedObjects) { - var options = fabric.util.object.clone(object, true); - delete options.objects; - fabric.util.enlivenObjectEnlivables(object, options, function () { - callback && callback(new fabric.Eraser(enlivenedObjects, options, true)); - }); + fabric.Eraser.fromObject = function (object) { + var objects = object.objects || [], + options = fabric.util.object.clone(object, true); + delete options.objects; + return Promise.all([ + fabric.util.enlivenObjects(objects), + fabric.util.enlivenObjectEnlivables(options) + ]).then(function (enlivedProps) { + return new fabric.Eraser(enlivedProps[0], Object.assign(options, enlivedProps[1]), true); }); }; @@ -600,27 +600,31 @@ * Called when a group has a clip path that should be applied to the path before applying erasing on the group's objects. * @param {fabric.Path} path The eraser path * @param {fabric.Object} object The clipPath to apply to path belongs to object - * @param {Function} callback Callback to be invoked with the cloned path after applying the clip path + * @returns {Promise} */ - clonePathWithClipPath: function (path, object, callback) { + clonePathWithClipPath: function (path, object) { var objTransform = object.calcTransformMatrix(); var clipPath = object.clipPath; var _this = this; - path.clone(function (_path) { - clipPath.clone(function (_clipPath) { - callback(_this.applyClipPathToPath(_path, _clipPath, objTransform)); - }, ['absolutePositioned', 'inverted']); + return Promise.all([ + path.clone(), + clipPath.clone(['absolutePositioned', 'inverted']) + ]).then(function (clones) { + return _this.applyClipPathToPath(clones[0], clones[1], objTransform); }); }, /** * Adds path to object's eraser, walks down object's descendants if necessary * + * @public * @fires erasing:end on object * @param {fabric.Object} obj * @param {fabric.Path} path + * @param {Object} [context] context to assign erased objects to + * @returns {Promise} */ - _addPathToObjectEraser: function (obj, path) { + _addPathToObjectEraser: function (obj, path, context) { var _this = this; // object is collection, i.e group if (obj.forEachObject && obj.erasable === 'deep') { @@ -628,16 +632,17 @@ return _obj.erasable; }); if (targets.length > 0 && obj.clipPath) { - this.clonePathWithClipPath(path, obj, function (_path) { - targets.forEach(function (_obj) { - _this._addPathToObjectEraser(_obj, _path); + return this.clonePathWithClipPath(path, obj) + .then(function (_path) { + return Promise.all(targets.map(function (_obj) { + return _this._addPathToObjectEraser(_obj, _path, context); + })); }); - }); } else if (targets.length > 0) { - targets.forEach(function (_obj) { - _this._addPathToObjectEraser(_obj, path); - }); + return Promise.all(targets.map(function (_obj) { + return _this._addPathToObjectEraser(_obj, path, context); + })); } return; } @@ -648,24 +653,27 @@ obj.eraser = eraser; } // clone and add path - path.clone(function (path) { - // http://fabricjs.com/using-transformations - var desiredTransform = fabric.util.multiplyTransformMatrices( - fabric.util.invertTransform( - obj.calcTransformMatrix() - ), - path.calcTransformMatrix() - ); - fabric.util.applyTransformToObject(path, desiredTransform); - eraser.addWithUpdate(path); - obj.set('dirty', true); - obj.fire('erasing:end', { - path: path + return path.clone() + .then(function (path) { + // http://fabricjs.com/using-transformations + var desiredTransform = fabric.util.multiplyTransformMatrices( + fabric.util.invertTransform( + obj.calcTransformMatrix() + ), + path.calcTransformMatrix() + ); + fabric.util.applyTransformToObject(path, desiredTransform); + eraser.add(path); + obj.set('dirty', true); + obj.fire('erasing:end', { + path: path + }); + if (context) { + (obj.group ? context.subTargets : context.targets).push(obj); + //context.paths.set(obj, path); + } + return path; }); - if (obj.group && Array.isArray(_this.__subTargets)) { - _this.__subTargets.push(obj); - } - }); }, /** @@ -673,22 +681,26 @@ * * @param {fabric.Canvas} source * @param {fabric.Canvas} path - * @returns {Object} canvas drawables that were erased by the path + * @param {Object} [context] context to assign erased objects to + * @returns {Promise} eraser paths */ - applyEraserToCanvas: function (path) { + applyEraserToCanvas: function (path, context) { var canvas = this.canvas; - var drawables = {}; - [ + return Promise.all([ 'backgroundImage', 'overlayImage', - ].forEach(function (prop) { + ].map(function (prop) { var drawable = canvas[prop]; - if (drawable && drawable.erasable) { - this._addPathToObjectEraser(drawable, path); - drawables[prop] = drawable; - } - }, this); - return drawables; + return drawable && drawable.erasable && + this._addPathToObjectEraser(drawable, path) + .then(function (path) { + if (context) { + context.drawables[prop] = drawable; + //context.paths.set(drawable, path); + } + return path; + }); + }, this)); }, /** @@ -727,30 +739,31 @@ canvas.fire('before:path:created', { path: path }); // finalize erasing - var drawables = this.applyEraserToCanvas(path); var _this = this; - this.__subTargets = []; - var targets = []; - canvas.forEachObject(function (obj) { - if (obj.erasable && obj.intersectsWithObject(path, true, true)) { - _this._addPathToObjectEraser(obj, path); - targets.push(obj); - } - }); - // fire erasing:end - canvas.fire('erasing:end', { - path: path, - targets: targets, - subTargets: this.__subTargets, - drawables: drawables + var context = { + targets: [], + subTargets: [], + //paths: new Map(), + drawables: {} + }; + var tasks = canvas._objects.map(function (obj) { + return obj.erasable && obj.intersectsWithObject(path, true, true) && + _this._addPathToObjectEraser(obj, path, context); }); - delete this.__subTargets; - - canvas.requestRenderAll(); - this._resetShadow(); - - // fire event 'path' created - canvas.fire('path:created', { path: path }); + tasks.push(_this.applyEraserToCanvas(path, context)); + return Promise.all(tasks) + .then(function () { + // fire erasing:end + canvas.fire('erasing:end', Object.assign(context, { + path: path + })); + + canvas.requestRenderAll(); + _this._resetShadow(); + + // fire event 'path' created + canvas.fire('path:created', { path: path }); + }); } } ); diff --git a/src/mixins/shared_methods.mixin.js b/src/mixins/shared_methods.mixin.js index 365cad0c256..312f858c544 100644 --- a/src/mixins/shared_methods.mixin.js +++ b/src/mixins/shared_methods.mixin.js @@ -13,32 +13,6 @@ fabric.CommonMethods = { } }, - /** - * @private - * @param {Object} [filler] Options object - * @param {String} [property] property to set the Gradient to - */ - _initGradient: function(filler, property) { - if (filler && filler.colorStops && !(filler instanceof fabric.Gradient)) { - this.set(property, new fabric.Gradient(filler)); - } - }, - - /** - * @private - * @param {Object} [filler] Options object - * @param {String} [property] property to set the Pattern to - * @param {Function} [callback] callback to invoke after pattern load - */ - _initPattern: function(filler, property, callback) { - if (filler && filler.source && !(filler instanceof fabric.Pattern)) { - this.set(property, new fabric.Pattern(filler, callback)); - } - else { - callback && callback(); - } - }, - /** * @private */ diff --git a/src/pattern.class.js b/src/pattern.class.js index 1c5a23014cf..4a6f6aa94e4 100644 --- a/src/pattern.class.js +++ b/src/pattern.class.js @@ -51,30 +51,18 @@ */ patternTransform: null, + type: 'pattern', + /** * Constructor * @param {Object} [options] Options object - * @param {Function} [callback] function to invoke after callback init. + * @param {option.source} [source] the pattern source, eventually empty or a drawable * @return {fabric.Pattern} thisArg */ - initialize: function(options, callback) { + initialize: function(options) { options || (options = { }); - this.id = fabric.Object.__uid++; this.setOptions(options); - if (!options.source || (options.source && typeof options.source !== 'string')) { - callback && callback(this); - return; - } - else { - // img src string - var _this = this; - this.source = fabric.util.createImage(); - fabric.util.loadImage(options.source, function(img, isError) { - _this.source = img; - callback && callback(_this, isError); - }, null, this.crossOrigin); - } }, /** @@ -186,4 +174,13 @@ return ctx.createPattern(source, this.repeat); } }); + + fabric.Pattern.fromObject = function(object) { + var patternOptions = Object.assign({}, object); + return fabric.util.loadImage(object.source, { crossOrigin: object.crossOrigin }) + .then(function(img) { + patternOptions.source = img; + return new fabric.Pattern(patternOptions); + }); + }; })(); diff --git a/src/shapes/active_selection.class.js b/src/shapes/active_selection.class.js index 93ee250c1a5..36b17c6b280 100644 --- a/src/shapes/active_selection.class.js +++ b/src/shapes/active_selection.class.js @@ -143,12 +143,14 @@ * @static * @memberOf fabric.ActiveSelection * @param {Object} object Object to create a group from - * @param {Function} [callback] Callback to invoke when an ActiveSelection instance is created + * @returns {Promise} */ - fabric.ActiveSelection.fromObject = function(object, callback) { - fabric.util.enlivenObjects(object.objects, function(enlivenedObjects) { - delete object.objects; - callback && callback(new fabric.ActiveSelection(enlivenedObjects, object, true)); + fabric.ActiveSelection.fromObject = function(object) { + var objects = object.objects, + options = fabric.util.object.clone(object, true); + delete options.objects; + return fabric.util.enlivenObjects(objects).then(function(enlivenedObjects) { + return new fabric.ActiveSelection(enlivenedObjects, object, true); }); }; diff --git a/src/shapes/circle.class.js b/src/shapes/circle.class.js index f8ff9791fdf..12c5449b1d3 100644 --- a/src/shapes/circle.class.js +++ b/src/shapes/circle.class.js @@ -200,11 +200,10 @@ * @static * @memberOf fabric.Circle * @param {Object} object Object to create an instance from - * @param {function} [callback] invoked with new instance as first argument - * @return {void} + * @returns {Promise} */ - fabric.Circle.fromObject = function(object, callback) { - fabric.Object._fromObject('Circle', object, callback); + fabric.Circle.fromObject = function(object) { + return fabric.Object._fromObject(fabric.Circle, object); }; })(typeof exports !== 'undefined' ? exports : this); diff --git a/src/shapes/ellipse.class.js b/src/shapes/ellipse.class.js index d4b2e48bc67..138f52e3547 100644 --- a/src/shapes/ellipse.class.js +++ b/src/shapes/ellipse.class.js @@ -171,11 +171,10 @@ * @static * @memberOf fabric.Ellipse * @param {Object} object Object to create an instance from - * @param {function} [callback] invoked with new instance as first argument - * @return {void} + * @returns {Promise} */ - fabric.Ellipse.fromObject = function(object, callback) { - fabric.Object._fromObject('Ellipse', object, callback); + fabric.Ellipse.fromObject = function(object) { + return fabric.Object._fromObject(fabric.Ellipse, object); }; })(typeof exports !== 'undefined' ? exports : this); diff --git a/src/shapes/group.class.js b/src/shapes/group.class.js index 5fa794f8ece..1bf2f6d3a6d 100644 --- a/src/shapes/group.class.js +++ b/src/shapes/group.class.js @@ -559,26 +559,15 @@ * @static * @memberOf fabric.Group * @param {Object} object Object to create a group from - * @param {Function} [callback] Callback to invoke when an group instance is created + * @returns {Promise} */ - fabric.Group.fromObject = function(object, callback) { - var objects = object.objects, + fabric.Group.fromObject = function(object) { + var objects = object.objects || [], options = fabric.util.object.clone(object, true); delete options.objects; - if (typeof objects === 'string') { - // it has to be an url or something went wrong. - fabric.loadSVGFromURL(objects, function (elements) { - var group = fabric.util.groupSVGElements(elements, object, objects); - group.set(options); - callback && callback(group); - }); - return; - } - fabric.util.enlivenObjects(objects, function (enlivenedObjects) { - var options = fabric.util.object.clone(object, true); - delete options.objects; - fabric.util.enlivenObjectEnlivables(object, options, function () { - callback && callback(new fabric.Group(enlivenedObjects, options, true)); + return fabric.util.enlivenObjects(objects).then(function (enlivenedObjects) { + return fabric.util.enlivenObjectEnlivables(options).then(function(enlivedProps) { + return new fabric.Group(enlivenedObjects, Object.assign(options, enlivedProps), true); }); }); }; diff --git a/src/shapes/image.class.js b/src/shapes/image.class.js index 701fd883fca..7a5964012b5 100644 --- a/src/shapes/image.class.js +++ b/src/shapes/image.class.js @@ -142,7 +142,6 @@ * Please check video element events for seeking. * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | String} element Image element * @param {Object} [options] Options object - * @param {function} [callback] callback function to call after eventual filters applied. * @return {fabric.Image} thisArg */ initialize: function(element, options) { @@ -370,20 +369,18 @@ /** * Sets source of an image * @param {String} src Source string (URL) - * @param {Function} [callback] Callback is invoked when image has been loaded (and all filters have been applied) * @param {Object} [options] Options object * @param {String} [options.crossOrigin] crossOrigin value (one of "", "anonymous", "use-credentials") * @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes - * @return {fabric.Image} thisArg - * @chainable - */ - setSrc: function(src, callback, options) { - fabric.util.loadImage(src, function(img, isError) { - this.setElement(img, options); - this._setWidthHeight(); - callback && callback(this, isError); - }, this, options && options.crossOrigin); - return this; + * @return {Promise} thisArg + */ + setSrc: function(src, options) { + var _this = this; + return fabric.util.loadImage(src, options).then(function(img) { + _this.setElement(img, options); + _this._setWidthHeight(); + return _this; + }); }, /** @@ -587,22 +584,6 @@ this._setWidthHeight(options); }, - /** - * @private - * @param {Array} filters to be initialized - * @param {Function} callback Callback to invoke when all fabric.Image.filters instances are created - */ - _initFilters: function(filters, callback) { - if (filters && filters.length) { - fabric.util.enlivenObjects(filters, function(enlivenedObjects) { - callback && callback(enlivenedObjects); - }, 'fabric.Image.filters'); - } - else { - callback && callback(); - } - }, - /** * @private * Set the width and the height of the image object, using the element or the @@ -700,39 +681,39 @@ * Creates an instance of fabric.Image from its object representation * @static * @param {Object} object Object to create an instance from - * @param {Function} callback Callback to invoke when an image instance is created + * @returns {Promise} */ - fabric.Image.fromObject = function(_object, callback) { - var object = fabric.util.object.clone(_object); - fabric.util.loadImage(object.src, function(img, isError) { - if (isError) { - callback && callback(null, true); - return; - } - fabric.Image.prototype._initFilters.call(object, object.filters, function(filters) { - object.filters = filters || []; - fabric.Image.prototype._initFilters.call(object, [object.resizeFilter], function(resizeFilters) { - object.resizeFilter = resizeFilters[0]; - fabric.util.enlivenObjectEnlivables(object, object, function () { - var image = new fabric.Image(img, object); - callback(image, false); - }); - }); + fabric.Image.fromObject = function(_object) { + var object = fabric.util.object.clone(_object), + filters = object.filters, + resizeFilter = object.resizeFilter; + // the generic enliving will fail on filters for now + delete object.resizeFilter; + delete object.filters; + return Promise.all([ + fabric.util.loadImage(object.src, { crossOrigin: _object.crossOrigin }), + filters && fabric.util.enlivenObjects(filters, 'fabric.Image.filters'), + resizeFilter && fabric.util.enlivenObjects([resizeFilter], 'fabric.Image.filters'), + fabric.util.enlivenObjectEnlivables(object), + ]) + .then(function(imgAndFilters) { + object.filters = imgAndFilters[1] || []; + object.resizeFilter = imgAndFilters[2] && imgAndFilters[2][0]; + return new fabric.Image(imgAndFilters[0], Object.assign(object, imgAndFilters[3])); }); - }, null, object.crossOrigin); }; /** * Creates an instance of fabric.Image from an URL string * @static * @param {String} url URL to create an image from - * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument). Second argument is a boolean indicating if an error occurred or not. * @param {Object} [imgOptions] Options object + * @returns {Promise} */ - fabric.Image.fromURL = function(url, callback, imgOptions) { - fabric.util.loadImage(url, function(img, isError) { - callback && callback(new fabric.Image(img, imgOptions), isError); - }, null, imgOptions && imgOptions.crossOrigin); + fabric.Image.fromURL = function(url, imgOptions) { + return fabric.util.loadImage(url, imgOptions || {}).then(function(img) { + return new fabric.Image(img, imgOptions); + }); }; /* _FROM_SVG_START_ */ @@ -756,8 +737,10 @@ */ fabric.Image.fromElement = function(element, callback, options) { var parsedAttributes = fabric.parseAttributes(element, fabric.Image.ATTRIBUTE_NAMES); - fabric.Image.fromURL(parsedAttributes['xlink:href'], callback, - extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes)); + fabric.Image.fromURL(parsedAttributes['xlink:href'], Object.assign({ }, options || { }, parsedAttributes)) + .then(function(fabricImage) { + callback(fabricImage); + }); }; /* _FROM_SVG_END_ */ diff --git a/src/shapes/itext.class.js b/src/shapes/itext.class.js index e7623637e80..b4e66b3ad63 100644 --- a/src/shapes/itext.class.js +++ b/src/shapes/itext.class.js @@ -1,14 +1,4 @@ (function() { - - function parseDecoration(object) { - if (object.textDecoration) { - object.textDecoration.indexOf('underline') > -1 && (object.underline = true); - object.textDecoration.indexOf('line-through') > -1 && (object.linethrough = true); - object.textDecoration.indexOf('overline') > -1 && (object.overline = true); - delete object.textDecoration; - } - } - /** * IText class (introduced in v1.4) Events are also fired with "text:" * prefix when observing canvas. @@ -507,17 +497,9 @@ * @static * @memberOf fabric.IText * @param {Object} object Object to create an instance from - * @param {function} [callback] invoked with new instance as argument + * @returns {Promise} */ - fabric.IText.fromObject = function(object, callback) { - parseDecoration(object); - if (object.styles) { - for (var i in object.styles) { - for (var j in object.styles[i]) { - parseDecoration(object.styles[i][j]); - } - } - } - fabric.Object._fromObject('IText', object, callback, 'text'); + fabric.IText.fromObject = function(object) { + return fabric.Object._fromObject(fabric.IText, object, 'text'); }; })(); diff --git a/src/shapes/line.class.js b/src/shapes/line.class.js index 005aa406357..c64beef282e 100644 --- a/src/shapes/line.class.js +++ b/src/shapes/line.class.js @@ -284,16 +284,15 @@ * @static * @memberOf fabric.Line * @param {Object} object Object to create an instance from - * @param {function} [callback] invoked with new instance as first argument + * @returns {Promise} */ - fabric.Line.fromObject = function(object, callback) { - function _callback(instance) { - delete instance.points; - callback && callback(instance); - }; + fabric.Line.fromObject = function(object) { var options = clone(object, true); options.points = [object.x1, object.y1, object.x2, object.y2]; - fabric.Object._fromObject('Line', options, _callback, 'points'); + return fabric.Object._fromObject(fabric.Line, options, 'points').then(function(fabricLine) { + delete fabricLine.points; + return fabricLine; + }); }; /** diff --git a/src/shapes/object.class.js b/src/shapes/object.class.js index d284ad2d6e7..1001b897255 100644 --- a/src/shapes/object.class.js +++ b/src/shapes/object.class.js @@ -815,10 +815,6 @@ */ setOptions: function(options) { this._setOptions(options); - this._initGradient(options.fill, 'fill'); - this._initGradient(options.stroke, 'stroke'); - this._initPattern(options.fill, 'fill'); - this._initPattern(options.stroke, 'stroke'); }, /** @@ -1657,18 +1653,13 @@ }, /** - * Clones an instance, using a callback method will work for every object. - * @param {Function} callback Callback is invoked with a clone as a first argument + * Clones an instance. * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @returns {Promise} */ - clone: function(callback, propertiesToInclude) { + clone: function(propertiesToInclude) { var objectForm = this.toObject(propertiesToInclude); - if (this.constructor.fromObject) { - this.constructor.fromObject(objectForm, callback); - } - else { - fabric.Object._fromObject('Object', objectForm, callback); - } + return this.constructor.fromObject(objectForm); }, /** @@ -1678,9 +1669,6 @@ * and format option. toCanvasElement is faster and produce no loss of quality. * If you need to get a real Jpeg or Png from an object, using toDataURL is the right way to do it. * toCanvasElement and then toBlob from the obtained canvas is also a good option. - * This method is sync now, but still support the callback because we did not want to break. - * When fabricJS 5.0 will be planned, this will probably be changed to not have a callback. - * @param {Function} callback callback, invoked with an instance as a first argument * @param {Object} [options] for clone as image, passed to toDataURL * @param {Number} [options.multiplier=1] Multiplier to scale by * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14 @@ -1690,14 +1678,11 @@ * @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 1.6.4 * @param {Boolean} [options.withoutTransform] Remove current object transform ( no scale , no angle, no flip, no skew ). Introduced in 2.3.4 * @param {Boolean} [options.withoutShadow] Remove current object shadow. Introduced in 2.4.2 - * @return {fabric.Object} thisArg + * @return {fabric.Image} Object cloned as image. */ - cloneAsImage: function(callback, options) { + cloneAsImage: function(options) { var canvasEl = this.toCanvasElement(options); - if (callback) { - callback(new fabric.Image(canvasEl)); - } - return this; + return new fabric.Image(canvasEl); }, /** @@ -1980,25 +1965,19 @@ * @constant * @type string[] */ - fabric.Object.ENLIVEN_PROPS = ['clipPath']; - fabric.Object._fromObject = function(className, object, callback, extraParam) { - var klass = fabric[className]; - object = clone(object, true); - fabric.util.enlivenPatterns([object.fill, object.stroke], function(patterns) { - if (typeof patterns[0] !== 'undefined') { - object.fill = patterns[0]; - } - if (typeof patterns[1] !== 'undefined') { - object.stroke = patterns[1]; - } - fabric.util.enlivenObjectEnlivables(object, object, function () { - var instance = extraParam ? new klass(object[extraParam], object) : new klass(object); - callback && callback(instance); - }); + fabric.Object._fromObject = function(klass, object, extraParam) { + var serializedObject = clone(object, true); + return fabric.util.enlivenObjectEnlivables(serializedObject).then(function(enlivedMap) { + var newObject = Object.assign(object, enlivedMap); + return extraParam ? new klass(object[extraParam], newObject) : new klass(newObject); }); }; + fabric.Object.fromObject = function(object) { + return fabric.Object._fromObject(fabric.Object, object); + }; + /** * Unique id used internally when creating SVG elements * @static diff --git a/src/shapes/path.class.js b/src/shapes/path.class.js index 5558c8e6244..f4b6898b98e 100644 --- a/src/shapes/path.class.js +++ b/src/shapes/path.class.js @@ -335,20 +335,10 @@ * @static * @memberOf fabric.Path * @param {Object} object - * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created + * @returns {Promise} */ - fabric.Path.fromObject = function(object, callback) { - if (typeof object.sourcePath === 'string') { - var pathUrl = object.sourcePath; - fabric.loadSVGFromURL(pathUrl, function (elements) { - var path = elements[0]; - path.setOptions(object); - callback && callback(path); - }); - } - else { - fabric.Object._fromObject('Path', object, callback, 'path'); - } + fabric.Path.fromObject = function(object) { + return fabric.Object._fromObject(fabric.Path, object, 'path'); }; /* _FROM_SVG_START_ */ diff --git a/src/shapes/polygon.class.js b/src/shapes/polygon.class.js index f5159b489cd..dc127b3aa06 100644 --- a/src/shapes/polygon.class.js +++ b/src/shapes/polygon.class.js @@ -71,11 +71,10 @@ * @static * @memberOf fabric.Polygon * @param {Object} object Object to create an instance from - * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created - * @return {void} + * @returns {Promise} */ - fabric.Polygon.fromObject = function(object, callback) { - fabric.Object._fromObject('Polygon', object, callback, 'points'); + fabric.Polygon.fromObject = function(object) { + return fabric.Object._fromObject(fabric.Polygon, object, 'points'); }; })(typeof exports !== 'undefined' ? exports : this); diff --git a/src/shapes/polyline.class.js b/src/shapes/polyline.class.js index 42e0f20a0bb..5d0b7b85b36 100644 --- a/src/shapes/polyline.class.js +++ b/src/shapes/polyline.class.js @@ -259,10 +259,10 @@ * @static * @memberOf fabric.Polyline * @param {Object} object Object to create an instance from - * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created + * @returns {Promise} */ - fabric.Polyline.fromObject = function(object, callback) { - return fabric.Object._fromObject('Polyline', object, callback, 'points'); + fabric.Polyline.fromObject = function(object) { + return fabric.Object._fromObject(fabric.Polyline, object, 'points'); }; })(typeof exports !== 'undefined' ? exports : this); diff --git a/src/shapes/rect.class.js b/src/shapes/rect.class.js index 4d6a2e4dda3..4b3d4166e12 100644 --- a/src/shapes/rect.class.js +++ b/src/shapes/rect.class.js @@ -178,10 +178,10 @@ * @static * @memberOf fabric.Rect * @param {Object} object Object to create an instance from - * @param {Function} [callback] Callback to invoke when an fabric.Rect instance is created + * @returns {Promise} */ - fabric.Rect.fromObject = function(object, callback) { - return fabric.Object._fromObject('Rect', object, callback); + fabric.Rect.fromObject = function(object) { + return fabric.Object._fromObject(fabric.Rect, object); }; })(typeof exports !== 'undefined' ? exports : this); diff --git a/src/shapes/text.class.js b/src/shapes/text.class.js index 71fc11573e6..2bb6bc2e5f7 100644 --- a/src/shapes/text.class.js +++ b/src/shapes/text.class.js @@ -1699,22 +1699,10 @@ * @static * @memberOf fabric.Text * @param {Object} object plain js Object to create an instance from - * @param {Function} [callback] Callback to invoke when an fabric.Text instance is created + * @returns {Promise} */ - fabric.Text.fromObject = function(object, callback) { - var objectCopy = clone(object), path = object.path; - delete objectCopy.path; - return fabric.Object._fromObject('Text', objectCopy, function(textInstance) { - if (path) { - fabric.Object._fromObject('Path', path, function(pathInstance) { - textInstance.set('path', pathInstance); - callback(textInstance); - }, 'path'); - } - else { - callback(textInstance); - } - }, 'text'); + fabric.Text.fromObject = function(object) { + return fabric.Object._fromObject(fabric.Text, object, 'text'); }; fabric.Text.genericFonts = ['sans-serif', 'serif', 'cursive', 'fantasy', 'monospace']; diff --git a/src/shapes/textbox.class.js b/src/shapes/textbox.class.js index da7355632e6..06cf7982cfc 100644 --- a/src/shapes/textbox.class.js +++ b/src/shapes/textbox.class.js @@ -450,9 +450,9 @@ * @static * @memberOf fabric.Textbox * @param {Object} object Object to create an instance from - * @param {Function} [callback] Callback to invoke when an fabric.Textbox instance is created + * @returns {Promise} */ - fabric.Textbox.fromObject = function(object, callback) { - return fabric.Object._fromObject('Textbox', object, callback, 'text'); + fabric.Textbox.fromObject = function(object) { + return fabric.Object._fromObject(fabric.Textbox, object, 'text'); }; })(typeof exports !== 'undefined' ? exports : this); diff --git a/src/shapes/triangle.class.js b/src/shapes/triangle.class.js index 144edfc0420..db5ebc56a81 100644 --- a/src/shapes/triangle.class.js +++ b/src/shapes/triangle.class.js @@ -84,10 +84,10 @@ * @static * @memberOf fabric.Triangle * @param {Object} object Object to create an instance from - * @param {function} [callback] invoked with new instance as first argument + * @returns {Promise} */ - fabric.Triangle.fromObject = function(object, callback) { - return fabric.Object._fromObject('Triangle', object, callback); + fabric.Triangle.fromObject = function(object) { + return fabric.Object._fromObject(fabric.Triangle, object); }; })(typeof exports !== 'undefined' ? exports : this); diff --git a/src/static_canvas.class.js b/src/static_canvas.class.js index 67f5fdd9da6..9e46d6d1fbb 100644 --- a/src/static_canvas.class.js +++ b/src/static_canvas.class.js @@ -49,7 +49,6 @@ /** * Background color of canvas instance. - * Should be set via {@link fabric.StaticCanvas#setBackgroundColor}. * @type {(String|fabric.Pattern)} * @default */ @@ -67,7 +66,6 @@ /** * Overlay color of canvas instance. - * Should be set via {@link fabric.StaticCanvas#setOverlayColor} * @since 1.3.9 * @type {(String|fabric.Pattern)} * @default @@ -204,7 +202,6 @@ * @param {Object} [options] Options object */ _initStatic: function(el, options) { - var cb = this.requestRenderAllBound; this._objects = []; this._createLowerCanvas(el); this._initOptions(options); @@ -212,19 +209,6 @@ if (!this.interactive) { this._initRetinaScaling(); } - - if (options.overlayImage) { - this.setOverlayImage(options.overlayImage, cb); - } - if (options.backgroundImage) { - this.setBackgroundImage(options.backgroundImage, cb); - } - if (options.backgroundColor) { - this.setBackgroundColor(options.backgroundColor, cb); - } - if (options.overlayColor) { - this.setOverlayColor(options.overlayColor, cb); - } this.calcOffset(); }, @@ -275,202 +259,6 @@ return this; }, - /** - * Sets {@link fabric.StaticCanvas#overlayImage|overlay image} for this canvas - * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set overlay to - * @param {Function} callback callback to invoke when image is loaded and set as an overlay - * @param {Object} [options] Optional options to set for the {@link fabric.Image|overlay image}. - * @return {fabric.Canvas} thisArg - * @chainable - * @see {@link http://jsfiddle.net/fabricjs/MnzHT/|jsFiddle demo} - * @example Normal overlayImage with left/top = 0 - * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), { - * // Needed to position overlayImage at 0/0 - * originX: 'left', - * originY: 'top' - * }); - * @example overlayImage with different properties - * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), { - * opacity: 0.5, - * angle: 45, - * left: 400, - * top: 400, - * originX: 'left', - * originY: 'top' - * }); - * @example Stretched overlayImage #1 - width/height correspond to canvas width/height - * fabric.Image.fromURL('http://fabricjs.com/assets/jail_cell_bars.png', function(img, isError) { - * img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'}); - * canvas.setOverlayImage(img, canvas.renderAll.bind(canvas)); - * }); - * @example Stretched overlayImage #2 - width/height correspond to canvas width/height - * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), { - * width: canvas.width, - * height: canvas.height, - * // Needed to position overlayImage at 0/0 - * originX: 'left', - * originY: 'top' - * }); - * @example overlayImage loaded from cross-origin - * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), { - * opacity: 0.5, - * angle: 45, - * left: 400, - * top: 400, - * originX: 'left', - * originY: 'top', - * crossOrigin: 'anonymous' - * }); - */ - setOverlayImage: function (image, callback, options) { - return this.__setBgOverlayImage('overlayImage', image, callback, options); - }, - - /** - * Sets {@link fabric.StaticCanvas#backgroundImage|background image} for this canvas - * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set background to - * @param {Function} callback Callback to invoke when image is loaded and set as background - * @param {Object} [options] Optional options to set for the {@link fabric.Image|background image}. - * @return {fabric.Canvas} thisArg - * @chainable - * @see {@link http://jsfiddle.net/djnr8o7a/28/|jsFiddle demo} - * @example Normal backgroundImage with left/top = 0 - * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), { - * // Needed to position backgroundImage at 0/0 - * originX: 'left', - * originY: 'top' - * }); - * @example backgroundImage with different properties - * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), { - * opacity: 0.5, - * angle: 45, - * left: 400, - * top: 400, - * originX: 'left', - * originY: 'top' - * }); - * @example Stretched backgroundImage #1 - width/height correspond to canvas width/height - * fabric.Image.fromURL('http://fabricjs.com/assets/honey_im_subtle.png', function(img, isError) { - * img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'}); - * canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas)); - * }); - * @example Stretched backgroundImage #2 - width/height correspond to canvas width/height - * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), { - * width: canvas.width, - * height: canvas.height, - * // Needed to position backgroundImage at 0/0 - * originX: 'left', - * originY: 'top' - * }); - * @example backgroundImage loaded from cross-origin - * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), { - * opacity: 0.5, - * angle: 45, - * left: 400, - * top: 400, - * originX: 'left', - * originY: 'top', - * crossOrigin: 'anonymous' - * }); - */ - // TODO: fix stretched examples - setBackgroundImage: function (image, callback, options) { - return this.__setBgOverlayImage('backgroundImage', image, callback, options); - }, - - /** - * Sets {@link fabric.StaticCanvas#overlayColor|foreground color} for this canvas - * @param {(String|fabric.Pattern)} overlayColor Color or pattern to set foreground color to - * @param {Function} callback Callback to invoke when foreground color is set - * @return {fabric.Canvas} thisArg - * @chainable - * @see {@link http://jsfiddle.net/fabricjs/pB55h/|jsFiddle demo} - * @example Normal overlayColor - color value - * canvas.setOverlayColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas)); - * @example fabric.Pattern used as overlayColor - * canvas.setOverlayColor({ - * source: 'http://fabricjs.com/assets/escheresque_ste.png' - * }, canvas.renderAll.bind(canvas)); - * @example fabric.Pattern used as overlayColor with repeat and offset - * canvas.setOverlayColor({ - * source: 'http://fabricjs.com/assets/escheresque_ste.png', - * repeat: 'repeat', - * offsetX: 200, - * offsetY: 100 - * }, canvas.renderAll.bind(canvas)); - */ - setOverlayColor: function(overlayColor, callback) { - return this.__setBgOverlayColor('overlayColor', overlayColor, callback); - }, - - /** - * Sets {@link fabric.StaticCanvas#backgroundColor|background color} for this canvas - * @param {(String|fabric.Pattern)} backgroundColor Color or pattern to set background color to - * @param {Function} callback Callback to invoke when background color is set - * @return {fabric.Canvas} thisArg - * @chainable - * @see {@link http://jsfiddle.net/fabricjs/hXzvk/|jsFiddle demo} - * @example Normal backgroundColor - color value - * canvas.setBackgroundColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas)); - * @example fabric.Pattern used as backgroundColor - * canvas.setBackgroundColor({ - * source: 'http://fabricjs.com/assets/escheresque_ste.png' - * }, canvas.renderAll.bind(canvas)); - * @example fabric.Pattern used as backgroundColor with repeat and offset - * canvas.setBackgroundColor({ - * source: 'http://fabricjs.com/assets/escheresque_ste.png', - * repeat: 'repeat', - * offsetX: 200, - * offsetY: 100 - * }, canvas.renderAll.bind(canvas)); - */ - setBackgroundColor: function(backgroundColor, callback) { - return this.__setBgOverlayColor('backgroundColor', backgroundColor, callback); - }, - - /** - * @private - * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundImage|backgroundImage} - * or {@link fabric.StaticCanvas#overlayImage|overlayImage}) - * @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. The first argument is the created image, the second argument is a flag indicating whether an error occurred or not. - * @param {Object} [options] Optional options to set for the {@link fabric.Image|image}. - */ - __setBgOverlayImage: function(property, image, callback, options) { - if (typeof image === 'string') { - fabric.util.loadImage(image, function(img, isError) { - if (img) { - var instance = new fabric.Image(img, options); - this[property] = instance; - instance.canvas = this; - } - callback && callback(img, isError); - }, this, options && options.crossOrigin); - } - else { - options && image.setOptions(options); - this[property] = image; - image && (image.canvas = this); - callback && callback(image, false); - } - - return this; - }, - - /** - * @private - * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundColor|backgroundColor} - * or {@link fabric.StaticCanvas#overlayColor|overlayColor}) - * @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) { - this[property] = color; - this._initGradient(color, property); - this._initPattern(color, property, callback); - return this; - }, - /** * @private */ diff --git a/src/util/dom_request.js b/src/util/dom_request.js index 13026af6ea7..03a82ab7d42 100644 --- a/src/util/dom_request.js +++ b/src/util/dom_request.js @@ -9,6 +9,7 @@ /** * Cross-browser abstraction for sending XMLHttpRequest * @memberOf fabric.util + * @deprecated this has to go away, we can use a modern browser method to do the same. * @param {String} url URL to send XMLHttpRequest to * @param {Object} [options] Options object * @param {String} [options.method="GET"] diff --git a/src/util/lang_object.js b/src/util/lang_object.js index adbed06be89..5b2820fd1ba 100644 --- a/src/util/lang_object.js +++ b/src/util/lang_object.js @@ -54,7 +54,7 @@ /** * Creates an empty object and copies all enumerable properties of another object to it - * This method is mostly for internal use, and not intended for duplicating shapes in canvas. + * This method is mostly for internal use, and not intended for duplicating shapes in canvas. * @memberOf fabric.util.object * @param {Object} object Object to clone * @param {Boolean} [deep] Whether to clone nested objects @@ -63,7 +63,7 @@ //TODO: this function return an empty object if you try to clone null function clone(object, deep) { - return extend({ }, object, deep); + return deep ? extend({ }, object, deep) : Object.assign({}, object); } /** @namespace fabric.util.object */ diff --git a/src/util/misc.js b/src/util/misc.js index 9e3ba19dac9..5362d86b359 100644 --- a/src/util/misc.js +++ b/src/util/misc.js @@ -457,185 +457,84 @@ }, /** - * Loads image element from given url and passes it to a callback + * Loads image element from given url and resolve it, or catch. * @memberOf fabric.util * @param {String} url URL representing an image - * @param {Function} callback Callback; invoked with loaded image - * @param {*} [context] Context to invoke callback in - * @param {Object} [crossOrigin] crossOrigin value to set image element to + * @param {Object} [options] image loading options + * @param {string} [options.crossOrigin] cors value for the image loading, default to anonymous + * @param {Promise} img the loaded image. */ - loadImage: function(url, callback, context, crossOrigin) { - if (!url) { - callback && callback.call(context, url); - return; - } - - var img = fabric.util.createImage(); - - /** @ignore */ - var onLoadCallback = function () { - callback && callback.call(context, img, false); - img = img.onload = img.onerror = null; - }; - - img.onload = onLoadCallback; - /** @ignore */ - img.onerror = function() { - fabric.log('Error loading ' + img.src); - callback && callback.call(context, null, true); - img = img.onload = img.onerror = null; - }; - - // data-urls appear to be buggy with crossOrigin - // https://github.com/kangax/fabric.js/commit/d0abb90f1cd5c5ef9d2a94d3fb21a22330da3e0a#commitcomment-4513767 - // see https://code.google.com/p/chromium/issues/detail?id=315152 - // https://bugzilla.mozilla.org/show_bug.cgi?id=935069 - // crossOrigin null is the same as not set. - if (url.indexOf('data') !== 0 && - crossOrigin !== undefined && - crossOrigin !== null) { - img.crossOrigin = crossOrigin; - } - - // IE10 / IE11-Fix: SVG contents from data: URI - // will only be available if the IMG is present - // in the DOM (and visible) - if (url.substring(0,14) === 'data:image/svg') { - img.onload = null; - fabric.util.loadImageInDom(img, onLoadCallback); - } - - img.src = url; - }, - - /** - * Attaches SVG image with data: URL to the dom - * @memberOf fabric.util - * @param {Object} img Image object with data:image/svg src - * @param {Function} callback Callback; invoked with loaded image - * @return {Object} DOM element (div containing the SVG image) - */ - loadImageInDom: function(img, onLoadCallback) { - var div = fabric.document.createElement('div'); - div.style.width = div.style.height = '1px'; - div.style.left = div.style.top = '-100%'; - div.style.position = 'absolute'; - div.appendChild(img); - fabric.document.querySelector('body').appendChild(div); - /** - * Wrap in function to: - * 1. Call existing callback - * 2. Cleanup DOM - */ - img.onload = function () { - onLoadCallback(); - div.parentNode.removeChild(div); - div = null; - }; + loadImage: function(url, options) { + return new Promise(function(resolve, reject) { + var img = fabric.util.createImage(); + var done = function() { + img.onload = img.onerror = null; + resolve(img); + }; + if (!url) { + done(); + } + else { + img.onload = done; + img.onerror = function () { + reject(new Error('Error loading ' + img.src)); + }; + options && options.crossOrigin && (img.crossOrigin = options.crossOrigin); + img.src = url; + } + }); }, /** * Creates corresponding fabric instances from their object representations * @static * @memberOf fabric.util - * @param {Array} objects Objects to enliven - * @param {Function} callback Callback to invoke when all objects are created + * @param {Object[]} objects Objects to enliven * @param {String} namespace Namespace to get klass "Class" object from * @param {Function} reviver Method for further parsing of object elements, * called after each fabric object created. */ - enlivenObjects: function(objects, callback, namespace, reviver) { - objects = objects || []; - - var enlivenedObjects = [], - numLoadedObjects = 0, - numTotalObjects = objects.length; - - function onLoaded() { - if (++numLoadedObjects === numTotalObjects) { - callback && callback(enlivenedObjects.filter(function(obj) { - // filter out undefined objects (objects that gave error) - return obj; - })); - } - } - - if (!numTotalObjects) { - callback && callback(enlivenedObjects); - return; - } - - objects.forEach(function (o, index) { - // if sparse array - if (!o || !o.type) { - onLoaded(); - return; - } - var klass = fabric.util.getKlass(o.type, namespace); - klass.fromObject(o, function (obj, error) { - error || (enlivenedObjects[index] = obj); - reviver && reviver(o, obj, error); - onLoaded(); + enlivenObjects: function(objects, namespace, reviver) { + return Promise.all(objects.map(function(obj) { + var klass = fabric.util.getKlass(obj.type, namespace); + return klass.fromObject(obj).then(function(fabricInstance) { + reviver && reviver(obj, fabricInstance); + return fabricInstance; }); - }); + })); }, /** * Creates corresponding fabric instances residing in an object, e.g. `clipPath` - * @see {@link fabric.Object.ENLIVEN_PROPS} - * @param {Object} object - * @param {Object} [context] assign enlived props to this object (pass null to skip this) - * @param {(objects:fabric.Object[]) => void} callback + * @param {Object} object with properties to enlive ( fill, stroke, clipPath, path ) + * @returns {Promise} the input object with enlived values */ - enlivenObjectEnlivables: function (object, context, callback) { - var enlivenProps = fabric.Object.ENLIVEN_PROPS.filter(function (key) { return !!object[key]; }); - fabric.util.enlivenObjects(enlivenProps.map(function (key) { return object[key]; }), function (enlivedProps) { - var objects = {}; - enlivenProps.forEach(function (key, index) { - objects[key] = enlivedProps[index]; - context && (context[key] = enlivedProps[index]); - }); - callback && callback(objects); - }); - }, - /** - * Create and wait for loading of patterns - * @static - * @memberOf fabric.util - * @param {Array} patterns Objects to enliven - * @param {Function} callback Callback to invoke when all objects are created - * called after each fabric object created. - */ - enlivenPatterns: function(patterns, callback) { - patterns = patterns || []; - - function onLoaded() { - if (++numLoadedPatterns === numPatterns) { - callback && callback(enlivenedPatterns); + enlivenObjectEnlivables: function (serializedObject) { + // enlive every possible property + var promises = Object.values(serializedObject).map(function(value) { + if (!value) { + return value; } - } - - var enlivenedPatterns = [], - numLoadedPatterns = 0, - numPatterns = patterns.length; - - if (!numPatterns) { - callback && callback(enlivenedPatterns); - return; - } - - patterns.forEach(function (p, index) { - if (p && p.source) { - new fabric.Pattern(p, function(pattern) { - enlivenedPatterns[index] = pattern; - onLoaded(); + if (value.colorStops) { + return new fabric.Gradient(value); + } + if (value.type) { + return fabric.util.enlivenObjects([value]).then(function (enlived) { + return enlived[0]; }); } - else { - enlivenedPatterns[index] = p; - onLoaded(); + if (value.source) { + return fabric.Pattern.fromObject(value); } + return value; + }); + var keys = Object.keys(serializedObject); + return Promise.all(promises).then(function(enlived) { + return enlived.reduce(function(acc, instance, index) { + acc[keys[index]] = instance; + return acc; + }, {}); }); }, diff --git a/test/unit/activeselection.js b/test/unit/activeselection.js index 89b5fc75bb6..b2f52f175a6 100644 --- a/test/unit/activeselection.js +++ b/test/unit/activeselection.js @@ -138,7 +138,7 @@ assert.ok(typeof fabric.ActiveSelection.fromObject === 'function'); var groupObject = group.toObject(); - fabric.ActiveSelection.fromObject(groupObject, function(newGroupFromObject) { + fabric.ActiveSelection.fromObject(groupObject).then(function(newGroupFromObject) { var objectFromOldGroup = group.toObject(); var objectFromNewGroup = newGroupFromObject.toObject(); diff --git a/test/unit/animation.js b/test/unit/animation.js index 2bfb2641e61..023398ca8ad 100644 --- a/test/unit/animation.js +++ b/test/unit/animation.js @@ -52,7 +52,7 @@ var options = { foo: 'bar' }; fabric.util.animate(options); assert.propEqual(options, { foo: 'bar' }, 'options were mutated'); - setTimeout(() => { + setTimeout(function() { assert.equal(fabric.runningAnimations.length, 0, 'animation should exist in registry'); done(); }, 1000); @@ -334,6 +334,7 @@ QUnit.test('animate with list of values', function(assert) { var done = assert.async(); + var run = false; fabric.util.animate({ startValue: [1, 2, 3], @@ -350,10 +351,12 @@ // Make sure mutations are not kept assert.ok(currentValue[0] <= 2, 'mutating callback values must not persist'); currentValue[0] = 200; + run = true; }, onComplete: function(endValue) { assert.equal(endValue.length, 3); assert.deepEqual(endValue, [2, 4, 6]); + assert.equal(run, true, 'something run'); done(); } }) diff --git a/test/unit/brushes.js b/test/unit/brushes.js index a018089ad69..4efd687e84d 100644 --- a/test/unit/brushes.js +++ b/test/unit/brushes.js @@ -31,7 +31,7 @@ assert.equal(newPoints[1], points[points.length-1], 'last point is always present'); assert.equal(newPoints.length, 2, 'All points removed except first and last'); }); - + [true, false].forEach(function(val) { QUnit.module('fabric.BaseBrush with canvas.enableRetinaScaling = ' + val, function(hooks) { hooks.beforeEach(function() { diff --git a/test/unit/canvas.js b/test/unit/canvas.js index ef8ad66bdb0..b618c32dbff 100644 --- a/test/unit/canvas.js +++ b/test/unit/canvas.js @@ -79,7 +79,7 @@ } var IMG_SRC = fabric.isLikelyNode ? ('file://' + __dirname + '/../fixtures/test_image.gif') : getAbsolutePath('../fixtures/test_image.gif'); - + var canvas = this.canvas = new fabric.Canvas(null, {enableRetinaScaling: false, width: 600, height: 600}); var upperCanvasEl = canvas.upperCanvasEl; var lowerCanvasEl = canvas.lowerCanvasEl; @@ -99,8 +99,8 @@ } /** - * - * @param {*} actual + * + * @param {*} actual * @param {*} [expected] */ QUnit.assert.sameImageObject = function (actual, expected) { @@ -1458,7 +1458,7 @@ QUnit.test('loadFromJSON with json string Canvas', function(assert) { var done = assert.async(); assert.ok(typeof canvas.loadFromJSON === 'function'); - canvas.loadFromJSON(PATH_JSON, function() { + canvas.loadFromJSON(PATH_JSON).then(function() { var obj = canvas.item(0); assert.ok(!canvas.isEmpty(), 'canvas is not empty'); @@ -1486,7 +1486,7 @@ QUnit.test('loadFromJSON with json object', function(assert) { var done = assert.async(); - canvas.loadFromJSON(JSON.parse(PATH_JSON), function(){ + canvas.loadFromJSON(JSON.parse(PATH_JSON)).then(function(){ var obj = canvas.item(0); assert.ok(!canvas.isEmpty(), 'canvas is not empty'); @@ -1514,7 +1514,7 @@ QUnit.test('loadFromJSON with json object without default values', function(assert) { var done = assert.async(); - canvas.loadFromJSON(JSON.parse(PATH_WITHOUT_DEFAULTS_JSON), function(){ + canvas.loadFromJSON(JSON.parse(PATH_WITHOUT_DEFAULTS_JSON)).then(function(){ var obj = canvas.item(0); assert.ok(!canvas.isEmpty(), 'canvas is not empty'); @@ -1550,9 +1550,8 @@ instance.customID = 'fabric_1'; } } - - canvas.loadFromJSON(JSON.parse(PATH_JSON), function(){ - var done = assert.async(); + var done = assert.async(); + canvas.loadFromJSON(JSON.parse(PATH_JSON), reviver).then(function(){ var obj = canvas.item(0); assert.ok(!canvas.isEmpty(), 'canvas is not empty'); @@ -1576,7 +1575,7 @@ assert.equal(obj.get('customID'), 'fabric_1'); assert.ok(obj.get('path').length > 0); done(); - }, reviver); + }); }); QUnit.test('loadFromJSON with no objects', function(assert) { @@ -1588,7 +1587,7 @@ var json = c1.toJSON(); var fired = false; - c2.loadFromJSON(json, function() { + c2.loadFromJSON(json).then(function() { fired = true; assert.ok(fired, 'Callback should be fired even if no objects'); @@ -1610,7 +1609,7 @@ delete json.objects; - c2.loadFromJSON(json, function() { + c2.loadFromJSON(json).then(function() { fired = true; assert.ok(fired, 'Callback should be fired even if no "objects" property exists'); @@ -1633,7 +1632,7 @@ var json = c1.toJSON(); var fired = false; - c2.loadFromJSON(json, function() { + c2.loadFromJSON(json).then(function() { fired = true; assert.ok(fired, 'Callback should be fired even if empty fabric.Group exists'); @@ -1656,7 +1655,7 @@ assert.equal(0, canvas.getObjects().length); - canvas.loadFromJSON(json, function() { + canvas.loadFromJSON(json).then(function() { assert.equal(3, canvas.getObjects().length); done(); @@ -1670,7 +1669,7 @@ serialized.preserveObjectStacking = true; assert.equal(canvas.controlsAboveOverlay, fabric.Canvas.prototype.controlsAboveOverlay); assert.equal(canvas.preserveObjectStacking, fabric.Canvas.prototype.preserveObjectStacking); - canvas.loadFromJSON(serialized, function() { + canvas.loadFromJSON(serialized).then(function() { assert.ok(!canvas.isEmpty(), 'canvas is not empty'); assert.equal(canvas.controlsAboveOverlay, true); assert.equal(canvas.preserveObjectStacking, true); @@ -1689,15 +1688,15 @@ serialized.preserveObjectStacking = true; assert.equal(canvas.controlsAboveOverlay, fabric.Canvas.prototype.controlsAboveOverlay); assert.equal(canvas.preserveObjectStacking, fabric.Canvas.prototype.preserveObjectStacking); - canvas.loadFromJSON(serialized, function() { + // before callback the properties are still false. + assert.equal(canvas.controlsAboveOverlay, false); + assert.equal(canvas.preserveObjectStacking, false); + canvas.loadFromJSON(serialized).then(function() { assert.ok(!canvas.isEmpty(), 'canvas is not empty'); assert.equal(canvas.controlsAboveOverlay, true); assert.equal(canvas.preserveObjectStacking, true); done(); }); - // before callback the properties are still false. - assert.equal(canvas.controlsAboveOverlay, false); - assert.equal(canvas.preserveObjectStacking, false); }); @@ -2147,7 +2146,7 @@ canvas.add(new fabric.Rect({ width: 100, height: 110, top: 120, left: 130, fill: 'rgba(0,1,2,0.3)' })); var canvasData = JSON.stringify(canvas); - canvas.clone(function(clone) { + canvas.clone().then(function(clone) { assert.ok(clone instanceof fabric.Canvas); // alert(JSON.stringify(clone)); @@ -2166,7 +2165,7 @@ canvas.add(new fabric.Rect({ width: 100, height: 110, top: 120, left: 130, fill: 'rgba(0,1,2,0.3)' })); - canvas.cloneWithoutData(function(clone) { + canvas.cloneWithoutData().then(function(clone) { assert.ok(clone instanceof fabric.Canvas); diff --git a/test/unit/canvas_events.js b/test/unit/canvas_events.js index df9bce5288b..c407a807627 100644 --- a/test/unit/canvas_events.js +++ b/test/unit/canvas_events.js @@ -697,6 +697,7 @@ }); QUnit.test('Fabric mouseover, mouseout events fire for subTargets when subTargetCheck is enabled', function(assert){ + var done = assert.async(); var counterOver = 0, counterOut = 0, canvas = new fabric.Canvas(); function setSubTargetCheckRecursive(obj) { if (obj._objects) { @@ -710,7 +711,7 @@ counterOut++; }); } - canvas.loadFromJSON(SUB_TARGETS_JSON, function() { + canvas.loadFromJSON(SUB_TARGETS_JSON).then(function() { var activeSelection = new fabric.ActiveSelection(canvas.getObjects(), { canvas: canvas }); @@ -737,6 +738,7 @@ assert.equal(counterOut, 4, 'mouseout fabric event fired 4 times for primary hoveredTarget & subTargets'); assert.equal(canvas._hoveredTarget, null, '_hoveredTarget has been set to null'); assert.equal(canvas._hoveredTargets.length, 0, '_hoveredTargets array is empty'); + done(); }); }); diff --git a/test/unit/canvas_static.js b/test/unit/canvas_static.js index 0e3257a306e..bbf050f209c 100644 --- a/test/unit/canvas_static.js +++ b/test/unit/canvas_static.js @@ -160,9 +160,9 @@ } /** - * - * @param {*} actual - * @param {*} [expected] + * + * @param {*} actual + * @param {*} [expected] */ QUnit.assert.sameImageObject = function (actual, expected) { var a = {}, b = {}; @@ -668,7 +668,7 @@ croppingHeight = 50, dataURL = canvas.toDataURL({width: croppingWidth, height: croppingHeight}); - fabric.Image.fromURL(dataURL, function (img) { + fabric.Image.fromURL(dataURL).then(function (img) { assert.equal(img.width, croppingWidth, 'Width of exported image should correspond to cropping width'); assert.equal(img.height, croppingHeight, 'Height of exported image should correspond to cropping height'); done(); @@ -878,8 +878,8 @@ canvas.renderOnAddRemove = false; canvas.add(circle, rect, path1, tria, polygon, polyline, group, ellipse, image, pathGroup); - canvas.setBackgroundImage(imageBG); - canvas.setOverlayImage(imageOL); + canvas.backgroundImage = imageBG; + canvas.overlayImage = imageOL; var reviverCount = 0, len = canvas.size() + group.size() + pathGroup.size(); @@ -890,8 +890,8 @@ canvas.toSVG(null, reviver); assert.equal(reviverCount, len + 2, 'reviver should include background and overlay image'); - canvas.setBackgroundImage(null); - canvas.setOverlayImage(null); + canvas.backgroundImage = null; + canvas.overlayImage = null; canvas.renderOnAddRemove = true; }); @@ -1112,7 +1112,7 @@ canvas.backgroundImage = rect; canvas.overlayImage = rect2; canvas.backgroundColor = bgColor; - canvas.setOverlayColor('red'); + canvas.overlayColor = 'red'; canvas.add(rect3); var rectToObject = rect.toObject(); var rect2ToObject = rect2.toObject(); @@ -1178,7 +1178,7 @@ var done = assert.async(); assert.ok(typeof canvas.loadFromJSON === 'function'); - canvas.loadFromJSON(PATH_JSON, function(){ + canvas.loadFromJSON(PATH_JSON).then(function(){ var obj = canvas.item(0); assert.ok(!canvas.isEmpty(), 'canvas is not empty'); @@ -1207,7 +1207,7 @@ var done = assert.async(); assert.ok(typeof canvas.loadFromJSON === 'function'); - canvas.loadFromJSON(JSON.parse(PATH_JSON), function(){ + canvas.loadFromJSON(JSON.parse(PATH_JSON)).then(function(){ var obj = canvas.item(0); assert.ok(!canvas.isEmpty(), 'canvas is not empty'); @@ -1238,7 +1238,7 @@ var done = assert.async(); assert.ok(typeof canvas.loadFromJSON === 'function'); - canvas.loadFromJSON(JSON.parse(PATH_WITHOUT_DEFAULTS_JSON), function(){ + canvas.loadFromJSON(JSON.parse(PATH_WITHOUT_DEFAULTS_JSON)).then(function(){ var obj = canvas.item(0); assert.ok(!canvas.isEmpty(), 'canvas is not empty'); @@ -1270,7 +1270,7 @@ var serialized = JSON.parse(PATH_JSON); serialized.background = 'green'; serialized.backgroundImage = { "type": "image", "originX": "left", "originY": "top", "left": 13.6, "top": -1.4, "width": 3000, "height": 3351, "fill": "rgb(0,0,0)", "stroke": null, "strokeWidth": 0, "strokeDashArray": null, "strokeLineCap": "butt", "strokeDashOffset": 0, "strokeLineJoin": "miter", "strokeMiterLimit": 4, "scaleX": 0.05, "scaleY": 0.05, "angle": 0, "flipX": false, "flipY": false, "opacity": 1, "shadow": null, "visible": true, "backgroundColor": "", "fillRule": "nonzero", "globalCompositeOperation": "source-over", "skewX": 0, "skewY": 0, "src": IMG_SRC, "filters": [], "crossOrigin": "" }; - canvas.loadFromJSON(serialized, function() { + canvas.loadFromJSON(serialized).then(function() { assert.ok(!canvas.isEmpty(), 'canvas is not empty'); assert.equal(canvas.backgroundColor, 'green'); assert.ok(canvas.backgroundImage instanceof fabric.Image); @@ -1293,7 +1293,7 @@ assert.ok(jsonWithoutFoo !== RECT_JSON_WITH_PADDING); canvas.clear(); - canvas.loadFromJSON(jsonWithFoo, function() { + canvas.loadFromJSON(jsonWithFoo).then(function() { var obj = canvas.item(0); assert.equal(obj.padding, 123, 'padding on object is set properly'); @@ -1305,7 +1305,7 @@ QUnit.test('loadFromJSON with text', function(assert) { var done = assert.async(); var json = '{"objects":[{"type":"text","left":150,"top":200,"width":128,"height":64.32,"fill":"#000000","stroke":"","strokeWidth":"","scaleX":0.8,"scaleY":0.8,"angle":0,"flipX":false,"flipY":false,"opacity":1,"text":"NAME HERE","fontSize":24,"fontWeight":"","fontFamily":"Delicious_500","fontStyle":"","lineHeight":"","textDecoration":"","textAlign":"center","path":"","strokeStyle":"","backgroundColor":""}],"background":"#ffffff"}'; - canvas.loadFromJSON(json, function() { + canvas.loadFromJSON(json).then(function() { canvas.renderAll(); @@ -1320,10 +1320,11 @@ QUnit.test('loadFromJSON with clipPath', function(assert) { var done = assert.async(); + var canvas3 = new fabric.StaticCanvas(); var json = '{"clipPath": {"type":"text","left":150,"top":200,"width":128,"height":64.32,"fill":"#000000","stroke":"","strokeWidth":"","scaleX":0.8,"scaleY":0.8,"angle":0,"flipX":false,"flipY":false,"opacity":1,"text":"NAME HERE","fontSize":24,"fontWeight":"","fontFamily":"Delicious_500","fontStyle":"","lineHeight":"","textDecoration":"","textAlign":"center","path":"","strokeStyle":"","backgroundColor":""}}'; - canvas.loadFromJSON(json, function() { - canvas.renderAll(); - assert.equal('text', canvas.clipPath.type); + canvas3.loadFromJSON(json).then(function() { + assert.ok(canvas3.clipPath instanceof fabric.Text); + assert.equal('text', canvas3.clipPath.type); done(); }); }); @@ -1561,8 +1562,36 @@ }); QUnit.test('clone', function(assert) { + var done = assert.async(); + var canvas2 = new fabric.StaticCanvas(null, { renderOnAddRemove: false, width: 10, height: 10 }); + assert.ok(typeof canvas.clone === 'function'); + var rect = new fabric.Rect(); + canvas2.add(rect); + canvas2.clone().then(function(cloned) { + assert.ok(cloned instanceof fabric.Canvas, 'is cloned in a Canvas, sad but true'); + var clonedRect = cloned.getObjects()[0]; + assert.equal(clonedRect.type, 'rect', 'the rect has been cloned too'); + assert.equal(clonedRect.width, rect.width, 'the rect has been cloned too with properties'); + assert.equal(cloned.width, canvas2.width, 'the canvas has been cloned with properties'); + done(); + }); + }); + + QUnit.test('cloneWithoutData', function(assert) { + var done = assert.async(); + var canvas2 = new fabric.StaticCanvas(null, { renderOnAddRemove: false, width: 10, height: 10 }); assert.ok(typeof canvas.clone === 'function'); - // TODO (kangax): test clone + var rect = new fabric.Rect(); + canvas2.add(rect); + canvas2.backgroundColor = 'red'; + canvas2.cloneWithoutData().then(function(cloned) { + assert.ok(cloned instanceof fabric.Canvas, 'is cloned in a Canvas, sad but true'); + var clonedObjects = cloned.getObjects(); + assert.equal(clonedObjects.length, 0, 'no cloend objects'); + assert.equal(cloned.width, canvas2.width, 'the canvas has been cloned with properties'); + assert.equal(cloned.backgroundColor, 'red', 'background color has been cloned'); + done(); + }); }); QUnit.test('getSetWidth', function(assert) { @@ -1652,32 +1681,6 @@ assert.ok(typeof canvas.fxRemove(rect, { onComplete: onComplete }) === 'function', 'should return animation abort function'); }); - QUnit.test('options in setBackgroundImage from URL', function(assert) { - var done = assert.async(); - canvas.setBackgroundImage(IMG_SRC, function() { - assert.equal(canvas.backgroundImage.canvas, canvas, 'canvas is referenced'); - assert.equal(canvas.backgroundImage.left, 50); - assert.equal(canvas.backgroundImage.originX, 'right'); - done(); - }, { - left: 50, - originX: 'right' - }); - }); - - QUnit.test('options in setOverlayImage from URL', function(assert) { - var done = assert.async(); - canvas.setOverlayImage(IMG_SRC, function() { - assert.equal(canvas.overlayImage.canvas, canvas, 'canvas is referenced'); - assert.equal(canvas.overlayImage.left, 50); - assert.equal(canvas.overlayImage.originX, 'right'); - done(); - }, { - left: 50, - originX: 'right' - }); - }); - QUnit.test('setViewportTransform', function(assert) { assert.ok(typeof canvas.setViewportTransform === 'function'); var vpt = [2, 0, 0, 2, 50, 50]; @@ -1831,38 +1834,6 @@ assert.equal(scaling, 1, 'retina is disabled, 1'); }); - QUnit.test('options in setBackgroundImage from image instance', function(assert) { - var done = assert.async(); - createImageObject(function(imageInstance) { - canvas.setBackgroundImage(imageInstance, function() { - assert.equal(canvas.backgroundImage.canvas, canvas, 'canvas get referenced'); - assert.equal(canvas.backgroundImage.left, 100); - assert.equal(canvas.backgroundImage.originX, 'center'); - - done(); - }, { - left: 100, - originX: 'center' - }); - }); - }); - - QUnit.test('options in setOverlayImage from image instance', function(assert) { - var done = assert.async(); - createImageObject(function(imageInstance) { - canvas.setOverlayImage(imageInstance, function() { - assert.equal(canvas.overlayImage, imageInstance); - assert.equal(imageInstance.left, 100); - assert.equal(imageInstance.originX, 'center'); - assert.equal(imageInstance.canvas, canvas, 'canvas get referenced'); - done(); - }, { - left: 100, - originX: 'center' - }); - }); - }); - QUnit.test('createPNGStream', function(assert) { if (!fabric.isLikelyNode) { assert.ok(true, 'not supposed to run outside node'); @@ -1946,12 +1917,15 @@ QUnit.test('toSVG with background pattern', function(assert) { fabric.Object.__uid = 0; var canvas2 = new fabric.StaticCanvas(); + + var img = fabric.document.createElement('img'); + img.src = 'a.jpg'; canvas2.backgroundColor = new fabric.Pattern({ - source: 'a.jpeg', repeat: 'repeat', + source: img, }); var svg = canvas2.toSVG(); - var expectedSVG = '\n\n\nCreated with Fabric.js ' + fabric.version + '\n\n\n\n\n\n\n'; + var expectedSVG = '\n\n\nCreated with Fabric.js ' + fabric.version + '\n\n\n\n\n\n\n'; assert.equal(svg, expectedSVG, 'svg is as expected'); }); diff --git a/test/unit/circle.js b/test/unit/circle.js index b23b199b499..b12575139dd 100644 --- a/test/unit/circle.js +++ b/test/unit/circle.js @@ -231,7 +231,7 @@ fabric.Circle.fromObject({ left: left, top: top, radius: radius, fill: fill - }, function(circle) { + }).then(function(circle) { assert.ok(circle instanceof fabric.Circle); assert.equal(circle.get('left'), left); @@ -240,7 +240,7 @@ assert.equal(circle.get('fill'), fill); var expected = circle.toObject(); - fabric.Circle.fromObject(expected, function(actual) { + fabric.Circle.fromObject(expected).then(function(actual) { assert.deepEqual(actual.toObject(), expected); done(); }); @@ -248,15 +248,17 @@ }); QUnit.test('cloning and radius, width, height', function(assert) { + var done = assert.async(); var circle = new fabric.Circle({ radius: 10, strokeWidth: 0}); circle.scale(2); - circle.clone(function(clone) { + circle.clone().then(function(clone) { assert.equal(clone.width, 20); assert.equal(clone.getScaledWidth(), 40); assert.equal(clone.height, 20); assert.equal(clone.getScaledHeight(), 40); assert.equal(clone.radius, 10); + done(); }); }); })(); diff --git a/test/unit/ellipse.js b/test/unit/ellipse.js index 9624535e239..c7d59a06c07 100644 --- a/test/unit/ellipse.js +++ b/test/unit/ellipse.js @@ -171,7 +171,7 @@ fabric.Ellipse.fromObject({ left: left, top: top, rx: rx, ry: ry, fill: fill - }, function(ellipse) { + }).then(function(ellipse) { assert.ok(ellipse instanceof fabric.Ellipse); assert.equal(ellipse.get('left'), left); @@ -181,12 +181,10 @@ assert.equal(ellipse.get('fill'), fill); var expected = ellipse.toObject(); - fabric.Ellipse.fromObject(expected, function(actual) { + fabric.Ellipse.fromObject(expected).then(function(actual) { assert.deepEqual(actual.toObject(), expected); done(); }); }); - - }); })(); diff --git a/test/unit/group.js b/test/unit/group.js index 87359715b22..fbb44674aa9 100644 --- a/test/unit/group.js +++ b/test/unit/group.js @@ -380,7 +380,7 @@ assert.ok(typeof fabric.Group.fromObject === 'function'); var groupObject = group.toObject(); - fabric.Group.fromObject(groupObject, function(newGroupFromObject) { + fabric.Group.fromObject(groupObject).then(function(newGroupFromObject) { var objectFromOldGroup = group.toObject(); var objectFromNewGroup = newGroupFromObject.toObject(); @@ -420,7 +420,7 @@ var groupToObject = groupObject.toObject(); - fabric.Group.fromObject(groupToObject, function(newGroupFromObject) { + fabric.Group.fromObject(groupToObject).then(function(newGroupFromObject) { var objectFromNewGroup = newGroupFromObject.toObject(); @@ -438,10 +438,9 @@ var groupObject = group.toObject(); - fabric.Group.fromObject(groupObject, function(newGroupFromObject) { + fabric.Group.fromObject(groupObject).then(function(newGroupFromObject) { assert.ok(newGroupFromObject._objects[0].lineCoords.tl, 'acoords 0 are restored'); assert.ok(newGroupFromObject._objects[1].lineCoords.tl, 'acoords 1 are restored'); - done(); }); }); @@ -451,28 +450,13 @@ var group = makeGroupWith2ObjectsWithOpacity(); var groupObject = group.toObject(); - fabric.Group.fromObject(groupObject, function(newGroupFromObject) { + fabric.Group.fromObject(groupObject).then(function(newGroupFromObject) { assert.equal(newGroupFromObject.objects, undefined, 'the objects array has not been pulled in'); assert.notEqual(groupObject.objects, undefined, 'the objects array has not been deleted from object source'); done(); }); }); - QUnit.test('fromObject with svg url', function(assert) { - var done = assert.async(); - var url = 'data:image/svg+xml,%3csvg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="612px" height="502.174px" viewBox="0 65.326 612 502.174" enable-background="new 0 65.326 612 502.174" xml:space="preserve"%3e %3cellipse fill="%23C6C6C6" cx="283.5" cy="487.5" rx="259" ry="80"/%3e %3cpath id="bird" d="M210.333%2c65.331C104.367%2c66.105-12.349%2c150.637%2c1.056%2c276.449c4.303%2c40.393%2c18.533%2c63.704%2c52.171%2c79.03 c36.307%2c16.544%2c57.022%2c54.556%2c50.406%2c112.954c-9.935%2c4.88-17.405%2c11.031-19.132%2c20.015c7.531-0.17%2c14.943-0.312%2c22.59%2c4.341 c20.333%2c12.375%2c31.296%2c27.363%2c42.979%2c51.72c1.714%2c3.572%2c8.192%2c2.849%2c8.312-3.078c0.17-8.467-1.856-17.454-5.226-26.933 c-2.955-8.313%2c3.059-7.985%2c6.917-6.106c6.399%2c3.115%2c16.334%2c9.43%2c30.39%2c13.098c5.392%2c1.407%2c5.995-3.877%2c5.224-6.991 c-1.864-7.522-11.009-10.862-24.519-19.229c-4.82-2.984-0.927-9.736%2c5.168-8.351l20.234%2c2.415c3.359%2c0.763%2c4.555-6.114%2c0.882-7.875 c-14.198-6.804-28.897-10.098-53.864-7.799c-11.617-29.265-29.811-61.617-15.674-81.681c12.639-17.938%2c31.216-20.74%2c39.147%2c43.489 c-5.002%2c3.107-11.215%2c5.031-11.332%2c13.024c7.201-2.845%2c11.207-1.399%2c14.791%2c0c17.912%2c6.998%2c35.462%2c21.826%2c52.982%2c37.309 c3.739%2c3.303%2c8.413-1.718%2c6.991-6.034c-2.138-6.494-8.053-10.659-14.791-20.016c-3.239-4.495%2c5.03-7.045%2c10.886-6.876 c13.849%2c0.396%2c22.886%2c8.268%2c35.177%2c11.218c4.483%2c1.076%2c9.741-1.964%2c6.917-6.917c-3.472-6.085-13.015-9.124-19.18-13.413 c-4.357-3.029-3.025-7.132%2c2.697-6.602c3.905%2c0.361%2c8.478%2c2.271%2c13.908%2c1.767c9.946-0.925%2c7.717-7.169-0.883-9.566 c-19.036-5.304-39.891-6.311-61.665-5.225c-43.837-8.358-31.554-84.887%2c0-90.363c29.571-5.132%2c62.966-13.339%2c99.928-32.156 c32.668-5.429%2c64.835-12.446%2c92.939-33.85c48.106-14.469%2c111.903%2c16.113%2c204.241%2c149.695c3.926%2c5.681%2c15.819%2c9.94%2c9.524-6.351 c-15.893-41.125-68.176-93.328-92.13-132.085c-24.581-39.774-14.34-61.243-39.957-91.247 c-21.326-24.978-47.502-25.803-77.339-17.365c-23.461%2c6.634-39.234-7.117-52.98-31.273C318.42%2c87.525%2c265.838%2c64.927%2c210.333%2c65.331 z M445.731%2c203.01c6.12%2c0%2c11.112%2c4.919%2c11.112%2c11.038c0%2c6.119-4.994%2c11.111-11.112%2c11.111s-11.038-4.994-11.038-11.111 C434.693%2c207.929%2c439.613%2c203.01%2c445.731%2c203.01z"/%3e %3c/svg%3e'; - var groupObject = { - left: 10, - top: 10, - objects: url - }; - fabric.Group.fromObject(groupObject, function(newGroupFromObject) { - assert.equal(newGroupFromObject.sourcePath, url, 'the url is copied in sourcePath'); - assert.equal(newGroupFromObject._objects.length, 2, '2 objects are created'); - done(); - }); - }); - QUnit.test('toSVG', function(assert) { var group = makeGroupWith2Objects(); assert.ok(typeof group.toSVG === 'function'); @@ -505,11 +489,9 @@ QUnit.test('cloning group with 2 objects', function(assert) { var done = assert.async(); var group = makeGroupWith2Objects(); - group.clone(function(clone) { - + group.clone().then(function(clone) { assert.ok(clone !== group); assert.deepEqual(clone.toObject(), group.toObject()); - done(); }); }); diff --git a/test/unit/image.js b/test/unit/image.js index a1a0a2d8e36..665160d8906 100644 --- a/test/unit/image.js +++ b/test/unit/image.js @@ -122,8 +122,8 @@ } /** - * - * @param {*} actual + * + * @param {*} actual * @param {*} [expected] */ QUnit.assert.sameImageObject = function (actual, expected) { @@ -180,7 +180,7 @@ assert.ok(typeof image.setSrc === 'function'); assert.equal(image.width, 100); assert.equal(image.height, 100); - image.setSrc(IMG_SRC, function() { + image.setSrc(IMG_SRC).then(function() { assert.equal(image.width, IMG_WIDTH); assert.equal(image.height, IMG_HEIGHT); done(); @@ -196,13 +196,11 @@ assert.ok(typeof image.setSrc === 'function'); assert.equal(image.width, 100); assert.equal(image.height, 100); - image.setSrc(IMG_SRC, function() { + image.setSrc(IMG_SRC, { crossOrigin: 'anonymous' }).then(function() { assert.equal(image.width, IMG_WIDTH); assert.equal(image.height, IMG_HEIGHT); assert.equal(image.getCrossOrigin(), 'anonymous', 'setSrc will respect crossOrigin'); done(); - }, { - crossOrigin: 'anonymous' }); }); }); @@ -233,7 +231,7 @@ assert.ok(image.resizeFilter instanceof fabric.Image.filters.Resize, 'should inherit from fabric.Image.filters.Resize'); var toObject = image.toObject(); assert.deepEqual(toObject.resizeFilter, filter.toObject(), 'the filter is in object form now'); - fabric.Image.fromObject(toObject, function(imageFromObject) { + fabric.Image.fromObject(toObject).then(function(imageFromObject) { var filterFromObj = imageFromObject.resizeFilter; assert.ok(filterFromObj instanceof fabric.Image.filters.Resize, 'should inherit from fabric.Image.filters.Resize'); assert.deepEqual(filterFromObj, filter, 'the filter has been restored'); @@ -257,7 +255,7 @@ var toObject = image.toObject(); assert.deepEqual(toObject.resizeFilter, filter.toObject(), 'the filter is in object form now'); assert.deepEqual(toObject.filters[0], filterBg.toObject(), 'the filter is in object form now brightness'); - fabric.Image.fromObject(toObject, function(imageFromObject) { + fabric.Image.fromObject(toObject).then(function(imageFromObject) { var filterFromObj = imageFromObject.resizeFilter; var brightnessFromObj = imageFromObject.filters[0]; assert.ok(filterFromObj instanceof fabric.Image.filters.Resize, 'should inherit from fabric.Image.filters.Resize'); @@ -284,7 +282,7 @@ assert.deepEqual(toObject.filters[0], filter.toObject()); assert.equal(toObject.width, width, 'width is stored as before filters'); assert.equal(toObject.height, height, 'height is stored as before filters'); - fabric.Image.fromObject(toObject, function(_imageFromObject) { + fabric.Image.fromObject(toObject).then(function(_imageFromObject) { var filterFromObj = _imageFromObject.filters[0]; assert.ok(filterFromObj instanceof fabric.Image.filters.Resize, 'should inherit from fabric.Image.filters.Resize'); assert.equal(filterFromObj.scaleY, 0.2); @@ -455,8 +453,7 @@ done(); return; } - console.log(objRepr); - fabric.Image.fromObject(objRepr, function(img) { + fabric.Image.fromObject(objRepr).then(function(img) { assert.equal(img.getCrossOrigin(), null, 'image without src return no element'); done(); }); @@ -467,9 +464,9 @@ var done = assert.async(); createImageObject(function(image) { assert.ok(typeof image.clone === 'function'); - image.clone(function(clone) { + image.clone().then(function(clone) { assert.ok(clone instanceof fabric.Image); - assert.deepEqual(clone.toObject(), image.toObject()); + assert.deepEqual(clone.toObject(), image.toObject(), 'clone and original image are equal'); done(); }); }); @@ -478,7 +475,7 @@ QUnit.test('cloneWidthHeight', function(assert) { var done = assert.async(); createSmallImageObject(function(image) { - image.clone(function(clone) { + image.clone().then(function(clone) { assert.equal(clone.width, IMG_WIDTH / 2, 'clone\'s element should have width identical to that of original image'); assert.equal(clone.height, IMG_HEIGHT / 2, @@ -496,7 +493,7 @@ var obj = fabric.util.object.extend(fabric.util.object.clone(REFERENCE_IMG_OBJECT), { src: IMG_SRC }); - fabric.Image.fromObject(obj, function(instance){ + fabric.Image.fromObject(obj).then(function(instance){ assert.ok(instance instanceof fabric.Image); done(); }); @@ -509,7 +506,7 @@ src: IMG_SRC, clipPath: (new fabric.Rect({ width: 100, height: 100 })).toObject(), }); - fabric.Image.fromObject(obj, function(instance){ + fabric.Image.fromObject(obj).then(function(instance){ assert.ok(instance instanceof fabric.Image); assert.ok(instance.clipPath instanceof fabric.Rect); done(); @@ -537,7 +534,7 @@ var copyOfBrighteness = brightness; var copyOfContrast = contrast; var copyOfObject = obj; - fabric.Image.fromObject(obj, function(){ + fabric.Image.fromObject(obj).then(function(){ assert.ok(copyOfFilters === obj.filters, 'filters array did not mutate'); assert.ok(copyOfBrighteness === copyOfFilters[0], 'filter is same object'); assert.deepEqual(copyOfBrighteness, obj.filters[0], 'did not mutate filter'); @@ -552,7 +549,7 @@ QUnit.test('fromURL', function(assert) { var done = assert.async(); assert.ok(typeof fabric.Image.fromURL === 'function'); - fabric.Image.fromURL(IMG_SRC, function(instance) { + fabric.Image.fromURL(IMG_SRC).then(function(instance) { assert.ok(instance instanceof fabric.Image); assert.sameImageObject(REFERENCE_IMG_OBJECT, instance.toObject()); done(); @@ -562,9 +559,10 @@ QUnit.test('fromURL error', function(assert) { var done = assert.async(); assert.ok(typeof fabric.Image.fromURL === 'function'); - fabric.Image.fromURL(IMG_URL_NON_EXISTING, function(instance, isError) { + fabric.Image.fromURL(IMG_URL_NON_EXISTING, function(instance) { assert.ok(instance instanceof fabric.Image); - assert.equal(isError, true); + }).catch(function(e) { + assert.ok(e instanceof Error); done(); }); }); diff --git a/test/unit/image_filters.js b/test/unit/image_filters.js index 190996b2932..6a803b8cb9e 100644 --- a/test/unit/image_filters.js +++ b/test/unit/image_filters.js @@ -82,11 +82,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Brightness(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.Brightness.fromObject(object), filter); + fabric.Image.filters.Brightness.fromObject(object).then((newFilter) => { + assert.deepEqual(newFilter, filter, 'enlived filter match'); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -150,24 +153,30 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Composed(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.Composed.fromObject(object), filter); + fabric.Image.filters.Composed.fromObject(object).then(function(restoredFilters) { + assert.deepEqual(restoredFilters, filter); + done(); + }); }); QUnit.test('fromObject with subfilters', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Composed(); var brightness = new fabric.Image.filters.Brightness(); var contrast = new fabric.Image.filters.Contrast(); filter.subFilters.push(brightness); filter.subFilters.push(contrast); var toObject = filter.toObject(); - var newFilter = fabric.Image.filters.Composed.fromObject(toObject); - assert.ok(newFilter instanceof fabric.Image.filters.Composed, 'should inherit from fabric.Image.filters.Composed'); - assert.ok(newFilter.subFilters[0] instanceof fabric.Image.filters.Brightness, 'should inherit from fabric.Image.filters.Brightness'); - assert.ok(newFilter.subFilters[1] instanceof fabric.Image.filters.Contrast, 'should inherit from fabric.Image.filters.Contrast'); + fabric.Image.filters.Composed.fromObject(toObject).then(function(newFilter){ + assert.ok(newFilter instanceof fabric.Image.filters.Composed, 'should inherit from fabric.Image.filters.Composed'); + assert.ok(newFilter.subFilters[0] instanceof fabric.Image.filters.Brightness, 'should inherit from fabric.Image.filters.Brightness'); + assert.ok(newFilter.subFilters[1] instanceof fabric.Image.filters.Contrast, 'should inherit from fabric.Image.filters.Contrast'); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -275,11 +284,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.ColorMatrix(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.ColorMatrix.fromObject(object), filter); + fabric.Image.filters.ColorMatrix.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -359,11 +371,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.HueRotation(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.HueRotation.fromObject(object), filter); + fabric.Image.filters.HueRotation.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -436,11 +451,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Contrast(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.Contrast.fromObject(object), filter); + fabric.Image.filters.Contrast.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -513,11 +531,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Saturation(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.Saturation.fromObject(object), filter); + fabric.Image.filters.Saturation.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -590,11 +611,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Gamma(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.Gamma.fromObject(object), filter); + fabric.Image.filters.Gamma.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -648,11 +672,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Convolute(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.Convolute.fromObject(object), filter); + fabric.Image.filters.Convolute.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -729,11 +756,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Grayscale(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.Grayscale.fromObject(object), filter); + fabric.Image.filters.Grayscale.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -789,11 +819,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Invert(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.Invert.fromObject(object), filter); + fabric.Image.filters.Invert.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -854,11 +887,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Noise(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.Noise.fromObject(object), filter); + fabric.Image.filters.Noise.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -920,11 +956,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Pixelate(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.Pixelate.fromObject(object), filter); + fabric.Image.filters.Pixelate.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -990,11 +1029,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.RemoveColor(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.RemoveColor.fromObject(object), filter); + fabric.Image.filters.RemoveColor.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -1039,11 +1081,14 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Sepia(); var object = filter.toObject(); - - assert.deepEqual(fabric.Image.filters.Sepia.fromObject(object), filter); + fabric.Image.filters.Sepia.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -1095,16 +1140,21 @@ }); QUnit.test('fromObject', function(assert) { + var done = assert.async(); var filter = new fabric.Image.filters.Resize(); var object = filter.toObject(); - var fromObject = fabric.Image.filters.Resize.fromObject(object); - assert.deepEqual(fromObject, filter); - assert.ok(fromObject instanceof fabric.Image.filters.Resize, 'should inherit from fabric.Image.filters.Resize'); - filter.resizeType = 'bilinear'; - filter.scaleX = 0.8; - filter.scaleY = 0.8; - assert.deepEqual(fabric.Image.filters.Resize.fromObject(filter.toObject()), filter); + fabric.Image.filters.Resize.fromObject(object).then(function(restoredFilter) { + assert.ok(restoredFilter instanceof fabric.Image.filters.Resize, 'should inherit from fabric.Image.filters.Resize'); + assert.deepEqual(restoredFilter, filter); + filter.resizeType = 'bilinear'; + filter.scaleX = 0.8; + filter.scaleY = 0.8; + return fabric.Image.filters.Resize.fromObject(filter.toObject()).then(function(restoredFilter2) { + assert.deepEqual(restoredFilter2, filter); + done(); + }); + }); }); QUnit.test('isNeutralState', function(assert) { @@ -1122,4 +1172,108 @@ filter.blur = 0.3; assert.notOk(filter.isNeutralState(), 'Is not neutral when blur changes'); }); + + QUnit.module('fabric.Image.filters.Vibrance'); + + QUnit.test('constructor', function(assert) { + assert.ok(fabric.Image.filters.Vibrance); + + var filter = new fabric.Image.filters.Vibrance({ + vibrance: 0.6, + }); + assert.ok(filter instanceof fabric.Image.filters.Vibrance, 'should inherit from fabric.Image.filters.Vibrance'); + assert.equal(filter.vibrance, 0.6, 'parameters are initialized'); + assert.equal(filter.type, 'Vibrance'); + }); + + QUnit.test('applyTo2d', function(assert) { + var filter = new fabric.Image.filters.Vibrance(); + assert.ok(typeof filter.applyTo2d === 'function'); + }); + + QUnit.test('toObject', function(assert) { + var filter = new fabric.Image.filters.Vibrance(); + assert.ok(typeof filter.toObject === 'function'); + + var object = filter.toObject(); + assert.equal(JSON.stringify(object), '{"type":"Vibrance","vibrance":0}'); + }); + + QUnit.test('toJSON', function(assert) { + var filter = new fabric.Image.filters.Vibrance(); + assert.ok(typeof filter.toJSON === 'function'); + + var json = filter.toJSON(); + assert.equal(JSON.stringify(json), '{"type":"Vibrance","vibrance":0}'); + }); + + QUnit.test('fromObject', function(assert) { + var done = assert.async(); + var filter = new fabric.Image.filters.Vibrance({ vibrance: 0.3 }); + + var object = filter.toObject(); + fabric.Image.filters.Vibrance.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); + }); + + QUnit.test('isNeutralState', function(assert) { + var filter = new fabric.Image.filters.Vibrance(); + filter.vibrance = 0; + assert.ok(filter.isNeutralState(), '0 is neutral'); + filter.vibrance = 0.5; + assert.notOk(filter.isNeutralState(), '0.5 is not neutral'); + }); + + QUnit.module('fabric.Image.filters.BlendColor'); + + QUnit.test('constructor', function(assert) { + assert.ok(fabric.Image.filters.BlendColor); + + var filter = new fabric.Image.filters.BlendColor({ + color: 'red', + }); + assert.ok(filter instanceof fabric.Image.filters.BlendColor, 'should inherit from fabric.Image.filters.Vibrance'); + assert.equal(filter.color, 'red', 'parameters are initialized'); + assert.equal(filter.type, 'BlendColor'); + }); + + QUnit.test('applyTo2d', function(assert) { + var filter = new fabric.Image.filters.BlendColor(); + assert.ok(typeof filter.applyTo2d === 'function'); + }); + + QUnit.test('toObject', function(assert) { + var filter = new fabric.Image.filters.BlendColor(); + assert.ok(typeof filter.toObject === 'function'); + + var object = filter.toObject(); + var expected = { + type: 'BlendColor', + color: '#F95C63', + alpha: 1, + mode: 'multiply', + }; + assert.deepEqual(object, expected); + var json = filter.toJSON(); + assert.deepEqual(json, expected); + }); + + QUnit.test('fromObject', function(assert) { + var done = assert.async(); + var filter = new fabric.Image.filters.BlendColor({ color: 'blue', alpha: 0.5 }); + + var object = filter.toObject(); + fabric.Image.filters.BlendColor.fromObject(object).then(function(restoredFilter){ + assert.deepEqual(restoredFilter, filter); + done(); + }); + }); + + QUnit.test('isNeutralState', function(assert) { + var filter = new fabric.Image.filters.BlendColor(); + assert.notOk(filter.isNeutralState(), 'is never neutral'); + }); + })(); diff --git a/test/unit/itext.js b/test/unit/itext.js index 72d65cfda41..3bb0704e8de 100644 --- a/test/unit/itext.js +++ b/test/unit/itext.js @@ -103,7 +103,7 @@ QUnit.test('fromObject', function(assert) { var done = assert.async(); assert.ok(typeof fabric.IText.fromObject === 'function'); - fabric.IText.fromObject(ITEXT_OBJECT, function(iText) { + fabric.IText.fromObject(ITEXT_OBJECT).then(function(iText) { assert.ok(iText instanceof fabric.IText); assert.deepEqual(ITEXT_OBJECT, iText.toObject()); done(); diff --git a/test/unit/line.js b/test/unit/line.js index b3377403090..2dfffa47e2a 100644 --- a/test/unit/line.js +++ b/test/unit/line.js @@ -82,7 +82,7 @@ QUnit.test('fromObject', function(assert) { var done = assert.async(); assert.ok(typeof fabric.Line.fromObject === 'function'); - fabric.Line.fromObject(LINE_OBJECT, function(line) { + fabric.Line.fromObject(LINE_OBJECT).then(function(line) { assert.ok(line instanceof fabric.Line); assert.deepEqual(LINE_OBJECT, line.toObject()); done(); diff --git a/test/unit/object.js b/test/unit/object.js index 25d73d2e2b4..437178a965a 100644 --- a/test/unit/object.js +++ b/test/unit/object.js @@ -357,9 +357,10 @@ }); QUnit.test('clone', function(assert) { + var done = assert.async(); var cObj = new fabric.Object({ left: 123, top: 456, opacity: 0.66 }); assert.ok(typeof cObj.clone === 'function'); - cObj.clone(function(clone) { + cObj.clone().then(function(clone) { assert.equal(clone.get('left'), 123); assert.equal(clone.get('top'), 456); assert.equal(clone.get('opacity'), 0.66); @@ -370,32 +371,27 @@ assert.equal(cObj.get('left'), 123); assert.equal(cObj.get('scaleX'), 1); assert.equal(cObj.get('angle'), 0); + done(); }); }); QUnit.test('cloneAsImage', function(assert) { - var done = assert.async(); var cObj = new fabric.Rect({ width: 100, height: 100, fill: 'red', strokeWidth: 0 }); assert.ok(typeof cObj.cloneAsImage === 'function'); - cObj.cloneAsImage(function(image) { - assert.ok(image); - assert.ok(image instanceof fabric.Image); - assert.equal(image.width, 100, 'the image has same dimension of object'); - done(); - }); + var image = cObj.cloneAsImage(); + assert.ok(image); + assert.ok(image instanceof fabric.Image); + assert.equal(image.width, 100, 'the image has same dimension of object'); }); QUnit.test('cloneAsImage with retina scaling enabled', function(assert) { - var done = assert.async(); var cObj = new fabric.Rect({ width: 100, height: 100, fill: 'red', strokeWidth: 0 }); fabric.devicePixelRatio = 2; - cObj.cloneAsImage(function(image) { - assert.ok(image); - assert.ok(image instanceof fabric.Image); - assert.equal(image.width, 200, 'the image has been scaled by retina'); - fabric.devicePixelRatio = 1; - done(); - }, { enableRetinaScaling: true }); + var image = cObj.cloneAsImage({ enableRetinaScaling: true }); + assert.ok(image); + assert.ok(image instanceof fabric.Image); + assert.equal(image.width, 200, 'the image has been scaled by retina'); + fabric.devicePixelRatio = 1; }); QUnit.test('toCanvasElement', function(assert) { diff --git a/test/unit/object_clipPath.js b/test/unit/object_clipPath.js index 90033311016..d77a769747c 100644 --- a/test/unit/object_clipPath.js +++ b/test/unit/object_clipPath.js @@ -62,7 +62,7 @@ expected.clipPath = expectedClipPath; assert.deepEqual(expected, cObj.toObject()); cObj.clipPath.excludeFromExport = true; - assert.true(cObj.toObject().clipPath === undefined); + assert.ok(cObj.toObject().clipPath === undefined); }); QUnit.test('from object with clipPath', function(assert) { @@ -70,7 +70,7 @@ var rect = new fabric.Rect({ width: 100, height: 100 }); rect.clipPath = new fabric.Circle({ radius: 50 }); var toObject = rect.toObject(); - fabric.Rect.fromObject(toObject, function(rect) { + fabric.Rect.fromObject(toObject).then(function(rect) { assert.ok(rect.clipPath instanceof fabric.Circle, 'clipPath is enlived'); assert.equal(rect.clipPath.radius, 50, 'radius is restored correctly'); done(); @@ -82,7 +82,7 @@ var rect = new fabric.Rect({ width: 100, height: 100 }); rect.clipPath = new fabric.Circle({ radius: 50, inverted: true, absolutePositioned: true }); var toObject = rect.toObject(); - fabric.Rect.fromObject(toObject, function(rect) { + fabric.Rect.fromObject(toObject).then(function(rect) { assert.ok(rect.clipPath instanceof fabric.Circle, 'clipPath is enlived'); assert.equal(rect.clipPath.radius, 50, 'radius is restored correctly'); assert.equal(rect.clipPath.inverted, true, 'inverted is restored correctly'); @@ -97,7 +97,7 @@ rect.clipPath = new fabric.Circle({ radius: 50 }); rect.clipPath.clipPath = new fabric.Text('clipPath'); var toObject = rect.toObject(); - fabric.Rect.fromObject(toObject, function(rect) { + fabric.Rect.fromObject(toObject).then(function(rect) { assert.ok(rect.clipPath instanceof fabric.Circle, 'clipPath is enlived'); assert.equal(rect.clipPath.radius, 50, 'radius is restored correctly'); assert.ok(rect.clipPath.clipPath instanceof fabric.Text, 'nested clipPath is enlived'); @@ -112,7 +112,7 @@ rect.clipPath = new fabric.Circle({ radius: 50 }); rect.clipPath.clipPath = new fabric.Text('clipPath', { inverted: true, absolutePositioned: true}); var toObject = rect.toObject(); - fabric.Rect.fromObject(toObject, function(rect) { + fabric.Rect.fromObject(toObject).then(function(rect) { assert.ok(rect.clipPath instanceof fabric.Circle, 'clipPath is enlived'); assert.equal(rect.clipPath.radius, 50, 'radius is restored correctly'); assert.ok(rect.clipPath.clipPath instanceof fabric.Text, 'neted clipPath is enlived'); diff --git a/test/unit/path.js b/test/unit/path.js index dbc1a143a76..dbf77d19689 100644 --- a/test/unit/path.js +++ b/test/unit/path.js @@ -209,7 +209,7 @@ QUnit.test('path array not shared when cloned', function(assert) { var done = assert.async(); makePathObject(function(originalPath) { - originalPath.clone(function(clonedPath) { + originalPath.clone().then(function(clonedPath) { clonedPath.path[0][1] = 200; assert.equal(originalPath.path[0][1], 100); done(); @@ -250,7 +250,7 @@ QUnit.test('fromObject', function(assert) { var done = assert.async(); assert.ok(typeof fabric.Path.fromObject === 'function'); - fabric.Path.fromObject(REFERENCE_PATH_OBJECT, function(path) { + fabric.Path.fromObject(REFERENCE_PATH_OBJECT).then(function(path) { assert.ok(path instanceof fabric.Path); assert.deepEqual(path.toObject(), REFERENCE_PATH_OBJECT); done(); @@ -260,7 +260,7 @@ QUnit.test('fromObject with sourcePath', function(assert) { var done = assert.async(); assert.ok(typeof fabric.Path.fromObject === 'function'); - fabric.Path.fromObject(REFERENCE_PATH_OBJECT, function(path) { + fabric.Path.fromObject(REFERENCE_PATH_OBJECT).then(function(path) { assert.ok(path instanceof fabric.Path); assert.deepEqual(path.toObject(), REFERENCE_PATH_OBJECT); done(); diff --git a/test/unit/pattern.js b/test/unit/pattern.js index 83c2e782919..dd18e54f8f0 100644 --- a/test/unit/pattern.js +++ b/test/unit/pattern.js @@ -23,17 +23,6 @@ assert.ok(pattern instanceof fabric.Pattern, 'should inherit from fabric.Pattern'); }); - QUnit.test('constructor with source string and with callback', function(assert) { - var done = assert.async(); - function callback(pattern) { - assert.equal(pattern.source.complete, true, 'pattern source has been loaded'); - done(); - } - new fabric.Pattern({ - source: IMG_SRC - }, callback); - }); - QUnit.test('properties', function(assert) { var pattern = createPattern(); assert.equal(pattern.source, img); @@ -85,14 +74,18 @@ }); QUnit.test('fromObject with crossOrigin', function(assert) { - var pattern = new fabric.Pattern({ + var done = assert.async(); + fabric.Pattern.fromObject({ source: IMG_SRC, - crossOrigin: 'anonymous' + crossOrigin: 'anonymous', + type: 'pattern', + }).then(function(patternEnlived) { + var object = patternEnlived.toObject(); + fabric.Pattern.fromObject(object).then(function(patternAgain) { + assert.equal(patternAgain.crossOrigin, 'anonymous'); + done(); + }); }); - - var object = pattern.toObject(); - var pattern2 = new fabric.Pattern(object); - assert.equal(pattern2.crossOrigin, 'anonymous'); }); QUnit.test('toLive', function(assert) { @@ -100,19 +93,21 @@ var canvas = new fabric.StaticCanvas(null, {enableRetinaScaling: false}); var patternHTML = canvas.contextContainer.createPattern(img, 'repeat'); assert.ok(typeof pattern.toLive === 'function'); - var created = pattern.toLive(canvas.contextContainer); assert.equal(created.toString(), patternHTML.toString(), 'is a pattern'); }); QUnit.test('pattern serialization / deserialization (image source)', function(assert) { + var done = assert.async(); var pattern = createPattern(); var obj = pattern.toObject(); // node-canvas doesn't give "src" - var patternDeserialized = new fabric.Pattern(obj); - assert.equal(typeof patternDeserialized.source, 'object'); - assert.equal(patternDeserialized.repeat, 'repeat'); + fabric.Pattern.fromObject(obj).then(function(patternDeserialized) { + assert.equal(typeof patternDeserialized.source, 'object'); + assert.equal(patternDeserialized.repeat, 'repeat'); + done(); + }); }); QUnit.test('toSVG', function(assert) { @@ -167,12 +162,17 @@ }); QUnit.test('initPattern from object', function(assert) { - var fillObj = { - type: 'pattern', - source: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==' - }; - var obj = new fabric.Object({ fill: fillObj }); - assert.ok(obj.fill instanceof fabric.Pattern, 'the pattern is enlived'); + var done = assert.async(); + var rectObj = { + fill: { + type: 'pattern', + source: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==' + } + } + var obj = fabric.Rect.fromObject(rectObj).then(function(obj){ + assert.ok(obj.fill instanceof fabric.Pattern, 'the pattern is enlived'); + done(); + }); }); })(); diff --git a/test/unit/polygon.js b/test/unit/polygon.js index e1510f46d2e..7dc3b224a10 100644 --- a/test/unit/polygon.js +++ b/test/unit/polygon.js @@ -111,7 +111,7 @@ QUnit.test('fromObject', function(assert) { var done = assert.async(); assert.ok(typeof fabric.Polygon.fromObject === 'function'); - fabric.Polygon.fromObject(REFERENCE_OBJECT, function(polygon) { + fabric.Polygon.fromObject(REFERENCE_OBJECT).then(function(polygon) { assert.ok(polygon instanceof fabric.Polygon); assert.deepEqual(polygon.toObject(), REFERENCE_OBJECT); done(); diff --git a/test/unit/polyline.js b/test/unit/polyline.js index 2843509e8d4..118fe2e56f1 100644 --- a/test/unit/polyline.js +++ b/test/unit/polyline.js @@ -89,7 +89,7 @@ QUnit.test('fromObject', function(assert) { var done = assert.async(); assert.ok(typeof fabric.Polyline.fromObject === 'function'); - fabric.Polyline.fromObject(REFERENCE_OBJECT, function(polyline) { + fabric.Polyline.fromObject(REFERENCE_OBJECT).then(function(polyline) { assert.ok(polyline instanceof fabric.Polyline); assert.deepEqual(polyline.toObject(), REFERENCE_OBJECT); done(); diff --git a/test/unit/rect.js b/test/unit/rect.js index dc96f6fc3c6..87761b8ded6 100644 --- a/test/unit/rect.js +++ b/test/unit/rect.js @@ -74,14 +74,14 @@ var done = assert.async(); assert.ok(typeof fabric.Rect.fromObject === 'function'); - fabric.Rect.fromObject(REFERENCE_RECT, function(rect) { + return fabric.Rect.fromObject(REFERENCE_RECT).then(function(rect) { assert.ok(rect instanceof fabric.Rect); assert.deepEqual(rect.toObject(), REFERENCE_RECT); var expectedObject = fabric.util.object.extend({ }, REFERENCE_RECT); expectedObject.fill = {type: 'linear',coords: {x1: 0,y1: 0,x2: 200,y2: 0},colorStops: [{offset: '0',color: 'rgb(255,0,0)',opacity: 1},{offset: '1',color: 'rgb(0,0,255)',opacity: 1}],offsetX: 0,offsetY: 0}; expectedObject.stroke = {type: 'linear',coords: {x1: 0,y1: 0,x2: 200,y2: 0},colorStops: [{offset: '0',color: 'rgb(255,0,0)',opacity: 1},{offset: '1',color: 'rgb(0,0,255)',opacity: 1}],offsetX: 0,offsetY: 0}; - fabric.Rect.fromObject(expectedObject, function(rect2) { + return fabric.Rect.fromObject(expectedObject).then(function(rect2) { assert.ok(rect2.fill instanceof fabric.Gradient); assert.ok(rect2.stroke instanceof fabric.Gradient); done(); @@ -95,7 +95,7 @@ type: 'pattern', source: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z/C/HgAGgwJ/lK3Q6wAAAABJRU5ErkJggg==' }; - fabric.Rect.fromObject({ fill: fillObj }, function(rect) { + fabric.Rect.fromObject({ fill: fillObj }).then(function(rect) { assert.ok(rect.fill instanceof fabric.Pattern); done(); }); @@ -164,10 +164,12 @@ }); QUnit.test('clone with rounded corners', function(assert) { + var done = assert.async(); var rect = new fabric.Rect({ width: 100, height: 100, rx: 20, ry: 30 }); - rect.clone(function(clone) { + rect.clone().then(function(clone) { assert.equal(clone.get('rx'), rect.get('rx')); assert.equal(clone.get('ry'), rect.get('ry')); + done(); }); }); diff --git a/test/unit/text.js b/test/unit/text.js index cbd956e5cd6..8df477ff256 100644 --- a/test/unit/text.js +++ b/test/unit/text.js @@ -187,7 +187,7 @@ QUnit.test('fabric.Text.fromObject', function(assert) { var done = assert.async(); assert.ok(typeof fabric.Text.fromObject === 'function'); - fabric.Text.fromObject(REFERENCE_TEXT_OBJECT, function(text) { + fabric.Text.fromObject(REFERENCE_TEXT_OBJECT).then(function(text) { assert.deepEqual(text.toObject(), REFERENCE_TEXT_OBJECT); done(); }); @@ -860,7 +860,7 @@ path: new fabric.Path('M0 0 h 100 v 100 h -100 z') }); var toObject = text.toObject(); - fabric.Text.fromObject(toObject, function(text) { + fabric.Text.fromObject(toObject).then(function(text) { assert.equal(text.path.type, 'path', 'the path is restored'); assert.ok(text.path instanceof fabric.Path, 'the path is a path'); assert.ok(toObject.path, 'the input has still a path property'); diff --git a/test/unit/textbox.js b/test/unit/textbox.js index e47522b19b7..90f8ff75461 100644 --- a/test/unit/textbox.js +++ b/test/unit/textbox.js @@ -93,7 +93,7 @@ QUnit.test('fromObject', function(assert) { var done = assert.async(); - fabric.Textbox.fromObject(TEXTBOX_OBJECT, function(textbox) { + fabric.Textbox.fromObject(TEXTBOX_OBJECT).then(function(textbox) { assert.equal(textbox.text, 'x', 'properties are respected'); assert.ok(textbox instanceof fabric.Textbox, 'the generated object is a textbox'); done(); diff --git a/test/unit/util.js b/test/unit/util.js index c7006e787fa..a1d0a52889b 100644 --- a/test/unit/util.js +++ b/test/unit/util.js @@ -444,11 +444,10 @@ return; } - fabric.util.loadImage(IMG_URL, function(obj, isError) { + fabric.util.loadImage(IMG_URL).then(function(obj) { if (obj) { var oImg = new fabric.Image(obj); assert.ok(/fixtures\/very_large_image\.jpg$/.test(oImg.getSrc()), 'image should have correct src'); - assert.ok(!isError); } done(); }); @@ -463,7 +462,7 @@ return; } - fabric.util.loadImage('', function() { + fabric.util.loadImage('').then(function() { assert.ok(1, 'callback should be invoked'); done(); }); @@ -478,12 +477,12 @@ return; } try { - fabric.util.loadImage(IMG_URL, function(img, isError) { + fabric.util.loadImage(IMG_URL, { crossOrigin: 'anonymous' }).then(function(img, isError) { assert.equal(basename(img.src), basename(IMG_URL), 'src is set'); assert.equal(img.crossOrigin, 'anonymous', 'crossOrigin is set'); assert.ok(!isError); done(); - }, null, 'anonymous'); + }); } catch (e) { console.log(e); @@ -493,13 +492,10 @@ QUnit.test('fabric.util.loadImage with url for a non exsiting image', function(assert) { var done = assert.async(); - try { - fabric.util.loadImage(IMG_URL_NON_EXISTING, function(img, error) { - assert.equal(error, true, 'callback should be invoked with error set to true'); - done(); - }, this); - } - catch (e) { } + fabric.util.loadImage(IMG_URL_NON_EXISTING).catch(function(err) { + assert.ok(err instanceof Error, 'callback should be invoked with error set to true'); + done(); + }); }); var SVG_WITH_1_ELEMENT = '\ @@ -974,13 +970,6 @@ 'stop attribs'); }); - QUnit.test('fabric.util.enlivenPatterns', function(assert) { - assert.ok(typeof fabric.util.enlivenPatterns === 'function'); - fabric.util.enlivenPatterns([], function() { - assert.ok(true, 'callBack is called when no patterns are available'); - }); - }); - QUnit.test('fabric.util.copyCanvasElement', function(assert) { assert.ok(typeof fabric.util.copyCanvasElement === 'function'); var c = fabric.util.createCanvasElement(); diff --git a/test/visual/clippath.js b/test/visual/clippath.js index e29262dd12d..2de265d2912 100644 --- a/test/visual/clippath.js +++ b/test/visual/clippath.js @@ -314,7 +314,7 @@ function clipping10(canvas, callback) { var jsonData = '{"version":"2.4.5","objects":[{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":12.844238038518533,"top":75.97237569060775,"width":50.4,"height":25.4,"fill":"#b8d783","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":2.07,"scaleY":2.07,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"clipPath":{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":-31.1,"top":-48.7,"width":61.2,"height":61.2,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"radius":30.6,"startAngle":0,"endAngle":360,"inverted":false,"absolutePositioned":false},"path":[["M",31.8,36.8],["c",-10.7,0,-25.2,6.8,-25.1,25.4],["L",57.1,62],["C",57.1,43.5,42.6,36.8,31.8,36.8],["z"]]},{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":38.95,"top":28.53,"width":25.6,"height":25.6,"fill":"#d7b047","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":2.07,"scaleY":2.07,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"clipPath":{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":-31.3,"top":-25.9,"width":61.2,"height":61.2,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"radius":30.6,"startAngle":0,"endAngle":360,"inverted":false,"absolutePositioned":false},"radius":12.8,"startAngle":0,"endAngle":360},{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":0.1,"top":2.87,"width":61.2,"height":61.2,"fill":"transparent","stroke":"#567bde","strokeWidth":2.5,"strokeDashArray":null,"strokeLineCap":"round","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":2.06,"scaleY":2.06,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"radius":30.6,"startAngle":0,"endAngle":360}]}'; - canvas.loadFromJSON(jsonData, function() { + canvas.loadFromJSON(jsonData).then(function() { canvas.renderAll(); callback(canvas.lowerCanvasEl); }); @@ -329,7 +329,7 @@ function clipping11(canvas, callback) { var jsonData = '{"version":"2.4.5","objects":[{"type":"group","version":"2.4.5","originX":"left","originY":"top","left":-1,"top":0,"width":400,"height":400,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"objects":[{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":-618.26087,"top":-618.26087,"width":600,"height":600,"fill":"#396","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.73913,"scaleY":1.73913,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"clipPath":{"type":"group","version":"2.4.5","originX":"left","originY":"top","left":-50.026294,"top":-16.249678,"width":318.906599,"height":295.383789,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":0.575,"scaleY":0.575,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"objects":[{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-125.590179,"top":-145.137671,"width":148,"height":146,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":393.45,"y":318.29},{"x":316.95,"y":259.79}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-4.528975,"width":78.96,"height":78.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":234.99,"y":339.36},{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":303.49,"y":411.86}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-145.137671,"width":81.96,"height":79.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":305.6,"y":264.97},{"x":316.95,"y":259.79},{"x":245.45,"y":333.29},{"x":234.99,"y":339.36}]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-152.94670044656436,"top":-106.34114919417823,"width":29.46,"height":35.71,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",231.15,283.42],["c",1.18,2.07,2.56,4.26,4.14,6.57],["l",10.62,13.65],["c",3.39,3.94,7.17,8.01,11.29,12.14],["l",3.41,-3.41],["c",0,0,-16.5,-17.25,-26.11,-32.3],["L",231.15,283.42],["z"]]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-159.45329955343573,"top":-147.691894284083,"width":68.811177,"height":29.095162,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",229.7,259.54],["c",-1.9,1.43,-2.31,3.86,-1.67,6.91],["l",0.08,0.15],["c",3.5,-2.53,11.03,-1.57,19.8,0.98],["h",0],["l",0,0],["c",20.02,5.83,46.53,19.97,46.53,19.97],["l",2.12,-3.62],["C",267.45,266.79,236.17,254.67,229.7,259.54],["z"]]}],"inverted":false,"absolutePositioned":false},"radius":300,"startAngle":0,"endAngle":360},{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":-148.695652,"top":-148.695652,"width":660,"height":660,"fill":"#900","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.73913,"scaleY":1.73913,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"clipPath":{"type":"group","version":"2.4.5","originX":"left","originY":"top","left":-350.026294,"top":-316.249678,"width":318.906599,"height":295.383789,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":0.575,"scaleY":0.575,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"objects":[{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-125.590179,"top":-145.137671,"width":148,"height":146,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":393.45,"y":318.29},{"x":316.95,"y":259.79}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-4.528975,"width":78.96,"height":78.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":234.99,"y":339.36},{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":303.49,"y":411.86}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-145.137671,"width":81.96,"height":79.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":305.6,"y":264.97},{"x":316.95,"y":259.79},{"x":245.45,"y":333.29},{"x":234.99,"y":339.36}]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-152.94670044656436,"top":-106.34114919417823,"width":29.46,"height":35.71,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",231.15,283.42],["c",1.18,2.07,2.56,4.26,4.14,6.57],["l",10.62,13.65],["c",3.39,3.94,7.17,8.01,11.29,12.14],["l",3.41,-3.41],["c",0,0,-16.5,-17.25,-26.11,-32.3],["L",231.15,283.42],["z"]]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-159.45329955343573,"top":-147.691894284083,"width":68.811177,"height":29.095162,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",229.7,259.54],["c",-1.9,1.43,-2.31,3.86,-1.67,6.91],["l",0.08,0.15],["c",3.5,-2.53,11.03,-1.57,19.8,0.98],["h",0],["l",0,0],["c",20.02,5.83,46.53,19.97,46.53,19.97],["l",2.12,-3.62],["C",267.45,266.79,236.17,254.67,229.7,259.54],["z"]]}],"inverted":false,"absolutePositioned":false},"radius":330,"startAngle":0,"endAngle":360},{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":-183.478261,"top":-1070.434783,"width":700,"height":700,"fill":"#009","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.73913,"scaleY":1.73913,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"clipPath":{"type":"group","version":"2.4.5","originX":"left","originY":"top","left":-350.026294,"top":193.750322,"width":318.906599,"height":295.383789,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":0.575,"scaleY":0.575,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"objects":[{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-125.590179,"top":-145.137671,"width":148,"height":146,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":393.45,"y":318.29},{"x":316.95,"y":259.79}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-4.528975,"width":78.96,"height":78.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":234.99,"y":339.36},{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":303.49,"y":411.86}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-145.137671,"width":81.96,"height":79.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":305.6,"y":264.97},{"x":316.95,"y":259.79},{"x":245.45,"y":333.29},{"x":234.99,"y":339.36}]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-152.94670044656436,"top":-106.34114919417823,"width":29.46,"height":35.71,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",231.15,283.42],["c",1.18,2.07,2.56,4.26,4.14,6.57],["l",10.62,13.65],["c",3.39,3.94,7.17,8.01,11.29,12.14],["l",3.41,-3.41],["c",0,0,-16.5,-17.25,-26.11,-32.3],["L",231.15,283.42],["z"]]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-159.45329955343573,"top":-147.691894284083,"width":68.811177,"height":29.095162,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",229.7,259.54],["c",-1.9,1.43,-2.31,3.86,-1.67,6.91],["l",0.08,0.15],["c",3.5,-2.53,11.03,-1.57,19.8,0.98],["h",0],["l",0,0],["c",20.02,5.83,46.53,19.97,46.53,19.97],["l",2.12,-3.62],["C",267.45,266.79,236.17,254.67,229.7,259.54],["z"]]}],"inverted":false,"absolutePositioned":false},"radius":350,"startAngle":0,"endAngle":360}]}]}'; - canvas.loadFromJSON(jsonData, function() { + canvas.loadFromJSON(jsonData).then(function() { canvas.renderAll(); callback(canvas.lowerCanvasEl); }); diff --git a/test/visual/control_rendering.js b/test/visual/control_rendering.js index bc4e97fbc8f..6d4836f84f8 100644 --- a/test/visual/control_rendering.js +++ b/test/visual/control_rendering.js @@ -285,8 +285,8 @@ }); function controlBoxes(canvas, callback) { - canvas.loadFromJSON('{"version":"4.6.0","objects":[{"type":"rect","version":"4.6.0","left":38,"top":201,"width":150,"height":150,"fill":"red","skewX":0.15,"skewY":36},{"type":"rect","version":"4.6.0","left":20,"top":2,"width":150,"height":150,"fill":"#020aed","scaleX":1.24,"scaleY":0.81,"angle":35.95,"skewX":25.46},{"type":"group","version":"4.6.0","left":60.65,"top":28,"width":320.4,"height":335.5,"objects":[{"type":"rect","version":"4.6.0","left":-29.85,"top":-167.75,"width":150,"height":150,"fill":"green","angle":30,"skewX":14.71,"skewY":36},{"type":"rect","version":"4.6.0","left":-29.85,"top":-167.75,"width":150,"height":150,"fill":"yellow","angle":45,"skewX":14.71}]}]}', - function() { + canvas.loadFromJSON('{"version":"4.6.0","objects":[{"type":"rect","version":"4.6.0","left":38,"top":201,"width":150,"height":150,"fill":"red","skewX":0.15,"skewY":36},{"type":"rect","version":"4.6.0","left":20,"top":2,"width":150,"height":150,"fill":"#020aed","scaleX":1.24,"scaleY":0.81,"angle":35.95,"skewX":25.46},{"type":"group","version":"4.6.0","left":60.65,"top":28,"width":320.4,"height":335.5,"objects":[{"type":"rect","version":"4.6.0","left":-29.85,"top":-167.75,"width":150,"height":150,"fill":"green","angle":30,"skewX":14.71,"skewY":36},{"type":"rect","version":"4.6.0","left":-29.85,"top":-167.75,"width":150,"height":150,"fill":"yellow","angle":45,"skewX":14.71}]}]}') + .then(function() { canvas.renderAll(); canvas.getObjects().forEach(function(object) { object.borderScaleFactor = 3; diff --git a/test/visual/text.js b/test/visual/text.js index 2f4781242a8..5ac5b3ef485 100644 --- a/test/visual/text.js +++ b/test/visual/text.js @@ -450,12 +450,12 @@ function text12(canvas, callback) { fabric.Text.fromObject( - JSON.parse('{"type":"i-text","version":"4.4.0","left":1.28,"top":0.19,"width":740.57,"height":150.06,"fill":"#e38644","scaleX":0.48,"scaleY":0.48,"angle":0.2,"text":"השועל החום והזריז קופץ מעל הכלב העצלן\\nהשועל החום והזר33יז קופץ מעל הכל העצלן\\nשלום עולם","fontWeight":"","fontFamily":"Arial","textAlign":"right","textBackgroundColor":"#d72323","direction":"rtl","styles":{"0":{"6":{"fill":"red"},"7":{"fill":"red"},"8":{"fill":"red","linethrough":true},"9":{"fill":"red","linethrough":true},"10":{"linethrough":true,"textBackgroundColor":"red"},"11":{"linethrough":true,"textBackgroundColor":"green"},"12":{"linethrough":true},"13":{"linethrough":true}},"1":{"8":{"underline":true},"9":{"underline":true},"10":{"underline":true},"11":{"underline":true},"12":{"underline":true},"13":{"underline":true,"fontSize":22},"14":{"underline":true,"fontSize":22},"15":{"underline":true,"fontSize":22},"16":{"underline":true,"fontSize":22},"17":{"fontSize":22},"18":{"fontSize":22},"19":{"fontSize":22},"20":{"fontSize":22},"21":{"fontSize":22},"22":{"fontSize":22,"textBackgroundColor":"blue"}}},"path":null}'), - function(text) { - canvas.add(text); - canvas.renderAll(); - callback(canvas.lowerCanvasEl); - }); + JSON.parse('{"type":"i-text","version":"4.4.0","left":1.28,"top":0.19,"width":740.57,"height":150.06,"fill":"#e38644","scaleX":0.48,"scaleY":0.48,"angle":0.2,"text":"השועל החום והזריז קופץ מעל הכלב העצלן\\nהשועל החום והזר33יז קופץ מעל הכל העצלן\\nשלום עולם","fontWeight":"","fontFamily":"Arial","textAlign":"right","textBackgroundColor":"#d72323","direction":"rtl","styles":{"0":{"6":{"fill":"red"},"7":{"fill":"red"},"8":{"fill":"red","linethrough":true},"9":{"fill":"red","linethrough":true},"10":{"linethrough":true,"textBackgroundColor":"red"},"11":{"linethrough":true,"textBackgroundColor":"green"},"12":{"linethrough":true},"13":{"linethrough":true}},"1":{"8":{"underline":true},"9":{"underline":true},"10":{"underline":true},"11":{"underline":true},"12":{"underline":true},"13":{"underline":true,"fontSize":22},"14":{"underline":true,"fontSize":22},"15":{"underline":true,"fontSize":22},"16":{"underline":true,"fontSize":22},"17":{"fontSize":22},"18":{"fontSize":22},"19":{"fontSize":22},"20":{"fontSize":22},"21":{"fontSize":22},"22":{"fontSize":22,"textBackgroundColor":"blue"}}},"path":null}') + ).then(function(text) { + canvas.add(text); + canvas.renderAll(); + callback(canvas.lowerCanvasEl); + }); } tests.push({ @@ -470,13 +470,12 @@ function text13(canvas, callback) { fabric.Textbox.fromObject( - JSON.parse('{"type":"textbox","version":"4.5.0","left":0.94,"top":0.46,"width":231.02,"height":254.93,"scaleX":0.9,"scaleY":0.9,"angle":0.19,"text":"اگر شما یک طراح هستین و یا با طراحی های گرافیکی سروکار دارید.","fontFamily":"Arial","underline":true,"linethrough":true,"textAlign":"right","direction":"rtl","minWidth":20,"splitByGrapheme":false,"styles":{},"path":null}'), - function(text) { - canvas.add(text); - canvas.renderAll(); - callback(canvas.lowerCanvasEl); - } - ); + JSON.parse('{"type":"textbox","version":"4.5.0","left":0.94,"top":0.46,"width":231.02,"height":254.93,"scaleX":0.9,"scaleY":0.9,"angle":0.19,"text":"اگر شما یک طراح هستین و یا با طراحی های گرافیکی سروکار دارید.","fontFamily":"Arial","underline":true,"linethrough":true,"textAlign":"right","direction":"rtl","minWidth":20,"splitByGrapheme":false,"styles":{},"path":null}') + ).then(function(text) { + canvas.add(text); + canvas.renderAll(); + callback(canvas.lowerCanvasEl); + }); } tests.push({ diff --git a/test/visual/text_path.js b/test/visual/text_path.js index 13e37cde2fe..43d54218465 100644 --- a/test/visual/text_path.js +++ b/test/visual/text_path.js @@ -109,10 +109,11 @@ }); function textpath5(canvas, callback) { - canvas.loadFromJSON('{"version":"4.5.1","objects":[{"type":"path","version":"4.5.1","left":213,"top":163,"width":180,"height":180,"fill":"","stroke":"red","strokeWidth":2,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},{"type":"path","version":"4.5.1","left":200,"top":6,"width":180,"height":180,"fill":"","stroke":"red","strokeWidth":2,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},{"type":"path","version":"4.5.1","left":18,"top":164,"width":180,"height":180,"fill":"","stroke":"red","strokeWidth":2,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},{"type":"path","version":"4.5.1","left":9,"top":14,"width":180,"height":180,"fill":"","stroke":"red","strokeWidth":2,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},{"type":"text","version":"4.5.1","left":10,"top":14,"width":180,"height":180,"text":"Text on a swirl textAlign right","fontSize":28,"textAlign":"right","charSpacing":50,"path":{"type":"path","version":"4.5.1","originX":"left","originY":"top","left":-0.5,"top":-180.5,"width":180,"height":180,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":false,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},"direction":"ltr","styles":{}},{"type":"text","version":"4.5.1","left":15,"top":165,"width":180,"height":180,"text":"Text on a swirl textAlign left","fontSize":28,"charSpacing":50,"path":{"type":"path","version":"4.5.1","originX":"left","originY":"top","left":-0.5,"top":-180.5,"width":180,"height":180,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":false,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},"direction":"ltr","styles":{}},{"type":"text","version":"4.5.1","left":201,"top":9,"width":180,"height":180,"text":"Text on a swirl textAlign center","fontSize":28,"textAlign":"center","charSpacing":50,"path":{"type":"path","version":"4.5.1","originX":"left","originY":"top","left":-0.5,"top":-180.5,"width":180,"height":180,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":false,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},"direction":"ltr","styles":{}},{"type":"text","version":"4.5.1","left":213,"top":164,"width":180,"height":180,"text":"full text to understand better a Text on a swirl textAlign","fontSize":28,"charSpacing":50,"path":{"type":"path","version":"4.5.1","originX":"left","originY":"top","left":-0.5,"top":-180.5,"width":180,"height":180,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":false,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},"direction":"ltr","styles":{}}]}', function() { - canvas.renderAll(); - callback(canvas.lowerCanvasEl); - }); + canvas.loadFromJSON('{"version":"4.5.1","objects":[{"type":"path","version":"4.5.1","left":213,"top":163,"width":180,"height":180,"fill":"","stroke":"red","strokeWidth":2,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},{"type":"path","version":"4.5.1","left":200,"top":6,"width":180,"height":180,"fill":"","stroke":"red","strokeWidth":2,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},{"type":"path","version":"4.5.1","left":18,"top":164,"width":180,"height":180,"fill":"","stroke":"red","strokeWidth":2,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},{"type":"path","version":"4.5.1","left":9,"top":14,"width":180,"height":180,"fill":"","stroke":"red","strokeWidth":2,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},{"type":"text","version":"4.5.1","left":10,"top":14,"width":180,"height":180,"text":"Text on a swirl textAlign right","fontSize":28,"textAlign":"right","charSpacing":50,"path":{"type":"path","version":"4.5.1","originX":"left","originY":"top","left":-0.5,"top":-180.5,"width":180,"height":180,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":false,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},"direction":"ltr","styles":{}},{"type":"text","version":"4.5.1","left":15,"top":165,"width":180,"height":180,"text":"Text on a swirl textAlign left","fontSize":28,"charSpacing":50,"path":{"type":"path","version":"4.5.1","originX":"left","originY":"top","left":-0.5,"top":-180.5,"width":180,"height":180,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":false,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},"direction":"ltr","styles":{}},{"type":"text","version":"4.5.1","left":201,"top":9,"width":180,"height":180,"text":"Text on a swirl textAlign center","fontSize":28,"textAlign":"center","charSpacing":50,"path":{"type":"path","version":"4.5.1","originX":"left","originY":"top","left":-0.5,"top":-180.5,"width":180,"height":180,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":false,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},"direction":"ltr","styles":{}},{"type":"text","version":"4.5.1","left":213,"top":164,"width":180,"height":180,"text":"full text to understand better a Text on a swirl textAlign","fontSize":28,"charSpacing":50,"path":{"type":"path","version":"4.5.1","originX":"left","originY":"top","left":-0.5,"top":-180.5,"width":180,"height":180,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":false,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",0,0],["Q",180,0,180,-101.25],["Q",180,-180,90,-180],["Q",0,-180,0,-112.5],["Q",0,-45,78.75,-45],["Q",135,-45,146.25,-90]]},"direction":"ltr","styles":{}}]}') + .then(function() { + canvas.renderAll(); + callback(canvas.lowerCanvasEl); + }); } tests.push({ diff --git a/test/visual/toDataURL.js b/test/visual/toDataURL.js index e1f11d52a40..24fcd8668ad 100644 --- a/test/visual/toDataURL.js +++ b/test/visual/toDataURL.js @@ -113,7 +113,7 @@ }); // function toDataURL4(fabricCanvas, callback) { - fabricCanvas.loadFromJSON(canvasWithObjects, function() { + fabricCanvas.loadFromJSON(canvasWithObjects).then(function() { var dataUrl = fabricCanvas.toDataURL(); callback(dataUrl); }); @@ -129,7 +129,7 @@ }); function toDataURL5(fabricCanvas, callback) { - fabricCanvas.loadFromJSON(canvasWithObjects, function() { + fabricCanvas.loadFromJSON(canvasWithObjects).then(function() { var dataurl = fabricCanvas.toDataURL({ multiplier: 0.3 }); callback(dataurl); }); @@ -147,7 +147,7 @@ function toDataURL6(fabricCanvas, callback) { // make so everything is smaller fabricCanvas.setZoom(0.1); - fabricCanvas.loadFromJSON(canvasWithObjects, function() { + fabricCanvas.loadFromJSON(canvasWithObjects).then(function() { var dataUrl = fabricCanvas.toDataURL({ multiplier: 4 }); callback(dataUrl); }); @@ -165,7 +165,7 @@ function toDataURL7(fabricCanvas, callback) { // make so everything is smaller fabricCanvas.setZoom(0.1); - fabricCanvas.loadFromJSON(canvasWithObjects, function() { + fabricCanvas.loadFromJSON(canvasWithObjects).then(function() { var dataUrl = fabricCanvas.toDataURL({ multiplier: 12, left: 20, top: 20, width: 20, height: 20 }); callback(dataUrl); }); @@ -182,7 +182,7 @@ function toDataURL8(fabricCanvas, callback) { // make so everything is smaller - fabricCanvas.loadFromJSON(canvasWithObjects, function() { + fabricCanvas.loadFromJSON(canvasWithObjects).then(function() { var dataUrl = fabricCanvas.toDataURL({ multiplier: 1.2, left: 200, top: 200, width: 200, height: 200 }); callback(dataUrl); }); @@ -201,7 +201,7 @@ function toDataURL9(fabricCanvas, callback) { // make so everything is smaller fabricCanvas.setZoom(3); - fabricCanvas.loadFromJSON(canvasWithObjects, function() { + fabricCanvas.loadFromJSON(canvasWithObjects).then(function() { var dataUrl = fabricCanvas.toDataURL({ multiplier: 0.4, left: 600, top: 600, width: 600, height: 600 }); callback(dataUrl); }); diff --git a/test/visual/z_svg_export.js b/test/visual/z_svg_export.js index 91ca350fbf7..cd9bc3eddc9 100644 --- a/test/visual/z_svg_export.js +++ b/test/visual/z_svg_export.js @@ -324,7 +324,7 @@ function clipping10(canvas, callback) { var jsonData = '{"version":"2.4.5","objects":[{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":12.844238038518533,"top":75.97237569060775,"width":50.4,"height":25.4,"fill":"#b8d783","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":2.07,"scaleY":2.07,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"clipPath":{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":-31.1,"top":-48.7,"width":61.2,"height":61.2,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"radius":30.6,"startAngle":0,"endAngle":360,"inverted":false,"absolutePositioned":false},"path":[["M",31.8,36.8],["c",-10.7,0,-25.2,6.8,-25.1,25.4],["L",57.1,62],["C",57.1,43.5,42.6,36.8,31.8,36.8],["z"]]},{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":38.95,"top":28.53,"width":25.6,"height":25.6,"fill":"#d7b047","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":2.07,"scaleY":2.07,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"clipPath":{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":-31.3,"top":-25.9,"width":61.2,"height":61.2,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"radius":30.6,"startAngle":0,"endAngle":360,"inverted":false,"absolutePositioned":false},"radius":12.8,"startAngle":0,"endAngle":360},{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":0.1,"top":2.87,"width":61.2,"height":61.2,"fill":"transparent","stroke":"#567bde","strokeWidth":2.5,"strokeDashArray":null,"strokeLineCap":"round","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":10,"scaleX":2.06,"scaleY":2.06,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"radius":30.6,"startAngle":0,"endAngle":360}]}'; - canvas.loadFromJSON(jsonData, function() { + canvas.loadFromJSON(jsonData).then(function() { toSVGCanvas(canvas, callback); }); } @@ -338,7 +338,7 @@ function clipping11(canvas, callback) { var jsonData = '{"version":"2.4.5","objects":[{"type":"group","version":"2.4.5","originX":"left","originY":"top","left":-1,"top":0,"width":400,"height":400,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"objects":[{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":-618.26087,"top":-618.26087,"width":600,"height":600,"fill":"#396","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.73913,"scaleY":1.73913,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"clipPath":{"type":"group","version":"2.4.5","originX":"left","originY":"top","left":-50.026294,"top":-16.249678,"width":318.906599,"height":295.383789,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":0.575,"scaleY":0.575,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"objects":[{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-125.590179,"top":-145.137671,"width":148,"height":146,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":393.45,"y":318.29},{"x":316.95,"y":259.79}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-4.528975,"width":78.96,"height":78.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":234.99,"y":339.36},{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":303.49,"y":411.86}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-145.137671,"width":81.96,"height":79.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":305.6,"y":264.97},{"x":316.95,"y":259.79},{"x":245.45,"y":333.29},{"x":234.99,"y":339.36}]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-152.94670044656436,"top":-106.34114919417823,"width":29.46,"height":35.71,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",231.15,283.42],["c",1.18,2.07,2.56,4.26,4.14,6.57],["l",10.62,13.65],["c",3.39,3.94,7.17,8.01,11.29,12.14],["l",3.41,-3.41],["c",0,0,-16.5,-17.25,-26.11,-32.3],["L",231.15,283.42],["z"]]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-159.45329955343573,"top":-147.691894284083,"width":68.811177,"height":29.095162,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",229.7,259.54],["c",-1.9,1.43,-2.31,3.86,-1.67,6.91],["l",0.08,0.15],["c",3.5,-2.53,11.03,-1.57,19.8,0.98],["h",0],["l",0,0],["c",20.02,5.83,46.53,19.97,46.53,19.97],["l",2.12,-3.62],["C",267.45,266.79,236.17,254.67,229.7,259.54],["z"]]}],"inverted":false,"absolutePositioned":false},"radius":300,"startAngle":0,"endAngle":360},{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":-148.695652,"top":-148.695652,"width":660,"height":660,"fill":"#900","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.73913,"scaleY":1.73913,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"clipPath":{"type":"group","version":"2.4.5","originX":"left","originY":"top","left":-350.026294,"top":-316.249678,"width":318.906599,"height":295.383789,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":0.575,"scaleY":0.575,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"objects":[{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-125.590179,"top":-145.137671,"width":148,"height":146,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":393.45,"y":318.29},{"x":316.95,"y":259.79}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-4.528975,"width":78.96,"height":78.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":234.99,"y":339.36},{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":303.49,"y":411.86}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-145.137671,"width":81.96,"height":79.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":305.6,"y":264.97},{"x":316.95,"y":259.79},{"x":245.45,"y":333.29},{"x":234.99,"y":339.36}]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-152.94670044656436,"top":-106.34114919417823,"width":29.46,"height":35.71,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",231.15,283.42],["c",1.18,2.07,2.56,4.26,4.14,6.57],["l",10.62,13.65],["c",3.39,3.94,7.17,8.01,11.29,12.14],["l",3.41,-3.41],["c",0,0,-16.5,-17.25,-26.11,-32.3],["L",231.15,283.42],["z"]]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-159.45329955343573,"top":-147.691894284083,"width":68.811177,"height":29.095162,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",229.7,259.54],["c",-1.9,1.43,-2.31,3.86,-1.67,6.91],["l",0.08,0.15],["c",3.5,-2.53,11.03,-1.57,19.8,0.98],["h",0],["l",0,0],["c",20.02,5.83,46.53,19.97,46.53,19.97],["l",2.12,-3.62],["C",267.45,266.79,236.17,254.67,229.7,259.54],["z"]]}],"inverted":false,"absolutePositioned":false},"radius":330,"startAngle":0,"endAngle":360},{"type":"circle","version":"2.4.5","originX":"left","originY":"top","left":-183.478261,"top":-1070.434783,"width":700,"height":700,"fill":"#009","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.73913,"scaleY":1.73913,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"clipPath":{"type":"group","version":"2.4.5","originX":"left","originY":"top","left":-350.026294,"top":193.750322,"width":318.906599,"height":295.383789,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":0.575,"scaleY":0.575,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"objects":[{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-125.590179,"top":-145.137671,"width":148,"height":146,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":393.45,"y":318.29},{"x":316.95,"y":259.79}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-4.528975,"width":78.96,"height":78.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":234.99,"y":339.36},{"x":245.45,"y":333.29},{"x":313.95,"y":405.79},{"x":303.49,"y":411.86}]},{"type":"polygon","version":"2.4.5","originX":"left","originY":"top","left":-145.600613,"top":-145.137671,"width":81.96,"height":79.57,"fill":"#8E8029","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"points":[{"x":305.6,"y":264.97},{"x":316.95,"y":259.79},{"x":245.45,"y":333.29},{"x":234.99,"y":339.36}]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-152.94670044656436,"top":-106.34114919417823,"width":29.46,"height":35.71,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",231.15,283.42],["c",1.18,2.07,2.56,4.26,4.14,6.57],["l",10.62,13.65],["c",3.39,3.94,7.17,8.01,11.29,12.14],["l",3.41,-3.41],["c",0,0,-16.5,-17.25,-26.11,-32.3],["L",231.15,283.42],["z"]]},{"type":"path","version":"2.4.5","originX":"left","originY":"top","left":-159.45329955343573,"top":-147.691894284083,"width":68.811177,"height":29.095162,"fill":"#D8CB3F","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1.913043,"scaleY":1.913043,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"path":[["M",229.7,259.54],["c",-1.9,1.43,-2.31,3.86,-1.67,6.91],["l",0.08,0.15],["c",3.5,-2.53,11.03,-1.57,19.8,0.98],["h",0],["l",0,0],["c",20.02,5.83,46.53,19.97,46.53,19.97],["l",2.12,-3.62],["C",267.45,266.79,236.17,254.67,229.7,259.54],["z"]]}],"inverted":false,"absolutePositioned":false},"radius":350,"startAngle":0,"endAngle":360}]}]}'; - canvas.loadFromJSON(jsonData, function() { + canvas.loadFromJSON(jsonData).then(function() { toSVGCanvas(canvas, callback); }); } @@ -354,7 +354,7 @@ function clipping12(canvas, callback) { var jsonData = '{"version":"2.4.6","objects":[{"type":"ellipse","version":"2.4.6","left":2.5,"top":-56.5,"width":220,"height":300,"fill":{"type":"radial","coords":{"x1":110.00000000000001,"y1":110.00000000000001,"x2":110.00000000000001,"y2":110.00000000000001,"r1":0,"r2":110.00000000000001},"colorStops":[{"offset":1,"color":"rgb(0,0,255)","opacity":1},{"offset":0.6,"color":"rgb(0,153,153)","opacity":0.5},{"offset":0.3,"color":"rgb(0,0,255)","opacity":1},{"offset":0,"color":"rgb(255,0,0)","opacity":0.8}],"offsetX":0,"offsetY":0,"gradientTransform":[1,0,0,1.3636363636363635,0,0]},"scaleX":0.69,"scaleY":1.07,"skewY":-32.03,"rx":110,"ry":150}]}'; - canvas.loadFromJSON(jsonData, function() { + canvas.loadFromJSON(jsonData).then(function() { toSVGCanvas(canvas, callback); }); } @@ -370,7 +370,7 @@ function clipping13(canvas, callback) { var jsonData = '{"version":"2.4.6","objects":[{"type":"path","version":"2.4.6","left":84.63385601266276,"top":385.11623376730074,"width":3.14,"height":10.44,"fill":{"type":"linear","coords":{"x1":481.066,"y1":785.465,"x2":480.953,"y2":793.102},"colorStops":[{"offset":1,"color":"rgb(160,137,44)","opacity":1},{"offset":0.9,"color":"rgb(85,68,0)","opacity":1},{"offset":0.78,"color":"rgb(80,68,22)","opacity":1},{"offset":0.607,"color":"rgb(160,137,44)","opacity":1},{"offset":0.467,"color":"rgb(255,255,255)","opacity":1},{"offset":0.299,"color":"rgb(200,171,55)","opacity":1},{"offset":0.24,"color":"rgb(160,137,44)","opacity":1},{"offset":0.096,"color":"rgb(120,103,33)","opacity":1},{"offset":0,"color":"rgb(211,188,95)","opacity":1}],"offsetX":-439.1113425994523,"offsetY":-783.951,"gradientTransform":[-1,0,0,1,921.58,0]},"scaleX":9.32,"scaleY":10.58,"angle":-90,"path":[["M",442.142,794.394],["l",-2.583,-1.46],["c",-0.644,-2.39,-0.512,-5.004,-0.113,-7.693],["l",2.808,-1.29]]},{"type":"path","version":"2.4.6","left":78.08737427855635,"top":315.5127636903678,"width":2.42,"height":11.51,"fill":{"type":"linear","coords":{"x1":473.934,"y1":792.821,"x2":473.822,"y2":784.005},"colorStops":[{"offset":1,"color":"rgb(211,188,95)","opacity":1},{"offset":0.904,"color":"rgb(120,103,33)","opacity":1},{"offset":0.76,"color":"rgb(160,137,44)","opacity":1},{"offset":0.701,"color":"rgb(200,171,55)","opacity":1},{"offset":0.533,"color":"rgb(255,255,255)","opacity":1},{"offset":0.393,"color":"rgb(160,137,44)","opacity":1},{"offset":0.22,"color":"rgb(80,68,22)","opacity":1},{"offset":0.1,"color":"rgb(85,68,0)","opacity":1},{"offset":0,"color":"rgb(160,137,44)","opacity":1}],"offsetX":-446.578,"offsetY":-783.332,"gradientTransform":[-1,0,0,1,921.58,0]},"scaleX":9.32,"scaleY":10.58,"angle":-90,"path":[["M",448.32,783.332],["l",0.673,2.02],["c",-0.885,1.242,-0.83,2.952,-0.075,7.92],["l",-1.16,1.57],["l",-1.18,-4.49],["l",0.17,-5.673],["z"]]},{"type":"path","version":"2.4.6","left":92.34368668174653,"top":366.5275069557187,"width":6.57,"height":5.67,"fill":{"type":"linear","coords":{"x1":475.081,"y1":785.381,"x2":479.3,"y2":788.975},"colorStops":[{"offset":1,"color":"rgb(120,103,33)","opacity":1},{"offset":0,"color":"rgb(200,171,55)","opacity":1}],"offsetX":-441.1054336190674,"offsetY":-784.68,"gradientTransform":[-1,0,0,1,921.58,0]},"scaleX":9.32,"scaleY":10.58,"angle":-90,"path":[["M",447.365,784.68],["h",-5.616],["c",-0.592,1.87,-0.812,3.743,-0.506,5.615],["l",5.952,0.056],["c",0.658,-1.976,0.554,-3.843,0.17,-5.67],["z"]]},{"type":"path","version":"2.4.6","left":151.23029459047214,"top":365.75783100618594,"width":6.58,"height":4.48,"fill":{"type":"linear","coords":{"x1":476.181,"y1":791.235,"x2":477.099,"y2":794.257},"colorStops":[{"offset":1,"color":"rgb(120,103,33)","opacity":1},{"offset":0,"color":"rgb(200,171,55)","opacity":1}],"offsetX":-441.18800000000005,"offsetY":-790.248,"gradientTransform":[-1,0,0,1,921.58,0]},"scaleX":9.32,"scaleY":10.58,"angle":-90,"path":[["M",447.196,790.248],["c",0.397,1.492,0.613,3.14,0.562,4.483],["l",-5.503,-0.056],["c",-0.974,-1.853,-0.957,-3.128,-1.067,-4.406],["z"]]},{"type":"path","version":"2.4.6","left":78.67962464545468,"top":360.50959855742764,"width":6.4,"height":1.35,"fill":{"type":"linear","coords":{"x1":473.32,"y1":784.06,"x2":479.896,"y2":784.06},"colorStops":[{"offset":1,"color":"rgb(200,171,55)","opacity":1},{"offset":0,"color":"rgb(120,103,33)","opacity":1}],"offsetX":-441.751,"offsetY":-783.3879999999999,"gradientTransform":[-1,0,0,1,921.58,0]},"scaleX":9.32,"scaleY":10.58,"angle":-90,"path":[["M",447.196,784.68],["c",0.783,-0.43,0.715,-0.862,0.955,-1.292],["l",-5.67,0.224],["c",-0.308,0.343,-0.704,0.64,-0.73,1.123],["z"]]},{"type":"path","version":"2.4.6","left":195.70884317712697,"top":264.26532049868615,"width":2.99,"height":8.78,"fill":{"type":"linear","coords":{"x1":481.066,"y1":785.465,"x2":480.953,"y2":793.102},"colorStops":[{"offset":1,"color":"rgb(160,137,44)","opacity":1},{"offset":0.9,"color":"rgb(85,68,0)","opacity":1},{"offset":0.78,"color":"rgb(80,68,22)","opacity":1},{"offset":0.607,"color":"rgb(160,137,44)","opacity":1},{"offset":0.467,"color":"rgb(255,255,255)","opacity":1},{"offset":0.299,"color":"rgb(200,171,55)","opacity":1},{"offset":0.24,"color":"rgb(160,137,44)","opacity":1},{"offset":0.096,"color":"rgb(120,103,33)","opacity":1},{"offset":0,"color":"rgb(211,188,95)","opacity":1}],"offsetX":-228.298,"offsetY":-835.244,"gradientTransform":[0.93343,0,0,0.85628,-219.064,163.965]},"scaleX":9.32,"scaleY":10.58,"angle":90,"flipY":true,"path":[["M",228.298,844.02],["l",2.57,-1.083],["c",0.6,-2.048,0.477,-4.285,0.104,-6.587],["l",-2.62,-1.106]]},{"type":"circle","version":"2.4.6","left":-28.49,"top":-28.49,"width":4.64,"height":4.64,"fill":{"type":"radial","coords":{"x1":193.676,"y1":141.252,"x2":193.676,"y2":141.252,"r1":0,"r2":4.082},"colorStops":[{"offset":1,"color":"rgb(0,0,0)","opacity":1},{"offset":0.969,"color":"rgb(0,0,0)","opacity":1},{"offset":0.904,"color":"rgb(236,236,236)","opacity":1},{"offset":0.874,"color":"rgb(77,77,77)","opacity":1},{"offset":0.837,"color":"rgb(237,237,237)","opacity":1},{"offset":0.817,"color":"rgb(0,0,0)","opacity":1},{"offset":0,"color":"rgb(0,0,0)","opacity":1}],"offsetX":-116.293,"offsetY":-166.167,"gradientTransform":[0.3487,0.40483,-0.40345,0.34752,108.054,40.97]},"scaleX":59.8,"scaleY":59.8,"radius":2.321,"startAngle":0,"endAngle":360},{"type":"circle","version":"2.4.6","left":32.24,"top":30.43,"width":3.58,"height":3.58,"fill":{"type":"linear","coords":{"x1":195.171,"y1":143.461,"x2":191.574,"y2":138.568},"colorStops":[{"offset":1,"color":"rgb(204,204,204)","opacity":1},{"offset":0.687,"color":"rgb(255,255,255)","opacity":1},{"offset":0,"color":"rgb(255,255,255)","opacity":1}],"offsetX":-116.817,"offsetY":-166.661,"gradientTransform":[0.52872,0,0,0.52872,16.3,93.714]},"stroke":"#b3b3b3","strokeWidth":0.02,"strokeLineCap":"round","scaleX":59.8,"scaleY":59.8,"radius":1.789,"startAngle":0,"endAngle":360},{"type":"circle","version":"2.4.6","left":125.91,"top":124.11,"width":0.46,"height":0.46,"fill":{"type":"linear","coords":{"x1":656.429,"y1":320.934,"x2":506.429,"y2":131.648},"colorStops":[{"offset":1,"color":"rgb(242,242,242)","opacity":1},{"offset":0,"color":"rgb(102,102,102)","opacity":1}],"offsetX":-118.37599999999999,"offsetY":-168.22,"gradientTransform":[0.0017,0,0,0.0017,117.64,168.082]},"stroke":"#999","strokeWidth":0,"strokeLineCap":"round","scaleX":59.8,"scaleY":59.8,"radius":0.23,"startAngle":0,"endAngle":360}]}'; - canvas.loadFromJSON(jsonData, function() { + canvas.loadFromJSON(jsonData).then(function() { toSVGCanvas(canvas, callback); }); } @@ -386,7 +386,7 @@ function group1(canvas, callback) { var jsonData = '{"version":"3.1.0","objects":[{"type":"group","version":"3.1.0","left":3,"top":2,"width":250,"height":250,"scaleX":0.9,"scaleY":0.9,"opacity":0.7,"shadow":{"color":"rgba(0,0,0,0.3)","blur":10,"offsetX":10,"offsetY":10,"affectStroke":false,"nonScaling":false},"objects":[{"type":"polygon","version":"3.1.0","left":-74.5,"top":67.46,"width":148,"height":54.92,"fill":{"type":"linear","coords":{"x1":175,"y1":111.8719,"x2":175,"y2":-135.0812},"colorStops":[{"offset":1,"color":"rgb(0,38,57)","opacity":1},{"offset":0,"color":"rgb(0,46,59)","opacity":1}],"offsetX":-51,"offsetY":-192.962,"gradientTransform":[1,0,0,-1,-50,111]},"stroke":{"type":"linear","coords":{"x1":175,"y1":111.8719,"x2":175,"y2":-135.0812},"colorStops":[{"offset":1,"color":"rgb(0,38,57)","opacity":1},{"offset":0,"color":"rgb(0,46,59)","opacity":1}],"offsetX":-51,"offsetY":-192.962,"gradientTransform":[1,0,0,-1,-50,111]},"shadow":{"color":"red","blur":10,"offsetX":0,"offsetY":0,"affectStroke":false,"nonScaling":false},"points":[{"x":124.913,"y":210.751},{"x":89.063,"y":193.264},{"x":89.103,"y":193.245},{"x":89.093,"y":193.24},{"x":51,"y":211.82},{"x":124.941,"y":247.884},{"x":199,"y":211.9},{"x":160.771,"y":192.962}]},{"type":"polygon","version":"3.1.0","left":-74.41,"top":31.4,"width":74.36,"height":55.04,"fill":{"type":"radial","coords":{"x1":63.3041,"y1":235.6129,"x2":63.3041,"y2":235.6129,"r1":0,"r2":219.7985},"colorStops":[{"offset":1,"color":"rgb(20,157,145)","opacity":1},{"offset":0,"color":"rgb(0,188,133)","opacity":1}],"offsetX":-51.091,"offsetY":-156.903},"stroke":{"type":"radial","coords":{"x1":63.3041,"y1":235.6129,"x2":63.3041,"y2":235.6129,"r1":0,"r2":219.7985},"colorStops":[{"offset":1,"color":"rgb(20,157,145)","opacity":1},{"offset":0,"color":"rgb(0,188,133)","opacity":1}],"offsetX":-51.091,"offsetY":-156.903},"opacity":0.2,"points":[{"x":51.091,"y":211.945},{"x":51.091,"y":174.781},{"x":87.749,"y":156.903},{"x":125.455,"y":175.5}]},{"type":"polygon","version":"3.1.0","left":-0.89,"top":-87.38,"width":74.39,"height":118.38,"fill":{"type":"radial","coords":{"x1":186.8275,"y1":123.7814,"x2":186.8275,"y2":123.7814,"r1":0,"r2":265.5574},"colorStops":[{"offset":1,"color":"rgb(20,157,145)","opacity":1},{"offset":0,"color":"rgb(0,188,133)","opacity":1}],"offsetX":-124.611,"offsetY":-38.123,"gradientTransform":[1,0,0,-1,-50,111]},"stroke":{"type":"radial","coords":{"x1":186.8275,"y1":123.7814,"x2":186.8275,"y2":123.7814,"r1":0,"r2":265.5574},"colorStops":[{"offset":1,"color":"rgb(20,157,145)","opacity":1},{"offset":0,"color":"rgb(0,188,133)","opacity":1}],"offsetX":-124.611,"offsetY":-38.123,"gradientTransform":[1,0,0,-1,-50,111]},"points":[{"x":165.596,"y":58.995},{"x":165.596,"y":117.758},{"x":165.596,"y":117.758},{"x":165.596,"y":117.758},{"x":124.611,"y":137.737},{"x":162.301,"y":156.506},{"x":198.996,"y":138.632},{"x":198.996,"y":38.123}]},{"type":"polygon","version":"3.1.0","left":-74.4,"top":-87.41,"width":147.9,"height":173.82,"fill":{"type":"radial","coords":{"x1":118.0562,"y1":143.2378,"x2":118.0562,"y2":143.2378,"r1":0,"r2":507.5908},"colorStops":[{"offset":1,"color":"rgb(0,52,95)","opacity":1},{"offset":0,"color":"rgb(0,68,115)","opacity":1}],"offsetX":-51.096,"offsetY":-38.088,"gradientTransform":[1,0,0,-1,-50,111]},"stroke":{"type":"radial","coords":{"x1":118.0562,"y1":143.2378,"x2":118.0562,"y2":143.2378,"r1":0,"r2":507.5908},"colorStops":[{"offset":1,"color":"rgb(0,52,95)","opacity":1},{"offset":0,"color":"rgb(0,68,115)","opacity":1}],"offsetX":-51.096,"offsetY":-38.088,"gradientTransform":[1,0,0,-1,-50,111]},"points":[{"x":199,"y":211.912},{"x":199,"y":211.912},{"x":199,"y":174.746},{"x":84.498,"y":117.723},{"x":84.498,"y":58.96},{"x":51.096,"y":38.088},{"x":51.096,"y":138.597}]},{"type":"polygon","version":"3.1.0","left":-74.5,"top":-123.52,"width":147.84,"height":56.93,"fill":{"type":"linear","coords":{"x1":174.922,"y1":110.6136,"x2":174.922,"y2":-135.0903},"colorStops":[{"offset":1,"color":"rgb(0,38,57)","opacity":1},{"offset":0,"color":"rgb(0,46,59)","opacity":1}],"offsetX":-51,"offsetY":-1.985,"gradientTransform":[1,0,0,-1,-50,111]},"stroke":{"type":"linear","coords":{"x1":174.922,"y1":110.6136,"x2":174.922,"y2":-135.0903},"colorStops":[{"offset":1,"color":"rgb(0,38,57)","opacity":1},{"offset":0,"color":"rgb(0,46,59)","opacity":1}],"offsetX":-51,"offsetY":-1.985,"gradientTransform":[1,0,0,-1,-50,111]},"points":[{"x":84.396,"y":58.904},{"x":84.396,"y":58.892},{"x":124.939,"y":39.118},{"x":165.485,"y":58.892},{"x":198.844,"y":38.046},{"x":124.912,"y":1.985},{"x":51,"y":38.035},{"x":51,"y":38.067},{"x":84.368,"y":58.918}]}]}]}'; - canvas.loadFromJSON(jsonData, function() { + canvas.loadFromJSON(jsonData).then(function() { toSVGCanvas(canvas, callback); }); }