drawable-js
Version:
A lightweight JavaScript library to draw shapes and effects on HTML canvas, inspired by Android's Drawable.
807 lines (790 loc) • 28.4 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.DrawableJS = {}));
})(this, (function (exports) { 'use strict';
function _arrayLikeToArray(r, a) {
(null == a || a > r.length) && (a = r.length);
for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
return n;
}
function _createForOfIteratorHelper(r, e) {
var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (!t) {
if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {
t && (r = t);
var n = 0,
F = function () {};
return {
s: F,
n: function () {
return n >= r.length ? {
done: true
} : {
done: false,
value: r[n++]
};
},
e: function (r) {
throw r;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var o,
a = true,
u = false;
return {
s: function () {
t = t.call(r);
},
n: function () {
var r = t.next();
return a = r.done, r;
},
e: function (r) {
u = true, o = r;
},
f: function () {
try {
a || null == t.return || t.return();
} finally {
if (u) throw o;
}
}
};
}
function _unsupportedIterableToArray(r, a) {
if (r) {
if ("string" == typeof r) return _arrayLikeToArray(r, a);
var t = {}.toString.call(r).slice(8, -1);
return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
}
}
/*
* DrawableJS
* Copyright (c) 2025 jaianper
*
* This file is part of DrawableJS.
* Licensed under the GNU General Public License v3.0.
* You may obtain a copy of the License at https://www.gnu.org/licenses/gpl-3.0.txt
*/
// --- Exportable constants ---
var Shape = {
LINE: 'LINE',
OVAL: 'OVAL',
RECTANGLE: 'RECT'
};
var Gradient = {
RADIAL_GRADIENT: 'R_G',
LINEAR_GRADIENT: 'L_G'
};
var Alignment = {
TOP: 'A_T',
BOTTOM: 'A_B',
LEFT: 'A_L',
RIGHT: 'A_R',
CENTER: 'A_C'
};
var Orientation = {
VERTICAL: 'O_V',
HORIZONTAL: 'O_H'
};
var DAR = 0.75; // DEFAULT_ASCENT_RATIO
var DDR = 0.03; // DEFAULT_DESCENT_RATIO
/**
* `ascentRatio` and `descentRatio` are empirical estimates of typographic layout proportions that are used
* as a fallback when the browser does not support the `actualBoundingBoxAscent` and `actualBoundingBoxDescent` properties.
*
* - 75% of the font size is usually above the baseline (ascent).
* - 3% is usually below (descent).
*/
var Font = {
ARIAL: {
name: 'Arial',
ascentRatio: 0.78,
descentRatio: DDR
},
AVERIA: {
name: 'Averia Gruesa',
ascentRatio: 0.76,
descentRatio: DDR
},
BALOO: {
name: 'Baloo',
ascentRatio: 0.69,
descentRatio: DDR
},
BEBAS_NEUE: {
name: 'Bebas Neue',
ascentRatio: DAR,
descentRatio: DDR
},
BUTCHERMAN: {
name: 'Butcherman',
ascentRatio: 0.77,
descentRatio: 0.05
},
CALIBRI: {
name: 'Calibri',
ascentRatio: 0.69,
descentRatio: DDR
},
COMIC_SANS: {
name: 'Comic Sans MS',
ascentRatio: 0.78,
descentRatio: DDR
},
CONSOLAS: {
name: 'Consolas',
ascentRatio: 0.69,
descentRatio: DDR
},
COURIER_NEW: {
name: 'Courier New',
ascentRatio: 0.65,
descentRatio: DDR
},
CRASH_NUMB: {
name: 'Crash Numbering Serif',
ascentRatio: 0.74,
descentRatio: DDR
},
CREEPSTER: {
name: 'Creepster',
ascentRatio: 0.76,
descentRatio: DDR
},
DROID_SANS: {
name: 'Droid Sans',
ascentRatio: 0.73,
descentRatio: DDR
},
DROID_SERIF: {
name: 'Droid Serif',
ascentRatio: 0.73,
descentRatio: DDR
},
EATER: {
name: 'Eater',
ascentRatio: 0.85,
descentRatio: 0.04
},
FLAVORS: {
name: 'Flavors',
ascentRatio: 0.78,
descentRatio: DDR
},
FREDOKA_ONE: {
name: 'Fredoka One',
ascentRatio: 0.76,
descentRatio: DDR
},
GEORGIA: {
name: 'Georgia',
ascentRatio: DAR,
descentRatio: DDR
},
GOCHI_HAND: {
name: 'Gochi Hand',
ascentRatio: 0.59,
descentRatio: DDR
},
IMPACT: {
name: 'Impact',
ascentRatio: 0.83,
descentRatio: DDR
},
MOUNT_CHRIST: {
name: 'Mountains of Christmas',
ascentRatio: 0.83,
descentRatio: 0.06
},
RAMABHADRA: {
name: 'Ramabhadra',
ascentRatio: 0.76,
descentRatio: DDR
},
TIMES_NEW_R: {
name: 'Times New Roman',
ascentRatio: DAR,
descentRatio: DDR
},
TREBUCHET: {
name: 'Trebuchet MS',
ascentRatio: DAR,
descentRatio: DDR
},
VERDANA: {
name: 'Verdana',
ascentRatio: 0.77,
descentRatio: DDR
},
values: function values() {
return Object.values(this).filter(function (f) {
return typeof f !== 'function';
});
},
getFonts: function getFonts() {
return this.values().map(function (f) {
return f.name;
});
},
keys: function keys() {
var _this = this;
return Object.keys(this).filter(function (k) {
return typeof _this[k] !== 'function';
});
},
getKeyByName: function getKeyByName(name) {
var _this2 = this;
return this.keys().find(function (k) {
return _this2[k].name === name;
});
}
};
var FontLoader = {
load: function load(info) {
var fonts = info.families;
var width = 150,
height = 25;
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var _loadFont = function loadFont(font) {
var text = new Drawable(width, height);
text.ctx = canvas.getContext('2d');
text.update = function () {
this.items = [{
text: 'AEIOUBCDFGHIJ/0123456789',
font: {
family: font,
size: 20
},
color: '#FFFFFF',
textAlign: 'left',
verticalAlign: 'top',
x: 0,
y: 0
}];
};
text.onPostBuild = function () {
if (fonts.length > 0) _loadFont(fonts.pop());else info.active();
};
text.build();
};
_loadFont(fonts.pop());
}
};
// --- Internal functions ---
var getPointsFromAngle = function getPointsFromAngle(angle, center, width, height) {
// Convert center of % to decimal values
var centerXPercent = center !== null && center !== void 0 && center.x ? parseFloat(center.x.replace('%', '')) / 100 : 0;
var centerYPercent = center !== null && center !== void 0 && center.y ? parseFloat(center.y.replace('%', '')) / 100 : 0;
var halfWidth = width / 2;
var halfHeight = height / 2;
// Critical angle separating width/height in the circle
var fovAngle = Math.atan(halfHeight / halfWidth) * (180 / Math.PI);
var altFovAngle = 90 - fovAngle;
// Ensure angle within 0–360°
var normalizedAngle = angle % 360;
// Determine quadrant and relative angle
var quadrant = 1;
var angleInQuadrant = normalizedAngle;
if (normalizedAngle >= 270) {
angleInQuadrant = normalizedAngle - 270;
quadrant = 4;
} else if (normalizedAngle >= 180) {
angleInQuadrant = normalizedAngle - 180;
quadrant = 3;
} else if (normalizedAngle >= 90) {
angleInQuadrant = normalizedAngle - 90;
quadrant = 2;
}
// Determine adjacent side and acute angle (to be used with tangent)
var adjacent, innerAngleDeg;
var inQuadrant13 = quadrant === 1 || quadrant === 3;
if (inQuadrant13) {
if (angleInQuadrant < fovAngle) {
adjacent = halfWidth;
innerAngleDeg = angleInQuadrant;
} else {
adjacent = halfHeight;
innerAngleDeg = 90 - angleInQuadrant;
}
} else {
if (angleInQuadrant < altFovAngle) {
adjacent = halfHeight;
innerAngleDeg = angleInQuadrant;
} else {
adjacent = halfWidth;
innerAngleDeg = 90 - angleInQuadrant;
}
}
var opposite = Math.tan(innerAngleDeg * (Math.PI / 180)) * adjacent;
// Coordinates of a symmetrical line with respect to the center
var x0, y0, x1, y1;
switch (quadrant) {
case 1:
if (angleInQuadrant < fovAngle) {
x0 = halfWidth - adjacent;
y0 = halfHeight + opposite;
x1 = halfWidth + adjacent;
y1 = halfHeight - opposite;
} else {
x0 = halfWidth - opposite;
y0 = halfHeight + adjacent;
x1 = halfWidth + opposite;
y1 = halfHeight - adjacent;
}
x0 += width * centerXPercent;
y0 -= height * centerYPercent;
break;
case 2:
if (angleInQuadrant < altFovAngle) {
x0 = halfWidth + opposite;
y0 = halfHeight + adjacent;
x1 = halfWidth - opposite;
y1 = halfHeight - adjacent;
} else {
x0 = halfWidth + adjacent;
y0 = halfHeight + opposite;
x1 = halfWidth - adjacent;
y1 = halfHeight - opposite;
}
x0 -= width * centerXPercent;
y0 -= height * centerYPercent;
break;
case 3:
if (angleInQuadrant < fovAngle) {
x0 = halfWidth + adjacent;
y0 = halfHeight - opposite;
x1 = halfWidth - adjacent;
y1 = halfHeight + opposite;
} else {
x0 = halfWidth + opposite;
y0 = halfHeight - adjacent;
x1 = halfWidth - opposite;
y1 = halfHeight + adjacent;
}
x0 -= width * centerXPercent;
y0 += height * centerYPercent;
break;
case 4:
if (angleInQuadrant < altFovAngle) {
x0 = halfWidth - opposite;
y0 = halfHeight - adjacent;
x1 = halfWidth + opposite;
y1 = halfHeight + adjacent;
} else {
x0 = halfWidth - adjacent;
y0 = halfHeight - opposite;
x1 = halfWidth + adjacent;
y1 = halfHeight + opposite;
}
x0 += width * centerXPercent;
y0 += height * centerYPercent;
break;
}
return {
x0: x0,
y0: y0,
x1: x1,
y1: y1
};
};
var ImageCache = {};
var getImgCopy = function getImgCopy(imgName, width, height) {
var imgSize = width + '_' + height;
var targetImages = ImageCache[imgSize];
var copy;
if (targetImages && targetImages[imgName]) {
copy = targetImages[imgName];
}
return copy;
};
var drawable2Image = function drawable2Image(drawable, type, callback) {
var canvas = document.createElement('canvas');
canvas.width = drawable.width;
canvas.height = drawable.height;
drawable.ctx = canvas.getContext('2d');
drawable.build();
var img = new Image();
if (typeof callback !== 'undefined') {
img.onload = callback;
}
img.src = canvas.toDataURL(type);
return img;
};
// --- Clase principal ---
function Drawable() {
var _this3 = this;
var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var x = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
var y = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
this.margin = {
top: 0,
left: 0,
bottom: 0,
right: 0
};
this.width = width;
this.height = height;
this.x = x;
this.y = y;
var tWidth = 0,
tHeight = 0;
var applyFilter = function applyFilter(imgInfo) {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = imgInfo.w || imgInfo.width;
canvas.height = imgInfo.h || imgInfo.height;
/*if(typeof imgInfo.angle !== 'undefined') {
ctx.save();
ctx.translate(canvas.width/2, canvas.height/2);
ctx.rotate(imgInfo.angle * (Math.PI / 180));
ctx.drawImage(imgInfo.image, -canvas.width / 2, -canvas.height / 2);
}
else {*/
ctx.drawImage(imgInfo.image, 0, 0, canvas.width, canvas.height);
//}
ctx.globalCompositeOperation = 'source-atop';
ctx.fillStyle = imgInfo.cf || imgInfo.colorFilter;
ctx.fillRect(0, 0, canvas.width, canvas.height);
/*if(typeof imgInfo.angle !== 'undefined') {
ctx.restore();
}*/
return canvas;
};
var removeShadow = function removeShadow() {
_this3.ctx.shadowOffsetX = 0;
_this3.ctx.shadowOffsetY = 0;
_this3.ctx.shadowColor = 'transparent';
_this3.ctx.shadowBlur = 0;
};
var addShadow = function addShadow(shadow) {
_this3.ctx.shadowOffsetX = shadow.dx;
_this3.ctx.shadowOffsetY = shadow.dy;
_this3.ctx.shadowColor = shadow.color;
_this3.ctx.shadowBlur = shadow.blur;
};
var draw = function draw() {
var _iterator = _createForOfIteratorHelper(_this3.items),
_step;
try {
var _loop = function _loop() {
var item = _step.value;
var cStroke = false;
if (typeof item.angle !== 'undefined') {
_this3.ctx.save();
_this3.ctx.translate(item.x + item.width / 2, item.y + item.height / 2);
_this3.ctx.rotate(item.angle * (Math.PI / 180)); // degrees to radians
}
if (typeof item.color !== 'undefined') {
_this3.ctx.fillStyle = item.color;
} else if (typeof item.gradient !== 'undefined') {
var gradient = item.gradient;
var grd;
if (gradient.type == Gradient.RADIAL_GRADIENT) {
grd = _this3.ctx.createRadialGradient(gradient.center1.x, gradient.center1.y, gradient.radius1, gradient.center2.x, gradient.center2.y, gradient.radius2);
} else if (gradient.type == Gradient.LINEAR_GRADIENT) {
points = getPointsFromAngle(gradient.angle, gradient.center, item.width, item.height);
grd = _this3.ctx.createLinearGradient(points.x0 + item.x, points.y0 + item.y, points.x1 + item.x, points.y1 + item.y);
}
grd.addColorStop(0, gradient.startColor);
if (typeof gradient.centerColor !== 'undefined') {
grd.addColorStop(0.5, gradient.centerColor);
}
grd.addColorStop(1, gradient.endColor);
_this3.ctx.fillStyle = grd;
}
if (typeof item.shadow !== 'undefined') {
addShadow(item.shadow);
}
if (typeof item.text !== 'undefined') {
// item.y indicates the position from where the text begins to be painted
// this.y indicates the position reserved to start erasing the text, given that some characters overflow and also because of shadows.
var fontFamily = item.font.family.name || 'Arial';
var fontStyle = item.font.style ? "".concat(item.font.style, " ") : '';
var fontSize = item.font.size || 12;
var ascentRatio = item.font.family.ascentRatio || DAR;
var descentRatio = item.font.family.descentRatio || DDR;
var shadowBlur = typeof item.shadow !== 'undefined' ? item.shadow.blur : 0;
// Set the font
_this3.ctx.font = "".concat(fontStyle).concat(fontSize, "px ").concat(fontFamily);
_this3.ctx.textBaseline = 'alphabetic'; // Consistent baseline for any source and on any device.
var metrics = _this3.ctx.measureText(item.text);
// Empirical estimates are used
// ascent: the distance from the baseline of the text to the highest part of the letters (e.g., the top of a "d").
// descent: distance from the baseline to the lowest point (e.g., the tail of a "g" or "p").
var ascent = fontSize * ascentRatio;
var descent = fontSize * descentRatio;
// `actualBoundingBoxAscent` and `actualBoundingBoxDescent` do not give exact values.
//const ascent = metrics.actualBoundingBoxAscent || ascent;
//const descent = metrics.actualBoundingBoxDescent || descent;
var halfAscent = ascent / 2;
var adjustedY = item.y - descent;
var mY;
if (typeof item.lineHeight !== 'undefined') adjustedY -= item.lineHeight;
switch (item.verticalAlign) {
case "top":
adjustedY -= shadowBlur;
mY = adjustedY;
adjustedY += ascent;
break;
case "middle":
mY = adjustedY - halfAscent;
adjustedY += halfAscent - descent / 2;
break;
case "bottom":
mY = adjustedY - ascent;
break;
default:
adjustedY -= shadowBlur;
mY = adjustedY;
adjustedY += ascent;
}
_this3.x = item.x - halfAscent;
_this3.y = mY - shadowBlur - halfAscent;
_this3.ctx.textAlign = item.textAlign;
_this3.ctx.fillText(item.text, item.x, adjustedY);
tWidth = metrics.width + ascent;
tHeight = ascent + descent + shadowBlur * 2;
} else if (item.shape == Shape.LINE) {
_this3.ctx.beginPath();
_this3.ctx.moveTo(item.from.x, item.from.y);
_this3.ctx.lineTo(item.to.x, item.to.y);
} else if (item.shape == Shape.OVAL) {
_this3.ctx.beginPath();
_this3.ctx.arc(item.x, item.y, item.radius, 0, Math.PI * 2);
_this3.ctx.closePath();
_this3.ctx.fill();
} else if (item.shape == Shape.RECTANGLE) {
var rx = item.x;
var ry = item.y;
var rw = item.width;
var rh = item.height;
if (typeof item.cornerRadius !== 'undefined') {
var cr0 = item.cornerRadius[0] || 0;
var cr1 = item.cornerRadius[1] || 0;
var cr2 = item.cornerRadius[2] || 0;
var cr3 = item.cornerRadius[3] || 0;
_this3.ctx.beginPath();
_this3.ctx.moveTo(rx + rw - cr1, ry);
_this3.ctx.arcTo(rx + rw, ry, rx + rw, ry + cr1, cr1);
_this3.ctx.lineTo(rx + rw, ry + rh - cr2);
_this3.ctx.arcTo(rx + rw, ry + rh, rx + rw - cr2, ry + rh, cr2);
_this3.ctx.lineTo(rx + cr3, ry + rh);
_this3.ctx.arcTo(rx, ry + rh, rx, ry + rh - cr3, cr3);
_this3.ctx.lineTo(rx, ry + cr0);
_this3.ctx.arcTo(rx, ry, rx + cr0, ry, cr0);
_this3.ctx.closePath();
_this3.ctx.fill();
} else {
_this3.ctx.fillRect(rx, ry, rw, rh);
if (typeof item.stroke !== 'undefined') {
_this3.ctx.lineWidth = item.stroke.width;
_this3.ctx.strokeStyle = item.stroke.color;
_this3.ctx.strokeRect(rx, ry, rw, rh);
cStroke = true;
}
}
} else if (typeof item.image !== 'undefined') {
if (item.image == 'image/url') {
imgUrl = item.url;
imgName = imgUrl.substring(imgUrl.lastIndexOf('/') + 1);
imgCopy = getImgCopy(imgName, item.width, item.height);
if (imgCopy) {
//console.log('cache');
if (typeof imgCopy.w !== 'undefined' && typeof imgCopy.h !== 'undefined') {
var posX = item.x;
var posY = item.y;
if (typeof item.angle !== 'undefined') {
posX = -imgCopy.w / 2;
posY = -imgCopy.h / 2;
}
if (typeof item.colorFilter !== 'undefined') {
imgCopy.cf = item.colorFilter;
_this3.ctx.drawImage(applyFilter(imgCopy), posX, posY);
} else {
_this3.ctx.drawImage(imgCopy.image, posX, posY, imgCopy.w, imgCopy.h);
}
} else {
_this3.ctx.drawImage(imgCopy.image, item.x, item.y);
}
if (typeof item.onLoadImg !== 'undefined') item.onLoadImg();
} else {
//console.log('new');
var img = new Image();
img.onload = function (n, w, h) {
if (typeof item.angle !== 'undefined') {
this.ctx.save();
this.ctx.translate(item.x + item.width / 2, item.y + item.height / 2);
this.ctx.rotate(item.angle * (Math.PI / 180)); // degrees to radians
}
var imgInfo = {
w: w,
h: h
};
var imgSize = w + '_' + h;
if (typeof w !== 'undefined' && typeof h !== 'undefined') {
var _posX = item.x;
var _posY = item.y;
if (typeof item.angle !== 'undefined') {
_posX = -w / 2;
_posY = -h / 2;
}
if (typeof item.colorFilter !== 'undefined') {
item.image = img;
imgInfo.cf = item.colorFilter;
this.ctx.drawImage(applyFilter(item), _posX, _posY);
} else {
this.ctx.drawImage(img, _posX, _posY, w, h);
}
imgInfo.image = img;
} else {
imgInfo.image = img;
this.ctx.drawImage(img, item.x, item.y);
}
if (typeof item.angle !== 'undefined') {
this.ctx.restore();
}
if (typeof ImageCache[imgSize] === 'undefined') ImageCache[imgSize] = {};
ImageCache[imgSize][n] = imgInfo;
if (item.onLoadImg) item.onLoadImg();
}.bind(_this3, imgName, item.width, item.height);
img.src = item.url;
/*const img = await loadImage(item.url);
if(typeof item.angle !== 'undefined') {
this.ctx.save();
this.ctx.translate(item.x + (item.width/2), item.y + (item.height/2));
this.ctx.rotate(item.angle * (Math.PI / 180)); // degrees to radians
}
var imgInfo = { w: item.width, h: item.height };
var imgSize = item.width + '_' + item.height;
if (typeof item.width !== 'undefined' && typeof item.height !== 'undefined') {
let posX = item.x;
let posY = item.y;
if(typeof item.angle !== 'undefined') {
posX = -item.width/2;
posY = -item.width/2;
}
if (typeof item.colorFilter !== 'undefined') {
item.image = img;
imgInfo.cf = item.colorFilter;
this.ctx.drawImage(applyFilter(item), posX, posY);
}
else {
this.ctx.drawImage(img, posX, posY, item.width, item.height);
}
imgInfo.image = img;
}
else {
imgInfo.image = img;
this.ctx.drawImage(img, item.x, item.y);
}
if(typeof item.angle !== 'undefined') {
this.ctx.restore();
}
if (typeof ImageCache[imgSize] === 'undefined') ImageCache[imgSize] = {};
ImageCache[imgSize][imgName] = imgInfo;
if (item.onLoadImg) item.onLoadImg();*/
}
} else {
if (item.width !== 'undefined' && typeof item.height !== 'undefined') {
if (typeof item.angle !== 'undefined') {
_this3.ctx.drawImage(item.data, -item.width / 2, -item.height / 2, item.width, item.height);
} else {
_this3.ctx.drawImage(item.data, item.x, item.y, item.width, item.height);
}
} else {
_this3.ctx.drawImage(item.data, item.x, item.y);
}
}
}
if (typeof item.stroke !== 'undefined' && !cStroke) {
_this3.ctx.lineWidth = item.stroke.width;
_this3.ctx.strokeStyle = item.stroke.color;
_this3.ctx.stroke();
}
if (typeof item.posDraw !== 'undefined') {
item.posDraw();
}
if (typeof item.shadow !== 'undefined') {
removeShadow();
}
if (typeof item.angle !== 'undefined') {
_this3.ctx.restore();
}
},
points,
imgUrl,
imgName,
imgCopy;
for (_iterator.s(); !(_step = _iterator.n()).done;) {
_loop();
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
_this3.width = tWidth > _this3.width ? tWidth : _this3.width;
_this3.height = tHeight > _this3.height ? tHeight : _this3.height;
};
this.clear = function () {
_this3.ctx.clearRect(_this3.x - 2, _this3.y - 2, _this3.width + 4, _this3.height + 4);
};
var animation = function animation() {
var next = _this3.transform();
_this3.clear();
_this3.update();
draw();
if (!next) _this3.stop();
};
var _animationFrame = function animationFrame() {
_this3.clear();
_this3.update();
draw();
if (_this3.transform()) window.requestAnimationFrame(function () {
return _animationFrame();
});
};
this.stop = function () {
return clearInterval(_this3.interval);
};
this.build = function () {
if (_this3.onFirstBuild) {
_this3.onFirstBuild();
delete _this3.onFirstBuild;
}
_this3.update();
draw();
if (_this3.onPostBuild) {
_this3.onPostBuild();
delete _this3.onPostBuild;
}
};
this.animate = function (msInterval) {
if (_this3.transform) {
if (msInterval) _this3.interval = setInterval(animation, msInterval);else window.requestAnimationFrame(function () {
return _animationFrame();
});
} else {
_this3.build();
}
};
} // End Drawable
exports.Alignment = Alignment;
exports.Drawable = Drawable;
exports.Font = Font;
exports.FontLoader = FontLoader;
exports.Gradient = Gradient;
exports.Orientation = Orientation;
exports.Shape = Shape;
exports.drawable2Image = drawable2Image;
}));
//# sourceMappingURL=drawable.umd.js.map