import { mergeOver, pushUnique, λnull, Ωempty } from '../helper/utilities.js';The asset factories - ImageAsset, SpriteAsset, and VideoAsset - are wrappers around images and videos which can either be pulled from the current document (DOM-based assets) or fetched from the server using an URL address.
Assets can be loaded into scrawl using dedicated import and create functions:
scrawl.importImagescrawl.importDomImagescrawl.importDomVideoscrawl.importVideoscrawl.importMediaStreamscrawl.importSpritescrawl.createImageFromCellscrawl.createImageFromGroupscrawl.createImageFromEntityAssets will also be created when Picture entitys or Pattern styles are defined using a ‘scrawl.make’ function (makePicture, makePattern), or updated with the set function, where the imageSource, videoSource or spriteSource key in the argument object has been set to a valid URL path string.
Be aware that loading assets takes time!
import { mergeOver, pushUnique, λnull, Ωempty } from '../helper/utilities.js';export default function (P = Ωempty) { const defaultAttributes = {sourceLoaded - A flag to indicate that the source image or video has completed sufficient loading (or streaming) to be usefully consumed by Picture entitys and Pattern styles.
sourceLoaded: false,source - A handle to the DOM element supplying the image - either an <img>, <video> or <canvas> element.
source: null,subscribers - An Array containing the Picture entity and Pattern style Objects, who wish to use the asset as their source.
subscribers: null,
};
P.defs = mergeOver(P.defs, defaultAttributes);Assets do not include their source images (or videos!) in their packet output. They do include the String name values of each of their subscribers.
P.packetExclusions = pushUnique(P.packetExclusions, ['sourceLoaded', 'source', 'subscribers']);
P.finalizePacketOut = function (copy) {
if (this.subscribers && this.subscribers.length) {
copy.subscribers = this.subscribers.map(sub => sub.name);
}
return copy;
}; P.kill = function (removeDomEntity = false) {
if (removeDomEntity && this.source) this.source.remove();
return this.deregister();
}; const S = P.setters;source - imageAsset.js and videoAsset.js overwrite this function, thus only put here so cell.js also gains the function - which I don’t think it will ever need as cells ARE their own source.
S.source = function (item) {
if (item) {No action required for Canvas objects as they don’t have a source; they ARE the source!
if (this.sourceLoaded) this.notifySubscribers();
}
};subscribers - we disable the ability to set the subscribers Array directly. Picture entitys and Pattern styles will manage their subscription to the asset using their subscribe() and unsubscribe() functions.
S.subscribers = λnull;assetConstructor - Common actions required by imageAsset, spriteAsset, and videoAsset factories as part if their instance constructor work.
P.assetConstructor = function (items) {
this.makeName(items.name);
this.register();
this.subscribers = [];
this.set(this.defs);
this.source = null;
this.currentSrc = null;
this.currentFile = null;
this.sourceNaturalWidth = 0;
this.sourceNaturalHeight = 0;
this.set(items);
if (items.subscribe) this.subscribers.push(items.subscribe);
return this;
}; P.subscribe = function (sub) {
if (sub && sub.name) {
const name = sub.name;
if (this.subscribers.every(item => item.name !== name)) this.subscribeAction(sub);
}
};subscribeAction - separated out because cells handle things differently (they ARE the source)
P.subscribeAction = function (sub) {
if (sub) {
this.subscribers.push(sub);
sub.asset = this;
sub.source = this.source;
this.notifySubscriber(sub);
}
};unsubscribe
P.unsubscribe = function (sub) {
if (sub && sub.name) {
const name = sub.name,
index = this.subscribers.findIndex(item => item.name === name);
if (index >= 0) {
sub.source = null;
sub.asset = null;
sub.sourceNaturalHeight = 0;
sub.sourceNaturalWidth = 0;
sub.sourceLoaded = false;
this.subscribers.splice(index, 1)
}
}
};notifySubscribers, notifySubscriber - Subscriber notification in the asset factories will happen when something changes with the image. Changes vary across the different types of asset:
All notifications are push; the notification is achieved by setting various attributes and flags in each subscriber.
P.notifySubscribers = function () {
this.subscribers.forEach(sub => this.notifySubscriber(sub), this);
};
P.notifySubscriber = function (sub) {
sub.sourceNaturalWidth = this.sourceNaturalWidth;
sub.sourceNaturalHeight = this.sourceNaturalHeight;
sub.sourceLoaded = this.sourceLoaded;
sub.source = this.source;
sub.dirtyImage = true;
sub.dirtyCopyStart = true;
sub.dirtyCopyDimensions = true;
sub.dirtyImageSubscribers = true;
sub.dirtyFilterIdentifier = true;
};
}