drawable-js
Version:
A lightweight JavaScript library to draw shapes and effects on HTML canvas, inspired by Android's Drawable.
937 lines (921 loc) • 31.2 kB
JavaScript
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 MIT License.
* You may obtain a copy of the License at https://opensource.org/licenses/MIT
*/
// --- 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
},
MOUNTAINS_CHRISTMAS: {
name: 'Mountains of Christmas',
ascentRatio: 0.83,
descentRatio: 0.06
},
RAMABHADRA: {
name: 'Ramabhadra',
ascentRatio: 0.76,
descentRatio: DDR
},
TIMES_NEW_ROMAN: {
name: 'Times New Roman',
ascentRatio: DAR,
descentRatio: DDR
},
TREBUCHET_MS: {
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;
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);
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
var firstLayout = false;
function LinearLayout(x, y) {
this.margin = {
top: 0,
left: 0,
bottom: 0,
right: 0
};
this.views = [];
this.x = x || 0;
this.y = y || 0;
this.verticalAlignment = Alignment.BOTTOM;
this.horizontalAlignment = Alignment.CENTER;
this.orientation = Orientation.HORIZONTAL;
this.addView = function (view) {
this.views.push(view);
};
this.onLayout = function () {
var width = 0;
var height = 0;
if (this.orientation === Orientation.HORIZONTAL) {
var _iterator2 = _createForOfIteratorHelper(this.views),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var view = _step2.value;
if (typeof view.onLayout !== 'undefined') view.onLayout();
var vHeight = view.height + view.margin.top + view.margin.bottom;
if (vHeight > height) height = vHeight;
width += view.width + view.margin.left + view.margin.right;
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
} else {
var _iterator3 = _createForOfIteratorHelper(this.views),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var _view = _step3.value;
if (typeof _view.onLayout !== 'undefined') _view.onLayout();
var vWidth = _view.width + _view.margin.left + _view.margin.right;
if (vWidth > width) width = vWidth;
height += _view.height + _view.margin.top + _view.margin.bottom;
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
}
this.width = this.width || width;
this.height = this.height || height;
};
this.build = function () {
if (!firstLayout) {
firstLayout = true;
this.onLayout();
}
if (typeof this.background !== 'undefined') {
var background = this.background;
var width = this.width + this.margin.left + this.margin.right;
var height = this.height + this.margin.top + this.margin.bottom;
var bgWidth = this.width;
var bgHeight = this.height;
var bg = new Drawable(width, height, this.x, this.y);
bg.ctx = background.ctx;
bg.margin = this.margin;
bg.update = function () {
this.items = [{
shape: Shape.RECTANGLE,
color: background.color,
x: bg.x + bg.margin.left,
y: bg.y + bg.margin.top,
width: bgWidth,
height: bgHeight
}];
if (typeof background.getItems !== 'undefined') {
this.items = background.getItems.bind(this).call();
}
/*if(typeof shadow !== 'undefined')
{
this.items[0].shadow = shadow;
}*/
};
bg.build();
}
if (this.orientation === Orientation.HORIZONTAL) {
if (this.verticalAlignment === Alignment.TOP) {
var cX = this.x + this.margin.left;
var _iterator4 = _createForOfIteratorHelper(this.views),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var view = _step4.value;
view.x = cX;
cX += view.margin.left + view.width + view.margin.right;
view.y = this.y + this.margin.top;
view.build();
if (typeof view.onLayoutBuild !== 'undefined') view.onLayoutBuild();
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
} else if (this.verticalAlignment === Alignment.BOTTOM) {
var _cX = this.x + this.margin.left;
var yToBottom = this.y + this.height;
var _iterator5 = _createForOfIteratorHelper(this.views),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var _view2 = _step5.value;
_view2.x = _cX;
_cX += _view2.margin.left + _view2.width + _view2.margin.right;
_view2.y = yToBottom - _view2.height + _view2.margin.bottom;
_view2.build();
if (typeof _view2.onLayoutBuild !== 'undefined') _view2.onLayoutBuild();
}
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
}
} else {
if (this.horizontalAlignment === Alignment.CENTER) {
var cY = this.y + this.margin.top;
var _iterator6 = _createForOfIteratorHelper(this.views),
_step6;
try {
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
var _view3 = _step6.value;
_view3.x = (this.width - _view3.width + _view3.margin.left + _view3.margin.right) / 2 + this.x - this.margin.left;
_view3.y = cY;
cY += _view3.margin.top + _view3.height + _view3.margin.bottom;
_view3.build();
if (typeof _view3.onLayoutBuild !== 'undefined') _view3.onLayoutBuild();
}
} catch (err) {
_iterator6.e(err);
} finally {
_iterator6.f();
}
}
}
if (typeof this.onPostBuild !== 'undefined') {
this.onPostBuild(); // It is executed once, on the first construction of the object
delete this.onPostBuild;
}
};
}
export { Alignment, Drawable, Font, FontLoader, Gradient, LinearLayout, Orientation, Shape, drawable2Image, getPointsFromAngle };
//# sourceMappingURL=drawable.js.map