783 lines
27 KiB
JavaScript
783 lines
27 KiB
JavaScript
|
Kanvas = function(input){
|
||
|
|
||
|
const self = this,
|
||
|
default_settings = {
|
||
|
quality : 1,
|
||
|
quality_x : 1,
|
||
|
quality_y : 1,
|
||
|
cells : 100,
|
||
|
origin : 5, // Posición origen. Mirar teclado numérico para ver los diferentes valores para cada posición.
|
||
|
frames_per_second : 60,
|
||
|
ratio : null, // Expone la proporción de tamaño del Canvas (16/9 para pantallas WideScreen por ejemplo). Si es equivalente a falso cubrirá todo el área de la capa donde se encuentre.
|
||
|
overwrite : false,
|
||
|
position : "body",
|
||
|
autostart : true,
|
||
|
object_name : "kanvas",
|
||
|
class : "kanvas",
|
||
|
application : "Kanvas",
|
||
|
x : 0,
|
||
|
y : 0,
|
||
|
width : 0,
|
||
|
height : 0,
|
||
|
color : "#000",
|
||
|
blur : 0,
|
||
|
italic : false,
|
||
|
bold : false,
|
||
|
size : 1,
|
||
|
font : "Arial",
|
||
|
align : "left",
|
||
|
alpha : 1,
|
||
|
degrees : 0,
|
||
|
baseline : "Alphabetic",
|
||
|
shadow_x : 0,
|
||
|
shadow_y : 0,
|
||
|
shadow_color : "#000",
|
||
|
shadow_blur : 0,
|
||
|
border_color : "#000",
|
||
|
border_width : 0,
|
||
|
text_italic : false,
|
||
|
text_bold : false,
|
||
|
text_size : 1,
|
||
|
font_family : "Arial",
|
||
|
text_color : "#000",
|
||
|
text_align : "left",
|
||
|
text_alpha : 1,
|
||
|
rotate_x : 0,
|
||
|
rotate_y : 0,
|
||
|
rotate_degrees : 0,
|
||
|
image_x : 0,
|
||
|
image_y : 0,
|
||
|
image_alpha : 1,
|
||
|
rectangle_color : "#000",
|
||
|
rectangle_alpha : 1,
|
||
|
rectangle_x : 0,
|
||
|
rectangle_y : 0,
|
||
|
text_baseline : "Alphabetic",
|
||
|
default_value : null,
|
||
|
hash_alphabet : "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
|
||
|
hash_length : 7
|
||
|
},
|
||
|
cache = [],
|
||
|
_screen = {x : 0, y : 0},
|
||
|
position = {x : 0, y : 0},
|
||
|
events = {},
|
||
|
threads = [],
|
||
|
hashes = [],
|
||
|
attributes = {
|
||
|
natives : ["id", "class", "onmousemove", "tabindex", "onkeydown", "onkeyup"]
|
||
|
};
|
||
|
let q, qx, qy, // Calidad porcentual.
|
||
|
c, // Número de celdas en el lado más corto de la pantalla o área de trabajo rectangular.
|
||
|
fx, fy, // Posición contra el foco.
|
||
|
dx, dy, // Distancia desde los laterales hasta el cuadrado de trabajo.
|
||
|
s, // Tamaño de la celda. Solo se mide un lado pues será cuadrada.
|
||
|
mx, my, // Posición origen del lienzo.
|
||
|
thread = null,
|
||
|
timeout = 0,
|
||
|
last_time = 0,
|
||
|
started = false,
|
||
|
cache_container, context, canvas,
|
||
|
cache_l = 0,
|
||
|
thread_object = null;
|
||
|
|
||
|
let item_self = this.item_self;
|
||
|
let hash_self = this.hash_self;
|
||
|
let object_name = this.object_name;
|
||
|
let mouse = this.mouse = {x : 0, y : 0};
|
||
|
|
||
|
this.map = [];
|
||
|
|
||
|
const null_or_undefined = this.null_or_undefined = value => value === undefined || value === null;
|
||
|
|
||
|
const allow_nulls = this.allow_nulls = nulls => typeof nulls == "boolean" ? nulls : settings(["nulls", "allow_nulls"], null, false, false);
|
||
|
|
||
|
const default_value = this.default_value = (_default, nulls) => _default !== undefined && (nulls || _default !== null) ? _default : settings(["default_value", "default", "by_default"], null, null, true);
|
||
|
|
||
|
const settings = this.settings = (names, inputs, _default, nulls) => {
|
||
|
if(!names)
|
||
|
return default_value(_default, nulls);
|
||
|
|
||
|
nulls = allow_nulls(nulls);
|
||
|
|
||
|
const l = (names.push ? names : names = [names]).length,
|
||
|
m = (inputs = (inputs ? inputs.push ? inputs : [inputs] : []).concat([input, default_settings])).length;
|
||
|
|
||
|
for(let j = 0; j < m; j ++)
|
||
|
if(typeof inputs[j] == "object")
|
||
|
for(let i = 0; i < l; i ++)
|
||
|
if(names[i] && inputs[j][names[i]] !== undefined && (nulls || inputs[j][names[i]] !== null))
|
||
|
return inputs[j][names[i]];
|
||
|
return default_value(_default, nulls);
|
||
|
};
|
||
|
|
||
|
const threads_function = () => threads.forEach(thread => thread && thread());
|
||
|
|
||
|
const threads_start = this.threads_start = frames_per_second => thread_object === null && (thread_object = setInterval(threads_function, 1000 / (isNaN(frames_per_second) || frames_per_second < 1 ? settings(["frames_per_second", "fps"]) : frames_per_second)));
|
||
|
|
||
|
const threads_stop = this.threads_stop = () => {
|
||
|
|
||
|
if(thread_object === null)
|
||
|
return;
|
||
|
|
||
|
clearInterval(thread_object);
|
||
|
thread_object = null;
|
||
|
|
||
|
};
|
||
|
|
||
|
const threads_add = this.threads_add = callback => {
|
||
|
if(typeof callback != "function")
|
||
|
return null;
|
||
|
|
||
|
let i = 0;
|
||
|
const l = threads.length;
|
||
|
|
||
|
for(; i < l; i ++)
|
||
|
if(!threads[i])
|
||
|
break;
|
||
|
|
||
|
threads[i] = callback;
|
||
|
|
||
|
return i;
|
||
|
};
|
||
|
|
||
|
const threads_remove = this.threads_remove = i => !isNaN(i) && threads[i] && (threads[i] = null);
|
||
|
|
||
|
const is_html_object = this.is_html_object = variable => typeof variable == "object" && (variable.tagName || variable.nodeName);
|
||
|
|
||
|
const preload = this.preload = (selector, callback) => {
|
||
|
if(typeof callback != "function")
|
||
|
return;
|
||
|
|
||
|
if(!selector){
|
||
|
callback(null, false, "NO_SELECTOR");
|
||
|
return;
|
||
|
};
|
||
|
if(is_html_object(selector)){
|
||
|
callback(selector, false, "OK");
|
||
|
return;
|
||
|
};
|
||
|
if(!selector.substr){
|
||
|
callback(null, false, "BAD_TYPE");
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
let item;
|
||
|
|
||
|
try{
|
||
|
if(item = document.querySelector(selector)){
|
||
|
callback(item, false, "OK");
|
||
|
return;
|
||
|
};
|
||
|
}catch(exception){
|
||
|
callback(null, false, "BAD_SELECTOR");
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
const timeout = settings(["preload_timeout", "timeout"]),
|
||
|
date = Date.now();
|
||
|
let preload = threads_add(() => {
|
||
|
if(item = document.querySelector(selector)){
|
||
|
threads_remove(preload);
|
||
|
callback(item, true, "OK");
|
||
|
}else if(Date.now() - date > timeout){
|
||
|
threads_remove(preload);
|
||
|
callback(null, true, "TIMEOUT");
|
||
|
};
|
||
|
});
|
||
|
|
||
|
};
|
||
|
|
||
|
const hash = this.hash = () => {
|
||
|
|
||
|
let hash, alphabet = settings(["hash_alphabet", "alphabet"]);
|
||
|
const length = settings(["hash_length", "length"]),
|
||
|
l = (alphabet.push ? alphabet : alphabet = alphabet.split("")).length;
|
||
|
|
||
|
do{
|
||
|
hash = "";
|
||
|
while((hash += alphabet[Math.random() * l >> 0]).length < length);
|
||
|
}while(
|
||
|
hashes.includes(hash) ||
|
||
|
/^\d/.test(hash) ||
|
||
|
document.querySelector("." + hash + ",#" + hash + ",[name=" + hash + "]")
|
||
|
);
|
||
|
hashes.push(hash);
|
||
|
|
||
|
return hash;
|
||
|
};
|
||
|
|
||
|
const set_attribute = this.set_attribute = (item, custom_attributes) => {
|
||
|
if(!is_html_object(item) || typeof custom_attributes != "object")
|
||
|
return;
|
||
|
|
||
|
for(const name in custom_attributes)
|
||
|
item.setAttribute((attributes.natives.includes(name) ? "" : "data-") + name.replace(/[^a-z\d-]+/g, "-"), custom_attributes[name]);
|
||
|
|
||
|
};
|
||
|
|
||
|
const construct = () => {
|
||
|
|
||
|
const custom_attributes = {
|
||
|
natives : settings("attributes_natives")
|
||
|
};
|
||
|
|
||
|
for(const key in custom_attributes){
|
||
|
!attributes[key] && (attributes[key] = []);
|
||
|
(custom_attributes ? custom_attributes.push ? custom_attributes : [custom_attributes] : []).forEach(new_attribute => attributes[key].push(new_attribute));
|
||
|
};
|
||
|
|
||
|
object_name = self.object_name = settings("object_name");
|
||
|
|
||
|
settings("autostart") && self.start();
|
||
|
|
||
|
};
|
||
|
|
||
|
const range_analyze = range => !range || (
|
||
|
mouse.x >= range.x && mouse.x <= range.x + range.width &&
|
||
|
mouse.y >= range.y && mouse.y <= range.y + range.height
|
||
|
);
|
||
|
|
||
|
const on_resize_method = screen => {
|
||
|
|
||
|
if(_screen.x == item_self.offsetWidth && _screen.y == item_self.offsetHeight)
|
||
|
return;
|
||
|
|
||
|
const width = canvas.width = (_screen.x = item_self.offsetWidth) * q * qx,
|
||
|
height = canvas.height = (_screen.y = item_self.offsetHeight) * q * qy;
|
||
|
|
||
|
if(width < height){
|
||
|
s = width / c;
|
||
|
dx = 0;
|
||
|
dy = -(c - (c * height / width)) / 2;
|
||
|
mx = position.x;
|
||
|
my = position.y + dy;
|
||
|
}else{
|
||
|
s = height / c;
|
||
|
dx = -(c - (c * width / height)) / 2;
|
||
|
dy = 0;
|
||
|
mx = position.x + dx;
|
||
|
my = position.y;
|
||
|
};
|
||
|
|
||
|
//resize_methods.forEach((method) => {if(method)method();});
|
||
|
execute_event("resize");
|
||
|
|
||
|
};
|
||
|
|
||
|
const position_set = () => {
|
||
|
|
||
|
const origin = settings("origin");
|
||
|
|
||
|
position.x = c * (.5 * ((origin - 1) % 3));
|
||
|
position.y = c * (1 - (.5 * ((origin - 1) / 3 >> 0)));
|
||
|
|
||
|
};
|
||
|
|
||
|
this.start = () => {
|
||
|
|
||
|
if(started)
|
||
|
return;
|
||
|
started = true;
|
||
|
|
||
|
q = settings(["quality", "q"]);
|
||
|
qx = settings(["quality_x", "qx"]);
|
||
|
qy = settings(["quality_y", "qy"]);
|
||
|
timeout = 1000 / settings("frames_per_second");
|
||
|
c = settings("cells");
|
||
|
position_set();
|
||
|
threads_start();
|
||
|
|
||
|
preload(settings("position"), (position, asynchronous, error) => {
|
||
|
|
||
|
if(!position){
|
||
|
console.error("ERROR. Position HTML for install GUI CANVAS is bad. [" + error + "]");
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
const _class = (hash_self = self.hash_self = hash()) + " " + settings("class");
|
||
|
|
||
|
!new RegExp("\\b" + default_settings.class + "\\b").test(_class) && (_class += " " + default_settings.class);
|
||
|
|
||
|
set_attribute(item_self = self.item_self = position.appendChild(document.createElement("div")), {
|
||
|
id : hash_self,
|
||
|
hash : hash_self,
|
||
|
class : _class,
|
||
|
application : default_settings.application,
|
||
|
onmousemove : object_name + ".check_mouse(this, event);",
|
||
|
tabindex : 0,
|
||
|
onkeydown : object_name + ".key_down(this, event);",
|
||
|
onkeyup : object_name + ".key_up(this, event);"
|
||
|
});
|
||
|
set_attribute(cache_container = item_self.appendChild(document.createElement("div")), {
|
||
|
class : "cache"
|
||
|
});
|
||
|
set_attribute(canvas = item_self.appendChild(document.createElement("canvas")), {
|
||
|
class : "canvas"
|
||
|
});
|
||
|
context = canvas.getContext("2d");
|
||
|
|
||
|
thread = threads_add(thread_method);
|
||
|
on_resize_thread = threads_add(on_resize_method);
|
||
|
item_self.onclick = () => execute_event("click");
|
||
|
|
||
|
});
|
||
|
|
||
|
};
|
||
|
|
||
|
// o = Origin {mx, my}
|
||
|
const draw = this.draw = (map, context, o) => map && map.forEach((level, i) => level && (level.push && draw(level, context, o || {mx : mx, my : my}) || (level.type && components[level.type] && components[level.type](level, context, self, o || {mx : mx, my : my}))));
|
||
|
|
||
|
const refresh_draw = () => {
|
||
|
|
||
|
if(!context)
|
||
|
return;
|
||
|
|
||
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
||
|
draw(self.map, context);
|
||
|
|
||
|
};
|
||
|
|
||
|
const thread_method = () => {
|
||
|
|
||
|
const date = Date.now();
|
||
|
|
||
|
if(date - last_time < timeout)
|
||
|
return;
|
||
|
last_time = date;
|
||
|
|
||
|
refresh_draw();
|
||
|
|
||
|
};
|
||
|
|
||
|
// Establecer posición sobre el foco de origen.
|
||
|
// Establecer posición sobre los laterales del recuadro o área de trabajo.
|
||
|
const value = this.value = (value, quality) => q * value * (quality || 1);
|
||
|
// const _x = this._x = value => q * qx * value * s;
|
||
|
// const _y = this._y = value => q * qy * value * s;
|
||
|
const _x = this._x = value => value * s;
|
||
|
const _y = this._y = value => value * s;
|
||
|
|
||
|
this.cache_set = item => {
|
||
|
|
||
|
let i = 0;
|
||
|
|
||
|
for(; i < cache_l; i ++)
|
||
|
if(cache[i] === null)
|
||
|
break;
|
||
|
|
||
|
cache[i] = item;
|
||
|
cache_l = cache.length;
|
||
|
|
||
|
return i;
|
||
|
};
|
||
|
|
||
|
const get_new_cache_i = item => item.cache_i = self.cache_set(true);
|
||
|
|
||
|
this.cache_clean = i => !isNaN(i) && i >= 0 && i < cache.length && cache[i] !== null && (cache[i] = null);
|
||
|
|
||
|
const preload_cache_items = (items, callback_per_item, callback, i) => {
|
||
|
|
||
|
if(i >= items.length){
|
||
|
typeof callback == "function" && callback();
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
const end = () => {
|
||
|
typeof callback_per_item == "function" && callback_per_item(i, items[i]);
|
||
|
preload_cache_items(items, callback_per_item, callback, i + 1);
|
||
|
};
|
||
|
|
||
|
if(!items[i]){
|
||
|
end();
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
switch(items[i].type){
|
||
|
case "image":
|
||
|
|
||
|
const source = items[i].source || items[i].value;
|
||
|
|
||
|
if(!source){
|
||
|
end();
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
const image = new Image();
|
||
|
|
||
|
image.src = source;
|
||
|
image.crossOrigin = "anonymous";
|
||
|
image.onload = () => {
|
||
|
items[i].cache_i = self.cache_set(image);
|
||
|
// console.log([items[i], items[i].source || items[i].value, cache[items[i].cache_i]]);
|
||
|
end();
|
||
|
};
|
||
|
image.onerror = end;
|
||
|
|
||
|
break;
|
||
|
default:
|
||
|
items[i].cache_i = self.cache_set(image);
|
||
|
end();
|
||
|
break;
|
||
|
};
|
||
|
|
||
|
};
|
||
|
|
||
|
this.preload_cache_items = (items, callback_per_item, callback) => {
|
||
|
|
||
|
if(!items){
|
||
|
typeof callback == "function" && callback();
|
||
|
return;
|
||
|
};
|
||
|
!items.pus && (items = [items]);
|
||
|
|
||
|
preload_cache_items(items, callback_per_item, callback, 0);
|
||
|
|
||
|
};
|
||
|
|
||
|
const angle = this.angle = (x, y, randians) => {
|
||
|
|
||
|
if(typeof x == "object"){
|
||
|
|
||
|
const line = x.push ? {
|
||
|
x : x[0] - y[0],
|
||
|
y : x[1] - y[1]
|
||
|
} : {
|
||
|
x : x.x - y.x,
|
||
|
y : x.y - y.y
|
||
|
};
|
||
|
|
||
|
x = line.x;
|
||
|
y = line.y;
|
||
|
|
||
|
};
|
||
|
|
||
|
let angle = Math.asin(y / ((x ** 2) + (y ** 2)) ** .5);
|
||
|
|
||
|
// if(x >= 0)
|
||
|
// angle += Math.PI / 2;
|
||
|
// else
|
||
|
// angle = (1.5 * Math.PI) - angle;
|
||
|
|
||
|
return (x >= 0 ? angle + (Math.PI / 2) : ((1.5 * Math.PI) - angle)) * (randians ? 1 : 180 / Math.PI);
|
||
|
};
|
||
|
|
||
|
const shadow = (data, context) => {
|
||
|
|
||
|
const z = dx < dy ? _x : _y;
|
||
|
|
||
|
if(!data.ok){
|
||
|
isNaN(data.x) && (data.x = settings(["shadow_x", "x"]));
|
||
|
isNaN(data.y) && (data.y = settings(["shadow_y", "y"]));
|
||
|
!data.color && (data.color = settings(["shadow_color", "color"]));
|
||
|
isNaN(data.blur) && (data.blur = settings(["shadow_blur", "blur"]));
|
||
|
data.ok = true;
|
||
|
};
|
||
|
|
||
|
context.shadowOffsetX = z(data.x);
|
||
|
context.shadowOffsetY = z(data.y);
|
||
|
context.shadowColor = data.color;
|
||
|
context.shadowBlur = z(data.blur);
|
||
|
|
||
|
};
|
||
|
|
||
|
const border = (data, context) => {
|
||
|
|
||
|
if(!data.ok){
|
||
|
!data.color && (data.color = settings(["border_color", "color"]));
|
||
|
isNaN(data.width) && (data.width = settings(["border_width", "width"]));
|
||
|
data.ok = true;
|
||
|
};
|
||
|
|
||
|
context.strokeStyle = data.color;
|
||
|
context.lineWidth = (dx < dy ? _x : _y)(data.width);
|
||
|
|
||
|
};
|
||
|
|
||
|
const components = {
|
||
|
rotate : (data, context, kanvas, o) => {
|
||
|
if(data.ignore)
|
||
|
return;
|
||
|
|
||
|
if(!data.ok){
|
||
|
isNaN(data.x) && (data.x = settings(["rotate_x", "x"]));
|
||
|
isNaN(data.y) && (data.y = settings(["rotate_y", "y"]));
|
||
|
isNaN(data.degrees) && (data.degrees = settings(["rotate_degrees", "degrees"]));
|
||
|
data.ok = true;
|
||
|
};
|
||
|
|
||
|
// console.log(JSON.stringify(data));
|
||
|
// console.log(JSON.stringify([_x(data.x + mx), _y(data.y + my)]));
|
||
|
|
||
|
context.save();
|
||
|
context.translate(_x(data.x + o.mx), _y(data.y + o.my));
|
||
|
context.rotate(data.degrees * Math.PI / 180);
|
||
|
draw(data.childs, context, {mx : 0, my : 0});
|
||
|
context.restore();
|
||
|
|
||
|
},
|
||
|
image : (data, context, kanvas, o) => {
|
||
|
if(data.ignore)
|
||
|
return;
|
||
|
|
||
|
const draw_image = () => {
|
||
|
|
||
|
if(!data.ok){
|
||
|
isNaN(data.swidth) && (data.swidth = cache[data.cache_i].width);
|
||
|
isNaN(data.sheight) && (data.sheight = cache[data.cache_i].height);
|
||
|
isNaN(data.width) && (data.width = data.swidth);
|
||
|
isNaN(data.height) && (data.height = data.sheight);
|
||
|
isNaN(data.x) && (data.x = settings(["image_x", "x"]));
|
||
|
isNaN(data.y) && (data.y = settings(["image_y", "y"]));
|
||
|
isNaN(data.alpha) && (data.alpha = settings(["image_alpha", "alpha"]));
|
||
|
isNaN(data.sx) && (data.sx = 0);
|
||
|
isNaN(data.sy) && (data.sy = 0);
|
||
|
isNaN(data.mx) && (data.mx = 0);
|
||
|
isNaN(data.my) && (data.my = 0);
|
||
|
data.ok = true;
|
||
|
};
|
||
|
|
||
|
const half_width = data.width / 2,
|
||
|
half_height = data.height / 2;
|
||
|
|
||
|
context.save();
|
||
|
context.globalAlpha = data.alpha;
|
||
|
context.translate(_x(o.mx + data.x + data.mx + half_width), _y(o.my + data.y + data.my + half_height));
|
||
|
context.rotate(data.rotate * Math.PI / 180);
|
||
|
context.drawImage(
|
||
|
cache[data.cache_i],
|
||
|
data.sx, data.sy, data.swidth, data.sheight,
|
||
|
_x(-half_width), _y(-half_height), _x(data.width), _y(data.height)
|
||
|
);
|
||
|
draw(data.childs, context, {mx : 0, my : 0});
|
||
|
context.restore();
|
||
|
|
||
|
};
|
||
|
|
||
|
if(isNaN(data.cache_i)){
|
||
|
|
||
|
const i = get_new_cache_i(data);
|
||
|
|
||
|
cache[i] = new Image();
|
||
|
cache[i].src = data.source || data.image;
|
||
|
cache[i].crossOrigin = "anonymous";
|
||
|
cache[i].onload = draw_image;
|
||
|
|
||
|
}else
|
||
|
draw_image();
|
||
|
|
||
|
},
|
||
|
cache : (data, context, kanvas, o) => {
|
||
|
if(data.ignore)
|
||
|
return;
|
||
|
|
||
|
context.save();
|
||
|
|
||
|
if(isNaN(data.cache_i)){
|
||
|
|
||
|
const cache_canvas = cache_container.appendChild(document.createElement("canvas")),
|
||
|
cache_context = cache_canvas.getContext("2d"),
|
||
|
width = data.width || canvas.width,
|
||
|
height = data.height || canvas.height;
|
||
|
image = new Image();
|
||
|
|
||
|
cache_canvas.width = width;
|
||
|
cache_canvas.height = height;
|
||
|
|
||
|
get_new_cache_i(data);
|
||
|
cache_context.save();
|
||
|
// cache_context.translate(_x(-o.mx), _y(-o.my));
|
||
|
draw(data.childs, cache_context, {mx : 0, my : 0});
|
||
|
image.src = cache_canvas.toDataURL("image/png");
|
||
|
cache[data.cache_i] = image;
|
||
|
cache_context.restore();
|
||
|
|
||
|
cache_canvas.remove();
|
||
|
|
||
|
};
|
||
|
|
||
|
context.drawImage(cache[data.cache_i], 0, 0);
|
||
|
context.restore();
|
||
|
|
||
|
},
|
||
|
rectangle : (data, context, kanvas, o) => {
|
||
|
if(data.ignore)return;
|
||
|
|
||
|
const proportion = canvas.width > canvas.height ? canvas.width / canvas.height : canvas.height / canvas.width;
|
||
|
|
||
|
if(!data.ok){
|
||
|
isNaN(data.alpha) && (data.alpha = settings(["rectangle_alpha", "alpha"]));
|
||
|
!data.color && (data.color = settings(["rectangle_color", "color"]));
|
||
|
isNaN(data.x) && (data.x = settings(["rectangle_x", "x"]));
|
||
|
isNaN(data.y) && (data.y = settings(["rectangle_y", "y"]));
|
||
|
isNaN(data.width) && (data.width = proportion * c);
|
||
|
isNaN(data.height) && (data.height = proportion * c);
|
||
|
isNaN(data.mx) && (data.mx = 0);
|
||
|
isNaN(data.my) && (data.my = 0);
|
||
|
data.ok = true;
|
||
|
};
|
||
|
|
||
|
context.save();
|
||
|
data.shadow && (shadow(data.shadow, context));
|
||
|
context.globalAlpha = data.alpha;
|
||
|
context.fillStyle = data.color;
|
||
|
context.translate(_x(o.mx + data.x + data.mx), _y(o.my + data.y + data.my));
|
||
|
context.rotate(data.rotate * Math.PI / 180);
|
||
|
context.translate(_x(-data.mx), _y(-data.my));
|
||
|
context.fillRect(_x(data.x), _y(data.y), _x(data.width), _y(data.height));
|
||
|
draw(data.childs, context, {mx : 0, my : 0});
|
||
|
context.restore();
|
||
|
|
||
|
},
|
||
|
text : (data, context, kanvas, o) => {
|
||
|
if(data.ignore)
|
||
|
return;
|
||
|
|
||
|
if(!data.ok){
|
||
|
typeof data.italic != "boolean" && (data.italic = settings(["text_italic", "italic"]));
|
||
|
isNaN(data.bold) && typeof data.bold != "boolean" && (data.bold = settings(["text_bold", "bold"]));
|
||
|
isNaN(data.size) && (data.size = settings(["text_size", "size"]));
|
||
|
data.font && (data.font_family = data.font);
|
||
|
!data.font_family && (data.font_family = settings(["text_font_family", "text_font", "font"]));
|
||
|
!data.align && (data.align = settings(["text_align", "align"]));
|
||
|
isNaN(data.x) && (data.x = settings(["text_x", "x"]));
|
||
|
isNaN(data.y) && (data.y = settings(["text_y", "y"]));
|
||
|
!data.text && (data.text = "");
|
||
|
isNaN(data.alpha) && (data.alpha = settings(["text_alpha", "alpha"]));
|
||
|
!data.baseline && (data.baseline = settings(["text_baseline", "baseline"]));
|
||
|
data.ok = true;
|
||
|
};
|
||
|
|
||
|
context.save();
|
||
|
data.shadow && (shadow(data.shadow, context));
|
||
|
context.globalAlpha = data.alpha;
|
||
|
context.textAlign = data.align;
|
||
|
context.textBaseline = data.baseline;
|
||
|
context.font = (
|
||
|
(data.italic ? "italic " : "") +
|
||
|
(data.bold ? isNaN(data.bold) ? "bold " : data.bold + " " : "") +
|
||
|
(dx < dy ? _x : _y)(data.size) + "px " +
|
||
|
data.font_family
|
||
|
);
|
||
|
if(data.color){
|
||
|
context.fillStyle = data.color;
|
||
|
context.fillText(data.text, _x(data.x + mx), _y(data.y + my));
|
||
|
};
|
||
|
if(data.border){
|
||
|
border(data.border, context);
|
||
|
context.strokeText(data.text, _x(data.x + mx), _y(data.y + my));
|
||
|
};
|
||
|
context.restore();
|
||
|
|
||
|
},
|
||
|
block : (data, context, kanvas, o) => {
|
||
|
if(data.ignore)
|
||
|
return;
|
||
|
|
||
|
if(!data.ok){
|
||
|
isNaN(data.alpha) && (data.alpha = settings(["block_alpha", "alpha"]));
|
||
|
data.ok = true;
|
||
|
};
|
||
|
|
||
|
context.save();
|
||
|
context.globalAlpha = data.alpha;
|
||
|
draw(data.childs, context, {mx : 0, my : 0});
|
||
|
context.restore();
|
||
|
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.add_components = (json, overwrite) => {
|
||
|
if(!json)
|
||
|
return;
|
||
|
|
||
|
!json.push && (json = [json]);
|
||
|
typeof overwrite != "bool" && (overwrite = settings("overwrite"));
|
||
|
|
||
|
json.forEach((items) => {
|
||
|
if(!items)
|
||
|
return;
|
||
|
if(items.push)
|
||
|
self.add_components(items, overwrite);
|
||
|
else if(typeof items == "object")
|
||
|
for(let key in items)
|
||
|
(overwrite || !components[key]) && (components[key] = items[key]);
|
||
|
});
|
||
|
|
||
|
};
|
||
|
|
||
|
this.check_mouse = (item, event) => {
|
||
|
|
||
|
item_self.setAttribute("data-mouse-x", mouse.x = (event.clientX * q * qx / s) - mx);
|
||
|
item_self.setAttribute("data-mouse-y", mouse.y = (event.clientY * q * qy / s) - my);
|
||
|
|
||
|
execute_event("mouse_move");
|
||
|
|
||
|
};
|
||
|
|
||
|
const on_event = this.on_event = (name, method, range) => {
|
||
|
|
||
|
if(typeof method != "function")
|
||
|
return null;
|
||
|
|
||
|
!events[name] && (events[name] = {
|
||
|
methods : [],
|
||
|
l : 0,
|
||
|
ranges : []
|
||
|
});
|
||
|
|
||
|
let i = 0;
|
||
|
|
||
|
for(; i < events[name].l; i ++)
|
||
|
if(!events[name].methods[i])
|
||
|
break;
|
||
|
|
||
|
events[name].methods[i] = method;
|
||
|
events[name].ranges[i] = range;
|
||
|
events[name].l = events[name].methods.length;
|
||
|
|
||
|
return i;
|
||
|
};
|
||
|
|
||
|
const remove_event = this.remove_event = (name, i) => events[name] && !isNaN(i) && i >= 0 && i < events[name].l && events[name].methods[i] && (events[name].methods[i] = null);
|
||
|
|
||
|
const execute_event = this.execute_event = (name, input) => {
|
||
|
|
||
|
if(events[name] && events[name].l)
|
||
|
for(let i = 0; i < events[name].l; i ++)
|
||
|
events[name].methods[i] && events[name].methods[i](range_analyze(events[name].ranges[i]), input);
|
||
|
|
||
|
};
|
||
|
|
||
|
const event_range = this.event_range = (name, i) => events[name] && !isNaN(i) && i >= 0 && i < events[name].l ? events[name].ranges[i] : null;
|
||
|
|
||
|
this.on_mouse_move = (method, range) => on_event("mouse_move", method, range);
|
||
|
this.on_resize = (method, range) => on_event("resize", method, range);
|
||
|
this.on_click = (method, range) => on_event("click", method, range);
|
||
|
this.on_key_down = (method, range) => on_event("key_down", method, range);
|
||
|
this.on_key_up = (method, range) => on_event("key_up", method, range);
|
||
|
|
||
|
this.remove_mouse_move = i => {remove_event("mouse_move", i);};
|
||
|
this.remove_resize = i => {remove_event("resize", i);};
|
||
|
this.remove_click = i => {remove_event("click", i);};
|
||
|
this.remove_key_down = i => {remove_event("key_down", i);};
|
||
|
this.remove_key_up = i => {remove_event("key_up", i);};
|
||
|
|
||
|
this.range_mouse_move = i => event_range("mouse_move", i);
|
||
|
this.range_resize = i => event_range("resize", i);
|
||
|
this.range_click = i => event_range("click", i);
|
||
|
this.range_key_down = i => event_range("key_down", i);
|
||
|
this.range_key_up = i => event_range("key_up", i);
|
||
|
|
||
|
this.key_down = (item, event) => execute_event("key_down", {code : event.keyCode});
|
||
|
this.key_up = (item, event) => execute_event("key_up", {code : event.keyCode});
|
||
|
|
||
|
this.get_margins = () => {return {x : mx, y : my};};
|
||
|
this.get_position = () => {return {x : position.x, y : position.y};};
|
||
|
this.get_cells = () => c;
|
||
|
this.get_canvas_distance = () => {return {x : dx, y : dy};};
|
||
|
this.get_cell_size = () => s;
|
||
|
|
||
|
construct();
|
||
|
|
||
|
};
|