fabric
Version:
Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.
146 lines (142 loc) • 5.04 kB
JavaScript
import { noop } from '../../constants.mjs';
import { createImage } from './dom.mjs';
import { classRegistry } from '../../ClassRegistry.mjs';
import { SignalAbortedError, FabricError } from '../internals/console.mjs';
/**
* Loads image element from given url and resolve it, or catch.
* @param {String} url URL representing an image
* @param {LoadImageOptions} [options] image loading options
* @returns {Promise<HTMLImageElement>} the loaded image.
*/
const loadImage = function (url) {
let {
signal,
crossOrigin = null
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return new Promise(function (resolve, reject) {
if (signal && signal.aborted) {
return reject(new SignalAbortedError('loadImage'));
}
const img = createImage();
let abort;
if (signal) {
abort = function (err) {
img.src = '';
reject(err);
};
signal.addEventListener('abort', abort, {
once: true
});
}
const done = function () {
img.onload = img.onerror = null;
abort && (signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', abort));
resolve(img);
};
if (!url) {
done();
return;
}
img.onload = done;
img.onerror = function () {
abort && (signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', abort));
reject(new FabricError("Error loading ".concat(img.src)));
};
crossOrigin && (img.crossOrigin = crossOrigin);
img.src = url;
});
};
/**
* @TODO type this correctly.
* Creates corresponding fabric instances from their object representations
* @param {Object[]} objects Objects to enliven
* @param {EnlivenObjectOptions} [options]
* @param {(serializedObj: object, instance: FabricObject) => any} [options.reviver] Method for further parsing of object elements,
* called after each fabric object created.
* @param {AbortSignal} [options.signal] handle aborting, see https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal
* @returns {Promise<FabricObject[]>}
*/
const enlivenObjects = function (objects) {
let {
signal,
reviver = noop
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return new Promise((resolve, reject) => {
const instances = [];
signal && signal.addEventListener('abort', reject, {
once: true
});
Promise.all(objects.map(obj => classRegistry.getClass(obj.type).fromObject(obj, {
signal
}).then(fabricInstance => {
reviver(obj, fabricInstance);
instances.push(fabricInstance);
return fabricInstance;
}))).then(resolve).catch(error => {
// cleanup
instances.forEach(instance => {
instance.dispose && instance.dispose();
});
reject(error);
}).finally(() => {
signal && signal.removeEventListener('abort', reject);
});
});
};
/**
* Creates corresponding fabric instances residing in an object, e.g. `clipPath`
* @param {Object} object with properties to enlive ( fill, stroke, clipPath, path )
* @param {object} [options]
* @param {AbortSignal} [options.signal] handle aborting, see https://developer.mozilla.org/en-US/docs/Web/API/AbortController/signal
* @returns {Promise<Record<string, FabricObject | TFiller | null>>} the input object with enlived values
*/
const enlivenObjectEnlivables = function (serializedObject) {
let {
signal
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return new Promise((resolve, reject) => {
const instances = [];
signal && signal.addEventListener('abort', reject, {
once: true
});
// enlive every possible property
const promises = Object.values(serializedObject).map(value => {
if (!value) {
return value;
}
/**
* clipPath or shadow or gradient or text on a path or a pattern,
* or the backgroundImage or overlayImage of canvas
* If we have a type and there is a classe registered for it, we enlive it.
* If there is no class registered for it we return the value as is
* */
if (value.type && classRegistry.has(value.type)) {
return enlivenObjects([value], {
signal
}).then(_ref => {
let [enlived] = _ref;
instances.push(enlived);
return enlived;
});
}
return value;
});
const keys = Object.keys(serializedObject);
Promise.all(promises).then(enlived => {
return enlived.reduce((acc, instance, index) => {
acc[keys[index]] = instance;
return acc;
}, {});
}).then(resolve).catch(error => {
// cleanup
instances.forEach(instance => {
instance.dispose && instance.dispose();
});
reject(error);
}).finally(() => {
signal && signal.removeEventListener('abort', reject);
});
});
};
export { enlivenObjectEnlivables, enlivenObjects, loadImage };
//# sourceMappingURL=objectEnlive.mjs.map