import { constructors } from '../core/library.js';
import { doCreate, isa_obj, mergeOver, λnull, λcloneError, Ωempty } from '../helper/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.import { constructors } from '../core/library.js';
import { doCreate, isa_obj, mergeOver, λnull, λcloneError, Ωempty } from '../helper/utilities.js';
import baseMix from '../mixin/base.js';
import assetMix from '../mixin/asset.js';Shared constants
import { _isArray, ANONYMOUS, ASSET, ASSET_IMPORT_REGEX, BLOCK, IMG, NONE, T_SPRITE, ZERO_STR } from '../helper/shared-vars.js';Local constants
const $JSON = '.json';const SpriteAsset = function (items = Ωempty) {
this.sourceHold = null;
this.manifest = null;
this.assetConstructor(items);
return this;
};const P = SpriteAsset.prototype = doCreate();
P.type = T_SPRITE;
P.lib = ASSET;
P.isArtefact = false;
P.isAsset = true;baseMix(P);
assetMix(P);const 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 = λcloneError;const S = P.setters;source
S.source = function (items = []) {
if (items && items[0]) {
if (!this.sourceHold) this.sourceHold = {};
const hold = this.sourceHold;
items.forEach(item => {
const 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;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]
],
}
export const importSprite = function (...args) {
const 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) {
const match = ASSET_IMPORT_REGEX.exec(item);
name = (match && match[1]) ? match[1] : ZERO_STR;
urls = [item];
className = ZERO_STR;
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 || ZERO_STR;
urls = _isArray(item.imageSrc) ? item.imageSrc : [item.imageSrc];
manifest = item.manifestSrc;
className = item.className || ZERO_STR;
visibility = item.visibility || false;
parent = document.querySelector(item.parent);
flag = true;
}
}
if (flag) {
const 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));
}
const imgArray = [];
urls.forEach(url => {
const img = document.createElement(IMG);
let filename, match;
if (fileTlas.test(url)) {
match = ASSET_IMPORT_REGEX.exec(url);
filename = (match && match[1]) ? match[1] : ZERO_STR;
}
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) {
if (!items) return false;
return new SpriteAsset(items);
};
constructors.SpriteAsset = SpriteAsset;Examples used in Demos