import { constructors } from '../core/library.js';
import { mergeOver, isa_obj, λnull, λthis } from '../core/utilities.js';
import baseMix from '../mixin/base.js';
import assetMix from '../mixin/asset.js';The factory generates wrapper Objects around spritesheet <img> elements fetched from the server using an URL address.
.json encoded file, or a Javascript object. There is no single source of truth for the requirements or format of manifests, so Scrawl-canvas uses its own manifest format.SpriteAssets are used by Picture and Grid entitys, and Pattern styles.
TODO: SpriteAssets don’t support animated .gif images (or if they do, then its entirely a lucky accident). Tested image formats are .jpg and .png.
import { constructors } from '../core/library.js';
import { mergeOver, isa_obj, λnull, λthis } from '../core/utilities.js';
import baseMix from '../mixin/base.js';
import assetMix from '../mixin/asset.js';const SpriteAsset = function (items = {}) {
this.assetConstructor(items);
return this;
};let P = SpriteAsset.prototype = Object.create(Object.prototype);
P.type = 'Sprite';
P.lib = 'asset';
P.isArtefact = false;
P.isAsset = true;P = baseMix(P);
P = assetMix(P);let defaultAttributes = {manifest - TODO - documentation
manifest: null,
};
P.defs = mergeOver(P.defs, defaultAttributes);Assets do not take part in the packet or clone systems; they can, however, be used for importing and actioning packets as they retain those base functions
P.saveAsPacket = function () {
return [this.name, this.type, this.lib, {}];
};
P.stringifyFunction = λnull;
P.processPacketOut = λnull;
P.finalizePacketOut = λnull;P.clone = λthis;let G = P.getters,
S = P.setters,
D = P.deltaSetters;source
S.source = function (items = []) {
if (items && items[0]) {
if (!this.sourceHold) this.sourceHold = {};
let hold = this.sourceHold;
items.forEach(item => {
let name = item.id || item.name;
if (name) hold[name] = item;
})
this.source = items[0];
this.sourceNaturalWidth = items[0].naturalWidth;
this.sourceNaturalHeight = items[0].naturalHeight;
this.sourceLoaded = items[0].complete;
}
};Sprite assets do not use the checkSource function. Instead, Picture entitys will interrogate the checkSpriteFrame function (defined in mixin/assetConsumer.js)
P.checkSource = λnull;gettableSpriteAssetAtributes, settableSpriteAssetAtributes - exported Arrays.
const gettableSpriteAssetAtributes = [];
const settableSpriteAssetAtributes = [];importSprite - load sprite images and manifest files from a remote server and create assets from them
Arguments can be a comma-separated list of String urls. For example, for a spritesheet at server url http://www.example.com/path/to/image/flower.jpg:
Note: if using an url string path to import the spritesheet image, a manifest JSON file with the same filename (ending in .json) in the same folder must also be supplied!
Alternatively, the arguments can include an object with the following attributes:
Note: strings and object arguments can be mixed - Scrawl-canvas will interrrogate each argument in turn and take appropriate action to load the assets.
The manifest must resolve to an object containing a set of attributes which represent ‘tracks’ - sequences of frames which, when run, will result in a particular animation (eg ‘walk’, ‘turn’, ‘fire-arrow’, ‘die’, etc). Each track attribute is an Array of arrays, with each sub-array supplying details of the source file, copy start coordinates, and copy dimensions for each frame:
manifestSrc: {
"default" : [
['picturename', copyStartX, copyStartY, width, height]
],
"walk": [
['picturename', copyStartX, copyStartY, width, height]
['picturename', copyStartX, copyStartY, width, height]
['picturename', copyStartX, copyStartY, width, height]
],
}
const importSprite = function (...args) {
let reg = /.*\/(.*?)\./,
fileTlas = /\.(jpeg|jpg|png|gif|webp|svg|JPEG|JPG|PNG|GIF|WEBP|SVG)/,
results = [];
args.forEach(item => {Load the sprite image in the normal way
let name, urls, className, visibility, manifest,
parent = false;
let flag = false;
if (item.substring) {
let match = reg.exec(item);
name = (match && match[1]) ? match[1] : '';
urls = [item];
className = '';
visibility = false;
manifest = item.replace(fileTlas, '.json');
flag = true;
}
else {
if (!isa_obj(item) || !item.imageSrc || !item.manifestSrc) results.push(false);
else {
name = item.name || '';
urls = Array.isArray(item.imageSrc) ? item.imageSrc : [item.imageSrc];
manifest = item.manifestSrc;
className = item.className || '';
visibility = item.visibility || false;
parent = document.querySelector(item.parent);
flag = true;
}
}
if (flag) {
let image = makeSpriteAsset({
name: name,
});Get manifest
if (isa_obj(manifest)) image.manifest = manifest;
else {
fetch(manifest)
.then(response => {
if (response.status !== 200) throw new Error('Failed to load manifest');
return response.json();
})
.then(jsonString => image.manifest = jsonString)
.catch(err => console.log(err.message));
}
let imgArray = [];
urls.forEach(url => {
let img = document.createElement('img'),
filename, match;
if (fileTlas.test(url)) {
match = reg.exec(url);
filename = (match && match[1]) ? match[1] : '';
}
img.name = filename || name;
img.className = className;
img.crossorigin = 'anonymous';
img.style.display = (visibility) ? 'block' : 'none';
if (parent) parent.appendChild(img);
img.src = url;
imgArray.push(img);
});
image.set({
source: imgArray,
});
results.push(name);
}
else results.push(false);
});
return results;
};TODO: Scrawl-canvas does not yet support importing spritesheets defined in the web page HTML code
const makeSpriteAsset = function (items) {
return new SpriteAsset(items);
};
constructors.SpriteAsset = SpriteAsset;export {
makeSpriteAsset,
gettableSpriteAssetAtributes,
settableSpriteAssetAtributes,
importSprite,
};Examples used in Demos