From a6cdaf3309128f8b1bed7a14c880eb8b337128bd Mon Sep 17 00:00:00 2001 From: KyMAN <0kyman0@gmail.com> Date: Mon, 27 Apr 2026 07:10:35 +0200 Subject: [PATCH] #wip(js): Building new models version. --- .gitignore | 3 +- Public/ecma/Kanvas.ecma.js | 2476 ++++-------------- Public/ecma/Modules/Parallax.ecma.js | 601 +++++ Public/ecma/t.js | 104 - Public/ecma/version/20230707/Kanvas.ecma.js | 747 ------ Public/ecma/version/20250107/Kanvas.ecma.js | 2535 ------------------- Public/ecma/version/221106/Kanvas.ecma.js | 936 ------- Public/ecma/version/30311230/Kanvas.ecma.js | 782 ------ Public/ecma/version/Kanvas.AnP.ecma.js | 456 ---- Public/ecma/version/Kanvas.ecma.js | 747 ------ Public/test/index.anp.html | 87 - Public/test/index.html | 3 + Public/test/shadow.html | 51 - Public/test/x.html | 20 - Public/test/y.html | 18 - version | 2 +- 16 files changed, 1036 insertions(+), 8532 deletions(-) create mode 100644 Public/ecma/Modules/Parallax.ecma.js delete mode 100644 Public/ecma/t.js delete mode 100644 Public/ecma/version/20230707/Kanvas.ecma.js delete mode 100644 Public/ecma/version/20250107/Kanvas.ecma.js delete mode 100755 Public/ecma/version/221106/Kanvas.ecma.js delete mode 100755 Public/ecma/version/30311230/Kanvas.ecma.js delete mode 100644 Public/ecma/version/Kanvas.AnP.ecma.js delete mode 100644 Public/ecma/version/Kanvas.ecma.js delete mode 100755 Public/test/index.anp.html delete mode 100644 Public/test/shadow.html delete mode 100644 Public/test/x.html delete mode 100644 Public/test/y.html diff --git a/.gitignore b/.gitignore index f724e26..42bffd7 100755 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ html.files.json /Python/Abstracts/AnPMap.py /Python/Abstracts/Applications.py __pycache__ -.sass-cache \ No newline at end of file +.sass-cache +*.deleted.* \ No newline at end of file diff --git a/Public/ecma/Kanvas.ecma.js b/Public/ecma/Kanvas.ecma.js index 5144cb8..4536b8a 100644 --- a/Public/ecma/Kanvas.ecma.js +++ b/Public/ecma/Kanvas.ecma.js @@ -1,231 +1,289 @@ "use strict"; /** - * @callback kanvas_event_callback - * @param {!number} i - * @param {...any} [parameters] - * @returns {Array.} + * @typedef {Object} KanvasItemType + * @property {!string} type */ /** - * @callback kanvas_thread_callback - * @param {!Kanvas.Thread} thread + * @typedef {Object} KanvasItemPosition + * @property {!number} [x = 0] + * @property {!number} [y = 0] */ /** - * @callback kanvas_execute_callback - * @param {...any} [parameters] - * @returns {any|null} + * @typedef {Object} KanvasItemSize + * @property {!number} [width = 0] + * @property {!number} [height = 0] */ /** - * @callback kanvas_preload_callback - * @param {?HTMLElement} item - * @param {!boolean} asynchronous - * @returns {void} + * @typedef {Object} KanvasItemCommon + * @property {!number} [alpha = 1] + * @property {!number} [rotation = 0] */ /** - * @callback kanvas_default_callback - * @returns {void} + * @typedef {Object} KanvasShapeBase + * @property {!string} [color = "#000"] + * @property {!number} [border_width = 0] + * @property {!string} [border_color = "#000"] + * @property {!number} [border_alpha = 1] + * @property {!string} [shadow = "#000"] + * @property {!number} [shadow_blur = 0] */ /** - * @class + * @typedef {Object} KanvasObjectChildren + * @property {!Array.} [children = []] + */ + +/** + * @typedef {Object} KanvasCircleSize + * @property {!number} [radius = 0] + */ + +// DSL inputs properties. +/** + * @typedef {KanvasItemPosition} KanvasBase + * @typedef {KanvasItemPosition} KanvasCache + * @typedef {KanvasItemPosition & KanvasItemSize} KanvasClean + * @typedef {KanvasItemPosition & KanvasItemSize & KanvasShapeBase & KanvasItemCommon} KanvasRectangle + * @typedef {KanvasItemPosition & KanvasCircleSize & KanvasShapeBase & KanvasItemCommon} KanvasCircle + */ + +// DSL Objects properties. +/** + * @typedef {KanvasItemType & KanvasItemPosition} KanvasObjectBase + * @typedef {KanvasObjectBase} KanvasObjectCache + * @typedef {KanvasObjectBase & KanvasItemSize & KanvasObjectChildren} KanvasObjectClean + * @typedef {KanvasObjectBase & KanvasItemSize & KanvasShapeBase & KanvasItemCommon & KanvasObjectChildren} KanvasObjectRectangle + * @typedef {KanvasObjectBase & KanvasCircleSize & KanvasShapeBase & KanvasItemCommon & KanvasObjectChildren} KanvasObjectCircle + */ + +/** + * @callback kanvas_dsl_callback + * @param {!KanvasBase} inputs + * @return {KanvasObjectBase} + */ + +/** + * @callback kanvas_shape_callback + * @param {!KanvasShapeBase} inputs + * @returns {boolean} + */ + +/** + * @class Kanvas * @constructor - * @param {!(Object.|Array.)} [inputs = {}] + * @param {!KanvasInputs} [inputs = {}] * @returns {void} * @access public + * @static */ export const Kanvas = (function(){ + /** + * @typedef {Object} kanvas_inputs + * @property {!(HTMLElement|string)} [position = document.querySelector("body")] + * @property {!number} [cells = 40] + * @property {!number} [frames_per_second = 60] + * @property {!number} [quality = 1] + * @property {!boolean} [autobuild = true] + */ + + /** + * @typedef {Object} kanvas_build + * @property {!(HTMLElement|string)} position + */ + + /** + * @callback preload_callback + * @param {HTMLElement|null} position + * @param {boolean} asinchronous + * @return {void} + */ + + /** + * @typedef {Object} kanvas_preload_html_item + * @property {!string} selector + * @property {!preload_callback} callback + * @property {!number} [timeout = 2000] + * @property {!number} [frames_per_second = 60] + */ + /** * @constructs Kanvas - * @param {!(Object.|Array.)} [inputs = {}] + * @param {!kanvas_inputs} [inputs = {}] * @returns {void} * @access private + * @static */ - const Kanvas = function(inputs = {}){ + const Kanvas = function({ + position = document.querySelector("body"), + cells = 40, + frames_per_second = 60, + quality = 1, + autobuild = true, + thread_mode = Kanvas.THREADS_MODE_ANIMATION + } = {}){ /** @type {Kanvas} */ - const self = this, - /** @type {Object.} */ - settings = Kanvas.get_dictionary(inputs, Kanvas.OVERWRITE), - /** @type {Array.} */ - threads = [], - /** @type {Kanvas.Cache} */ - cache = new Kanvas.Cache(), - /** @type {Object.} */ - images_cache = {}, - /** @type {Array.} */ - thread_times = []; - /** @type {Kanvas.Thread|null} */ - let screen_thread = null, - /** @type {Kanvas.Thread|null} */ - autodraw_thread = null, + const self = this, + /** @type {Object.} */ + cache = { + /** @type {Object.} */ + canvas : {x : 0, y : 0} + }, + /** @type {number} */ + frames_timer = 1000 / frames_per_second; + /** @type {number} */ + let cell_size = 0, /** @type {boolean} */ - clicking = false, - /** @type {number} */ - last_time = 0, - /** @type {number} */ - thread_times_summatory = 0, - /** @type {Kanvas.Thread|null} */ - delta_thread = null; + built = false, + /** @type {number|null} */ + thread = null; - /** @type {number} */ - this.threads_mode = Kanvas.THREADS_MODE_ANIMATION; - /** @type {number} */ - this.frames_per_second = 60; - /** @type {number} */ - this.preload_timeout = 2000; - /** @type {number} */ - this.delta = 0; - /** @type {number} */ - this.cells = 40; - /** @type {number} */ - this.quality = 1; - /** @type {number} */ - this.start_x = .5; - /** @type {number} */ - this.start_y = .5; - /** @type {number} */ - this.cells_x = 0; - /** @type {number} */ - this.cells_y = 0; - /** @type {number} */ - this.cell_size = 0; - /** @type {number} */ - this.x = 0; - /** @type {number} */ - this.y = 0; - /** @type {number} */ - this.default_font_family = "monospace"; - /** @type {number} */ - this.frames_per_second = 24; - /** @type {number} */ - this.real_frames_per_second = 0; - /** @type {number} */ - this.thread_times_samples = 3; - /** @type {number} */ - this.difference = 0; - - /** @type {HTMLElement|null} */ - this.item_self = null; /** @type {HTMLCanvasElement|null} */ this.canvas = null; /** @type {CanvasRenderingContext2D|null} */ this.context = null; - - /** @type {Kanvas.Event} */ - this.on_ready = new Kanvas.Event(Kanvas.ONCE); - /** @type {Kanvas.Event} */ - this.on_change_screen = new Kanvas.Event(); - - /** @type {Kanvas.Event} */ - this.on_mouse_down = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_up = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_click = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_over = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_out = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_move = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_key_down = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_key_up = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_key_press = new Kanvas.Event(); - - /** @type {Array.} */ + /** @type {Array.} */ this.map = []; + /** @type {Kanvas.Event} */ + this.threads = new Kanvas.Event(); /** * @returns {void} * @access private */ const constructor = () => { + autobuild && self.build(position); + }; - /** @type {string|HTMLElement|null} */ - const position = self.settings("position"), - on_ready_method = self.settings("on_ready"); + /** + * @param {!kanvas_build} [inputs = {}] + * @returns {void} + * @access public + */ + this.build = ({ + position = document.querySelector("body") + } = {}) => { - self.threads_mode = self.settings("threads_mode", null, self.threads_mode); - self.start_x = self.settings("start_x", null, self.start_x); - self.start_y = self.settings("start_y", null, self.start_y); - self.preload_timeout = self.settings(["preload_timeout", "timeout"], null, self.preload_timeout); - self.default_font_family = self.settings("default_font_family", null, self.default_font_family); - self.quality = self.settings(["quality", "q"], null, self.quality); - self.cells = self.settings("cells", null, self.cells); - self.thread_times_samples = self.settings("thread_times_samples", null, self.thread_times_samples); - self.frames_per_second = self.settings(["frames_per_second", "fps"], null, self.frames_per_second); + if(built) + return; + built = true; - on_ready_method && self.on_ready.add(on_ready_method); + self.preload(position, (position, _) => { + if(position){ - execute_threads_by_mode(); + ( + self.canvas = position.appendChild(document.createElement("canvas")) + ).setAttribute("class", "kanvas"); + self.context = self.canvas.getContext("2d"); - position && self.set(position); + thread = self.threads.add(thread_executor); + + }else + built = false; + }); }; /** - * @returns {number} + * @param {!KanvasObjectBase} item + * @return {void} * @access private */ - const thread_timer = () => self.frames_per_second && 1000 / self.frames_per_second; + const shape_common = (item, callback) => { + if(item.color) + self.context.fillStyle = item.color; + if(item.border_width){ + self.context.lineWidth = item.border_width; + self.context.strokeStyle = item.border_color; + // self.context.globalAlpha = item.border_alpha; + }; + if(item.shadow_blur){ + self.context.shadowColor = item.shadow; + self.context.shadowBlur = item.shadow_blur; + } + callback(); + if(item.border_width) + self.context.stroke(); + if(item.color) + self.context.fill(); + }; + + /** @type {Object.} */ + this.shapes = { + clean : item => { + self.context.clearRect(0, 0, item.width * cell_size, item.height * cell_size); + return true; + }, + rectangle : item => { + shape_common(item, () => { + self.context.rect(0, 0, item.width * cell_size, item.height * cell_size); + }); + } + }; + + /** + * @param {!Array.} map + * @returns {void} + * @access private + */ + const draw = map => { + map.forEach(item => { + if(!self.shapes[item.type]) + return; + + self.context.save(); + + self.context.translate(item.x * cell_size, item.y * cell_size); + if(item.rotation !== undefined) + self.context.rotate(item.rotation * Math.PI / 180); + if(item.alpha !== undefined) + self.context.globalAlpha = item.alpha; + + self.shapes[item.type](item) && item.children && draw(item.children); + + self.context.restore(); + + }); + }; /** * @returns {void} * @access private */ - const execute_threads_by_mode = () => { - switch(self.threads_mode){ - case Kanvas.THREADS_MODE_INTERVAL: - - /** @type {Object.} */ - const cache = { - frames_per_second : self.frames_per_second, - mode : self.threads_mode - }, - /** @type {number} */ - interval = setInterval(() => { - execute_threads(); - if( - cache.frames_per_seconds != self.frames_per_second || - cache.mode != self.threads_mode - ){ - clearInterval(interval); - execute_threads_by_mode(); - }; - }, thread_timer()); - + const thread_executor = () => { + switch(thread_mode){ + case Kanvas.THREAD_MODE_INTERVAL: + setInterval(thread_method, frames_timer); break; case Kanvas.THREADS_MODE_TIMEOUT: setTimeout(() => { - execute_threads(); - execute_threads_by_mode(); - }, thread_timer()); + thread_method(); + thread_executor(); + }, frames_timer); break; case Kanvas.THREADS_MODE_ANIMATION: - default: /** @type {number} */ - const time = Date.now(), - /** @type {number} */ - timer = thread_timer(); + const time = Date.now(); requestAnimationFrame(() => { - execute_threads(); - // execute_threads_by_mode(); - setTimeout(() => { - execute_threads_by_mode(); - }, timer - (Date.now() - time)); + thread_method(); + setTimeout(thread_executor, frames_timer - (Date.now() - time)); }); break; + case Kanvas.THREADS_MODE_ONLY_ANIMATION: + requestAnimationFrame(() => { + thread_method(); + thread_executor(); + }); + break; }; }; @@ -233,1879 +291,226 @@ export const Kanvas = (function(){ * @returns {void} * @access private */ - const execute_threads = () => { - threads.forEach(thread => { - thread && thread.execute(); - }); - }; + const thread_method = () => { - /** - * @param {!(string|Array.)} keys - * @param {!(Object.|Array.)} inputs - * @param {?any} [_default = null] - * @param {!number} [options = 0] - * @returns {any|null} - * @access public - */ - this.settings = (keys, inputs = null, _default = null, options = 0) => { - return Kanvas.get_value(keys, [inputs, settings], _default, options); - }; + /** @type {boolean} */ + let has_changes = false; - /** - * @param {!kanvas_thread_callback} callback - * @param {?(Object.|Array.)} inputs - * @returns {Kanvas.Thread} - * @access public - */ - this.thread_add = (callback, inputs = null) => { - - /** @type {Kanvas.Thread} */ - const thread = new Kanvas.Thread(self, callback, inputs), - /** @type {number} */ - l = threads.length; - - for(thread.i = 0; thread.i < l; thread.i ++) - if(!threads[thread.i]) - break; - - threads[thread.i] = thread; - - return thread; - }; - - /** - * @param {!Kanvas.Thread} thread - * @returns {void} - * @access public - */ - this.thread_remove = thread => { - thread instanceof Kanvas.Thread && threads[thread.i] && (threads[thread.i] = null); - }; - - /** - * @param {!(string|HTMLElement)} selector - * @param {!kanvas_preload_callback} callback - * @param {!number} timeout - * @returns {Array.} - * @access public - */ - this.preload_html_item = (selector, callback, timeout = 0) => { - - /** @type {kanvas_preload_callback} */ - const end = (item, asynchronous) => { - - Kanvas.execute(callback, item, asynchronous); - - return [item, asynchronous]; + if(cache.canvas.x != self.canvas.clientWidth){ + has_changes = true; + self.canvas.width = (cache.canvas.x = self.canvas.clientWidth) * quality; }; + if(cache.canvas.y != self.canvas.clientHeight){ + has_changes = true; + self.canvas.height = (cache.canvas.y = self.canvas.clientHeight) * quality; + } - if(Kanvas.is_html_item(selector)) - return end(selector, false); - if(Kanvas.is_string(selector)){ + if(has_changes) + cell_size = cache.canvas[cache.canvas.x < cache.canvas.y ? "x" : "y"] * quality / cells; - /** @type {HTMLElement|null} */ - let item; + self.context.clearRect(0, 0, self.canvas.width, self.canvas.height); + draw(self.map); - try{ - if(item = document.querySelector(selector)) - return end(item, false); - }catch(exception){ - return end(null, false); - }; - - timeout || (timeout = self.preload_timeout); - - /** @type {number} */ - const time = Date.now(), - /** @type {Kanvas.Thread} */ - thread = self.thread_add(() => { - if(item = document.querySelector(selector)){ - self.thread_remove(thread); - end(item, true); - }else if(Date.now() - time > timeout){ - self.thread_remove(thread); - end(null, true); - }; - }, { - /** @type {boolean} */ - start_now : true, - /** @type {boolean} */ - bucle : true - }); - - }else - return end(null, false); - }; - - const check_map_events = (event, device, events = null) => { - self.map.forEach(item => { - item && item.status && !item.ignore_events && item["check_" + device](event, events); - }); - }; - - /** - * @param {!(string|HTMLElement)} position - * @param {?kanvas_default_callback} [callback = null] - * @returns {void} - * @access public - */ - this.set = (position, callback = null) => { - self.preload_html_item(position, (item, asynchronous) => { - - if(item){ - - if(item.tagName.toLowerCase() == "canvas"){ - self.canvas = item; - (self.item_self = item.parentNode).classList.contains("kanvas") || self.item_self.classList.add("kanvas"); - }else if(item.classList.contains("kanvas")) - self.item_self = item; - else{ - (self.item_self = item.appendChild(document.createElement("div"))).setAttribute("class", "kanvas"); - self.canvas = self.item_self.appendChild(document.createElement("canvas")); - }; - self.item_self.setAttribute("data-cells", self.cells); - self.item_self.setAttribute("data-quality", self.quality); - self.context = self.canvas.getContext("2d"); - - self.canvas.addEventListener("mousemove", event => { - check_map_events(event, "mouse"); - self.on_mouse_move.execute(event); - }); - self.canvas.addEventListener("mousedown", event => { - check_map_events(event, "click", Kanvas.MOUSE_DOWN); - clicking || (clicking = true); - self.on_mouse_down.execute(event); - }); - self.canvas.addEventListener("mouseup", event => { - check_map_events(event, "click", Kanvas.MOUSE_UP | (clicking ? Kanvas.MOUSE_CLICK : 0)); - self.on_mouse_up.execute(event); - if(clicking){ - clicking = false; - self.on_click.execute(event); - }; - }); - self.canvas.addEventListener("mouseout", event => { - clicking && (clicking = false); - self.on_mouse_out.execute(event); - }); - self.canvas.addEventListener("mouseover", event => { - self.on_mouse_over.execute(event); - }); - - screen_thread = self.thread_add(screen_thread_method, { - bucle : true, - start_now : true - }); - - delta_thread = self.thread_add(screen_delta_method, { - bucle : true, - start_now : true - }); - - autodraw_thread = self.thread_add(draw_thread_method, { - bucle : true, - start_now : false - }); - - if(asynchronous){ - self.on_ready.mode |= Kanvas.AUTOEXECUTE; - self.on_ready.execute(); - }else - setTimeout(() => { - self.on_ready.mode |= Kanvas.AUTOEXECUTE; - self.on_ready.execute(); - }, 0); - - }; - - Kanvas.execute(callback); - - }); - }; - - const screen_delta_method = () => { - try{ - - /** @type {number} */ - const time = performance.now(); - - if(last_time){ - - /** @type {number} */ - const difference = last_time ? time - last_time : 0; - - self.difference = difference; - self.delta = difference / 100; - thread_times.push(difference); - thread_times_summatory += difference; - - if(thread_times.length){ - - while(thread_times.length > self.thread_times_samples) - thread_times_summatory -= thread_times.shift(); - - /** @type {number} */ - const average = thread_times_summatory / thread_times.length; - - average && (self.real_frames_per_second = 1000 / average); - - }; - - }; - last_time = time; - - }catch(exception){ - console.error(exception); - }; - }; - - const draw_thread_method = () => { - self.context.clearRect(0, 0, self.width, self.height); - self.draw(self.context); - }; - - /** - * @returns {void} - * @access private - */ - const screen_thread_method = () => { - if(cache.x != self.canvas.offsetWidth || cache.y != self.canvas.offsetHeight || cache.quality != self.quality){ - - cache.x = self.canvas.offsetWidth; - cache.y = self.canvas.offsetHeight; - cache.quality = self.quality; - - self.cell_size = (cache.x < cache.y ? cache.x : cache.y) / self.cells; - self.cells_x = cache.x / self.cell_size; - self.cells_y = cache.y / self.cell_size; - - self.x = cache.x * this.start_x; - self.y = cache.y * this.start_y; - - self.item_self.style.fontSize = self.cell_size + "px"; - self.canvas.setAttribute("width", self.width = cache.x * self.quality); - self.canvas.setAttribute("height", self.height = cache.y * self.quality); - - self.on_change_screen.execute(); - - }; - }; - - /** - * @param {!number} value - * @returns {number} - * @access public - */ - this._ = value => { - return value * self.quality * self.cell_size; - }; - - /** - * @param {!Array.|Object.>} level - * @param {!string} name - * @param {!(Object.|Array.)} inputs - * @param {!number} i - * @param {?Kanvas.ObjectBase} parent - * @returns {void} - * @access private - */ - const build_shape = (level, name, inputs, i, parent) => { - if(Kanvas.SHAPES[name]){ - try{ - (level[i] = new Kanvas.SHAPES[name](self, parent, inputs, i)).check_full_done(); - }catch(exception){ - console.error(exception); - }; - }else - level[i] = null; - - return level[i]; - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @param {?Array.|Object.>} level - * @param {?Kanvas.ObjectBase} parent - * @returns {void} - * @access public - */ - this.draw = (context, level = null, parent = null) => { - (level || (level = self.map)).forEach((item, i) => { - if(Kanvas.is_array(item)){ - if(Kanvas.is_string(item[0])) - item = build_shape(level, item[0], item, i, parent); - else - self.draw(context, item); - }else if(Kanvas.is_dictionary(item)) - item = build_shape(level, item.type, item, i, parent); - item && item.draw_level(context); - }); - }; - - /** - * @param {!(string|Image)} source - * @param {!kanvas_load_image_callback} callback - * @returns {void} - * @access public - */ - this.preload_image = (source, callback) => { - if(Kanvas.is_image(source)) - callback(source, ok); - else if(images_cache[source]) - callback(...images_cache[source]); - else - Kanvas.load_image(source, (image, ok) => { - callback(...(images_cache[source] = [image, ok])); - }); }; constructor(); }; - /** - * @class - * @constructor - * @returns {void} - * @access public - * @static - */ - Kanvas.Cache = function(){ - /** @type {number} */ - this.x = 0; - /** @type {number} */ - this.y = 0; - /** @type {number} */ - this.quality = 0; + /** @type {Object.} */ + Kanvas.DSL = { + + /** + * @param {!string} type + * @param {!KanvasBase} inputs + * @returns {KanvasObjectBase} + * @access public + */ + base : (type, inputs = {}) => { + + /** @type {{x: number, y: number}} */ + const {x = 0, y = 0} = inputs; + + return { + type : type, + x : x, + y : y + }; + }, + + /** + * @param {!KanvasItemCommon} inputs + * @returns {KanvasItemCommon} + * @access public + */ + item_common : (inputs = {}) => { + + /** @type {{alpha: number, rotation: number}} */ + const {alpha = 1, rotation = 0} = inputs; + + return { + alpha : alpha, + rotation : rotation + }; + }, + + /** + * @param {!KanvasShapeBase} inputs + * @returns {KanvasShapeBase} + * @access public + */ + shape_common : (inputs = {}) => { + + /** @type {{color: string, border_width: number, border_color: string, border_alpha: number, shadow: string}} */ + const { + color = "#000", + border_width = 0, + border_color = "#000", + border_alpha = 1, + shadow = "#000", + shadow_blur = 0 + } = inputs; + + return { + color : color, + border_width : border_width, + border_color : border_color, + border_alpha : border_alpha, + shadow : shadow, + shadow_blur : shadow_blur + }; + }, + + /** + * @param {!string} type + * @param {!KanvasItemSize} inputs + * @returns {KanvasItemSize} + */ + basic_rectangle : (type, inputs = {}) => { + + /** @type {{width: number, height: number}} */ + const {width = 0, height = 0} = inputs; + + return { + ...Kanvas.DSL.base(type, inputs), + width : width, + height : height + }; + }, + + /** + * @param {!KanvasClean} inputs + * @return {KanvasObjectClean} + * @access public + */ + clean : (inputs = {}) => Kanvas.DSL.basic_rectangle("clean", inputs), + + /** + * @param {!KanvasRectangle} inputs + * @return {KanvasObjectRectangle} + * @access public + */ + rectangle : (inputs = {}) => ({ + ...Kanvas.DSL.basic_rectangle("rectangle", inputs), + ...Kanvas.DSL.item_common(inputs), + ...Kanvas.DSL.shape_common(inputs) + }), + + /** + * @param {!KanvasCircle} inputs + * @return {KanvasObjectCircle} + * @access public + */ + circle : (inputs = {}) => { + + /** @type {{radius: number}} */ + const {radius = 0} = inputs; + + return { + ...Kanvas.DSL.base("circle", inputs), + ...Kanvas.DSL.item_common(inputs), + ...Kanvas.DSL.shape_common(inputs), + radius : radius + }; + } + }; + /** @type {number} */ + Kanvas.THREAD_MODE_INTERVAL = 0; + /** @type {number} */ + Kanvas.THREADS_MODE_TIMEOUT = 1; + /** @type {number} */ + Kanvas.THREADS_MODE_ANIMATION = 2; + /** @type {number} */ + Kanvas.THREADS_MODE_ONLY_ANIMATION = 3; + /** - * @class + * @class Kanvas.Event * @constructor - * @param {!number} [mode = 0] * @returns {void} * @access public - * @static */ - Kanvas.Event = function(mode = 0){ - - /** @type {Event} */ - const self = this, - /** @type {Array.} */ - events = []; - - this.mode = mode; + Kanvas.Event = function(){ /** - * @param {...any} [parameters] - * @returns {Array.} - * @access public + * @callback kanvas_event_callback + * @param {...(any|null)} [inputs] + * @returns {void} */ - this.execute = (...parameters) => events.map((callback, i) => { - if(callback){ - /** @type {any|null} */ - const response = callback(i, ...parameters); - - self.mode & Kanvas.ONCE && (events[i] = null); - - return response; - }; - return null; - }); + /** @type {Array.} */ + const events = []; /** - * @param {!kanvas_event_callback} callback - * @returns {number|null} + * @returns {void} + * @access private + */ + const constructor = () => {}; + + /** + * @param {...(any|null)} inputs + * @returns {void} * @access public */ - this.add = callback => { + this.execute = (...inputs) => { + events.forEach(event => { + event && event(...inputs); + }); + }; - /** @type {number|null} */ - let i = null; + /** + * @param {!kanvas_event_callback} event + * @returns {number} + * @access public + */ + this.add = event => { + + /** @type {number} */ + let i = 0; - if(Kanvas.is_function(callback)){ - if(self.mode & Kanvas.AUTOEXECUTE) - callback(); - else{ - - /** @type {number} */ - const l = events.length; - - for(i = 0; i < l; i ++) - if(!events[i]) - break; - - events[i] = callback; - - }; - }; + for(; i < events.length; i ++) + if(!events[i]) + break; + events[i] = event; return i; }; /** - * @param {!number} i - * @returns {void} + * @param {!number} i + * @return {void} * @access public */ this.remove = i => { - events[i] && (events[i] = null); + if(events[i]) + events[i] = null; }; + constructor(); + }; - /** - * @class - * @constructor - * @param {!Kanvas} kanvas - * @param {!kanvas_thread_callback} callback - * @param {!(Object.|Array.)} [inputs = null] - */ - Kanvas.Thread = function(kanvas, callback, inputs = null){ - - /** @type {Kanvas.Thread} */ - const self = this; - - /** @type {number} */ - let rest_time = 0; - - /** @type {kanvas_thread_callback} */ - this.callback = callback; - /** @type {boolean} */ - this.autostart = kanvas.settings(["thread_autostart", "autostart"], inputs, true); - /** @type {number} */ - this.last_date = kanvas.settings(["thread_start_now", "start_now"], inputs, true) ? 0 : Date.now(); - /** @type {boolean} */ - this.bucle = kanvas.settings(["thread_bucle", "bucle"], inputs, false); - /** @type {number} */ - this.timer = kanvas.settings(["thread_timer", "timer"], inputs, 0); - /** @type {number} */ - this.iterations = 0; - /** @type {number} */ - this.error = Kanvas.is_function(this.callback) ? 0 : 1 << 1; - /** @type {boolean} */ - this.autoremove = kanvas.settings(["thread_autoremove", "autoremove"], inputs, true); - /** @type {number} */ - this.i = 0; - /** @type {boolean} */ - this.allow_rest = kanvas.settings(["thread_allow_rest", "allow_rest"], inputs, true); - - Kanvas.is_number(this.timer = kanvas.settings(["thread_timer", "timer"], inputs)) || ( - (this.timer = kanvas.settings(["thread_frames_per_second", "thread_fps", "frames_per_second", "fps"], inputs, 60) || 0) && - (this.timer = 1000 / this.timer) - ); - - /** - * @returns {void} - * @access public - */ - this.execute = () => { - if(!(self.error >> 1) && (self.bucle || !self.iterations)){ - - /** @type {number} */ - const date = Date.now(); - - if(date + rest_time - self.last_date > self.timer){ - - rest_time = self.allow_rest && self.timer ? date + rest_time - self.last_date % self.timer : 0; - self.last_date = date; - - try{ - Kanvas.execute(self.callback); - }catch(exception){ - self.error |= 1 << 0; - }; - - self.iterations ++; - - }; - }; - }; - - }; - - /** - * @class - * @access public - * @static - */ - Kanvas.ObjectBase = class{ - - /** - * @param {!(string|Array.)} keys - * @param {?any} [_default = null] - * @returns {any|null} - * @access protected - */ - _get(keys, _default = null){ - return Kanvas.get_value(keys, this.inputs, _default); - }; - - /** - * @returns {void} - * @access public - */ - check_full_done(){ - if(this.childs && this.childs.length && this.childs.some(child => Kanvas.is_dictionary(child))) - setTimeout(() => { - this.check_full_done(); - }, 0); - else{ - if(this.done && !this.childs.some(child => child && !child.full_done)){ - this.full_done = true; - this.on_full_done.execute(); - }else if(this.full_done) - this.full_done = false; - }; - }; - - /** - * @returns {void} - * @access private - */ - #set_done(){ - this.done = true; - this.check_full_done(); - this.parent && this.parent.check_full_done(); - }; - - /** - * @param {!number} status - * @returns {void} - * @access public - */ - set_status(status){ - - /** @type {boolean} */ - const changed = this.status != status; - - if((this.status = status) & Kanvas.LOADED){ - if(!(this.on_load.mode & Kanvas.AUTOEXECUTE)){ - this.on_load.mode |= Kanvas.AUTOEXECUTE; - this.on_load.execute(this); - this.#set_done(); - }; - }else if(status & Kanvas.ERROR){ - this.on_error.execute(this); - this.#set_done(); - }; - - changed && this.on_status_change.execute(this); - - }; - - /** - * @param {?any} value - * @returns {string} - * @access public - * @static - */ - static get_inputs_type(value){ - return ( - Kanvas.is_string(value) ? "string" : - Kanvas.is_number(value) ? "number" : - Kanvas.is_array(value) ? "array" : - "unknown"); - }; - - /** - * @param {!(Array.|Object.)} inputs - * @param {!Object.>} array_map - * @returns {Object.} - * @access public - * @static - */ - static build_inputs(inputs, array_map){ - if(Kanvas.is_array(inputs)){ - - /** @type {Object.} */ - const map_i = Object.keys(array_map).reduce((dictionary, key) => { - - dictionary[key] = 0; - - return dictionary; - }, {}); - - inputs = inputs.slice(1).reduce((dictionary, value) => { - - /** @type {string} */ - const type = Kanvas.ObjectBase.get_inputs_type(value); - - map_i[type] !== undefined && - array_map[type] && - map_i[type] < array_map[type].length && - (dictionary[array_map[type][map_i[type] ++]] = value); - - return dictionary; - }, {}); - - }else if(!Kanvas.is_dictionary(inputs)) - inputs = {}; - - return inputs; - }; - - /** - * @constructor - * @param {!Kanvas} kanvas - * @param {!Kanvas.ObjectBase} parent - * @param {!(Object.|Array.)} inputs - * @param {?number} [i = null] - * @param {!Object.} [array_map = {}] - * @access public - */ - constructor(kanvas, parent, inputs, i = null, array_map = {}){ - - /** @type {Object.|Array.} */ - this.inputs = Kanvas.ObjectBase.build_inputs(inputs, array_map); - - /** @type {Kanvas} */ - this.kanvas = kanvas; - /** @type {Kanvas.ObjectBase} */ - this.parent = parent; - /** @type {Object} */ - this.type = Kanvas.ObjectBase; - /** @type {string} */ - this.type_name = "ObjectBase"; - /** @type {number} */ - this.x = this._get("x", 0); - /** @type {number} */ - this.y = this._get("y", 0); - /** @type {number} */ - this.width = this._get("width", 0); - /** @type {number} */ - this.height = this._get("height", 0); - /** @type {number|null} */ - this.rotation = this._get(["rotate", "rotation"], 0); - /** @type {string|null} */ - this.background = this._get(["background", "color"], null); - /** @type {number|null} */ - this.alpha = this._get("alpha", null); - /** @type {Array.|Object.} */ - this.childs = this._get("childs", []); - /** @type {string} */ - this.border_color = this._get("border_color", null); - /** @type {number} */ - this.border_size = this._get(["border_size", "border_weight"], null); - /** @type {Array.} */ - this.shadows = Kanvas.get_array(this._get(["shadow", "shadows"], [])).map(shadow => new Kanvas.Shadow(...shadow)); - /** @type {Path2D|null} */ - this.path = null; - /** @type {DOMMatrix|null} */ - this.matrix = null; - /** @type {number} */ - this.status = Kanvas.UNBUILT; - /** @type {number|null} */ - this.i = i; - /** @type {number} */ - this.ignore_mouse_events = this._get("ignore_mouse_events", false); - /** @type {boolean} */ - this.draw_childs = this._get("draw_childs", true); - /** @type {boolean} */ - this.registered = this._get("registered", false); - /** @type {boolean} */ - this.done = false; - /** @type {boolean} */ - this.full_done = false; - /** @type {boolean} */ - this.autoset_full_done = this._get("autoset_full_done", true); - - /** @type {Kanvas.Event} */ - this.on_load = new Kanvas.Event(Kanvas.ONCE); - /** @type {Kanvas.Event} */ - this.on_full_done = new Kanvas.Event(Kanvas.ONCE); - /** @type {Kanvas.Event} */ - this.on_error = new Kanvas.Event(Kanvas.ONCE); - /** @type {Kanvas.Event} */ - this.on_status_change = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_over = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_out = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_move = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_click = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_down = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_up = new Kanvas.Event(); - - [ - "load", "error", "status_change", "mouse_down", "mouse_up", "click", - "mouse_over", "mouse_out", "mouse_move", "full_done" - ].forEach(key => { - - /** @type {kanvas_event_callback} */ - const event = this._get("on_" + key); - - Kanvas.is_function(event) && this["on_" + key].add(event); - - }); - - }; - - /** - * @param {!DOMMatrix} matrix - * @returns {Array.} - * @access public - * @static - */ - static transform_array(matrix){ - return [matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f]; - }; - - /** - * @param {!EventMouse} event - * @returns {void} - * @access public - */ - check_mouse(event){ - if(this.path){ - - /** @type {boolean} */ - const is_over = this.kanvas.context.isPointInPath(this.path, event.clientX, event.clientY); - - if(this.is_mouse_over){ - if(!is_over){ - this.is_mouse_over = false; - this.on_mouse_out.execute(this, event); - }; - }else{ - if(is_over){ - this.is_mouse_over = true; - this.on_mouse_over.execute(this, event); - }; - }; - - if(is_over) - this.on_mouse_move.execute(this, event); - else - this.draw_childs && this.childs.forEach(child => child && child.status && child.check_mouse(event)); - - }; - }; - - /** - * @param {!EventMouse} event - * @param {!number} events - * @returns {void} - * @access public - */ - check_click(event, events){ - if(!this.ignore_mouse_events){ - if(this.path && this.kanvas.context.isPointInPath(this.path, event.clientX, event.clientY)) - ["click", "mouse_down", "mouse_up"].forEach((name, i) => { - events & (1 << i) && this["on_" + name].execute(this, event); - }); - else - this.childs.forEach(child => { - child && child.check_click && child.check_click(event, events); - }); - }; - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @param {!number} x - * @param {!number} y - * @returns {void} - * @access public - */ - predraw(context, x, y){ - - context.save(); - context.beginPath(); - this.matrix = new DOMMatrix(this.parent ? Kanvas.ObjectBase.transform_array(this.parent.matrix) : [1, 0, 0, 1, this.kanvas.x, this.kanvas.y]); - this.matrix.translateSelf(x, y); - - if(this.rotation){ - - /** @type {number} */ - const x = this.width ? this.kanvas._(this.width / 2) : 0, - /** @type {number} */ - y = this.height ? this.kanvas._(this.height / 2) : 0; - - this.matrix.translateSelf(x, y); - this.matrix.rotateSelf(this.rotation); - this.matrix.translateSelf(-x, -y); - - }; - - this.background !== null && (context.fillStyle = this.background); - this.alpha !== null && (context.globalAlpha = this.alpha); - this.border_size && (context.lineWidth = this.kanvas._(this.border_size)); - this.border_color && (context.strokeStyle = this.border_color); - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw(context, x, y){}; - - /** - * @param {!CanvasRenderingContext2D} context - * @param {!Array.} [shape = []] - * @returns {void} - * @access public - */ - fill(context, shape = []){ - (this.kanvas.shadow_cached || this.background) && context.fill(...shape); - this.border_size && context.stroke(...shape); - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @param {!number} x - * @param {!number} y - * @returns {void} - * @access public - */ - postdraw(context, x, y){ - - if(this.path){ - - const shape = new Path2D(); - - shape.addPath(this.path, this.matrix); - this.fill(context, [this.path = shape]); - - }; - - context.closePath(); - - this.draw_childs && - this.childs.length && - this.kanvas.draw(context, this.childs, this); - - this.parent && this.parent.set_child_path(self.path); - - if(this.shadows.length){}; - - context.restore(); - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw_level(context){ - if(this.status & Kanvas.LOADED){ - try{ - - /** @type {number} */ - const x = this.kanvas._(this.x), - /** @type {number} */ - y = this.kanvas._(this.y); - - this.path = new Path2D(); - - this.predraw(context, x, y); - this.draw(context, x, y); - this.postdraw(context, x, y); - - }catch(exception){ - // console.error(exception); - }; - }; - }; - - /** - * @param {!Path2D} path - * @returns {void} - * @access public - */ - set_child_path(path){ - this.path.addPath(new Path2D(path)); - }; - - }; - - /** @type {Object.} */ - Kanvas.SHAPES = { - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Rectangle : class extends Kanvas.ObjectBase{ - - /** - * @constructor - * @param {!Kanvas} kanvas - * @param {!Kanvas.ObjectBase} parent - * @param {!(Object.|Array)} inputs - * @param {?number} [i = null] - * @access public - */ - constructor(kanvas, parent, inputs, i = null){ - super(kanvas, parent, inputs, i, { - number : ["x", "y", "width", "height", "radius"], - string : ["color"], - array : ["radius", "childs"] - }); - - this.type = Kanvas.SHAPES.Rectangle; - this.type_name = "Rectangle"; - - /** @type {Array.} */ - this.radius = Kanvas.get_array(this._get("radius", [])); - /** @type {boolean} */ - this.use_modern_mode = this._get("use_modern_mode", true); - - this.set_status(Kanvas.LOADED); - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw(context, x, y){ - if(this.radius.every(radius => !radius)) - this.path.rect(0, 0, this.kanvas._(this.width), this.kanvas._(this.height)); - else{ - if(this.use_modern_mode) - this.path.roundRect(0, 0, this.kanvas._(this.width), this.kanvas._(this.height), this.radius.map(radius => this.kanvas._(radius))); - else{ - - switch(this.radius.length){ - case 1: - this.radius.push(...[0, 0, 0].map(_ => this.radius[0])); - break; - case 2: - this.radius.push(...this.radius); - break; - case 3: - this.radius.push(this.radius[1]); - break; - }; - - /** @type {number} */ - const radius_top_left = this.kanvas._(this.radius[0]), - /** @type {number} */ - radius_top_right = this.kanvas._(this.radius[1]), - /** @type {number} */ - radius_bottom_right = this.kanvas._(this.radius[2]), - /** @type {number} */ - radius_bottom_left = this.kanvas._(this.radius[3]), - /** @type {number} */ - width = this.kanvas._(this.width), - /** @type {number} */ - height = this.kanvas._(this.height); - - this.path.moveTo(radius_top_left, 0); - this.path.lineTo(width - radius_top_right, 0); - this.path.quadraticCurveTo(width, 0, width, radius_top_right); - this.path.lineTo(width, height - radius_bottom_right); - this.path.quadraticCurveTo(width, height, width - radius_bottom_right, height); - this.path.lineTo(radius_bottom_left, height); - this.path.quadraticCurveTo(0, height, 0, height - radius_bottom_left); - this.path.lineTo(0, radius_top_left); - this.path.quadraticCurveTo(0, 0, radius_top_left, 0); - - }; - }; - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Ellipse : class extends Kanvas.ObjectBase{ - - /** - * @param {!Kanvas} kanvas - * @param {!Kanvas.ObjectBase} parent - * @param {!(Object.|Array)} inputs - * @param {?number} [i = null] - * @access public - */ - constructor(kanvas, parent, inputs, i = null){ - super(kanvas, parent, inputs, i, {}, { - number : ["x", "y", "radius", "from", "to"], - string : ["color"], - array : ["radius", "childs"] - }); - - this.type = Kanvas.SHAPES.Ellipse; - this.type_name = "Ellipse"; - - /** @type {number|Array.} */ - this.radius = this._get("radius"); - /** @type {number} */ - this.from = this._get(["from", "start"], 0); - /** @type {number} */ - this.to = this._get(["to", "end"], 360); - - this.set_status(Kanvas.LOADED); - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw(context, x, y){ - if(Kanvas.is_array(this.radius)) - this.path.ellipse(0, 0, this.kanvas._(radius[0]), this.kanvas._(radius[1]), 0, Kanvas.to_radians(this.from), Kanvas.to_radians(this.to)); - else - this.path.arc(0, 0, this.kanvas._(this.radius), Kanvas.to_radians(this.from), Kanvas.to_radians(this.to)); - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Text : class extends Kanvas.ObjectBase{ - - static x = { - left : 0, - right : 1, - center : .5, - start : 0, - end : 1 - }; - static y = { - top : 0, - hanging : .1, - middle : .5, - alphabetic : .8, - ideographic : .9, - bottom : 1 - }; - - /** - * @param {!Kanvas} kanvas - * @param {!Kanvas.ObjectBase} parent - * @param {!(Object.|Array)} inputs - * @param {?number} [i = null] - * @access public - */ - constructor(kanvas, parent, inputs, i = null){ - super(kanvas, parent, inputs, i, {}, { - number : ["x", "y", "size", "baseline"], - string : ["text", "align", "font", "color", "baseline"], - array : ["childs"] - }); - - this.type = Kanvas.SHAPES.Text; - this.type_name = "Text"; - - /** @type {string} */ - this.text = this._get("text"); - /** @type {number} */ - this.size = this._get("size", 1); - /** @type {string} */ - this.font = this._get(["font", "family", "font_family"], this.kanvas.default_font_family); - /** @type {string|number|null} */ - this.weight = this._get("weight", null); - /** @type {string|null} */ - this.style = this._get("style", null); - /** @type {boolean} */ - this.bold = this._get("bold", false); - /** @type {boolean} */ - this.italic = this._get("italic", false); - /** @type {boolean} */ - this.oblique = this._get("oblique", false); - /** @type {string|number} */ - this.baseline = this._get(["baseline", "base_line", "vertical_align"], null); - /** @type {string} */ - this.align = this._get("align", null); - - this.set_status(Kanvas.LOADED); - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @param {!number} x - * @param {!number} y - * @returns {void} - * @access public - */ - predraw(context, x, y){ - super.predraw(context, x, y); - context.font = ( - (this.weight ? this.weight + " " : this.bold ? "bold " : "") + - (this.style ? this.style + " " : this.italic ? "italic " : this.oblique ? "oblique " : "") + - this.kanvas._(this.size) + "px " + - this.font - ); - this.align && (context.textAlign = this.align); - this.baseline && (context.textBaseline = this.baseline); - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw(context, x, y){ - - /** @type {number} */ - const width = context.measureText(this.text).width, - /** @type {number} */ - height = this.kanvas._(this.size), - /** @type {number} */ - _x = -Kanvas.SHAPES.Text.x[this.align || "start"] * width, - /** @type {number} */ - _y = -Kanvas.SHAPES.Text.y[this.baseline || "alphabetic"] * height; - - context.setTransform(...Kanvas.ObjectBase.transform_array(this.matrix)); - context[this.background ? "fillText" : "strokeText"](this.text, 0, 0); - this.fill(context); - context.setTransform(1, 0, 0, 1, 0, 0); - - this.path.moveTo(_x, _y); - this.path.lineTo(width + _x, _y); - this.path.lineTo(width + _x, height + _y); - this.path.lineTo(_x, height + _y); - - }; - - postdraw(context, x, y){ - this.background !== null && (context.fillStyle = "transparent"); - if(!this.kanvas.shadow_cached){ - this.border_size && (context.lineWidth = 0); - this.border_color && (context.strokeStyle = "transparent"); - }; - super.postdraw(context, x, y); - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Image : class extends Kanvas.ObjectBase{ - - /** - * @returns {void} - * @access public - */ - set_size(){ - this.width === null && (this.width = this.image.width); - this.height === null && (this.height = this.image.height); - }; - - /** - * @param {!Kanvas} kanvas - * @param {!Kanvas.ObjectBase} parent - * @param {!(Object.|Array)} inputs - * @param {?number} [i = null] - * @access public - */ - constructor(kanvas, parent, inputs, i = null){ - super(kanvas, parent, inputs, i, { - number : ["x", "y", "width", "height", "sub_x", "sub_y", "sub_width", "sub_height"], - string : ["source"], - array : ["childs"] - }); - - this.type = Kanvas.SHAPES.Image; - this.type_name = "Image"; - - /** @type {Image|null} */ - this.image = this._get(["image", "object", "image_object", "image_item", "item"], null); - /** @type {string|null} */ - this.source = this._get(["source", "src", "link", "url", "path"], null); - /** @type {number} */ - this.sub_x = this._get(["sub_x", "subx", "_x"], null); - /** @type {number} */ - this.sub_y = this._get(["sub_y", "suby", "_y"], null); - /** @type {number} */ - this.sub_width = this._get(["sub_width", "_width"], null); - /** @type {number} */ - this.sub_height = this._get(["sub_height", "_height"], null); - - this.set_status(Kanvas.LOADING); - - this.kanvas.preload_image(this.image || this.source, (image, ok) => { - this.image || (this.image = image); - if(ok){ - this.set_size(); - this.set_status(Kanvas.LOADED); - }else - this.set_status(Kanvas.ERROR); - }); - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw(context, x, y){ - - const width = this.kanvas._(this.width), - height = this.kanvas._(this.height); - - this.path.rect(0, 0, width, height); - context.save(); - context.setTransform(...Kanvas.ObjectBase.transform_array(this.matrix)); - context.drawImage(...[this.image].concat(( - this.sub_x !== null && - this.sub_y !== null && - this.sub_width !== null && - this.sub_height !== null - ) ? [ - this.sub_x, this.sub_y, this.sub_width, this.sub_height - ] : [], [0, 0, width, height])); - context.setTransform(1, 0, 0, 1, 0, 0); - context.restore(); - - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Position : class extends Kanvas.ObjectBase{ - - /** - * @param {!Kanvas} kanvas - * @param {!Kanvas.ObjectBase} parent - * @param {!(Object.|Array)} inputs - * @param {?number} [i = null] - * @access public - */ - constructor(kanvas, parent, inputs, i = null){ - super(kanvas, parent, inputs, i, { - number : ["x", "y"], - array : ["childs"] - }); - - this.type = Kanvas.SHAPES.Position; - this.type_name = "Position"; - - this.status = Kanvas.LOADED; - - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Shape : class extends Kanvas.ObjectBase{ - - /** @type {Array.} */ - static methods = [null, null, "line", null, "quadraticCurve", "arc", "bezierCurve"]; - - /** - * @param {!Kanvas} kanvas - * @param {!Kanvas.ObjectBase} parent - * @param {!(Object.|Array)} inputs - * @param {?number} [i = null] - * @access public - */ - constructor(kanvas, parent, inputs, i = null){ - super(kanvas, parent, inputs, i, { - number : ["x", "y"], - array : ["shape", "childs"] - }); - - this.type = Kanvas.SHAPES.Shape; - this.type_name = "Shape"; - - /** @type {Array.>} */ - this.shape = this._get(["shape", "setps", "marks"], []).filter(dot => ( - Kanvas.is_array(dot) && - [2, 4, 5, 6].includes(dot.length) && - dot.every(value => Kanvas.is_number(value)) - )); - - this.status = Kanvas.LOADED; - - }; - - /** - * @returns {void} - * @access public - */ - draw(context, x, y){ - this.path.moveTo(0, 0); - this.shape.length > 2 && this.shape.forEach(dot => { - this.methods[dot.length] && this.path[this.methods[dot.length] + "To"](...dot); - }); - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Sprite : class extends Kanvas.ObjectBase{ - - /** - * @param {!Kanvas} kanvas - * @param {!Kanvas.ObjectBase} parent - * @param {!(Object.|Array)} inputs - * @param {?number} [i = null] - * @access public - */ - constructor(kanvas, parent, inputs, i = null){ - super(kanvas, parent, inputs, i, { - number : ["x", "y"], - string : ["sources"], - array : ["sources", "map", "childs"] - }); - - const images = this._get(["images", "image"], {}), - _i = this._get(["i", "index", "position"], 0); - - this.type = Kanvas.SHAPES.Sprite; - this.type_name = "Sprite"; - - /** @type {Array.} */ - this.sources = Kanvas.get_array(this._get(["sources", "source", "src", "links", "urls", "paths", "link", "url", "path"], [])); - /** @type {Object.} */ - this.images = ( - Kanvas.is_dictionary(images) ? images : - (Kanvas.is_array(images) ? images : [images]).reduce((dictionary, image) => { - - if(Kanvas.is_image(image)) - dictionary[image.src] = image; - else if(Kanvas.is_string(image) && !this.sources.includes(image)) - this.sources.push(image); - - return dictionary; - }, {}) - ); - /** @type {Object.>} */ - this.map = Kanvas.SpritesMap.process(this._get("map"), source => { - this.sources.includes(source) || this.sources.push(source) - }); - /** @type {string|null} */ - this.group = this._get("group", null); - /** @type {number} */ - this.i = 0; - /** @type {number} */ - this.frames_per_second = this._get(["frames_per_second", "fps"], 12); - /** @type {boolean} */ - this.autoplay = this._get("autoplay", true); - /** @type {number} */ - this.last_next = 0; - - _i === null || this.next(_i); - - this.status = Kanvas.LOADING; - - Kanvas.execute_array(this.sources, (source, callback) => { - Kanvas.load_image(source, (image, ok) => { - this.images[source] = ok ? image : null; - Kanvas.execute(callback); - }); - }, () => { - this.status = Kanvas.LOADED; - }); - - }; - - /** - * @param {!string} group - * @param {!number} [i = 0] - * @param {boolean|null} [autoplay = null] - * @returns {void} - * @access public - */ - set(group, i = 0, autoplay = null){ - this.last_i_time = performance.now(); - this.group = group; - this.autoplay = autoplay === null ? this.autoplay : autoplay; - this.next(i); - }; - - next(i = null){ - this.i = i === null ? (this.i + i) % this.map[this.group].length : i; - this.width = this.map[this.group][this.i].width; - this.height = this.map[this.group][this.i].height; - }; - - /** - * @returns {void} - * @access public - */ - draw(context, x, y){ - if(this.group && this.map[this.group]){ - - if(this.autoplay && this.map[this.group].length > 1){ - - const next = performance.now() / (1000 / this.frames_per_second) >> 0; - - if(next != this.last_next){ - this.next((this.i + next - this.last_next) % this.map[this.group].length); - this.last_next = next; - }; - - }; - - /** @type {Kanvas.SpritesMap} */ - const sprite = this.map[this.group][this.i], - x = this.kanvas._(sprite.x), - y = this.kanvas._(sprite.y), - width = this.kanvas._(sprite.width), - height = this.kanvas._(sprite.height); - - this.path = new Path2D(); - this.path.rect(x, y, width, height); - - if(this.images[sprite.source]){ - context.save(); - context.setTransform(...Kanvas.ObjectBase.transform_array(this.matrix)); - context.drawImage( - this.images[sprite.source], - sprite.sub_x, sprite.sub_y, sprite.sub_width, sprite.sub_height, - 0, 0, width, height - ); - context.setTransform(1, 0, 0, 1, 0, 0); - context.restore(); - }; - - }; - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Cache : class extends Kanvas.ObjectBase{ - - /** - * @param {!Kanvas} kanvas - * @param {!Kanvas.ObjectBase} parent - * @param {!(Object.|Array)} inputs - * @param {?number} [i = null] - * @access public - */ - constructor(kanvas, parent, inputs, i = null){ - super(kanvas, parent, inputs, i, { - number : ["x", "y", "width", "height", "x_position", "y_position"], - array : ["childs"] - }); - - /** @type {number} */ - this.margin_x = this._get(["x_position", "sub_x", "subx", "xposition", "margin_x", "marginx"], 0); - /** @type {number} */ - this.margin_y = this._get(["y_position", "sub_y", "suby", "yposition", "margin_y", "marginy"], 0); - /** @type {HTMLCanvasElement} */ - this.subcanvas = document.createElement("canvas"); - /** @type {CanvasRenderingContext2D} */ - this.subcontext = this.subcanvas.getContext("2d"); - /** @type {boolean} */ - this.cache_full_loaded = false; - - this.on_full_done.add(() => { - this.cache_full_loaded = true; - }); - - this.kanvas.on_change_screen.add(() => { - this.cache_full_loaded = false; - }); - - this.status = Kanvas.LOADED; - - }; - - /** - * @returns {void} - * @access public - */ - rebuild(){ - this.cache_full_loaded = false; - }; - - /** - * @returns {void} - * @access public - */ - draw(context, x, y){ - if(this.cache_full_loaded) - context.drawImage(this.subcanvas, x - this.margin_x, y - this.margin_y); - else - this.kanvas.draw(this.subcontext, this.childs, this); - }; - - } - - }; - - /** - * @class - * @constructor - * @param {!(string|number|Array.|Object.)} inputs - * @returns {void} - * @access public - * @static - */ - Kanvas.SpritesMap = (function(){ - - /** - * @constructs Kanvas.SpritesMap - * @param {!(string|number|Array.|Object.)} inputs - * @returns {void} - * @access private - */ - const SpritesMap = function(...inputs){ - - /** @type {Kanvas.SpritesMap} */ - const self = this; - - /** @type {string|null} */ - this.source = null; - /** @type {number} */ - this.sub_x = 0; - /** @type {number} */ - this.sub_y = 0; - /** @type {number} */ - this.sub_width = 0; - /** @type {number} */ - this.sub_height = 0; - /** @type {number} */ - this.x = 0; - /** @type {number} */ - this.y = 0; - /** @type {number} */ - this.width = 0; - /** @type {number} */ - this.height = 0; - - const constructor = () => { - if(inputs.length){ - inputs.length == 1 && (inputs = inputs[0]); - if(Kanvas.is_array(inputs)) - [self.source, self.sub_x, self.sub_y, self.sub_width, self.sub_height, self.width, self.height, self.x, self.y] = inputs; - else if(Kanvas.is_dictionary(inputs)){ - self.source = Kanvas.get_value(["source", "src", "link", "url", "path"], inputs, self.source); - self.sub_x = Kanvas.get_value(["sub_x", "subx", "left", "horizontal"], inputs, self.sub_x); - self.sub_y = Kanvas.get_value(["sub_y", "suby", "top", "vertical"], inputs, self.sub_y); - self.sub_width = Kanvas.get_value("sub_width", inputs, self.sub_width); - self.sub_height = Kanvas.get_value("sub_height", inputs, self.sub_height); - self.width = Kanvas.get_value("width", inputs, self.width || self.sub_width); - self.height = Kanvas.get_value("height", inputs, self.height || self.sub_height); - self.x = Kanvas.get_value("width", inputs, self.x); - self.y = Kanvas.get_value("height", inputs, self.y); - }; - }; - }; - - constructor(); - - }; - - /** - * @param {!Object.|Kanvas.SpritesMap>>} map - * @param {!kanvas_source_callback} [source_callback] - * @returns {Object.>} - * @access public - * @static - */ - SpritesMap.process = (map, source_callback) => { - - /** @type {Object.>} */ - const processed = {}; - - for(const key in map) - if(Kanvas.is_array(map[key])){ - processed[key] = []; - map[key].forEach(sprite => { - if(Kanvas.is_array(sprite) && sprite[1] == "pattern"){ - - /** @type {number} */ - const l = sprite.length, - /** @type {[string, number, number, number, number, number, number, number, number, number, number, number, number]} */ - [source, sub_width, sub_height, sub_x, sub_y, width, height, x, y, margin_x, margin_y, padding_x, padding_y, length] = [ - sprite[0], - ...sprite.slice(2, 4), - ...(l > 5 ? sprite.slice(4, 6) : [0, 0]), - ...(l > 7 ? sprite.slice(6, 8) : [0, 0]), - ...(l > 9 ? sprite.slice(8, 10) : [0, 0]), - ...(l > 11 ? sprite.slice(10, 11) : [0, 0]), - ...(l > 13 ? sprite.slice(12, 14) : [0, 0]), - ...(l % 2 ? sprite.slice(-1) : [0]) - ]; - /** @type {number} */ - let k = 0, - /** @type {boolean} */ - ended = false; - - Kanvas.execute(source_callback, source); - - for(let i = 0; i < sub_x && !ended; i ++) - for(let j = 0; j < sub_y; j ++){ - processed[key].push(new Kanvas.SpritesMap([ - source, - padding_x + j * sub_width + j * margin_x, - padding_y + i * sub_height + i * margin_y, - sub_width, - sub_height, - width, - height, - x, - y - ])); - if(length && ++ k == length){ - ended = true; - break; - }; - }; - - }else - processed[key].push(sprite instanceof Kanvas.SpritesMap ? sprite : new Kanvas.SpritesMap(sprite)); - }); - }; - - return processed; - }; - - return SpritesMap; - })(); - - /** @type {number} */ - Kanvas.OVERWRITE = 1 << 0; - /** @type {number} */ - Kanvas.NULLS = 1 << 1; - - /** @type {number} */ - Kanvas.NO_EMPTY = 1 << 0; - /** @type {number} */ - Kanvas.NO_TRIM = 1 << 1; - /** @type {number} */ - Kanvas.KEY = 1 << 2; - - /** @type {number} */ - Kanvas.THREADS_MODE_INTERVAL = 1 << 0; - /** @type {number} */ - Kanvas.THREADS_MODE_TIMEOUT = 1 << 1; - /** @type {number} */ - Kanvas.THREADS_MODE_ANIMATION = 1 << 2; - - /** @type {number} */ - Kanvas.ONCE = 1 << 0; - /** @type {number} */ - Kanvas.AUTOEXECUTE = 1 << 1; - - /** @type {number} */ - Kanvas.UNLOADED = 1 << 0; - /** @type {number} */ - Kanvas.LOADING = 1 << 1; - /** @type {number} */ - Kanvas.LOADED = 1 << 2; - /** @type {number} */ - Kanvas.ERROR = 1 << 3; - /** @type {number} */ - Kanvas.UNBUILT = 1 < 4; - - /** @type {number} */ - Kanvas.THREADS_MODE_ANIMATION = 1 << 0; - /** @type {number} */ - Kanvas.THREADS_MODE_INTERVAL = 1 << 1; - /** @type {number} */ - Kanvas.THREADS_MODE_TIMEOUT = 1 << 2; - - /** @type {number} */ - Kanvas.MOUSE_CLICK = 1 << 0; - /** @type {number} */ - Kanvas.MOUSE_DOWN = 1 << 1; - /** @type {number} */ - Kanvas.MOUSE_UP = 1 << 2; - - /** - * @param {?any} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_array = item => item instanceof Array; - - /** - * @param {?any} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_dictionary = item => item && item.constructor == Object; - - /** - * @param {!(Object.|Array.)} items - * @param {!number} [options = 0] - * @returns {Object.} - * @access public - * @static - */ - Kanvas.get_dictionary = (items, options = 0) => ( - Kanvas.is_array(items) ? items.reduce(options & Kanvas.OVERWRITE ? (dictionary, subitem) => ({ - ...dictionary, - ...Kanvas.get_dictionary(subitem) - }) : (dictionary, subitem) => ({ - ...Kanvas.get_dictionary(subitem), - ...dictionary - }), {}) : - Kanvas.is_dictionary(items) ? items : - {}); - - /** - * @param {?any} item - * @param {!number} [options = 0] - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_string = (item, options = 0) => { - if(typeof item == "string"){ - - /** @type {boolean} */ - const no_empty = !!((Kanvas.NO_EMPTY | Kanvas.KEY) & options); - - if( - (!no_empty || item) && - (!((Kanvas.NO_TRIM | Kanvas.KEY) & options) || item.trim() == item) && - (!no_empty || item.trim()) && - (!(Kanvas.KEY & options) || /^[a-z0-9_]+$/i.test(item)) - ) - return true; - }; - return false; - }; - - /** - * @param {?any} items - * @returns {Array.} - * @access public - * @static - */ - Kanvas.get_array = items => Kanvas.is_array(items) ? items : [items]; - - /** - * @param {?any} items - * @returns {Array.} - * @access public - * @static - */ - Kanvas.get_keys = items => Kanvas.get_array(items).filter((key, i, keys) => ( - Kanvas.is_string(key, Kanvas.KEY) && - keys.indexOf(key) == i - )); - - /** - * @param {!Array.} keys - * @param {!(Object.|Array.)} inputs - * @param {?any} _default - * @param {!boolean} nulls - * @returns {any|null} - * @access public - * @static - */ - Kanvas.process_get_value = (keys, inputs, _default, nulls) => { - - /** @type {boolean} */ - let ok = false, - /** @type {any|null} */ - response = _default; - - if(keys.length){ - if(Kanvas.is_dictionary(inputs)){ - - /** @type {number} */ - const l = keys.length; - - for(let i = 0; i < l; i ++) - if(inputs[keys[i]] !== undefined && (nulls || inputs[keys[i]] !== null)){ - response = inputs[keys[i]]; - ok = true; - }; - - }else if(Kanvas.is_array(inputs)) - inputs.some(subinputs => { - [response, ok] = Kanvas.process_get_value(keys, subinputs, _default, nulls); - return ok; - }); - }; - return [ok ? response : _default, ok]; - }; - - /** - * @param {!(string|Array.)} keys - * @param {!(Object.|Array.)} inputs - * @param {?any} [_default = null] - * @param {!number} [options = 0] - * @returns {any|null} - * @access public - * @static - */ - Kanvas.get_value = (keys, inputs, _default = null, options = 0) => { - return Kanvas.process_get_value(Kanvas.get_keys(keys), inputs, _default, !!(Kanvas.NULLS & options))[0]; - }; - - /** - * @param {?any} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_function = item => typeof item == "function"; - - /** - * @param {?any} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_number = item => typeof item == "number"; - - /** - * @param {?any} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_integer = item => Kanvas.is_number(item) && item == item >> 0; - - /** - * @param {?any} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_index = item => Kanvas.is_integer(item) && item >= 0; - /** * @param {?any} item * @returns {boolean} @@ -2115,76 +520,53 @@ export const Kanvas = (function(){ Kanvas.is_html_item = item => item && (item.tagName || item.nodeName); /** - * @param {!kanvas_execute_callback} callback - * @param {...any} [parameters] - * @returns {any|null} + * @param {!kanvas_preload_html_item} options + * @return {void} * @access public * @static */ - Kanvas.execute = (callback, ...parameters) => Kanvas.is_function(callback) ? callback(...parameters) : null; + Kanvas.preload_html_item = ({ + selector, + callback, + timeout = 2000, + frames_per_second = 60 + } = {}) => { + if(!selector || !callback){ + callback(null, false); + return; + }; + if(Kanvas.is_html_item(selector)){ + callback(selector, false); + return; + }; - /** - * @param {!Array.} array - * @param {!kanvas_array_item_callback} callback_per_item - * @param {!kanvas_default_callback} [callback_end = null] - * @returns {void} - * @access public - * @static - */ - Kanvas.execute_array = (array, callback_per_item, callback_end = null) => { + /** @type {HTMLElement} */ + let item; - /** @type {number} */ - const l = array.length; - - if(!l){ - Kanvas.execute(callback_end); + try{ + if(item = document.querySelector(selector)){ + callback(item, false); + return; + }; + }catch(exception){ + callback(null, false); return; }; /** @type {number} */ - let loaded = 0; - - array.forEach(item => { - Kanvas.execute(callback_per_item, item, () => { - ++ loaded == l && Kanvas.execute(callback_end); - }); - }); + const date = Date.now(); + /** @type {number} */ + let interval = setInterval(() => { + if(item = document.querySelector(selector)){ + clearInterval(interval); + callback(item, true); + }else if(Date.now() - date >= timeout){ + clearInterval(interval); + callback(null, true); + }; + }, 1000 / frames_per_second); }; - /** - * @param {!number} degrees - * @returns {number} - * @access public - * @static - */ - Kanvas.to_radians = degrees => 2 * Math.PI * degrees / 360; - - /** - * @param {!string} source - * @param {!kanvas_load_image_callback} callback - * @returns {void} - * @access public - * @static - */ - Kanvas.load_image = (source, callback) => { - - /** @type {Image} */ - const image = new Image(); - - image.src = source; - image.onload = () => callback(image, true); - image.onerror = () => callback(image, false); - - }; - - /** - * @param {any|null} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_image = item => item instanceof Image; - return Kanvas; })(); \ No newline at end of file diff --git a/Public/ecma/Modules/Parallax.ecma.js b/Public/ecma/Modules/Parallax.ecma.js new file mode 100644 index 0000000..ce4616c --- /dev/null +++ b/Public/ecma/Modules/Parallax.ecma.js @@ -0,0 +1,601 @@ +"use strict"; + +import {Kanvas} from "../Kanvas.ecma.js"; + +/** + * @class + * @constructor + * @param {!Kanvas} kanvas + * @returns {void} + * @access public + */ +export const Parallax = (function(){ + + /** + * @constructs Parallax + * @param {!Kanvas} kanvas + * @returns {void} + * @access private + */ + const Parallax = function(kanvas){ + + /** @type {Parallax} */ + const self = this; + + /** + * @returns {void} + * @access private + */ + const constructor = () => {}; + + constructor(); + + }; + + /** + * @class + * @constructor + * @param {?(Object.|Array.)} [inputs = null] + * @returns {void} + * @access public + * @static + */ + Parallax.Position = function(inputs = null){ + + /** @type {Parallax.Position} */ + const self = this; + + /** @type {number} */ + this.x = Kanvas.get_value("x", inputs, 0); + /** @type {number} */ + this.y = Kanvas.get_value("y", inputs, 0); + /** @type {number} */ + this.limit_x = Kanvas.get_value("limit_x", inputs, 1); + /** @type {number} */ + this.limit_y = Kanvas.get_value("limit_y", inputs, 1); + + /** + * @returns {void} + * @access private + */ + const fix_x = () => { + self.x = (self.x + self.limit_x) % self.limit_x; + }; + + /** + * @returns {void} + * @access private + */ + const fix_y = () => { + self.y = (self.y + self.limit_y) % self.limit_y; + }; + + /** + * @param {!number} x + * @returns {void} + * @access public + */ + this.add_x = x => { + if(Kanvas.is_number(x)){ + self.x += x; + fix_x(); + }; + }; + + /** + * @param {!number} y + * @returns {void} + * @access public + */ + this.add_y = y => { + if(Kanvas.is_number(y)){ + self.y += y; + fix_y(); + }; + }; + + /** + * @param {!number} x + * @returns {void} + * @access public + */ + this.set_x = x => { + if(Kanvas.is_number(x)){ + self.x = x; + fix_x(); + }; + }; + + /** + * @param {!number} y + * @returns {void} + * @access public + */ + this.set_y = y => { + if(Kanvas.is_number(y)){ + self.y = y; + fix_y(); + }; + }; + + /** + * @returns {number} + * @access public + */ + this.get_x = () => self.x || 0; + + /** + * @returns {number} + * @access public + */ + this.get_y = () => self.y || 0; + + /** + * @param {!number} x + * @param {!number} y + * @returns {void} + * @access public + */ + this.add = (x, y) => { + self.add_x(x); + self.add_y(y); + }; + + /** + * @param {!number} x + * @param {!number} y + * @returns {void} + * @access public + */ + this.set = (x, y) => { + self.set_x(x); + self.set_y(x); + }; + + /** + * @returns {Array.} + * @access public + */ + this.get = () => [self.get_x(), self.get_y()]; + + }; + + /** + * @class + * @constructor + * @param {!Kanvas} kanvas + * @param {?Parallax.Class} [parent = null] + * @param {?(Object.|Array.)} [inputs = null] + * @returns {void} + * @access public + * @static + */ + Parallax.Stage = function(kanvas, parent = null, inputs = null){ + + /** @type {Parallax.Stage} */ + const self = this; + + /** @type {Parallax.Class|null} */ + this.parent = parent; + /** @type {number} */ + this.width = Kanvas.get_value(["width", "size", "x"], inputs, kanvas.cells); + /** @type {number} */ + this.height = Kanvas.get_value(["height", "size", "y"], inputs, kanvas.cells); + /** @type {Array.|Array.|Kanvas.ObjectBase|null>} */ + this.childs = Kanvas.get_array(Kanvas.get_value("childs", inputs, [])); + /** @type {boolean} */ + this.fixed = !!Kanvas.get_value("fixed", inputs, false); + /** @type {Array.} */ + this.framed_in = Kanvas.get_value("framed_in", inputs, [1, 1]); + /** @type {boolean} */ + this.repeated = !!Kanvas.get_value("repeated", inputs, false); + /** @type {Array., HTMLCanvasElement|null>>} */ + this.frames = []; + /** @type {boolean} */ + this.done = false; + /** @type {number} */ + this.childs_margin_x = Kanvas.get_value("childs_margin_x", 0); + /** @type {number} */ + this.childs_margin_y = Kanvas.get_value("childs_margin_y", 0); + /** @type {number} */ + this.start_x = Kanvas.get_value("start_x", inputs, kanvas.start_x); + /** @type {number} */ + this.start_y = Kanvas.get_value("start_y", inputs, kanvas.start_y); + + /** + * @returns {void} + * @access private + */ + const constructor = () => { + + self.rebuild(); + + }; + + /** + * @returns {void} + * @access public + */ + this.build_frames = () => { + + /** @type {[number, number]} */ + const [frames_x, frames_y] = self.framed_in, + /** @type {[number, number]} */ + [size_x, size_y] = [frames_x, frames_y].map(value => 1 / value); + + self.frames = []; + + for(let x = 0, _x; x < frames_x; x ++) + for(let y = 0, _x = x + 1; y < frames_y;) + self.frames.push([x * size_x, y * size_y, _x * size_x, ++ y * size_y, [], null]); + + }; + + /** + * @param {!HTMLCanvasElement} canvas + * @returns {void} + * @access private + */ + const set_canvas_size = canvas => { + canvas.setAttribute("width", self.width * kanvas.cell_size * kanvas.quality); + canvas.setAttribute("height", self.height * kanvas.cell_size * kanvas.quality); + }; + + /** + * @param {!number} i + * @returns {Array.} + * @access public + */ + this.get_frame_position = i => [i % self.framed_in[Parallax.X], i / self.framed_in[Parallax.Y] >> 0]; + + /** + * @param {!(Object.|Kanvas.ObjectBase)} item + * @returns {Array., Array.>} + * @access private + */ + const get_item_range_position = item => { + + /** @type {Array., Array.>} */ + const ranges = [ + [item.x - item.width * item.align_x, item.x + item.width * (1 - item.align_x)], + [item.y - item.height * item.align_y, item.y + item.height * (1 - item.align_y)] + ]; + + ["width", "height"].forEach((key, i) => { + ranges[i][0] < 0 && (ranges[i][0] += self[key]); + ranges[i][1] %= self[key]; + }); + + return ranges; + }; + + /** + * @param {!Array.} ks + * @returns {void} + * @access public + */ + this.recalculate_items_in_frames = (ks = []) => { + + /** @type {Array.} */ + const frame_size = [self.width / framed_in[Parallax.X], self.height / framed_in[Parallax.Y]], + /** @type {number} */ + l = self.frames.length; + + Kanvas.get_array(ks).forEach(k => { + + /** @type {Array., Array.>} */ + const [x_positions, y_positions] = get_item_range_position(self.childs[k]).map((range, i) => ( + Parallax.get_range_positions(range.map(value => value / frame_size[i] >> 0), framed_in[i]) + )); + + self.frames.forEach(frame => { + frame.includes(k) && frame.splice(frame.indexOf(k), 1); + }); + + x_positions.forEach(x => { + y_positions.forEach(y => { + + /** @type {number} */ + const i = y * framed_in[0] + x; + + self.frames[i] && self.frames[i].push(k); + + }); + }); + + }); + }; + + // /** + // * @returns {void} + // * @access public + // */ + // this.recalculate_frames_items = () => { + // self.recalculate_items_in_frames(Object.keys(self.childs)); + // }; + + this.build_cache = callback => { + + // if(self.fixed){ + + // /** @type {number} */ + // let loaded = 0, + // /** @type {number + // * } */ + // items_l = 0; + // /** @type {number} */ + // const l = self.frames.length, + // end = () => { + // ++ loaded == l && Kanvas.execute(callback); + // }; + + // self.done = false; + + // self.frames.forEach(([from_x, from_y, to_x, to_y, childs, cache], i) => { + + // /** @type {HTMLCanvasElement} */ + // const canvas = cache || document.createElement("canvas"), + // /** @type {CanvasRenderingContext2D} */ + // context = canvas.getContext("2d"), + // /** @type {[number, number]} */ + // [main_x, main_y] = self.get_frame_position(i); + + // set_canvas_size(canvas); + + // cache || (self.frames[i][Parallax.CACHE] = canvas); + + // Parallax.FRAMES_BROTHERS.forEach(plus_x => { + + // /** @type {number} */ + // const x = (main_x + plus_x + self.framed_in[Parallax.X]) % self.framed_in[Parallax.X]; + + // Parallax.FRAMES_BROTHERS.forEach(plus_y => { + + // /** @type {number} */ + // const y = (main_y + plus_y + self.framed_in[Parallax.Y]) % self.framed_in[Parallax.Y], + // /** @type {number} */ + // j = y * self.framed_in[Parallax.X] + x; + + // kanvas.draw(context, self.frames[j][Parallax.CHILDS].map(k => { + + // items_l += Parallax.set_on_load(self.childs[k], end, (i, item) => { + // self.childs[k] = item; + // }); + + // return self.childs[k]; + // }), [{ + // child_margin_x : -from_x * self.width, + // child_margin_y : -from_y * self.height + // }, self.parent]); + + // }); + + // }); + + // items_l || end(); + + // }); + + // }; + + }; + + /** + * @returns {void} + * @access public + */ + this.resize_cache = () => { + self.fixed && + self.frames.forEach(([from_x, from_y, to_x, to_y, childs, cache]) => { + set_canvas_size(cache); + }); + }; + + /** + * @param {?kanvas_default_callback} [callback = null] + * @returns {void} + * @access public + */ + this.rebuild = (callback = null) => { + self.build_frames(); + self.build_cache(() => { + self.resize_cache(); + Kanvas.execute(callback); + }); + }; + + constructor(); + + }; + + /** + * @class + * @param {!Kanvas} kanvas + * @returns {void} + * @access public + * @static + */ + Parallax.Class = class extends Kanvas.ObjectBase{ + + /** + * @constructor + * @param {!Kanvas} kanvas + * @param {!Kanvas.ObjectBase} parent + * @param {!(Object.|Array)} inputs + * @param {?number} [i = null] + * @access public + */ + constructor(kanvas, parent, inputs, i = null){ + super(kanvas, parent, inputs, i, {}, { + number : ["x", "y", "width", "height"], + array : ["stages", "childs"] + }); + + this.type_name = "Parallax"; + this.type = Kanvas.SHAPES.Parallax; + + /** @type {Parallax.Position} */ + this.position = new Parallax.Position(); + /** @type {Array.} */ + this.stages = Kanvas.get_array(this._get("stages", [])).map(item => ( + Parallax.is_stage(item) ? item : + Kanvas.is_array(item) || Kanvas.is_dictionary(item) ? new Parallax.Stage(this.kanvas, this, item) : + null)); + + this.set_status(Kanvas.LOADED); + + }; + + /** + * @param {!CanvasRenderingContext2D} context + * @param {!number} x + * @param {!number} y + * @returns {void} + * @access public + */ + draw(context, x, y){ + // try{ + // this.stages.forEach(stage => { + + // /** @type {number} */ + // const x = stage.width * this.position.x, + // /** @type {number} */ + // y = stage.height * this.position.y; + + // stage.frames.forEach(([from_x, from_y, to_x, to_y, childs, cache], i) => { + + // /** @type {Array.} */ + // const ks = []; + + // from_x *= stage.width; + // to_x *= stage.width; + // from_y *= stage.height; + // to_y *= stage.height; + + // if(x >= from_x && x <= to_x && y >= from_y && y >= to_y){ + // console.log(stage.fixed); + // if(stage.fixed) + // cache && context.drawImage(cache, from_x - x, from_y - y); + // else + // childs.forEach(k => { + // if(!ks.includes(k)){ + // ks.push(k); + // }; + // }); + // }; + + // stage.fixed || + // this.kanvas.draw(context, ks.sort((a, b) => a - b).map(k => stage.childs[k]), [{ + // margin_x : from_x - x, + // margin_y : from_y - y, + // without_parent : true + // }, this]); + + // }); + + // }); + // }catch(exception){ + // console.error(exception); + // }; + }; + + }; + + /** @type {number} */ + Parallax.X = 0; + /** @type {number} */ + Parallax.Y = 1; + + /** @type {number} */ + Parallax.FROM_X = 0; + /** @type {number} */ + Parallax.FROM_Y = 1; + /** @type {number} */ + Parallax.TO_X = 2; + /** @type {number} */ + Parallax.TO_Y = 3; + /** @type {number} */ + Parallax.CHILDS = 4; + /** @type {number} */ + Parallax.CACHE = 5; + + /** @type {Array.} */ + Parallax.FRAMES_BROTHERS = [-1, 0, 1]; + + /** + * @param {?any} item + * @returns {boolean} + * @access public + * @static + */ + Parallax.is_stage = item => item instanceof Parallax.Stage; + + /** + * @param {!(Object.|Array.|Kanvas.ObjectBase|null)} item + * @param {!kanvas_default_callback} callback + * @param {?kanvas_event_callback} [child_callback = null] + * @returns {number} + * @access public + */ + Parallax.set_on_load = (item, callback, child_callback = null) => { + + /** @type {number} */ + let i = 0; + const end = () => { + Kanvas.execute(callback); + Kanvas.execute(child_callback); + }; + + if(item){ + if(Kanvas.is_array(item)) + item.forEach(sub_item => i += Parallax.set_on_load(sub_item, callback)); + else{ + + const callbacks = [callback, child_callback]; + + i = 1; + + if(item.status && item.status & Kanvas.LOADED) + setTimeout(end, 0); + else if(Kanvas.is_dictionary){ + item.on_load && callbacks.push(item.on_load); + item.on_load = (j, item_loaded) => { + callbacks.forEach(subcallback => Kanvas.execute(subcallback, j, item_loaded)); + }; + }else + item.on_load.add(end); + + }; + }; + + return i; + }; + + /** + * @param {!Array.} range + * @param {!number} limit + * @returns {Array.} + * @access public + * @static + */ + Parallax.get_range_positions = (range, limit) => { + + /** @type {Array.} */ + const positions = []; + + if(range[0] > range[1]){ + for(let i = 0; i <= range[0]; i ++) + positions.push(i); + for(let i = range[1]; i < limit; i ++) + positions.push(i); + }else + for(let i = range[0]; i <= range[1]; i ++) + positions.push(i); + + return positions; + }; + + return Parallax; +})(); + +Kanvas.SHAPES.Parallax = Parallax.Class; \ No newline at end of file diff --git a/Public/ecma/t.js b/Public/ecma/t.js deleted file mode 100644 index 624a475..0000000 --- a/Public/ecma/t.js +++ /dev/null @@ -1,104 +0,0 @@ -"use strict"; - -/** - * @class - * @constructor - * @returns {void} - * @access public - */ -const X = (function(){ - - /** - * @constructs X - * @returns {void} - * @access private - */ - const X = function(){ - - /** @type {X} */ - const self = this; - - /** @type {number} */ - this.frames_per_second = 60; - /** @type {number} */ - this.threads_mode = X.THREADS_MODE_ANIMATION; - - /** - * @returns {number} - * @access private - */ - const thread_timer = () => self.frames_per_second && 1000 / self.frames_per_second; - - /** - * @returns {void} - * @access private - */ - const execute_threads_by_mode = () => { - switch(self.threads_mode){ - case X.THREADS_MODE_INTERVAL: - - /** @type {Object.} */ - const cache = { - frames_per_second : self.frames_per_second, - mode : self.threads_mode - }, - /** @type {number} */ - interval = setInterval(() => { - execute_threads(); - if( - cache.frames_per_seconds != self.frames_per_second || - cache.mode != self.threads_mode - ){ - clearInterval(interval); - execute_threads_by_mode(); - }; - }, thread_timer()); - - break; - case X.THREADS_MODE_TIMEOUT: - setTimeout(() => { - execute_threads(); - execute_threads_by_mode(); - }, thread_timer()); - break; - case X.THREADS_MODE_ANIMATION: - default: - - /** @type {number} */ - const time = Date.now(), - /** @type {number} */ - timer = thread_timer(); - - requestAnimationFrame(() => { - execute_threads(); - setTimeout(() => { - execute_threads_by_mode(); - }, timer - (Date.now() - time)); - }); - - break; - }; - }; - - /** @type {number} */ - X.THREADS_MODE_INTERVAL = 1 << 0; - /** @type {number} */ - X.THREADS_MODE_TIMEOUT = 1 << 1; - /** @type {number} */ - X.THREADS_MODE_ANIMATION = 1 << 2; - - /** - * @returns {void} - * @access private - */ - const execute_threads = () => {}; - - execute_threads_by_mode(); - - }; - - return X; -})(); - -/** @type {X} */ -const x = X(); \ No newline at end of file diff --git a/Public/ecma/version/20230707/Kanvas.ecma.js b/Public/ecma/version/20230707/Kanvas.ecma.js deleted file mode 100644 index 144f9e9..0000000 --- a/Public/ecma/version/20230707/Kanvas.ecma.js +++ /dev/null @@ -1,747 +0,0 @@ -Kanvas = function(settings){ - - const self = this, - default_settings = { - nulls : false, - default_value : null, - position : ".kanvas", - preload_timeout : 2000, - frames_per_second : 60, - quality : 1, - quality_x : 1, - quality_y : 1, - cells : 40, - swap_and_drop_timer : 5000, - font_size : 1, - font_family : "Arial", - settings_overwrite : false, - autostart : true, - autobuild : true, - font_minimum_size : 12, - events_cache_timer : 100 - }, - custom = {}, - cache = {}, - frames_times = [], - id_length = 11, - id_alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", - ids = [], - threads = [], - number_of_cells = {x : 0, y : 0}, - events_cache = []; - let thread = null, - frames_per_second = null, - canvas, context, - last_frame_time = 0, frames_times_summatory = 0, - swap_and_drop_timer, - cache_box, - default_font_size, default_font_family, - settings_overwrite, - built = false, - started = false, - font_minimum_size, - events_cache_timer; - - this.map = []; - let cells = this.cells; - let cell_size = this.cell_size; - let quality = this.quality; - let quality_x = this.quality_x; - let quality_y = this.quality_y; - this.cells_x = 0; - this.cells_y = 0; - this.delta_time = 0; - - let item_self = this.item_self; - let hash_self = this.hash_self; - let object_name = this.object_name; - - this.Event = function(){ - - const self = this, - events = [], - properties = []; - - const construct = () => { - - events_cache.push(autoclean); - - }; - - this.execute = (callback, ...arguments) => events.forEach((event, i) => ( - event && - (typeof callback == "function" ? callback(properties[i]) : true) && - event(...arguments) - )); - - this.add = (callback, own_properties) => { - - let i = 0; - const l = events.length; - - for(; i < l; i ++) - if(!events[i]) - break; - - events[i] = callback; - properties[i] = own_properties; - - return i; - }; - - this.remove = i => events[i] = null; - - const autoclean = () => { - - const date = Date.now(); - - properties.forEach((own_properties, i) => { - if(own_properties && own_properties.last_used && date - own_properties.last_used > events_cache_timer){ - events[i] = null; - properties[i] = null; - }; - }); - - }; - - this.update = (i, date) => events[i] && (properties[i].last_used = date); - - construct(); - - }; - - this.on_screen_change = new this.Event(); - this.on_ready = new this.Event(); - this.on_click = new this.Event(); - this.on_click_down = new this.Event(); - this.on_click_up = new this.Event(); - this.on_key_down = new this.Event(); - this.on_key_up = new this.Event(); - - const construct = () => { - - settings = ( - settings instanceof Array ? settings : - typeof settings == "object" ? [settings] : - []).filter(inputs => typeof inputs == "object" && !(inputs instanceof Array)); - - self.settings("autostart") && self.start(); - - }; - - this.start = callback => { - - const end = status => typeof callback == "function" && callback(status); - - if(started){ - end(false); - return false; - }; - started = true; - - settings_overwrite = self.settings(["settings_overwrite", "overwrite"]); - frames_per_second = self.settings(["frames_per_second", "fps"]); - events_cache_timer = self.settings("events_cache_timer"); - object_name = self.object_name = self.settings("object_name"); - - thread = setInterval(execute, 1000 / frames_per_second); - - if(self.settings("autobuild")) - self.build(callback); - else - end(true); - - return true; - }; - - this.build = callback => { - - const position = self.settings("position"), - end = status => typeof callback == "function" && callback(status); - - if(built){ - end(false); - return false; - }; - built = true; - - if(position){ - - if(position.tagName || position.nodeName){ - end_build(position); - end(true); - return; - }; - - if(typeof position != "string"){ - console.error("position_not_string"); - end(false); - return; - }; - - if(!position.trim()){ - console.error("position_selector_empty"); - end(false); - return; - }; - - let html_object; - - try{ - if(html_object = document.querySelector(position)){ - end_build(html_object); - end(true); - return; - }; - }catch(exception){ - console.error(exception); - console.error("position_bad_selector"); - end(false); - return; - }; - - const date = Date.now(), - timeout = self.settings("preload_timeout"); - let interval = setInterval(() => { - if(html_object = document.querySelector(position)){ - clearInterval(interval); - end_build(html_object); - end(true); - }else if(Date.now() - date > timeout){ - clearInterval(interval); - console.error("position_timeout"); - end(false); - }; - }, frames_per_second); - - }else{ - console.error("no_position"); - end(false); - }; - - return true; - }; - - const end_build = position => { - - quality = self.quality = self.settings("quality"); - quality_x = self.quality_x = self.settings("quality_x"); - quality_y = self.quality_y = self.settings("quality_y"); - cells = self.cells = self.settings("cells"); - default_font_size = self.settings("font_size"); - default_font_family = self.settings("font_family"); - - cache.quality = 0; - cache.quality_x = 0; - cache.quality_y = 0; - - cache.screen = {x : 0, y : 0}; - cache.origin = {x : 0, y : 0}; - - item_self = self.item_self = (position || document.querySelector("body")).appendChild(document.createElement("div")); - cache_box = item_self.appendChild(document.createElement("div")); - canvas = item_self.appendChild(document.createElement("canvas")); - hash_self = self.hash_self = self.settings(["id", "hash"]) || self.create_id(); - - item_self.setAttribute("id", hash_self); - item_self.setAttribute("class", ["kanvas", hash_self].concat((self.settings("class") || "").split(/\s+/)).filter((key, i, array) => array.indexOf(key) == i).join(" ")); - item_self.setAttribute("data-hash", hash_self); - item_self.setAttribute("data-cells", cells); - item_self.setAttribute("data-minimum-font-size", font_minimum_size = self.settings("font_minimum_size")); - - cache_box.setAttribute("class", "kanvas-cache-box"); - cache_box.setAttribute("style", ` - position : absolute; - top : 0%; - left : 0%; - width : 100%; - height : 100%; - visibility : hidden; - z-index : 10; - opacity : 0; - `.replace(/[\r\n\s]+/g, "")); - - canvas.setAttribute("class", "kanvas-ui"); - canvas.setAttribute("style", ` - position : absolute; - top : 0%; - left : 0%; - width : 100%; - height : 100%; - z-index : 20; - `.replace(/[\r\n\s]+/g, "")); - canvas.onclick = event => on_click(canvas, event, "click"); - canvas.onmousedown = event => on_click(canvas, event, "down"); - canvas.onmouseup = event => on_click(canvas, event, "up"); - canvas.onkeydown = event => on_key(canvas, event, "down"); - canvas.onkeyup = event => on_key(canvas, event, "up"); - - context = canvas.getContext("2d"); - - context.id = self.create_id(); - - swap_and_drop_timer = self.settings("swap_and_drop_timer"); - - self.on_ready.execute(); - - }; - - this.nulls = nulls => typeof nulls == "boolean" ? nulls : self.settings("nulls", null, false, false); - - this.default_value = (_default, nulls) => _default !== undefined && (self.nulls(nulls) || _default !== null) ? _default : self.settings("default_value", null, null, true); - - this.settings = (names, inputs, _default, nulls) => { - - const l = (names = ( - names instanceof Array ? names : - typeof names == "string" ? [names] : - [] - ).filter((name, i, array) => name && typeof name == "string" && array.indexOf(name) == i)).length; - - if(l){ - - const m = (inputs = ( - inputs instanceof Array ? inputs : - typeof inputs == "object" ? [inputs] : - []).concat(settings, custom, [default_settings])).length; - - nulls = self.nulls(nulls); - - for(let j = 0; j < m; j ++) - if(inputs[j] && typeof inputs[j] == "object" && !(inputs[j] instanceof Array)) - for(let i = 0; i < l; i ++) - if(inputs[j][names[i]] !== undefined && (nulls || inputs[j][names[i]] !== null)) - return inputs[j][names[i]]; - }; - return self.default_value(_default, nulls); - }; - - this.settings_add = (inputs, overwrite) => { - if(!inputs) - return; - - if(typeof inputs == "string"){ - try{ - inputs = JSON.parse(inputs); - }catch(exception){}; - }; - - if(typeof inputs == "object"){ - if(inputs instanceof Array) - inputs.forEach(inputs, overwrite); - else{ - typeof overwrite != "boolean" && (overwrite = settings_overwrite); - for(const key in inputs) - if(overwrite || custom[key] === undefined) - custom[key] = inputs[key]; - }; - }; - - }; - - this.create_id = () => { - - let id; - const l = id_alphabet.length; - - do{ - id = ""; - while((id += id_alphabet[l * Math.random() >> 0]).length < id_length); - }while( - ids.includes(id) || - !/^[a-z]/i.test(id) || - document.querySelector("." + id + ",#" + id + ",[name=" + id + "]") - ); - ids.push(id); - - return id; - }; - - const execute = () => { - - const date = Date.now(); - let screen_changed = false; - - if(item_self && (cache.screen.x != item_self.offsetWidth || cache.screen.y != item_self.offsetHeight)){ - screen_changed = true; - - cache.screen.x = item_self.offsetWidth; - cache.screen.y = item_self.offsetHeight; - - const font_size = cache.screen[cache.screen.x < cache.screen.y ? "x" : "y"] / cells; - - item_self.style.fontSize = (font_size < font_minimum_size ? font_minimum_size : font_size) + "px"; - - }; - - if(canvas){ - - if(last_frame_time){ - - const frame_time = date - last_frame_time; - - frames_times.push(frame_time); - frames_times_summatory += frame_time; - - self.delta_time = frame_time / 1000; - - while(frames_times.length > frames_per_second) - frames_times_summatory -= frames_times.shift(); - - }; - - last_frame_time = date; - - if(screen_changed || cache.quality != quality){ - - const width = cache.screen.x * quality, - height = cache.screen.y * quality; - - cache.quality = quality; - canvas.setAttribute("width", width); - canvas.setAttribute("height", height); - cache.origin.x = width / 2; - cache.origin.y = height / 2; - - cell_size = self.cell_size = (width > height ? height : width) / cells; - - number_of_cells.x = width / cell_size; - number_of_cells.y = height / cell_size; - - this.cells_x = number_of_cells.x / 2; - this.cells_y = number_of_cells.y / 2; - - for(const key in cache) - if(cache[key] && cache[key].data) - cache[key].data = null; - - self.on_screen_change.execute(); - - }; - - }; - - threads.forEach(thread => thread && thread()); - - if(canvas){ - - context.beginPath(); - context.clearRect(0, 0, cache.screen.x * quality, cache.screen.y * quality); - context.translate(cache.origin.x, cache.origin.y); - - draw(context, self.map, 0, 0); - - context.translate(-cache.origin.x, -cache.origin.y); - - for(const key in cache) - if(cache[key] && cache[key].last_used && date - cache[key].last_used > swap_and_drop_timer) - delete cache[key]; - - }; - - events_cache.forEach(autoclean => autoclean()); - - }; - - this.set_quality = new_quality => quality = self.quality = new_quality; - this.set_quality_x = new_quality => quality_x = self.quality_x = new_quality; - this.set_quality_y = new_quality => quality_y = self.quality_y = new_quality; - - const _x = x => x * cell_size; - const _y = y => y * cell_size; - const size = size => size * cell_size; - - const set_cache = (context, status) => { - - !status && cache[context.id] && cache[context.id].ok && (cache[context.id].ok = false); - - return status; - }; - - const set_border = (context, inputs) => { - - const has_border = !!(inputs.border_color || !isNaN(inputs.border_width)); - - inputs.border_color && (context.strokeStyle = inputs.border_color); - !isNaN(inputs.border_width) && (context.lineWidth = size(inputs.border_width)); - - return has_border; - }; - - const set_background = (context, inputs) => { - - const has_background = !!(inputs.background || (!inputs.border_color && isNaN(inputs.border_width))); - - if(inputs.background){ - if(inputs.background instanceof Array){ - - const v = inputs.background, - is_linear = v.length == 5, - gradient = ( - is_linear ? context.createLinearGradient(_x(v[0]), _y(v[1]), _x(v[2]), _y(v[3])) : - context.createRadialGradient(_x(v[0]), _y(v[1]), _x(v[2]), _y(v[3]), size(v[4]), size(v[5])) - ); - - inputs.background[is_linear ? 4 : 6].forEach(color => gradient.addColorStop(color[0], color[1])); - - context.fillStyle = gradient; - - }else - context.fillStyle = inputs.background; - }; - - return has_background; - }; - - const set_shadow = (context, inputs, shape_callback) => { - - const shadows = inputs.shadow || inputs.shadows; - - (shadows && shadows.length ? shadows[0] instanceof Array ? shadows : [shadows] : []).forEach(shadow => { - [context.shadowOffsetX, context.shadowOffsetY, context.shadowBlur, context.shadowColor] = shadow; - context.shadowOffsetX = size(shadow[0]); - context.shadowOffsetY = size(shadow[1]); - context.shadowBlur = size(shadow[2]); - context.shadowColor = size(shadow[3]); - shape_callback(); - }); - - }; - - const shapes = { - rectangle : (context, inputs) => { - - const x = _x(inputs.x), - y = _y(inputs.y), - width = size(inputs.width), - height = size(inputs.height), - has_border = set_border(context, inputs), - has_background = set_background(context, inputs); - - set_shadow(context, inputs, () => context.rect(x, y, width, height)); - has_background && context.fillRect(x, y, width, height); - has_border && context.strokeRect(x, y, width, height); - - return set_cache(context, true); - }, - image : (context, inputs) => { - - const url = inputs.url; - - if(url){ - - const cached = cache[url]; - - if(!cached){ - (cache[url] = { - image : new Image(), - loaded : false, - last_used : Date.now() - }).image.src = url; - cache[url].image.crossOrigin = "anonymous"; - cache[url].image.onload = () => cache[url].loaded = true; - return set_cache(context, false); - }; - - if(cached.loaded){ - - let width = inputs.width, - height = inputs.height; - const cut_x = inputs.cut_x || 0, - cut_y = inputs.cut_y || 0, - cut_width = inputs.cut_width || 0, - cut_height = inputs.cut_height || 0, - position_x = inputs.x || 0, - position_y = inputs.y || 0, - x = _x(position_x), - y = _y(position_y), - end_width = size(width), - end_height = size(height); - - !width && (width = cache.quality * (cut_width || cache[url].image.width - cut_x) / cell_size); - !height && (height = cache.quality * (cut_height || cache[url].image.height - cut_y) / cell_size); - - set_shadow(context, inputs, () => context.rect(x, y, end_width, end_height)); - set_border(context, inputs); - context.drawImage( - cache[url].image, - cut_x, cut_y, cut_width || cache[url].image.width - cut_x, cut_height || cache[url].image.height - cut_y, - x, y, end_width, end_height - ); - cache[url].last_used = Date.now(); - - return set_cache(context, true); - }; - - }; - - return set_cache(context, false); - }, - cache : (context, inputs) => { - - const width = inputs.width ? inputs.width * cell_size : canvas.getAttribute("width"), - height = inputs.height ? inputs.height * cell_size : canvas.getAttribute("height"); - let status = false; - - if(!cache[inputs.name]){ - - const subcanvas = cache_box.appendChild(document.createElement("canvas")); - - cache[inputs.name] = { - canvas : subcanvas, - data : null - }; - cache[inputs.name].context = subcanvas.getContext("2d"); - - cache[inputs.name].context.id = inputs.name; - - subcanvas.setAttribute("data-id", cache[inputs.name].context.id); - - cache[inputs.name].context.translate(inputs.x || 0, inputs.y || 0); - - }; - - if(cache[inputs.name].data){ - if(cache[inputs.name].image_loaded){ - context.drawImage(cache[inputs.name].image, _x(inputs.x || 0), _y(inputs.y || 0), cache[inputs.name].image.width, cache[inputs.name].image.height); - status = true; - }else if(!cache[inputs.name].image){ - - cache[inputs.name].image = new Image(); - - cache[inputs.name].image.src = cache[inputs.name].data; - cache[inputs.name].image.onload = () => { - // cache[inputs.name].canvas.remove(); - cache[inputs.name].image_loaded = true; - }; - // cache[inputs.name].image.onerror = () => cache[inputs.name].canvas.remove(); - - }; - }else{ - - cache[inputs.name].canvas.setAttribute("width", width); - cache[inputs.name].canvas.setAttribute("height", height); - - cache[inputs.name].context.beginPath(); - cache[inputs.name].context.clearRect(0, 0, width, height); - cache[inputs.name].context.translate(width / 2, height / 2); - - cache[inputs.name].image = null; - cache[inputs.name].image_loaded = false; - cache[inputs.name].ok = true; - - draw(cache[inputs.name].context, inputs.childs, 0, 0); - - cache[inputs.name].context.closePath(); - - cache[inputs.name].ok && - (cache[inputs.name].data = cache[inputs.name].canvas.toDataURL("image/png", 1.0)); - - }; - - cache[inputs.name].last_used = Date.now(); - - return set_cache(context, status); - }, - text : (context, inputs) => { - - const x = _x(inputs.x), - y = _y(inputs.y), - has_border = set_border(context, inputs), - has_background = set_background(context, inputs); - - inputs.align && (context.textAlign = inputs.align); - inputs.baseline && (context.textBaseline = inputs.baseline); - !isNaN(inputs.border_width) && (context.lineWidth = size(inputs.border_width)); - context.font = (inputs.style ? inputs.style + " " : "") + size(inputs.size || default_font_size) + "px " + (inputs.family || default_font_family); - - set_shadow(context, inputs, () => context.fillText(inputs.text, x, y)); - has_background && context.fillText(inputs.text, x, y); - has_border && context.strokeText(inputs.text, x, y); - - return true; - } - }; - - this.string_variables = (string, variables) => string.replace(/\{([^\{\}]+)\}/g, (...arguments) => variables[arguments[1]] !== undefined ? variables[arguments[1]] : arguments[0]); - - const draw = (context, level, x, y) => level.forEach(values => { - if(values && (shapes[values.type] || ["block"].includes(values.type))){ - - const sub_x = _x(x + (values.margin_x || 0)), - sub_y = _y(y + (values.margin_y || 0)), - date = Date.now(); - - context.save(); - context.translate(sub_x, sub_y); - - const transform = context.getTransform(); - - values.rotate && context.rotate(2 * Math.PI * values.rotate / 360); - !isNaN(values.alpha) && (context.globalAlpha = values.alpha); - - if(values.on_click){ - values.context_x = transform.e / quality; - values.context_y = transform.f / quality; - if(!values.last_used || date - values.last_used > events_cache_timer) - values.i = self.on_click.add(eval(self.string_variables(values.on_click, {object_name : object_name})), values); - else - self.on_click.update(values.i, date); - values.last_used = date; - }; - - values.type != "block" && shapes[values.type](context, values); - - values.type != "cache" && values.childs && draw(context, values.childs, values.x, values.y); - - context.translate(-sub_x, -sub_y); - context.restore(); - - }; - }); - - this.get_real_fps = this.get_real_frames_per_second = () => frames_times_summatory ? 1000 / (frames_times_summatory / frames_times.length) : 0; - - this.threads_add = callback => { - - let i = 0; - const l = threads.length; - - for(; i < l; i ++) - if(!threads[i]) - break; - - threads[i] = callback; - - return i; - }; - - this.threads_remove = i => threads[i] = null; - - this.get_cells_x = () => number_of_cells.x; - this.get_cells_y = () => number_of_cells.y; - - this.extends = object => { - for(const key in self) - if(object[key] === undefined) - object[key] = self[key]; - }; - - const on_click = (canvas, event, action) => { - - switch(action){ - case "click": - self.on_click.execute(properties => ( - event.clientX >= properties.context_x + (properties.x * cell_size) && - event.clientY >= properties.context_y + (properties.y * cell_size) && - event.clientX <= properties.context_x + ((properties.x + properties.width) * cell_size) && - event.clientY <= properties.context_y + ((properties.y + properties.height) * cell_size) - ), canvas, event); - break; - }; - - }; - - construct(); - -}; \ No newline at end of file diff --git a/Public/ecma/version/20250107/Kanvas.ecma.js b/Public/ecma/version/20250107/Kanvas.ecma.js deleted file mode 100644 index 01d83d5..0000000 --- a/Public/ecma/version/20250107/Kanvas.ecma.js +++ /dev/null @@ -1,2535 +0,0 @@ -"use strict"; - -/** - * @callback kanvas_default_callback - * @returns {void} - */ - -/** - * @callback kanvas_thread_callback - * @param {Kanvas.ThreadModel} thread - * @returns {void} - */ - -/** - * @callback kanvas_preload_callback - * @param {!HTMLElement} selector - * @param {!boolean} asynchronous - * @returns {void} - */ - -/** - * @callback kanvas_event_callback - * @param {!number} i - * @param {...any} [parameters] - * @returns {any|null|void} - */ - -/** - * @callback kanvas_event_mouse_callback - * @param {!number} i - * @param {!number} x - * @param {!number} y - * @param {...any} [parameters] - * @returns {any|null|void} - */ - -/** - * @callback kanvas_on_change_callback - * @param {Kanvas.ObjectBase|null} child - * @returns {void} - */ - -/** - * @callback kanvas_load_image_callback - * @param {!Image} image - * @param {!boolean} ok - * @returns {void} - */ - -/** - * @callback kanvas_execute_callback - * @param {...(any|null)} [parameters] - * @returns {any|null} - */ - -/** - * @callback kanvas_source_callback - * @param {string} source - */ - -/** - * @callback kanvas_array_item_callback - * @param {any|null} item - * @param {!kanvas.kanvas_default_callback} callback - * @returns {void} - */ - -/** - * @class - * @constructor - * @param {Object.|Array.>} inputs - * @returns {void} - * @access public - */ -export const Kanvas = (function(){ - - /** - * @constructs Kanvas - * @param {Object.|Array.>} custom - * @returns {void} - * @access public - */ - const Kanvas = function(custom){ - - /** @type {Kanvas} */ - const self = this, - /** @type {Object.} */ - default_settings = {}, - /** @type {Array.} */ - threads = [], - /** @type {Array.} */ - thread_times = [], - /** @type {Kanvas.Screen} */ - screen = new Kanvas.Screen(), - /** @type {Object.} */ - images_cache = {}; - /** @type {number} */ - let last_time = 0, - /** @type {number} */ - thread_times_summatory = 0, - /** @type {number|null} */ - draw_thread_i = null, - /** @type {boolean} */ - screen_done = false, - /** @type {number} */ - last_thread_iteration = 0; - - /** @type {number} */ - this.frames_per_second = 24; - /** @type {number} */ - this.real_frames_per_second = 0; - /** @type {number} */ - this.thread_times_samples = 3; - /** @type {number} */ - this.delta = 0; - /** @type {number} */ - this.cells = 40; - /** @type {number} */ - this.quality = 1; - /** @type {HTMLCanvasElement|null} */ - this.canvas = null; - /** @type {CanvasRenderingContext2D|null} */ - this.context = null; - /** @type {number} */ - this.preload_timeout = 2000; - /** @type {string} */ - this.default_font_family = "monospace"; - /** @type {number} */ - this.x = 0; - /** @type {number} */ - this.y = 0; - /** @type {number} */ - this.height = 0; - /** @type {number} */ - this.width = 0; - /** @type {number} */ - this.cells_x = 0; - /** @type {number} */ - this.cells_y = 0; - /** @type {number} */ - this.cell_size = 0; - /** @type {number} */ - this.start_x = .5; - /** @type {number} */ - this.start_y = .5; - /** @type {HTMLElement|null} */ - this.cache = null; - /** @type {HTMLElement|null} */ - this.item_self = null; - /** @type {number} */ - this.threads_mode = Kanvas.THREADS_MODE_ANIMATION; - /** @type {number} */ - this.difference = 0; - /** @type {string} */ - this.context = "2d"; - - /** @type {Array.} */ - this.map = []; - /** @type {boolean} */ - this.shadow_cached = false; - /** @type {Kanvas.Event} */ - this.on_ready = new Kanvas.Event(true); - /** @type {Kanvas.Event} */ - this.on_change_screen = new Kanvas.Event(); - - /** @type {Kanvas.Event} */ - this.on_mouse_down = new Kanvas.EventMouse(); - /** @type {Kanvas.Event} */ - this.on_mouse_up = new Kanvas.EventMouse(); - /** @type {Kanvas.Event} */ - this.on_click = new Kanvas.EventMouse(); - /** @type {Kanvas.Event} */ - this.on_mouse_over = new Kanvas.EventMouse(); - /** @type {Kanvas.Event} */ - this.on_mouse_out = new Kanvas.EventMouse(); - /** @type {Kanvas.Event} */ - this.on_mouse_move = new Kanvas.EventMouse(); - /** @type {Kanvas.Event} */ - this.on_key_down = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_key_up = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_key_press = new Kanvas.Event(); - - /** - * @returns {void} - * @access private - */ - const constructor = () => { - - /** @type {kanvas_event_callback|null} */ - const on_ready_event = self.settings("on_ready"); - - self.preload_timeout = self.settings(["preload_timeout", "timeout"], null, self.preload_timeout); - self.quality = self.settings(["quality", "q"], null, self.quality); - self.cells = self.settings("cells", null, self.cells); - self.thread_times_samples = self.settings("thread_times_samples", null, self.thread_times_samples); - self.frames_per_second = self.settings(["frames_per_second", "fps"], null, self.frames_per_second); - self.default_font_family = self.settings("default_font_family", null, self.default_font_family); - self.start_x = self.settings("start_x", null, self.start_x); - self.start_y = self.settings("start_y", null, self.start_y); - self.threads_mode = self.settings("threads_mode", null, self.threads_mode); - self.context = self.settings("context", null, self.context); - - threads_run(); - self.thread_add(check_screen); - - Kanvas.is_function(on_ready_event) && self.on_ready.add(on_ready_event); - - self.preload(self.settings("position"), (position, asynchronous) => { - if(position){ - - if(position.tagName.toLowerCase() != "canvas") - self.canvas = ( - self.item_self = position.appendChild(document.createElement("span")) - ).appendChild(document.createElement("canvas")); - else - self.item_self = (self.canvas = position).parentNode; - self.item_self.classList.contains("kanvas") || self.item_self.classList.add("kanvas"); - (self.cache = self.item_self.querySelector(".cache")) || ( - self.cache = self.item_self.appendChild(document.createElement("span")) - ).classList.add("cache"); - - start(); - - }; - }); - - }; - - /** - * @param {!Event} event - * @param {!string} name - * @returns {void} - * @access private - */ - const check_event = (event, name) => { - - /** @type {Kanvas.Event} */ - const event_manager = self["on_" + name]; - - if(event_manager){ - if(event instanceof MouseEvent || event instanceof PointerEvent) - event_manager.execute( - (event.clientX - self.width * self.start_x) / self.cell_size, - (event.clientY - self.height * self.start_y) / self.cell_size - ); - else if(event instanceof KeyboardEvent){ - event.key == "Tab" && event.preventDefault(); - event_manager.execute(event.key); - }; - }; - - }; - - /** - * @returns {void} - * @access private - */ - const start = () => { - self.thread_add({ - bucle : false, - start_now : false, - callback : () => { - - self.context = self.canvas.getContext(self.context, { - // willReadFrequently : true - }); - - self.canvas.setAttribute("tabindex", 0); - self.canvas.focus(); - // [ - // "mouse_down", "mouse_up", "click", "mouse_over", "mouse_out", "mouse_move", - // "key_down", "key_up", "key_press" - // ].forEach(event_name => { - // self["on_" + event_name] && self.canvas.addEventListener(event_name.replace(/[^a-z]+/g, ""), event => { - // check_event(event, event_name); - // if(event_name == "click") - // this.map.forEach(item => item && item.status && item.check_click(event)); - // else if(!event_name.includes("key")){ - // this.map.forEach(item => item && item.status && item["on_" + event_name].execute(item, event)) - // }); - // }); - - self.canvas.addEventListener("mousemove", event => { - self.on_mouse_move.execute(event); - self.map.forEach(item => item && item.status && item.check_mouse(event)); - }); - self.canvas.addEventListener("click", event => { - self.on_click.execute(event); - self.map.forEach(item => item && item.status && item.check_click(event)); - }); - - draw_thread_i = self.thread_add(thread => { - - /** @type {number} */ - const x = self._(self.start_x * self.cells_x), - /** @type {number} */ - y = self._(self.start_y * self.cells_y); - - self.x = self._(self.start_x * self.cells_x); - self.y = self._(self.start_y * self.cells_y); - - self.context.clearRect(0, 0, self.width, self.height >> 0); - // self.context.translate(x, y); - self.draw(self.context); - // self.context.translate(-x, -y); - - }); - - const wait_for_screen = self.thread_add({ - callback : () => { - if(screen_done){ - self.thread_remove(wait_for_screen); - self.on_ready.autoexecute = true; - self.on_ready.execute(); - }; - }, - bucle : true, - start_now : true - }); - - } - }); - }; - - /** - * @param {!(string|Array.)} keys - * @param {?(Object.|Array.)} [inputs = null] - * @param {any|null} [_default = null] - * @returns {any|null} - * @access public - */ - this.settings = (keys, inputs = null, _default = null) => Kanvas.get_value(keys, [inputs, custom, default_settings], _default); - - /** - * @returns {void} - * @access private - */ - const check_screen = () => { - if(!self.canvas) - return; - screen_done || (screen_done = true); - - if( - screen.x != self.canvas.offsetWidth || - screen.y != self.canvas.offsetHeight || - screen.quality != self.quality - ){ - - screen.x = self.canvas.offsetWidth; - screen.y = self.canvas.offsetHeight; - screen.quality = self.quality; - - self.canvas.setAttribute("width", self.width = screen.x * self.quality); - self.canvas.setAttribute("height", self.height = screen.y * self.quality); - - self.cell_size = self.quality * (screen.x < screen.y ? screen.x : screen.y) / self.cells; - self.cells_x = self.width / self.cell_size; - self.cells_y = self.height / self.cell_size; - - self.on_change_screen.execute(); - - }; - - }; - - const rerun_threads = () => { - const timeout = setTimeout(() => { - clearTimeout(timeout); - threads_run(); - }, 1); - }; - - /** - * @returns {void} - * @access private - */ - const threads_run = () => { - switch(self.threads_mode){ - case Kanvas.THREADS_MODE_INTERVAL: - - /** @type {number} */ - const current_frames_per_second = self.frames_per_second, - /** @type {number} */ - interval = setInterval(() => { - thread_method(); - if( - !(self.threads_mode & Kanvas.THREADS_MODE_INTERVAL) || - current_frames_per_second != self.frames_per_second - ){ - clearInterval(interval); - threads_run(); - }; - }, self.frames_per_second ? 1000 / self.frames_per_second : 0); - - break; - case Kanvas.THREADS_MODE_TIMEOUT: - setTimeout(() => { - thread_method(); - threads_run(); - }, self.frames_per_second ? 1000 / self.frames_per_second : 0); - break; - case Kanvas.THREADS_MODE_ANIMATION: - default: - requestAnimationFrame(() => { - - /** @type {number} */ - const time = Kanvas.get_time(); - - if(!self.frames_per_second || time - last_thread_iteration >= 1000 / self.frames_per_second){ - last_thread_iteration = time; - thread_method(); - }; - - threads_run(); - - }); - break; - }; - }; - - /** - * @returns {void} - * @access private - */ - const thread_method = () => { - - /** @type {number} */ - const time = performance.now(); - - if(last_time){ - - /** @type {number} */ - const difference = last_time ? time - last_time : 0; - - self.difference = difference; - self.delta = difference / (1 / self.real_frames_per_second) / 10000; - thread_times.push(difference); - thread_times_summatory += difference; - - if(thread_times.length){ - - while(thread_times.length > self.thread_times_samples) - thread_times_summatory -= thread_times.shift(); - - /** @type {number} */ - const average = thread_times_summatory / thread_times.length; - - average && (self.real_frames_per_second = 1000 / average); - - }; - - }; - last_time = time; - - threads.forEach(thread => { - thread && thread.execute(); - }); - - }; - - /** - * @param {!(kanvas_thread_callback|Object.)} inputs - * @returns {number|null} - * @access public - */ - this.thread_add = inputs => { - - /** @type {number} */ - const thread = new Kanvas.ThreadModel(this, inputs); - /** @type {number|null} */ - let i = null; - - if(thread.ok()){ - - /** @type {number} */ - const l = threads.length; - - for(i = 0; i < l; i ++) - if(!threads[i]) - break; - - (threads[i] = thread).i = i; - - }; - - return i; - }; - - /** - * @param {!(number)} i - * @returns {void} - * @access public - */ - this.thread_remove = i => { - threads[i] && (threads[i] = null); - }; - - /** - * @param {!number} size - * @returns {number} - * @access public - */ - this._ = size => size * self.cell_size; - - /** - * @param {!CanvasRenderingContext2D} context - * @param {Array.|Object.|null} [level = null] - * @param {kanvas_on_change_callback|null} [on_change = null] - * @param {?Kanvas.ObjectBase} [parent = null] - * @returns {void} - * @access public - */ - this.draw = (context, level = null, on_change = null, parent = null) => { - (level || (level = self.map)).forEach((item, i) => { - if(item){ - if(item.draw_level){ - item.draw_level(context); - // on_change && item.on_load.add(() => { - // console.log("PASA CHANGE") - // on_change(item); - // }); - }else if(typeof item == "object"){ - - /** @type {string|Class} */ - const type = Kanvas.is_array(item) ? item[0] : item.type; - - if(level[i] = ( - Kanvas.is_string(type) && Kanvas.SHAPES[type] ? new Kanvas.SHAPES[type](self, parent, item, i) : - Kanvas.is_class(type) ? new type(self, parent, item, i) : - null)){ - level[i].draw_level(context); - if(Kanvas.is_function(on_change)){ - level[i].on_status_change.add(on_change); - on_change(level[i]); - }; - }else - Kanvas.is_function(on_change) && on_change(null); - - }; - }; - }); - }; - - /** - * @param {!(string|HTMLElement)} selector - * @param {!kanvas_preload_callback} callback - * @returns {void} - * @access public - */ - this.preload = (selector, callback) => { - if(!Kanvas.is_function(callback)) - return; - - if(Kanvas.is_string(selector)){ - - /** @type {HTMLElement|null} */ - let item; - - try{ - if(item = document.querySelector(selector)){ - callback(item, false); - return; - }; - }catch(exception){ - callback(null, false); - return; - }; - - /** @type {number} */ - const time = Kanvas.get_time(), - /** @type {number} */ - preload = self.thread_add(thread => { - if(item = document.querySelector(selector)){ - self.thread_remove(preload); - callback(item, true); - }else if(Kanvas.get_time() - time > self.preload_timeout){ - self.thread_remove(preload); - callback(null, true); - }; - }); - - }else if(Kanvas.is_html_object(selector)) - callback(selector, false); - else - callback(null, false); - - }; - - /** - * @param {!(string|Image)} source - * @param {!kanvas_load_image_callback} callback - * @returns {void} - * @access public - */ - this.preload_image = (source, callback) => { - if(Kanvas.is_image(source)) - callback(source, ok); - else if(images_cache[source]) - callback(...images_cache[source]); - else - Kanvas.load_image(source, (image, ok) => { - callback(...(images_cache[source] = [image, ok])); - }); - }; - - constructor(); - - }; - - /** - * @returns {number} - * @access public - * @static - */ - Kanvas.get_time = () => Date.now(); - // Kanvas.get_time = () => performance.now(); - - /** - * @constructor - * @param {!(kanvas_thread_callback|Object.)} inputs - * @returns {void} - * @access public - */ - Kanvas.ThreadModel = function(kanvas, inputs){ - - Kanvas.is_function(inputs) && (inputs = {callback : inputs}); - - /** @type {Kanvas.ThreadModel} */ - const self = this, - /** @type {kanvas_thread_callback} */ - callback = Kanvas.get_value(["threads_callback", "callback"], inputs), - /** @type {boolean} */ - is_function = Kanvas.is_function(callback); - /** @type {number} */ - let iterations = 0; - - /** @type {boolean} */ - this.bucle = Kanvas.get_value(["threads_bucle", "bucle"], inputs, true); - /** @type {number} */ - this.timer = Kanvas.get_value(["threads_timer", "timer"], inputs, 16.6667); - /** @type {number} */ - this.last_time = Kanvas.get_value(["threads_start_now", "start_now"], inputs, true) ? 0 : Kanvas.get_time(); - /** @type {number|null} */ - this.i = null; - /** @type {boolean} */ - this.play = Kanvas.get_value(["threads_autostart", "autostart"], inputs, true); - - /** - * @returns {void} - * @access public - */ - this.execute = () => { - if(is_function && self.play){ - - /** @type {number} */ - const time = Kanvas.get_time(); - - if(iterations && !self.bucle) - kanvas.thread_remove(self.i); - else if(time - self.last_time >= self.timer){ - self.last_time = time; - callback(self); - iterations ++; - }; - - }; - }; - - /** - * @returns {void} - * @access public - */ - this.retry = () => { - iterations = 0; - }; - - /** - * - * @returns {boolean} - * @access public - */ - this.ok = () => is_function; - - }; - - /** @type {number} */ - Kanvas.UNLOADED = 1 << 0; - /** @type {number} */ - Kanvas.LOADING = 1 << 1; - /** @type {number} */ - Kanvas.LOADED = 1 << 2; - /** @type {number} */ - Kanvas.ERROR = 1 << 3; - /** @type {number} */ - Kanvas.UNBUILT = 1 < 4; - /** @type {number} */ - Kanvas.THREADS_MODE_ANIMATION = 1 << 0; - /** @type {number} */ - Kanvas.THREADS_MODE_INTERVAL = 1 << 1; - /** @type {number} */ - Kanvas.THREADS_MODE_TIMEOUT = 1 << 2; - - /** - * @class - * @constructor - * @param {!number} x - * @param {!number} y - * @param {!number} blur - * @param {!string} color - * @returns {void} - * @access public - * @static - */ - Kanvas.Shadow = function(x, y, blur, color){ - /** @type {number} */ - this.x = x; - /** @type {number} */ - this.y = y; - /** @type {number} */ - this.blur = blur; - /** @type {number} */ - this.color = color; - }; - - /** - * @class - * @access public - * @static - */ - Kanvas.ObjectBase = class{ - - /** - * @param {!(string|Array.)} keys - * @param {anmy|null} [_default = null] - * @returns {any|null} - * @access protected - */ - _get(keys, _default = null){ - return Kanvas.get_value(keys, this.inputs, _default); - }; - - - /** - * @param {!Kanvas} kanvas - * @param {?Kanvas.ObjectBase} parent - * @param {!(Object.|Array)} inputs - * @param {!number} [i = -1] - * @param {!(Object.|Array)} [custom = {}] - * @param {!Array.} [inputs_map = []] - * @access public - */ - constructor(kanvas, parent, inputs, i = -1, custom = {}, inputs_map = [ - "_", "x", "y", "width", "height", "background", "childs" - ]){ - - /** @type {Object.} */ - this.inputs = Kanvas.get_dictionary([( - Kanvas.is_array(inputs) ? inputs = Kanvas.map_dictionary(inputs, inputs_map) : - Kanvas.is_dictionary(inputs) ? inputs : - {}), custom], false); - - // /** @type {kanvas_on_change_callback|null} */ - // const on_load_event = this._get("on_load", null), - // /** @type {kanvas_on_change_callback|null} */ - // on_error_event = this._get("on_error", null), - // /** @type {kanvas_on_change_callback|null} */ - // on_status_change_event = this._get("on_status_change", null); - - /** @type {Kanvas} */ - this.kanvas = kanvas; - /** @type {Object} */ - this.type = Kanvas.ObjectBase; - /** @type {string} */ - this.type_name = "ObjectBase"; - /** @type {boolean} */ - this.full = this._get("full", false); - /** @type {boolean} */ - this.percentaje = this._get("percentaje", false); - /** @type {number|null} */ - this.rotation = this._get(["rotate", "rotation"], null); - /** @type {string|null} */ - this.background = this._get(["background", "color"], null); - /** @type {number|null} */ - this.alpha = this._get("alpha", null); - /** @type {number} */ - this.status = Kanvas.UNBUILT; - // /** @type {Array.|Object.|Object>|null} */ - // this.childs = this._get("childs", null); - /** @type {number} */ - this.x = this._get("x", 0); - /** @type {number} */ - this.y = this._get("y", 0); - /** @type {number} */ - this.width = this._get("width", 0); - /** @type {number} */ - this.height = this._get("height", 0); - /** @type {boolean} */ - this.print = this._get("print", inputs, false); - /** @type {Array.|Object.} */ - this.childs = this._get("childs", []); - /** @type {string} */ - this.border_color = this._get("border_color", null); - /** @type {number} */ - this.border_size = this._get(["border_size", "border_weight"], null); - /** @type {boolean} */ - this.draw_childs = true; - /** @type {number} */ - this.i = i; - /** @type {Array.} */ - this.shadows = Kanvas.get_array(this._get(["shadow", "shadows"], [])).map(shadow => new Kanvas.Shadow(...shadow)); - /** @type {HTMLCanvasElement|null} */ - this.shadow_shape_cache = null; - /** @type {boolean} */ - this.shadow_cached = false; - /** @type {boolean} */ - this.is_mouse_over = false; - /** @type {Path2D|null} */ - this.path = null; - /** @type {boolean} */ - this.recreate_path_automatically = true; - /** @type {Kanvas.ObjectBase|null} */ - this.parent = parent; - /** @type {DOMMatrix|null} */ - this.matrix = null; - - /** @type {Kanvas.Event} */ - this.on_load = new Kanvas.Event(true); - /** @type {Kanvas.Event} */ - this.on_error = new Kanvas.Event(true); - /** @type {Kanvas.Event} */ - this.on_status_change = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_over = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_out = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_move = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_click = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_down = new Kanvas.Event(); - /** @type {Kanvas.Event} */ - this.on_mouse_up = new Kanvas.Event(); - - /** @type {number} */ - this.childs_with_errors = 0; - /** @type {number} */ - this.childs_loaded = 0; - /** @type {number} */ - this.childs_loading = 0; - /** @type {number} */ - this.childs_null = 0; - /** @type {number} */ - this.childs_unbuilt = 0; - /** @type {boolean} */ - this.full_loaded = !this.childs.length; - - // on_load_event && this.on_load.add(on_load_event); - // on_error_event && this.on_error.add(on_error_event); - // on_status_change_event && this.on_status_change.add(on_status_change_event); - - [ - "load", "error", "status_change", "mouse_down", "mouse_up", "click", - "mouse_over", "mouse_out", "mouse_move" - ].forEach(key => { - - /** @type {kanvas_event_callback} */ - const event = this._get("on_" + key); - - Kanvas.is_function(event) && this["on_" + key].add(event); - - }); - - }; - - /** - * @param {!EventMouse} event - * @returns {void} - * @access public - */ - check_mouse(event){ - if(this.path){ - - /** @type {boolean} */ - const is_over = this.kanvas.context.isPointInPath(this.path, event.clientX, event.clientY); - - if(this.is_mouse_over){ - if(!is_over){ - this.is_mouse_over = false; - this.on_mouse_out.execute(this, event); - }; - }else{ - if(is_over){ - this.is_mouse_over = true; - this.on_mouse_over.execute(this, event); - }; - }; - - if(is_over) - this.on_mouse_move.execute(this, event); - else - this.draw_childs && this.childs.forEach(child => child && child.status && child.check_mouse(event)); - - }; - }; - - /** - * @param {!EventMouse} event - * @returns {void} - * @access public - */ - check_click(event){ - if(this.path && this.kanvas.context.isPointInPath(this.path, event.clientX, event.clientY)) - this.on_click.execute(this, event); - else - this.childs.forEach(child => child.check_click(event)); - }; - - /** - * @param {number|null} [status = null] - * @returns {void} - * @access public - */ - set_status(status = null){ - - status !== null && (this.status = status); - - this.on_status_change.execute(this); - switch(this.status){ - case Kanvas.ERROR: - this.on_error.autoexecute = true; - this.on_error.execute(this); - break; - case Kanvas.LOADED: - if(this.full_loaded){ - this.on_load.autoexecute = true; - this.on_load.execute(this); - }; - break; - default: - this.on_load.autoexecute = false; - this.on_error.autoexecute = false; - break; - }; - - }; - - /** - * @param {!Kanvas.ObjectBase} child - * @returns {void} - * @access public - */ - #set_child_status(child){ - - this.childs_loaded = 0; - this.childs_with_errors = 0; - this.childs_loading = 0; - this.childs_null = 0; - this.childs_unbuilt = 0; - - this.childs.forEach(child => { - if(child === null) - this.childs_null ++; - else if(child.status !== undefined) - this.childs_unbuilt ++; - else if(child.status & Kanvas.ERROR) - this.childs_with_errors ++; - else if(child.status & Kanvas.LOADED) - this.childs_loaded ++; - else - this.childs_loading ++; - }); - - (this.full_loaded = this.childs.length == this.childs_null + this.childs_loaded + this.childs_with_errors) && - self.set_status(); - - }; - - /** - * @param {number} degrees - * @returns {void} - * @access public - */ - rotate(degrees){ - this.rotation = (this.rotation + degrees) % 360; - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @param {!Kanvas.Shadow} shadow - * @returns {void} - * @access public - */ - set_shadow(context, shadow){ - context.shadowOffsetX = this.kanvas._(shadow.x); - context.shadowOffsetY = this.kanvas._(shadow.y); - context.shadowBlur = this.kanvas._(shadow.blur); - context.shadowColor = shadow.color; - }; - - static transform_array(matrix){ - return [matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f]; - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @param {!number} x - * @param {!number} y - * @returns {void} - * @access public - */ - predraw(context, x, y){ - - // if(!this.shadow_cached && this.shadows.length > 1){ - - // if(this.shadow_shape_cache === null){ - // this.shadow_shape_cache = this.kanvas.cache.appendChild(document.createElement("canvas")); - // ["width", "height"].forEach(key => { - // this.shadow_shape_cache.setAttribute(key, this.kanvas[key]); - // }); - // }; - - // const shape_context = this.shadow_shape_cache.getContext("2d"), - // shadows_saved = this.shadows, - // /** @type {DOMMatrix} */ - // matrix = context.getTransform(); - - // shape_context.beginPath(); - // shape_context.clearRect(0, 0, this.kanvas.width, this.kanvas.height); - // shape_context.translate(matrix.e, matrix.f); - - // this.shadows = []; - // this.kanvas.shadow_cached = true; - - // this.kanvas.draw(shape_context, [this]); - // shape_context.translate(-matrix.e, -matrix.f); - // shape_context.closePath(); - // context.save(); - // context.translate(-matrix.e, -matrix.f); - // shadows_saved.forEach(shadow => { - // context.beginPath(); - // this.set_shadow(context, shadow); - // context.drawImage(this.shadow_shape_cache, 0, 0); - // context.closePath(); - // }); - // context.translate(matrix.e, matrix.f); - // context.restore(); - - // this.kanvas.shadow_cached = false; - // this.shadows = shadows_saved; - - // }; - - context.save(); - context.beginPath(); - this.matrix = new DOMMatrix(this.parent ? Kanvas.ObjectBase.transform_array(this.parent.matrix) : [1, 0, 0, 1, this.kanvas.x, this.kanvas.y]); - this.matrix.translateSelf(x, y); - - if(this.rotation){ - - /** @type {number} */ - const x = this.width ? this.kanvas._(this.width / 2) : 0, - /** @type {number} */ - y = this.height ? this.kanvas._(this.height / 2) : 0; - - this.matrix.translateSelf(x, y); - this.matrix.rotateSelf(this.rotation); - this.matrix.translateSelf(-x, -y); - - }; - - if(this.shadows.length < 2){ - if(!this.kanvas.shadow_cached && this.shadow_shape_cache){ - this.shadow_shape_cache.remove(); - this.shadow_shape_cache = null; - }; - if(this.shadows.length == 1) - this.set_shadow(context, this.shadows[0]); - }; - - this.background !== null && (context.fillStyle = this.background); - if(!this.kanvas.shadow_cached){ - this.alpha !== null && (context.globalAlpha = this.alpha); - this.border_size && (context.lineWidth = this.kanvas._(this.border_size)); - this.border_color && (context.strokeStyle = this.border_color); - }; - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw(context, x, y){}; - - /** - * @param {!CanvasRenderingContext2D} context - * @param {!Array.} [shape = []] - * @returns {void} - * @access public - */ - fill(context, shape = []){ - (this.kanvas.shadow_cached || this.background) && context.fill(...shape); - this.border_size && context.stroke(...shape); - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @param {!number} x - * @param {!number} y - * @returns {void} - * @access public - */ - postdraw(context, x, y){ - - if(this.path){ - - /** @type {Array.} */ - const shape = (this.path ? [this.path] : []).map(shape => { - - const real = new Path2D(); - - real.addPath(shape, this.matrix); - - return real; - }); - - this.path && (this.path = shape[0]); - - this.fill(context, shape); - - }; - - // this.matrix = new DOMMatrix(context.getTransform()); - context.closePath(); - - // this.type_name == "Position" && console.log(JSON.stringify([this.draw_childs, this.childs.length])); - if(this.draw_childs && this.childs.length){ - this.path || (this.path = new Path2D()); - this.kanvas.draw(context, this.childs, child => { - child && child.path && this.path.addPath(child.path); - this.#set_child_status(child); - }, this); - }; - - if(this.shadows.length){ - - // image.src = this.kanvas.canvas.toDataURL(); - - // context.save(); - // context.clip(this.path); - // const data = context.getImageData(0, 0, this.kanvas.width, this.kanvas.height); - // context.restore(); - - this.shadows.forEach(shadow => { - - const subcanvas = document.createElement("canvas"), - subcontext = subcanvas.getContext("2d"); - - subcanvas.setAttribute("width", this.kanvas.width); - subcanvas.setAttribute("height", this.kanvas.height); - subcontext.beginPath(); - subcontext.styleFill = "#000"; - this.set_shadow(subcontext, shadow); - subcontext.fill(this.path); - - subcontext.globalCompositeOperation = "destination-out"; - subcontext.beginPath(); - subcontext.fillStyle = "black"; - subcontext.fill(this.path); - subcontext.globalCompositeOperation = "source-over"; - - subcontext.clip(this.path); - subcontext.clearRect(0, 0, this.kanvas.width, this.kanvas.height); - subcontext.closePath(); - - context.drawImage(subcanvas, 0, 0); - - subcanvas.remove(); - - // context.save(); - // this.set_shadow(context, shadow); - // context.beginPath(); - // context.fillStyle = "black"; - // context.fill(this.path); - // context.restore(); - // context.globalCompositeOperation = "source-atop"; - // context.beginPath(); - // context.fillStyle = "black"; - // context.fill(this.path); - // context.closePath(); - // context.fillStyle = "transparent"; - // context.fill(this.path); - // context.globalCompositeOperation = "source-over"; - // context.clip(this.path); - // context.clearRect(0, 0, this.kanvas.width, this.kanvas.height); - // context.transform(1, 0, 0, 1, 0, 0); - // context.closePath(); - - // context.save(); - // this.set_shadow(context, shadow); - // context.fillStyle = "#000"; - // context.fill(this.path); - // context.globalCompositeOperation = "destination-out"; - // context.fill(this.path); - // context.globalCompositeOperation = "source-over"; - // context.restore(); - - // context.save(); - // this.set_shadow(context, shadow); - // context.fillStyle = "#000"; - // context.fill(this.path); - // context.restore(); - - // context.save(); - // context.clip(this.path); - // context.clearRect(0, 0, this.kanvas.width, this.kanvas.height); - // context.restore(); - - }); - - // context.save(); - // context.clip(this.path); - // context.drawImage(image, 0, 0); - // context.restore(); - - // context.putImageData(data, 0, 0); - - }; - - // context.translate(-x, -y); - context.restore(); - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw_level(context){ - if(this.status == Kanvas.LOADED){ - - /** @type {number} */ - const x = this.kanvas._(this.x), - /** @type {number} */ - y = this.kanvas._(this.y); - - this.recreate_path_automatically && (this.path = new Path2D()); - - this.predraw(context, x, y); - this.draw(context, x, y); - this.postdraw(context, x, y); - - }; - }; - - }; - - /** @type {Object.} */ - Kanvas.SHAPES = { - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Rectangle : class extends Kanvas.ObjectBase{ - - /** - * @param {!Kanvas} kanvas - * @param {!(Object.|Array)} inputs - * @param {!number} [i = -1] - * @access public - */ - constructor(kanvas, parent, inputs, i = -1){ - super(kanvas, parent, inputs, i); - - this.type = Kanvas.SHAPES.Rectangle; - this.type_name = "Rectangle"; - - /** @type {Array.} */ - this.radius = Kanvas.get_array(this._get("radius", [])); - /** @type {boolean} */ - this.use_modern_mode = this._get("use_modern_mode", true); - - this.set_status(Kanvas.LOADED); - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw(context, x, y){ - if(this.radius.every(radius => !radius)) - this.path.rect(0, 0, this.kanvas._(this.width), this.kanvas._(this.height)); - else{ - if(this.use_modern_mode) - this.path.roundRect(0, 0, this.kanvas._(this.width), this.kanvas._(this.height), this.radius.map(radius => this.kanvas._(radius))); - else{ - - switch(this.radius.length){ - case 1: - this.radius.push(...[0, 0, 0].map(_ => this.radius[0])); - break; - case 2: - this.radius.push(...this.radius); - break; - case 3: - this.radius.push(this.radius[1]); - break; - }; - - /** @type {number} */ - const radius_top_left = this.kanvas._(this.radius[0]), - /** @type {number} */ - radius_top_right = this.kanvas._(this.radius[1]), - /** @type {number} */ - radius_bottom_right = this.kanvas._(this.radius[2]), - /** @type {number} */ - radius_bottom_left = this.kanvas._(this.radius[3]), - /** @type {number} */ - width = this.kanvas._(this.width), - /** @type {number} */ - height = this.kanvas._(this.height); - - this.path.moveTo(radius_top_left, 0); - this.path.lineTo(width - radius_top_right, 0); - this.path.quadraticCurveTo(width, 0, width, radius_top_right); - this.path.lineTo(width, height - radius_bottom_right); - this.path.quadraticCurveTo(width, height, width - radius_bottom_right, height); - this.path.lineTo(radius_bottom_left, height); - this.path.quadraticCurveTo(0, height, 0, height - radius_bottom_left); - this.path.lineTo(0, radius_top_left); - this.path.quadraticCurveTo(0, 0, radius_top_left, 0); - - }; - }; - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Ellipse : class extends Kanvas.ObjectBase{ - - /** - * @param {!Kanvas} kanvas - * @param {!(Object.|Array)} inputs - * @param {!number} [i = -1] - * @access public - */ - constructor(kanvas, parent, inputs, i = -1){ - super(kanvas, parent, inputs, i, {}, ["_", "x", "y", "radius", "from", "to"]); - - this.type = Kanvas.SHAPES.Ellipse; - this.type_name = "Ellipse"; - - /** @type {number|Array.} */ - this.radius = this._get("radius"); - /** @type {number} */ - this.from = this._get(["from", "start"], 0); - /** @type {number} */ - this.to = this._get(["to", "end"], 360); - - this.set_status(Kanvas.LOADED); - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw(context, x, y){ - if(Kanvas.is_array(this.radius)) - this.path.ellipse(0, 0, this.kanvas._(radius[0]), this.kanvas._(radius[1]), 0, Kanvas.to_radians(this.from), Kanvas.to_radians(this.to)); - else - this.path.arc(0, 0, this.kanvas._(this.radius), Kanvas.to_radians(this.from), Kanvas.to_radians(this.to)); - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Text : class extends Kanvas.ObjectBase{ - - static x = { - left : 0, - right : 1, - center : .5, - start : 0, - end : 1 - }; - static y = { - top : 0, - hanging : .1, - middle : .5, - alphabetic : .8, - ideographic : .9, - bottom : 1 - }; - - /** - * @param {!Kanvas} kanvas - * @param {!(Object.|Array)} inputs - * @param {!number} [i = -1] - * @access public - */ - constructor(kanvas, parent, inputs, i = -1){ - super(kanvas, parent, inputs, i, {}, [ - "_", "x", "y", "text", "size", "font", "color", "align", "baseline", "childs" - ]); - - this.type = Kanvas.SHAPES.Text; - this.type_name = "Text"; - - /** @type {string} */ - this.text = this._get("text"); - /** @type {number} */ - this.size = this._get("size", 1); - /** @type {string} */ - this.font = this._get(["font", "family", "font_family"], this.kanvas.default_font_family); - /** @type {string|number|null} */ - this.weight = this._get("weight", null); - /** @type {string|null} */ - this.style = this._get("style", null); - /** @type {boolean} */ - this.bold = this._get("bold", false); - /** @type {boolean} */ - this.italic = this._get("italic", false); - /** @type {boolean} */ - this.oblique = this._get("oblique", false); - /** @type {string|number} */ - this.baseline = this._get(["baseline", "base_line", "vertical_align"], null); - /** @type {string} */ - this.align = this._get("align", null); - - this.set_status(Kanvas.LOADED); - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @param {!number} x - * @param {!number} y - * @returns {void} - * @access public - */ - predraw(context, x, y){ - super.predraw(context, x, y); - context.font = ( - (this.weight ? this.weight + " " : this.bold ? "bold " : "") + - (this.style ? this.style + " " : this.italic ? "italic " : this.oblique ? "oblique " : "") + - this.kanvas._(this.size) + "px " + - this.font - ); - this.align && (context.textAlign = this.align); - this.baseline && (context.textBaseline = this.baseline); - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw(context, x, y){ - - /** @type {number} */ - const width = context.measureText(this.text).width, - /** @type {number} */ - height = this.kanvas._(this.size), - /** @type {number} */ - _x = -Kanvas.SHAPES.Text.x[this.align || "start"] * width, - /** @type {number} */ - _y = -Kanvas.SHAPES.Text.y[this.baseline || "alphabetic"] * height; - - context.setTransform(...Kanvas.ObjectBase.transform_array(this.matrix)); - context[this.background ? "fillText" : "strokeText"](this.text, 0, 0); - this.fill(context); - context.setTransform(1, 0, 0, 1, 0, 0); - - this.path.moveTo(_x, _y); - this.path.lineTo(width + _x, _y); - this.path.lineTo(width + _x, height + _y); - this.path.lineTo(_x, height + _y); - - }; - - postdraw(context, x, y){ - this.background !== null && (context.fillStyle = "transparent"); - if(!this.kanvas.shadow_cached){ - this.border_size && (context.lineWidth = 0); - this.border_color && (context.strokeStyle = "transparent"); - }; - super.postdraw(context, x, y); - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Image : class extends Kanvas.ObjectBase{ - - /** - * @returns {void} - * @access public - */ - set_size(){ - this.width === null && (this.width = this.image.width); - this.height === null && (this.height = this.image.height); - }; - - /** - * @param {!Kanvas} kanvas - * @param {!(Object.|Array)} inputs - * @param {!number} [i = -1] - * @access public - */ - constructor(kanvas, parent, inputs, i = -1){ - super(kanvas, parent, inputs, i, {}, ["_", "source", "x", "y"].concat(...(Kanvas.is_array(inputs) ? [ - inputs.length > 4 ? ["width", "height"] : [], - inputs.length > 6 ? ["sub_x", "sub_y", "sub_width", "sub_height"] : [] - ] : []), ["childs"])); - - this.type = Kanvas.SHAPES.Image; - this.type_name = "Image"; - - /** @type {Image|null} */ - this.image = this._get(["image", "object", "image_object", "image_item", "item"], null); - /** @type {string|null} */ - this.source = this._get(["source", "src", "link", "url", "path"], null); - /** @type {number} */ - this.sub_x = this._get(["sub_x", "subx", "_x"], null); - /** @type {number} */ - this.sub_y = this._get(["sub_y", "suby", "_y"], null); - /** @type {number} */ - this.sub_width = this._get(["sub_width", "_width"], null); - /** @type {number} */ - this.sub_height = this._get(["sub_height", "_height"], null); - - this.set_status(Kanvas.LOADING); - - this.kanvas.preload_image(this.image || this.source, (image, ok) => { - this.image || (this.image = image); - if(ok){ - this.set_size(); - this.set_status(Kanvas.LOADED); - }else - this.set_status(Kanvas.ERROR); - }); - - }; - - /** - * @param {!CanvasRenderingContext2D} context - * @returns {void} - * @access public - */ - draw(context, x, y){ - - const width = this.kanvas._(this.width), - height = this.kanvas._(this.height); - - this.path.rect(0, 0, width, height); - context.save(); - context.setTransform(...Kanvas.ObjectBase.transform_array(this.matrix)); - context.drawImage(...[this.image].concat(( - this.sub_x !== null && - this.sub_y !== null && - this.sub_width !== null && - this.sub_height !== null - ) ? [ - this.sub_x, this.sub_y, this.sub_width, this.sub_height - ] : [], [0, 0, width, height])); - context.setTransform(1, 0, 0, 1, 0, 0); - context.restore(); - - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Cache : class extends Kanvas.ObjectBase{ - - /** - * @param {!Kanvas} kanvas - * @param {!(Object.|Array)} inputs - * @param {!number} [i = -1] - * @access public - */ - constructor(kanvas, parent, inputs, i = -1){ - super(kanvas, parent, inputs, i, {}, [ - "_", "x", "y", "width", "height", "childs" - ]); - - this.type = Kanvas.SHAPES.Cache; - this.type_name = "Cache"; - this.draw_childs = false; - this.full_loaded = true; - this.recreate_path_automatically = false; - this.status = Kanvas.LOADED; - - /** @type {boolean} */ - this.built = false; - /** @type {Image|null} */ - this.cache = null; - - }; - - predraw(context, x, y){ - super.predraw(context, x, y); - if(!this.built){ - this.build(); - this.built = true; - }; - }; - - /** - * @returns {void} - * @access public - */ - build(){ - - this.set_status(Kanvas.LOADING); - - /** @type {HTMLCanvasElement} */ - const canvas = document.createElement("canvas"), - /** @type {CanvasRenderingContext2D} */ - context = canvas.getContext("2d"), - width = this.kanvas._(this.width), - height = this.kanvas._(this.height); - /** @type {number} */ - let loading = this.childs.reduce((total, child) => total + (child ? 1 : 0), 0), - /** @type {number} */ - done = 0, - /** @type {boolean} */ - synchronous = true; - - this.path = new Path2D(); - - const end = () => { - if(++ done != loading) - return; - - if(!synchronous){ - this.path = new Path2D(); - context.clearRect(0, 0, width, height); - console.log(this.childs); - this.kanvas.draw(context, this.childs, child => { - child && this.path.addPath(child.path); - }, { - matrix : new DOMMatrix([1, 0, 0, 1, 0, 0]) - }); - }; - - /** @type {string} */ - const data = canvas.toDataURL("image/webp", 1); - - Kanvas.load_image(data, (image, ok) => { - this.cache = image; - this.set_status(ok ? Kanvas.LOADED : Kanvas.ERROR); - // console.log([this.status, this.full_loaded, this.childs.length, this.childs_null, this.childs_loaded, this.childs_with_errors, this]); - }); - canvas.remove(); - - }; - - canvas.setAttribute("width", width); - canvas.setAttribute("height", height); - - this.kanvas.draw(context, this.childs, child => { - console.log(child); - if(child){ - this.path.addPath(child.path); - child.on_load.add(end); - }else - end(); - }, { - matrix : new DOMMatrix([1, 0, 0, 1, 0, 0]) - }); - - synchronous = false; - - }; - - /** - * @returns {void} - * @access public - */ - draw(context, x, y){ - if(this.cache){ - this.path.rect(0, 0, this.cache.width, this.cache.height); - context.save(); - context.setTransform(...Kanvas.ObjectBase.transform_array(this.matrix)); - context.drawImage(this.cache, 0, 0); - context.setTransform(1, 0, 0, 1, 0, 0); - context.restore(); - }; - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Position : class extends Kanvas.ObjectBase{ - - /** - * @param {!Kanvas} kanvas - * @param {!(Object.|Array)} inputs - * @param {!number} [i = -1] - * @access public - */ - constructor(kanvas, parent, inputs, i = -1){ - super(kanvas, parent, inputs, i, {}, ["_", "x", "y", "childs"]); - - this.type = Kanvas.SHAPES.Position; - this.type_name = "Position"; - - this.status = Kanvas.LOADED; - - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Shape : class extends Kanvas.ObjectBase{ - - /** @type {Array.} */ - static methods = [null, null, "line", null, "quadraticCurve", "arc", "bezierCurve"]; - - /** - * @param {!Kanvas} kanvas - * @param {!(Object.|Array)} inputs - * @param {!number} [i = -1] - * @access public - */ - constructor(kanvas, parent, inputs, i = -1){ - super(kanvas, parent, inputs, i, {}, ["_", "x", "y", "shape"]); - - this.type = Kanvas.SHAPES.Shape; - this.type_name = "Shape"; - - /** @type {Array.>} */ - this.shape = this._get(["shape", "setps", "marks"], []).filter(dot => ( - Kanvas.is_array(dot) && - [2, 4, 5, 6].includes(dot.length) && - dot.every(value => Kanvas.is_number(value)) - )); - - this.status = Kanvas.LOADED; - - }; - - /** - * @returns {void} - * @access public - */ - draw(context, x, y){ - this.path.moveTo(0, 0); - this.shape.length > 2 && this.shape.forEach(dot => { - this.methods[dot.length] && this.path[this.methods[dot.length] + "To"](...dot); - }); - }; - - }, - - /** - * @class - * @extends Kanvas.ObjectBase - * @access public - * @static - */ - Sprite : class extends Kanvas.ObjectBase{ - - /** - * @param {!Kanvas} kanvas - * @param {!(Object.|Array)} inputs - * @param {!number} [i = -1] - * @access public - */ - constructor(kanvas, parent, inputs, i = -1){ - super(kanvas, parent, inputs, i, {}, ["_", "x", "y", "sources", "map", "childs"]); - - const images = this._get(["images", "image"], {}), - _i = this._get(["i", "index", "position"], 0); - - this.type = Kanvas.SHAPES.Sprite; - this.type_name = "Sprite"; - - /** @type {Array.} */ - this.sources = Kanvas.get_array(this._get(["sources", "source", "src", "links", "urls", "paths", "link", "url", "path"], [])); - /** @type {Object.} */ - this.images = ( - Kanvas.is_dictionary(images) ? images : - (Kanvas.is_array(images) ? images : [images]).reduce((dictionary, image) => { - - if(Kanvas.is_image(image)) - dictionary[image.src] = image; - else if(Kanvas.is_string(image) && !this.sources.includes(image)) - this.sources.push(image); - - return dictionary; - }, {}) - ); - /** @type {Object.>} */ - this.map = Kanvas.SpritesMap.process(this._get("map"), source => { - this.sources.includes(source) || this.sources.push(source) - }); - /** @type {string|null} */ - this.group = this._get("group", null); - /** @type {number} */ - this.i = 0; - /** @type {number} */ - this.frames_per_second = this._get(["frames_per_second", "fps"], 12); - /** @type {boolean} */ - this.autoplay = this._get("autoplay", true); - /** @type {number} */ - this.last_next = 0; - - _i === null || this.next(_i); - - this.status = Kanvas.LOADING; - - Kanvas.execute_array(this.sources, (source, callback) => { - Kanvas.load_image(source, (image, ok) => { - this.images[source] = ok ? image : null; - Kanvas.execute(callback); - }); - }, () => { - this.status = Kanvas.LOADED; - }); - - }; - - /** - * @param {!string} group - * @param {!number} [i = 0] - * @param {boolean|null} [autoplay = null] - * @returns {void} - * @access public - */ - set(group, i = 0, autoplay = null){ - this.last_i_time = performance.now(); - this.group = group; - this.autoplay = autoplay === null ? this.autoplay : autoplay; - this.next(i); - }; - - next(i = null){ - this.i = i === null ? (this.i + i) % this.map[this.group].length : i; - this.width = this.map[this.group][this.i].width; - this.height = this.map[this.group][this.i].height; - }; - - /** - * @returns {void} - * @access public - */ - draw(context, x, y){ - if(this.group && this.map[this.group]){ - - if(this.autoplay && this.map[this.group].length > 1){ - - const next = performance.now() / (1000 / this.frames_per_second) >> 0; - - if(next != this.last_next){ - this.next((this.i + next - this.last_next) % this.map[this.group].length); - this.last_next = next; - }; - - }; - - /** @type {Kanvas.SpritesMap} */ - const sprite = this.map[this.group][this.i], - x = this.kanvas._(sprite.x), - y = this.kanvas._(sprite.y), - width = this.kanvas._(sprite.width), - height = this.kanvas._(sprite.height); - - this.path = new Path2D(); - this.path.rect(x, y, width, height); - - if(this.images[sprite.source]){ - context.save(); - context.setTransform(...Kanvas.ObjectBase.transform_array(this.matrix)); - context.drawImage( - this.images[sprite.source], - sprite.sub_x, sprite.sub_y, sprite.sub_width, sprite.sub_height, - 0, 0, width, height - ); - context.setTransform(1, 0, 0, 1, 0, 0); - context.restore(); - }; - - }; - }; - - } - - }; - - /** - * @class - * @constructor - * @param {!(string|number|Array.|Object.)} inputs - * @returns {void} - * @access public - * @static - */ - Kanvas.SpritesMap = (function(){ - - /** - * @constructs Kanvas.SpritesMap - * @param {!(string|number|Array.|Object.)} inputs - * @returns {void} - * @access private - */ - const SpritesMap = function(...inputs){ - - /** @type {Kanvas.SpritesMap} */ - const self = this; - - /** @type {string|null} */ - this.source = null; - /** @type {number} */ - this.sub_x = 0; - /** @type {number} */ - this.sub_y = 0; - /** @type {number} */ - this.sub_width = 0; - /** @type {number} */ - this.sub_height = 0; - /** @type {number} */ - this.x = 0; - /** @type {number} */ - this.y = 0; - /** @type {number} */ - this.width = 0; - /** @type {number} */ - this.height = 0; - - const constructor = () => { - if(inputs.length){ - inputs.length == 1 && (inputs = inputs[0]); - if(Kanvas.is_array(inputs)) - [self.source, self.sub_x, self.sub_y, self.sub_width, self.sub_height, self.width, self.height, self.x, self.y] = inputs; - else if(Kanvas.is_dictionary(inputs)){ - self.source = Kanvas.get_value(["source", "src", "link", "url", "path"], inputs, self.source); - self.sub_x = Kanvas.get_value(["sub_x", "subx", "left", "horizontal"], inputs, self.sub_x); - self.sub_y = Kanvas.get_value(["sub_y", "suby", "top", "vertical"], inputs, self.sub_y); - self.sub_width = Kanvas.get_value("sub_width", inputs, self.sub_width); - self.sub_height = Kanvas.get_value("sub_height", inputs, self.sub_height); - self.width = Kanvas.get_value("width", inputs, self.width || self.sub_width); - self.height = Kanvas.get_value("height", inputs, self.height || self.sub_height); - self.x = Kanvas.get_value("width", inputs, self.x); - self.y = Kanvas.get_value("height", inputs, self.y); - }; - }; - }; - - constructor(); - - }; - - /** - * @param {!Object.|Kanvas.SpritesMap>>} map - * @param {!kanvas_source_callback} [source_callback] - * @returns {Object.>} - * @access public - * @static - */ - SpritesMap.process = (map, source_callback) => { - - /** @type {Object.>} */ - const processed = {}; - - for(const key in map) - if(Kanvas.is_array(map[key])){ - processed[key] = []; - map[key].forEach(sprite => { - if(Kanvas.is_array(sprite) && sprite[1] == "pattern"){ - - /** @type {number} */ - const l = sprite.length, - /** @type {[string, number, number, number, number, number, number, number, number, number, number, number, number]} */ - [source, sub_width, sub_height, sub_x, sub_y, width, height, x, y, margin_x, margin_y, padding_x, padding_y, length] = [ - sprite[0], - ...sprite.slice(2, 4), - ...(l > 5 ? sprite.slice(4, 6) : [0, 0]), - ...(l > 7 ? sprite.slice(6, 8) : [0, 0]), - ...(l > 9 ? sprite.slice(8, 10) : [0, 0]), - ...(l > 11 ? sprite.slice(10, 11) : [0, 0]), - ...(l > 13 ? sprite.slice(12, 14) : [0, 0]), - ...(l % 2 ? sprite.slice(-1) : [0]) - ]; - /** @type {number} */ - let k = 0, - /** @type {boolean} */ - ended = false; - - Kanvas.execute(source_callback, source); - - for(let i = 0; i < sub_x && !ended; i ++) - for(let j = 0; j < sub_y && !ended; j ++){ - processed[key].push(new Kanvas.SpritesMap([ - source, - padding_x + j * sub_width + j * margin_x, - padding_y + i * sub_height + i * margin_y, - sub_width, - sub_height, - width, - height, - x, - y - ])); - length && ++ k == length && (ended = true); - }; - - }else - processed[key].push(sprite instanceof Kanvas.SpritesMap ? sprite : new Kanvas.SpritesMap(sprite)); - }); - }; - - return processed; - }; - - return SpritesMap; - })(); - - /** - * @class - * @constructor - * @returns {void} - * @access public - * @static - */ - Kanvas.Event = function(unique = false){ - - /** @type {Kanvas.Event} */ - const self = this, - /** @type {Array.} */ - events = []; - - /** @type {boolean} */ - this.autoexecute = false; - /** @type {number} */ - this.length = 0; - /** @type {boolean} */ - this.unique = unique; - - /** - * @param {...any} [parameters] - * @returns {Array.} - * @access public - */ - this.execute = (...parameters) => events.map((event, i) => { - - let response = null; - - if(event){ - response = event(...parameters, i); - self.unique && (events[i] = null); - }; - - return response; - }); - - /** - * @param {!kanvas_event_callback} callback - * @returns {number|null} - * @access public - */ - this.add = callback => { - - /** @type {number|null} */ - let i = null; - - if(Kanvas.is_function(callback)){ - - /** @type {number} */ - const l = events.length; - - for(i = 0; i < l; i ++) - if(!events[i]) - break; - - this.length ++; - events[i] = callback; - - self.autoexecute && callback(); - - }; - - return i; - }; - - /** - * @param {!number} i - * @returns {boolean} - * @access public - */ - this.remove = i => { - if(Kanvas.is_index(i) && events[i]){ - events[i] = null; - this.length --; - return true; - }; - return false; - }; - - }; - - /** - * @class - * @constructor - * @param {!number} x - * @param {!number} y - * @param {!number} radius - * @returns {void} - * @access public - * @static - */ - Kanvas.Circle = function(i, x, y, radius){ - - /** @type {Kanvas.Circle} */ - const self = this; - - /** @type {number} */ - this.i = i; - /** @type {string} */ - this.type = "circle"; - /** @type {number} */ - this.x = x; - /** @type {number} */ - this.y = y; - /** @type {number} */ - this.radius = radius; - - /** - * @param {!number} x - * @param {!number} y - * @returns {boolean} - * @access public - */ - this.check = (x, y) => ( - (x - self.x) ** 2 + - (y - self.y) ** 2 - ) ** .5 <= self.radius; - - }; - - /** - * @class - * @constructor - * @param {!number} x - * @param {!number} y - * @param {!number} width - * @param {!number} height - * @returns {void} - * @access public - * @static - */ - Kanvas.Rectangle = function(i, x, y, width, height){ - - /** @type {Kanvas.Rectangle} */ - const self = this; - - /** @type {number} */ - this.i = i; - /** @type {string} */ - this.type = "rectangle"; - /** @type {number} */ - this.x = x; - /** @type {number} */ - this.y = y; - /** @type {number} */ - this.width = width; - /** @type {number} */ - this.height = height; - - /** - * @param {!number} x - * @param {!number} y - * @returns {boolean} - * @access public - */ - this.check = (x, y) => ( - x >= self.x && x <= self.x + self.width && - y >= self.y && y <= self.y + self.height - ); - - }; - - /** - * @class - * @constructor - * @returns {void} - * @access public - * @static - */ - Kanvas.EventMouse = function(){ - - /** @type {Kanvas.Event} */ - const event = new Kanvas.Event(), - /** @type {Array.} */ - properties = []; - - /** - * @param {...any} [parameters] - * @returns {Array.} - * @access public - */ - this.execute = event.execute; - - /** - * @param {!kanvas_event_mouse_callback} callback - * @param {!number} x - * @param {!number} y - * @param {...any} size - * @returns {number|null} - * @access public - */ - this.add = (callback, x, y, ...size) => { - - /** @type {number|null} */ - const i = event.add((x, y, ...parameters) => { - properties[i].check(x, y) && callback(x, y, ...parameters); - }); - - i !== null && (properties[i] = new Kanvas[ - size.length == 1 ? "Circle" : - "Rectangle"](i, x, y, ...size)); - - return properties[i]; - }; - - /** - * @param {!(Kanvas.Rectangle|Kanvas.Circle)} property - * @returns {boolean} - * @access public - */ - this.remove = property => { - if(property && Kanvas.number(property.i) && event.remove(property.i)){ - properties[property.i] = null; - return true; - }; - return false; - }; - - }; - - /** - * @constructor - * @returns {void} - * @access public - * @static - */ - Kanvas.Screen = function(){ - /** @type {number} */ - this.x = 0; - /** @type {number} */ - this.y = 0; - }; - - /** - * @param {any|null} value - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_array = value => value instanceof Array; - - /** - * @param {any|null} value - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_dictionary = value => value && value.constructor == Object; - - /** - * @param {any|null} value - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_string = value => typeof value == "string"; - - /** - * @param {any|null} value - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_function = value => typeof value == "function"; - - /** - * @param {!(string|Array.)} value - * @returns {Array.} - * @access public - * @static - */ - Kanvas.get_keys = keys => (Kanvas.is_array(keys) ? keys : [keys]).filter((key, i, keys) => Kanvas.is_string(key) && keys.indexOf(key) == i); - - /** - * @param {!(string|Array.)} value - * @param {!(Object.|Array)} inputs - * @param {any|null|undefined} [_default = undefined] - * @returns {any|null|undefined} - * @access public - * @static - */ - Kanvas.get_value = (keys, inputs, _default = undefined) => { - - /** @type {any|null|undefined} */ - let response; - - Kanvas.is_array(keys) || (keys = Kanvas.get_keys(keys)); - - return ( - Kanvas.is_dictionary(inputs) ? keys.some(key => (response = inputs[key]) !== undefined) : - Kanvas.is_array(inputs) ? inputs.some(subinputs => (response = Kanvas.get_value(keys, subinputs)) !== undefined) : - false) ? response : _default; - }; - - /** - * @param {any|null} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_class = item => typeof item == "function" && item.toString().startsWith("class "); - - /** - * @param {any|null} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_html_object = item => item && (item.tagName || item.nodeName); - - /** - * @param {any|null} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_number = item => typeof item == "number"; - - /** - * @param {any|null} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_integer = item => Kanvas.is_number(item) && item == item >> 0; - - /** - * @param {any|null} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_index = item => Kanvas.is_integer(item) && item >= 0; - - /** - * @param {any|null|Array} item - * @returns {Array.} - * @access public - * @static - */ - Kanvas.get_array = item => Kanvas.is_array(item) ? item : [item]; - - /** - * @param {!(Object.|Array)} dictionaries - * @param {!boolean} [overwrite = false] - * @param {!Object.} [dictionary = {}] - * @returns {Object.} - * @access public - * @static - */ - Kanvas.get_dictionary = (dictionaries, overwrite = false, dictionary = {}) => { - - Kanvas.get_array(dictionaries).forEach(value => { - if(Kanvas.is_array(value)) - Kanvas.get_dictionary(value, overwrite, dictionary); - else if(Kanvas.is_dictionary(value)){ - for(const key in value) - (overwrite || dictionary[key] === undefined) && (dictionary[key] = value[key]); - }; - }); - - return dictionary; - }; - - /** - * @param {!Array.} array - * @param {!Array.} map - * @returns {Object.} - * @access public - * @static - */ - Kanvas.map_dictionary = (array, map) => map.reduce((dictionary, key, i) => { - - dictionary[key] = array[i]; - - return dictionary; - }, {}); - - /** - * @param {any|null} value - * @param {!Array.} nested_array - * @param {number|null} [_default = null] - * @returns {number|null} - * @access public - * @static - */ - Kanvas.get_i_from_nested_array = (value, nested_array, _default = null) => { - - /** @type {number} */ - const l = nested_array.length; - - for(let i = 0; i < l; i ++) - if(nested_array[i].includes(value)) - return i; - return _default; - }; - - /** - * @param {!string} source - * @param {!kanvas_load_image_callback} callback - * @returns {void} - * @access public - * @static - */ - Kanvas.load_image = (source, callback) => { - - /** @type {Image} */ - const image = new Image(); - - image.src = source; - image.onload = () => callback(image, true); - image.onerror = () => callback(image, false); - - }; - - /** - * @param {!number} degrees - * @returns {number} - * @access public - * @static - */ - Kanvas.to_radians = degrees => 2 * Math.PI * degrees / 360; - - /** - * @param {!kanvas_execute_callback} method - * @param {...any} parameters - * @returns {any|null} - * @access public - * @static - */ - Kanvas.execute = (method, ...parameters) => Kanvas.is_function(method) && method(...parameters); - - /** - * @param {!Array.} array - * @param {!kanvas_array_item_callback} callback_per_item - * @param {!kanvas_default_callback} [callback_end = null] - * @returns {void} - * @access public - * @static - */ - Kanvas.execute_array = (array, callback_per_item, callback_end = null) => { - - /** @type {number} */ - const l = array.length; - - if(!l){ - Kanvas.execute(callback_end); - return; - }; - - /** @type {number} */ - let loaded = 0; - - array.forEach(item => { - Kanvas.execute(callback_per_item, item, () => { - ++ loaded == l && Kanvas.execute(callback_end); - }); - }); - - }; - - /** - * @param {any|null} item - * @returns {boolean} - * @access public - * @static - */ - Kanvas.is_image = item => item instanceof Image; - - return Kanvas; -})(); \ No newline at end of file diff --git a/Public/ecma/version/221106/Kanvas.ecma.js b/Public/ecma/version/221106/Kanvas.ecma.js deleted file mode 100755 index 38dcfa5..0000000 --- a/Public/ecma/version/221106/Kanvas.ecma.js +++ /dev/null @@ -1,936 +0,0 @@ -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, - frames_per_second_samples : 20, - settings_overwrite : false, - ajax_timeout : 2000 - }, - custom = {}, - // cache = [], - _screen = {x : 0, y : 0}, - position = {x : 0, y : 0}, - events = {}, - threads = [], - hashes = [], - attributes = { - natives : ["id", "class", "onmousemove", "tabindex", "onkeydown", "onkeyup"] - }, - cache = {}, - frames_per_second_samples = [], - delta_time = 0; - 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, - frames_per_second_samples_number, - last_frame_per_second_sample = Date.now(), - real_frames_per_seconds = 0, - ajax_timeout; - - 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.LOADING = 1 << 0; - this.LOADED = 1 << 1; - this.ERROR = 1 << 2; - - this.map = []; - - const null_or_undefined = this.null_or_undefined = value => value === undefined || value === null; - - this.get = (url, callback) => { - - let ended = false; - const ajax = new XMLHttpRequest(), - end = status => { - if(ended) - return; - ended = true; - typeof callback == "function" && callback(ajax.response, ajax.status, ajax.readyState, status, status == "OK"); - }, - date = Date.now(); - - ajax.open("get", url, true); - ajax.timeout = ajax_timeout; - ajax.onreadystatechange = () => { - if(ended) - return; - if(ajax.readyState == 4) - end((ajax.status >= 200 && ajax.status < 300) || [301, 302, 304].includes(ajax.status) ? "OK" : "HTTP_ERROR"); - else if(Date.now() - date > ajax_timeout) - end("FORCED_TIMEOUT"); - }; - ajax.send(null); - - ajax.ontimeout = () => end("TIMEOUT"); - ajax.onabort = () => end("ABORTED"); - ajax.onerror = () => end("ERROR"); - - return ajax; - }; - - 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); - - this.settings_add = (inputs, overwrite, callback) => { - - if(inputs instanceof Array){ - - let loaded = 0; - const end = () => ++ loaded == inputs.length && typeof callback == "function" && callback(); - - inputs.forEach(input => self.settings_add(input, overwrite, end)); - - return; - }; - - if(typeof inputs == "object"){ - typeof overwrite != "boolean" && (overwrite = settings(["settings_overwrite", "overwrite"])); - for(const key in inputs) - (overwrite || custom[key] === undefined) && (custom[key] = inputs[key]); - inputs.autostart !== undefined && (input.autostart = inputs.autostart); - typeof callback == "function" && callback(); - return; - }; - - if(typeof inputs == "string"){ - - let json; - - try{ - if(json = JSON.parse(inputs)){ - self.settings_add(json, overwrite, callback); - return; - }; - }catch(exception){}; - - self.get(inputs, response => { - try{ - if(json = JSON.parse(response)){ - self.settings_add(json, overwrite, callback); - return; - }; - }catch(exception){}; - typeof callback == "function" && callback(); - }); - - return; - }; - - typeof callback == "function" && callback(); - - }; - - 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, custom, 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 Events = this.Events = function(){ - - const events = []; - - this.add = callback => { - if(typeof callback != "function") - return null; - - let i = 0; - const l = events.length; - - while(i < l){ - if(events[i] === null) - break; - i ++; - }; - - events[i] = callback; - - return i; - }; - - this.remove = i => !isNaN(i) && i >= 0 && events[i] && (events[i] = null); - - this.execute = (...inputs) => events.forEach(event => event && event(...inputs)); - - }; - - 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))); - - }; - - const calculate_real_frames_per_seconds = () => { - - const now = Date.now(), - time = now - last_frame_per_second_sample; - - frames_per_second_samples.push(time); - last_frame_per_second_sample = now; - - while(frames_per_second_samples.length > frames_per_second_samples_number) - frames_per_second_samples.shift(); - - real_frames_per_seconds = 1000 / (frames_per_second_samples.reduce((a, b) => a + b) / frames_per_second_samples.length); - delta_time = time / 1000; - - }; - - this.start = callback => { - - const end = status => typeof callback == "function" && callback(status); - - if(started){ - end(false); - return false; - }; - 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(); - ajax_timeout = settings("ajax_timeout"); - - 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);", - cells : c, - mouse_x : 0, - mouse_y : 0 - }); - 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"); - - frames_per_second_samples_number = self.settings("frames_per_second_samples"); - threads_add(calculate_real_frames_per_seconds); - - end(true); - - }); - - return true; - }; - - // 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.preload_cache_items = (items, callback_per_item, callback) => { - - const end = status => typeof callback == "function" && callback(status); - - typeof items == "string" && (items = [items]); - - if(!(items instanceof Array)){ - end(false); - return; - }; - - let fully = true, - loaded = 0; - const has_callback_per_item = typeof callback_per_item == "function", - on_item_loaded = (url, ok) => { - ok !== undefined && (cache[url].status = ok ? self.LOADED : self.ERROR); - cache[url].on_load.execute(url, ok); - has_callback_per_item && callback_per_item(url, ok); - ok === false && fully && (fully = false); - ++ loaded == items.length && end(fully); - }; - - items.forEach(url => { - - if(cache[url]){ - if(cache[url].status == self.LOADING) - cache[url].on_load.add(has_callback_per_item); - else - on_item_loaded(url); - return; - }; - - const extension = ((url.match(/\.([^\.]+)/) || [])[1] || "").toLowerCase(); - - cache[url] = { - status : self.LOADING, - on_load : new Events() - }; - - switch(extension){ - case "jpg": - case "jpeg": - case "jpge": - case "png": - case "webp": - case "gif": - case "tif": - case "tiff": - case "pcx": - case "bmp": - - const image = new Image(); - - cache[url].type = "image"; - cache[url].image = image; - - image.src = url; - image.onload = () => on_item_loaded(url, true); - image.onerror = () => on_item_loaded(url, false); - - break; - default: - - cache[url].type = "unknown"; - cache[url].status = self.ERROR; - on_item_loaded(url, false); - - break; - }; - - }); - - }; - - 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; - - !data.ok && !data.source && (data.source = data.src || data.url); - - if(cache[data.source]){ - - if(!data.ok){ - if(cache[data.source] && cache[data.source].status == self.LOADED){ - isNaN(data.swidth) && (data.swidth = cache[data.source].image.width); - isNaN(data.sheight) && (data.sheight = cache[data.source].image.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; - }; - - if(cache[data.source].status != self.LOADED) - return; - - 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.source].image, - 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(); - - }else - self.preload_cache_items([data.source]); - - }, - // 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.extends = (object, overwrite) => { - for(const key in self) - (overwrite || object[key] === undefined) && (object[key] = self[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 = () => ({x : mx, y : my}); - this.get_position = () => ({x : position.x, y : position.y}); - this.get_cells = () => c; - this.get_canvas_distance = () => ({x : dx, y : dy}); - this.get_cell_size = () => s; - - this.get_real_frames_per_second = () => real_frames_per_seconds; - this.delta_time = () => delta_time; - - construct(); - -}; diff --git a/Public/ecma/version/30311230/Kanvas.ecma.js b/Public/ecma/version/30311230/Kanvas.ecma.js deleted file mode 100755 index 7c89766..0000000 --- a/Public/ecma/version/30311230/Kanvas.ecma.js +++ /dev/null @@ -1,782 +0,0 @@ -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(); - -}; diff --git a/Public/ecma/version/Kanvas.AnP.ecma.js b/Public/ecma/version/Kanvas.AnP.ecma.js deleted file mode 100644 index f35a866..0000000 --- a/Public/ecma/version/Kanvas.AnP.ecma.js +++ /dev/null @@ -1,456 +0,0 @@ -"use strict"; - -/** - * @typedef {import("../../../AnP/Public/ecma/AnP.ecma.js").AnP} AnP - */ - -/** - * @constructor - * @param {!AnP} anp - * @param {!(Object.|Array.>)} [inputs] - * @param {!anp_default_callback} [callback] - * @returns {void} - * @access public - */ -const Kanvas = function(anp, inputs, callback){ - - /** @type {Kanvas} */ - const self = this, - /** @type {Object.} */ - settings = AnP.prototype.get_dictionary([{ - /** @type {HTMLElement|string} */ - position : "body", - /** @type {boolean} */ - autocreate : true, - /** @type {number} */ - quality : 1, - /** @type {number} */ - base_x : .5, - /** @type {number} */ - base_y : .5, - /** @type {number} */ - cells : 40, - /** @type {boolean} */ - autostart : true - }, inputs]), - /** @type {Object.} */ - screen = {x : 0, y : 0, quality : 0}, - /** @type {Object.} */ - base = {x : .5, y : .5}; - /** @type {boolean} */ - let started = false, - /** @type {HTMLCanvasElement|null} */ - canvas = null, - /** @type {CanvasRenderingContext2D|null} */ - context = null, - /** @type {number|null} */ - thread = null, - /** @type {number} */ - quality = 1, - /** @type {number} */ - cell_size = 1, - fps_time = 0; - - /** @type {Array.|Array.|null>} */ - this.map = []; - /** @type {Object.} */ - this.screen = {x : 0, y : 0}; - /** @type {number} */ - this.cells = 40; - this.delta = 0; - this.fps = 0; - - /** - * @returns {void} - * @access private - */ - const constructor = () => { - - anp.settings.get("autostart", settings) && self.start(callback); - - }; - - /** - * @param {!anp_start_callback} [callback] - * @returns {boolean} - * @access public - */ - this.start = callback => { - - /** - * @param {!boolean} status - * @returns {void} - */ - const end = status => AnP.prototype.execute(callback, status); - - if(started){ - end(false); - return false; - }; - started = true; - - quality = anp.settings.get("quality", settings); - base.x = anp.settings.get("base_x", settings); - base.y = anp.settings.get("base_y", settings); - self.cells = anp.settings.get("cells", settings); - - if(anp.settings.get("autocreate", settings)) - self.create(anp.settings.get("position", settings), () => end(true)); - else - end(true); - - return true; - }; - - /** - * @param {!number} value - * @returns {number} - * @access public - */ - this.aexis = value => value * cell_size; - /** - * @param {!number} value - * @returns {number} - * @access private - */ - const _ = this.aexis; - - /** - * @returns {Array.} - * @access public - * @deprecated - */ - this.get_transform_matrix = () => { - - /** @type {DOMMatrix} */ - const transform = context.getTransform(); - - return [ - transform.a, - transform.b, - transform.c, - transform.d, - transform.e, - transform.f - ]; - }; - - /** - * @returns {void} - * @access private - */ - const thread_method = () => { - - const new_time = Date.now(); - - if(screen.x != canvas.offsetWidth || screen.y != canvas.offsetHeight || screen.quality != quality){ - - screen.quality = quality; - canvas.width = quality * (screen.x = canvas.offsetWidth); - canvas.height = quality * (screen.y = canvas.offsetHeight); - - cell_size = quality * screen[screen.y < screen.x ? "y" : "x"] / self.cells; - self.screen.x = quality * screen.x / cell_size; - self.screen.y = quality * screen.y / cell_size; - - }; - - /** @type {Array.} */ - const x = _(base.x * self.screen.x), - y = _(base.y * self.screen.y); - - context.clearRect(0, 0, _(self.screen.x), _(self.screen.y)); - context.translate(x, y); - draw(self.map); - context.translate(-x, -y); - - if(fps_time){ - self.fps = 1000 / (new_time - fps_time); - self.delta = 24 / self.fps; - }; - fps_time = new_time; - - }; - - /** - * @param {!(string|HTMLElement)} position - * @param {!anp_default_callback} [callback] - * @returns {void} - * @access public - */ - this.create = (position, callback) => { - if(canvas) - AnP.prototype.execute(callback); - else - new HTMLPreload(anp, position, item => { - if(item){ - anp.attributes.set(canvas = item.appendChild(document.createElement("canvas")), { - class : ["kanvas"].concat(AnP.prototype.get_class_keys(AnP.prototype.get_value("class", settings))).join(" ").trim(), - git : AnP.prototype.get_value("git", settings), - link : AnP.prototype.get_value("link", settings) - }); - context = canvas.getContext("2d"); - thread = anp.threads.add(thread_method); - }; - AnP.prototype.execute(callback); - }); - }; - - /** - * @param {!Array.|Object.|Kanvas.prototype.ObjectBase|null>} map - * @returns {void} - * @access private - */ - const draw = map => map.forEach((item, i) => { - - if((AnP.prototype.is_dictionary(item) && !item.draw) || AnP.prototype.is_array(item)){ - - /** @type {string} */ - const type = AnP.prototype.is_dictionary(item) ? item.type : item.shift(), - /** @type {Kanvas.prototype.ObjectBase} */ - _class = self.objects[type] || self.objects[object_synonyms[type]]; - - map[i] = _class ? _class(item) : null; - - map[i].print && console.log(map[i]); - - }; - - if(item && item.state & Kanvas.prototype.LOADED){ - - const base_x = _(item.x), - base_y = _(item.y); - - context.save(); - context.translate(base_x, base_y); - - if(item.rotation){ - - /** @type {number} */ - const x = item.width ? _(item.width / 2) : 0, - /** @type {number} */ - y = item.height ? _(item.height / 2) : 0; - - context.translate(x, y); - context.rotate(2 * Math.PI * item.rotation / 360); - context.translate(-x, -y); - - }; - - item.background && (context.fillStyle = item.background); - item.alpha !== null && (context.globalAlpha = item.alpha); - - item.draw(); - - item.background && context.fill(); - - item.childs && draw(item.childs); - - context.translate(-base_x, -base_y); - context.restore(); - - }; - - }); - - /** - * @constructor - * @callback kanvas_builder_callback - * @param {!Object.} inputs - * @returns {void} - */ - - /** - * @constructor - * @callback kanvas_object_callback - * @param {!(Object.|Object.)} inputs - * @returns {void} - */ - - /** - * - * @param {!Array.} keys - * @param {!(Object.|Array.>)} inputs - * @param {!kanvas_builder_callback} Builder - * @returns {Kanvas.prototype.ObjectBase} - */ - const build_shape = (keys, inputs, Builder) => { - - const base = new Kanvas.prototype.ObjectBase( - inputs = Kanvas.prototype.to_dictionary_values(keys, inputs) - ); - - return AnP.prototype.extends(base, true, new Builder(base, inputs)); - }; - - /** @type {Object.} */ - const object_synonyms = { - rectangle : "Rectangle", - image : "Image", - text : "Text", - image : "Image" - }; - - /** @type {Object.} */ - this.objects = { - Rectangle : inputs => build_shape(["x", "y", "width", "height"], inputs, function(item, inputs){ - - /** @type {string} */ - this.type = self.objects.Rectangle; - this.type_name = "Rectangle"; - this.width = AnP.prototype.get_value("width", inputs, 0); - this.height = AnP.prototype.get_value("height", inputs, 0); - this.state = Kanvas.prototype.LOADED; - - this.draw = () => context.fillRect(0, 0, _(item.width), _(item.height)); - - }), - Image : inputs => build_shape(["source", "x", "y", "width", "height", "cut_x", "cut_y", "cut_width", "cut_height"], inputs, function(item, inputs){ - - const image_item = AnP.prototype.get_value(["image", "source", "src"], inputs, null), - has = {any : false, all : true}, - set_sizes = () => { - ["x", "y", "width", "height"].forEach(key => this[key] === null && (this[key] = "xy".includes(key) ? 0 : this.image[key])); - if(!has.all && has.any){ - ["x", "y", "width", "height"].forEach(key => this["cut_" + key] === null && (this["cut_" + key] = "xy".includes(key) ? 0 : this.image[key])); - }; - }; - - ["x", "y", "width", "height"].forEach(key => { - has.any = ( - has["cut_" + key] = ( - this["cut_" + key] = AnP.prototype.get_value("cut_" + key, inputs, null) - ) !== null - ) || has.any; - has.all = has.all && has["cut_" + key]; - }); - - this.type = self.objects.Image; - this.type_name = "Image"; - this.url = AnP.prototype.is_string(image_item) ? image_item : image_item ? image_item.src : null; - this.image = AnP.prototype.is_object(image_item) ? image_item : null; - this.width = AnP.prototype.get_value("width", inputs, null); - this.height = AnP.prototype.get_value("height", inputs, null); - this.state = this.image ? Kanvas.prototype.LOADED : Kanvas.prototype.UNLOADED; - this.object = null; - - if(this.state & Kanvas.prototype.UNLOADED && !this.image && this.url){ - - const image_object = new Image(); - - item.state = Kanvas.prototype.LOADING; - image_object.src = this.url; - image_object.onload = () => { - item.image = image_object; - item.state = Kanvas.prototype.LOADED; - set_sizes(); - }; - image_object.onerror = () => { - item.state |= Kanvas.prototype.ERROR; - }; - - }else - set_sizes(); - - this.draw = () => context.drawImage(item.image, 0, 0, _(item.width), _(item.height)); - - }), - Text : inputs => build_shape(["text", "x", "y"], inputs, function(item, inputs){ - - this.type = self.objects.Text; - this.type_name = "Text"; - this.text = AnP.prototype.get_value("text", inputs, ""); - this.align = AnP.prototype.get_value("align", inputs, null); - this.baseline = AnP.prototype.get_value("baseline", inputs, null); - this.size = AnP.prototype.get_value("size", inputs, null); - this.style = AnP.prototype.get_value("style", inputs, null); - this.font = AnP.prototype.get_value(["font_family", "font"], inputs, null); - this.direction = AnP.prototype.get_value("direction", inputs, null); - this.state = Kanvas.prototype.LOADED; - - this.draw = () => { - item.direction && (context.direction = item.direction); - item.baseline && (context.textBaseline = item.baseline); - (item.size || item.font || item.style) && (context.font = (item.style ? item.style + " " : "") + (quality * (item.size || 1) * cell_size) + "px " + (item.font || "sans")); - item.align && (context.textAlign = item.align); - context[item.background ? "fillText" : "strokeText"](item.text, 0, 0); - }; - - }) - }; - - constructor(); - -}; - -/** - * @param {!(Array.|string)} keys - * @param {!(Object.|Array.)} inputs - * @returns {Object.} - * @access public - * @static - */ -Kanvas.prototype.to_dictionary_values = (keys, inputs) => ( - AnP.prototype.is_array(inputs) ? AnP.prototype.get_dictionary_from_array(keys, inputs) : - AnP.prototype.is_object(inputs) ? inputs || {} : -{}); - -/** @type {number} */ -Kanvas.prototype.UNLOADED = 1 << 0; -/** @type {number} */ -Kanvas.prototype.LOADING = 1 << 1; -/** @type {number} */ -Kanvas.prototype.LOADED = 1 << 2; -/** @type {number} */ -Kanvas.prototype.ERROR = 1 << 3; -/** @type {number} */ -Kanvas.prototype.UNBUILT = 1 < 4; - -/** - * @constructor - * @param {Object.} inputs - * @returns {void} - * @access public - * @static - */ -Kanvas.prototype.ObjectBase = function(inputs){ - - /** @type {Object} */ - this.type = Kanvas.prototype.ObjectBase; - /** @type {string} */ - this.type_name = "ObjectBase"; - /** @type {boolean} */ - this.full = AnP.prototype.get_value("full", inputs, false); - /** @type {boolean} */ - this.percentaje = AnP.prototype.get_value("percentaje", inputs, false); - /** @type {number|null} */ - this.rotation = AnP.prototype.get_value("rotate", inputs, null); - /** @type {string|null} */ - this.background = AnP.prototype.get_value(["background", "color"], inputs, null); - /** @type {number|null} */ - this.alpha = AnP.prototype.get_value("alpha", inputs, null); - /** @type {number} */ - this.state = Kanvas.prototype.UNBUILT; - /** @type {Array.|Object.|Object>|null} */ - this.childs = AnP.prototype.get_value("childs", inputs, null); - /** @type {number} */ - this.x = AnP.prototype.get_value("x", inputs, 0); - /** @type {number} */ - this.y = AnP.prototype.get_value("y", inputs, 0); - /** @type {boolean} */ - this.print = AnP.prototype.get_value("print", inputs, false); - - /** - * @param {number} degrees - * @returns {void} - * @access public - */ - this.rotate = degrees => this.rotation = (this.rotation + degrees) % 360; - - /** - * @returns {void} - * @access public - */ - this.draw = () => {}; - -}; \ No newline at end of file diff --git a/Public/ecma/version/Kanvas.ecma.js b/Public/ecma/version/Kanvas.ecma.js deleted file mode 100644 index 144f9e9..0000000 --- a/Public/ecma/version/Kanvas.ecma.js +++ /dev/null @@ -1,747 +0,0 @@ -Kanvas = function(settings){ - - const self = this, - default_settings = { - nulls : false, - default_value : null, - position : ".kanvas", - preload_timeout : 2000, - frames_per_second : 60, - quality : 1, - quality_x : 1, - quality_y : 1, - cells : 40, - swap_and_drop_timer : 5000, - font_size : 1, - font_family : "Arial", - settings_overwrite : false, - autostart : true, - autobuild : true, - font_minimum_size : 12, - events_cache_timer : 100 - }, - custom = {}, - cache = {}, - frames_times = [], - id_length = 11, - id_alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", - ids = [], - threads = [], - number_of_cells = {x : 0, y : 0}, - events_cache = []; - let thread = null, - frames_per_second = null, - canvas, context, - last_frame_time = 0, frames_times_summatory = 0, - swap_and_drop_timer, - cache_box, - default_font_size, default_font_family, - settings_overwrite, - built = false, - started = false, - font_minimum_size, - events_cache_timer; - - this.map = []; - let cells = this.cells; - let cell_size = this.cell_size; - let quality = this.quality; - let quality_x = this.quality_x; - let quality_y = this.quality_y; - this.cells_x = 0; - this.cells_y = 0; - this.delta_time = 0; - - let item_self = this.item_self; - let hash_self = this.hash_self; - let object_name = this.object_name; - - this.Event = function(){ - - const self = this, - events = [], - properties = []; - - const construct = () => { - - events_cache.push(autoclean); - - }; - - this.execute = (callback, ...arguments) => events.forEach((event, i) => ( - event && - (typeof callback == "function" ? callback(properties[i]) : true) && - event(...arguments) - )); - - this.add = (callback, own_properties) => { - - let i = 0; - const l = events.length; - - for(; i < l; i ++) - if(!events[i]) - break; - - events[i] = callback; - properties[i] = own_properties; - - return i; - }; - - this.remove = i => events[i] = null; - - const autoclean = () => { - - const date = Date.now(); - - properties.forEach((own_properties, i) => { - if(own_properties && own_properties.last_used && date - own_properties.last_used > events_cache_timer){ - events[i] = null; - properties[i] = null; - }; - }); - - }; - - this.update = (i, date) => events[i] && (properties[i].last_used = date); - - construct(); - - }; - - this.on_screen_change = new this.Event(); - this.on_ready = new this.Event(); - this.on_click = new this.Event(); - this.on_click_down = new this.Event(); - this.on_click_up = new this.Event(); - this.on_key_down = new this.Event(); - this.on_key_up = new this.Event(); - - const construct = () => { - - settings = ( - settings instanceof Array ? settings : - typeof settings == "object" ? [settings] : - []).filter(inputs => typeof inputs == "object" && !(inputs instanceof Array)); - - self.settings("autostart") && self.start(); - - }; - - this.start = callback => { - - const end = status => typeof callback == "function" && callback(status); - - if(started){ - end(false); - return false; - }; - started = true; - - settings_overwrite = self.settings(["settings_overwrite", "overwrite"]); - frames_per_second = self.settings(["frames_per_second", "fps"]); - events_cache_timer = self.settings("events_cache_timer"); - object_name = self.object_name = self.settings("object_name"); - - thread = setInterval(execute, 1000 / frames_per_second); - - if(self.settings("autobuild")) - self.build(callback); - else - end(true); - - return true; - }; - - this.build = callback => { - - const position = self.settings("position"), - end = status => typeof callback == "function" && callback(status); - - if(built){ - end(false); - return false; - }; - built = true; - - if(position){ - - if(position.tagName || position.nodeName){ - end_build(position); - end(true); - return; - }; - - if(typeof position != "string"){ - console.error("position_not_string"); - end(false); - return; - }; - - if(!position.trim()){ - console.error("position_selector_empty"); - end(false); - return; - }; - - let html_object; - - try{ - if(html_object = document.querySelector(position)){ - end_build(html_object); - end(true); - return; - }; - }catch(exception){ - console.error(exception); - console.error("position_bad_selector"); - end(false); - return; - }; - - const date = Date.now(), - timeout = self.settings("preload_timeout"); - let interval = setInterval(() => { - if(html_object = document.querySelector(position)){ - clearInterval(interval); - end_build(html_object); - end(true); - }else if(Date.now() - date > timeout){ - clearInterval(interval); - console.error("position_timeout"); - end(false); - }; - }, frames_per_second); - - }else{ - console.error("no_position"); - end(false); - }; - - return true; - }; - - const end_build = position => { - - quality = self.quality = self.settings("quality"); - quality_x = self.quality_x = self.settings("quality_x"); - quality_y = self.quality_y = self.settings("quality_y"); - cells = self.cells = self.settings("cells"); - default_font_size = self.settings("font_size"); - default_font_family = self.settings("font_family"); - - cache.quality = 0; - cache.quality_x = 0; - cache.quality_y = 0; - - cache.screen = {x : 0, y : 0}; - cache.origin = {x : 0, y : 0}; - - item_self = self.item_self = (position || document.querySelector("body")).appendChild(document.createElement("div")); - cache_box = item_self.appendChild(document.createElement("div")); - canvas = item_self.appendChild(document.createElement("canvas")); - hash_self = self.hash_self = self.settings(["id", "hash"]) || self.create_id(); - - item_self.setAttribute("id", hash_self); - item_self.setAttribute("class", ["kanvas", hash_self].concat((self.settings("class") || "").split(/\s+/)).filter((key, i, array) => array.indexOf(key) == i).join(" ")); - item_self.setAttribute("data-hash", hash_self); - item_self.setAttribute("data-cells", cells); - item_self.setAttribute("data-minimum-font-size", font_minimum_size = self.settings("font_minimum_size")); - - cache_box.setAttribute("class", "kanvas-cache-box"); - cache_box.setAttribute("style", ` - position : absolute; - top : 0%; - left : 0%; - width : 100%; - height : 100%; - visibility : hidden; - z-index : 10; - opacity : 0; - `.replace(/[\r\n\s]+/g, "")); - - canvas.setAttribute("class", "kanvas-ui"); - canvas.setAttribute("style", ` - position : absolute; - top : 0%; - left : 0%; - width : 100%; - height : 100%; - z-index : 20; - `.replace(/[\r\n\s]+/g, "")); - canvas.onclick = event => on_click(canvas, event, "click"); - canvas.onmousedown = event => on_click(canvas, event, "down"); - canvas.onmouseup = event => on_click(canvas, event, "up"); - canvas.onkeydown = event => on_key(canvas, event, "down"); - canvas.onkeyup = event => on_key(canvas, event, "up"); - - context = canvas.getContext("2d"); - - context.id = self.create_id(); - - swap_and_drop_timer = self.settings("swap_and_drop_timer"); - - self.on_ready.execute(); - - }; - - this.nulls = nulls => typeof nulls == "boolean" ? nulls : self.settings("nulls", null, false, false); - - this.default_value = (_default, nulls) => _default !== undefined && (self.nulls(nulls) || _default !== null) ? _default : self.settings("default_value", null, null, true); - - this.settings = (names, inputs, _default, nulls) => { - - const l = (names = ( - names instanceof Array ? names : - typeof names == "string" ? [names] : - [] - ).filter((name, i, array) => name && typeof name == "string" && array.indexOf(name) == i)).length; - - if(l){ - - const m = (inputs = ( - inputs instanceof Array ? inputs : - typeof inputs == "object" ? [inputs] : - []).concat(settings, custom, [default_settings])).length; - - nulls = self.nulls(nulls); - - for(let j = 0; j < m; j ++) - if(inputs[j] && typeof inputs[j] == "object" && !(inputs[j] instanceof Array)) - for(let i = 0; i < l; i ++) - if(inputs[j][names[i]] !== undefined && (nulls || inputs[j][names[i]] !== null)) - return inputs[j][names[i]]; - }; - return self.default_value(_default, nulls); - }; - - this.settings_add = (inputs, overwrite) => { - if(!inputs) - return; - - if(typeof inputs == "string"){ - try{ - inputs = JSON.parse(inputs); - }catch(exception){}; - }; - - if(typeof inputs == "object"){ - if(inputs instanceof Array) - inputs.forEach(inputs, overwrite); - else{ - typeof overwrite != "boolean" && (overwrite = settings_overwrite); - for(const key in inputs) - if(overwrite || custom[key] === undefined) - custom[key] = inputs[key]; - }; - }; - - }; - - this.create_id = () => { - - let id; - const l = id_alphabet.length; - - do{ - id = ""; - while((id += id_alphabet[l * Math.random() >> 0]).length < id_length); - }while( - ids.includes(id) || - !/^[a-z]/i.test(id) || - document.querySelector("." + id + ",#" + id + ",[name=" + id + "]") - ); - ids.push(id); - - return id; - }; - - const execute = () => { - - const date = Date.now(); - let screen_changed = false; - - if(item_self && (cache.screen.x != item_self.offsetWidth || cache.screen.y != item_self.offsetHeight)){ - screen_changed = true; - - cache.screen.x = item_self.offsetWidth; - cache.screen.y = item_self.offsetHeight; - - const font_size = cache.screen[cache.screen.x < cache.screen.y ? "x" : "y"] / cells; - - item_self.style.fontSize = (font_size < font_minimum_size ? font_minimum_size : font_size) + "px"; - - }; - - if(canvas){ - - if(last_frame_time){ - - const frame_time = date - last_frame_time; - - frames_times.push(frame_time); - frames_times_summatory += frame_time; - - self.delta_time = frame_time / 1000; - - while(frames_times.length > frames_per_second) - frames_times_summatory -= frames_times.shift(); - - }; - - last_frame_time = date; - - if(screen_changed || cache.quality != quality){ - - const width = cache.screen.x * quality, - height = cache.screen.y * quality; - - cache.quality = quality; - canvas.setAttribute("width", width); - canvas.setAttribute("height", height); - cache.origin.x = width / 2; - cache.origin.y = height / 2; - - cell_size = self.cell_size = (width > height ? height : width) / cells; - - number_of_cells.x = width / cell_size; - number_of_cells.y = height / cell_size; - - this.cells_x = number_of_cells.x / 2; - this.cells_y = number_of_cells.y / 2; - - for(const key in cache) - if(cache[key] && cache[key].data) - cache[key].data = null; - - self.on_screen_change.execute(); - - }; - - }; - - threads.forEach(thread => thread && thread()); - - if(canvas){ - - context.beginPath(); - context.clearRect(0, 0, cache.screen.x * quality, cache.screen.y * quality); - context.translate(cache.origin.x, cache.origin.y); - - draw(context, self.map, 0, 0); - - context.translate(-cache.origin.x, -cache.origin.y); - - for(const key in cache) - if(cache[key] && cache[key].last_used && date - cache[key].last_used > swap_and_drop_timer) - delete cache[key]; - - }; - - events_cache.forEach(autoclean => autoclean()); - - }; - - this.set_quality = new_quality => quality = self.quality = new_quality; - this.set_quality_x = new_quality => quality_x = self.quality_x = new_quality; - this.set_quality_y = new_quality => quality_y = self.quality_y = new_quality; - - const _x = x => x * cell_size; - const _y = y => y * cell_size; - const size = size => size * cell_size; - - const set_cache = (context, status) => { - - !status && cache[context.id] && cache[context.id].ok && (cache[context.id].ok = false); - - return status; - }; - - const set_border = (context, inputs) => { - - const has_border = !!(inputs.border_color || !isNaN(inputs.border_width)); - - inputs.border_color && (context.strokeStyle = inputs.border_color); - !isNaN(inputs.border_width) && (context.lineWidth = size(inputs.border_width)); - - return has_border; - }; - - const set_background = (context, inputs) => { - - const has_background = !!(inputs.background || (!inputs.border_color && isNaN(inputs.border_width))); - - if(inputs.background){ - if(inputs.background instanceof Array){ - - const v = inputs.background, - is_linear = v.length == 5, - gradient = ( - is_linear ? context.createLinearGradient(_x(v[0]), _y(v[1]), _x(v[2]), _y(v[3])) : - context.createRadialGradient(_x(v[0]), _y(v[1]), _x(v[2]), _y(v[3]), size(v[4]), size(v[5])) - ); - - inputs.background[is_linear ? 4 : 6].forEach(color => gradient.addColorStop(color[0], color[1])); - - context.fillStyle = gradient; - - }else - context.fillStyle = inputs.background; - }; - - return has_background; - }; - - const set_shadow = (context, inputs, shape_callback) => { - - const shadows = inputs.shadow || inputs.shadows; - - (shadows && shadows.length ? shadows[0] instanceof Array ? shadows : [shadows] : []).forEach(shadow => { - [context.shadowOffsetX, context.shadowOffsetY, context.shadowBlur, context.shadowColor] = shadow; - context.shadowOffsetX = size(shadow[0]); - context.shadowOffsetY = size(shadow[1]); - context.shadowBlur = size(shadow[2]); - context.shadowColor = size(shadow[3]); - shape_callback(); - }); - - }; - - const shapes = { - rectangle : (context, inputs) => { - - const x = _x(inputs.x), - y = _y(inputs.y), - width = size(inputs.width), - height = size(inputs.height), - has_border = set_border(context, inputs), - has_background = set_background(context, inputs); - - set_shadow(context, inputs, () => context.rect(x, y, width, height)); - has_background && context.fillRect(x, y, width, height); - has_border && context.strokeRect(x, y, width, height); - - return set_cache(context, true); - }, - image : (context, inputs) => { - - const url = inputs.url; - - if(url){ - - const cached = cache[url]; - - if(!cached){ - (cache[url] = { - image : new Image(), - loaded : false, - last_used : Date.now() - }).image.src = url; - cache[url].image.crossOrigin = "anonymous"; - cache[url].image.onload = () => cache[url].loaded = true; - return set_cache(context, false); - }; - - if(cached.loaded){ - - let width = inputs.width, - height = inputs.height; - const cut_x = inputs.cut_x || 0, - cut_y = inputs.cut_y || 0, - cut_width = inputs.cut_width || 0, - cut_height = inputs.cut_height || 0, - position_x = inputs.x || 0, - position_y = inputs.y || 0, - x = _x(position_x), - y = _y(position_y), - end_width = size(width), - end_height = size(height); - - !width && (width = cache.quality * (cut_width || cache[url].image.width - cut_x) / cell_size); - !height && (height = cache.quality * (cut_height || cache[url].image.height - cut_y) / cell_size); - - set_shadow(context, inputs, () => context.rect(x, y, end_width, end_height)); - set_border(context, inputs); - context.drawImage( - cache[url].image, - cut_x, cut_y, cut_width || cache[url].image.width - cut_x, cut_height || cache[url].image.height - cut_y, - x, y, end_width, end_height - ); - cache[url].last_used = Date.now(); - - return set_cache(context, true); - }; - - }; - - return set_cache(context, false); - }, - cache : (context, inputs) => { - - const width = inputs.width ? inputs.width * cell_size : canvas.getAttribute("width"), - height = inputs.height ? inputs.height * cell_size : canvas.getAttribute("height"); - let status = false; - - if(!cache[inputs.name]){ - - const subcanvas = cache_box.appendChild(document.createElement("canvas")); - - cache[inputs.name] = { - canvas : subcanvas, - data : null - }; - cache[inputs.name].context = subcanvas.getContext("2d"); - - cache[inputs.name].context.id = inputs.name; - - subcanvas.setAttribute("data-id", cache[inputs.name].context.id); - - cache[inputs.name].context.translate(inputs.x || 0, inputs.y || 0); - - }; - - if(cache[inputs.name].data){ - if(cache[inputs.name].image_loaded){ - context.drawImage(cache[inputs.name].image, _x(inputs.x || 0), _y(inputs.y || 0), cache[inputs.name].image.width, cache[inputs.name].image.height); - status = true; - }else if(!cache[inputs.name].image){ - - cache[inputs.name].image = new Image(); - - cache[inputs.name].image.src = cache[inputs.name].data; - cache[inputs.name].image.onload = () => { - // cache[inputs.name].canvas.remove(); - cache[inputs.name].image_loaded = true; - }; - // cache[inputs.name].image.onerror = () => cache[inputs.name].canvas.remove(); - - }; - }else{ - - cache[inputs.name].canvas.setAttribute("width", width); - cache[inputs.name].canvas.setAttribute("height", height); - - cache[inputs.name].context.beginPath(); - cache[inputs.name].context.clearRect(0, 0, width, height); - cache[inputs.name].context.translate(width / 2, height / 2); - - cache[inputs.name].image = null; - cache[inputs.name].image_loaded = false; - cache[inputs.name].ok = true; - - draw(cache[inputs.name].context, inputs.childs, 0, 0); - - cache[inputs.name].context.closePath(); - - cache[inputs.name].ok && - (cache[inputs.name].data = cache[inputs.name].canvas.toDataURL("image/png", 1.0)); - - }; - - cache[inputs.name].last_used = Date.now(); - - return set_cache(context, status); - }, - text : (context, inputs) => { - - const x = _x(inputs.x), - y = _y(inputs.y), - has_border = set_border(context, inputs), - has_background = set_background(context, inputs); - - inputs.align && (context.textAlign = inputs.align); - inputs.baseline && (context.textBaseline = inputs.baseline); - !isNaN(inputs.border_width) && (context.lineWidth = size(inputs.border_width)); - context.font = (inputs.style ? inputs.style + " " : "") + size(inputs.size || default_font_size) + "px " + (inputs.family || default_font_family); - - set_shadow(context, inputs, () => context.fillText(inputs.text, x, y)); - has_background && context.fillText(inputs.text, x, y); - has_border && context.strokeText(inputs.text, x, y); - - return true; - } - }; - - this.string_variables = (string, variables) => string.replace(/\{([^\{\}]+)\}/g, (...arguments) => variables[arguments[1]] !== undefined ? variables[arguments[1]] : arguments[0]); - - const draw = (context, level, x, y) => level.forEach(values => { - if(values && (shapes[values.type] || ["block"].includes(values.type))){ - - const sub_x = _x(x + (values.margin_x || 0)), - sub_y = _y(y + (values.margin_y || 0)), - date = Date.now(); - - context.save(); - context.translate(sub_x, sub_y); - - const transform = context.getTransform(); - - values.rotate && context.rotate(2 * Math.PI * values.rotate / 360); - !isNaN(values.alpha) && (context.globalAlpha = values.alpha); - - if(values.on_click){ - values.context_x = transform.e / quality; - values.context_y = transform.f / quality; - if(!values.last_used || date - values.last_used > events_cache_timer) - values.i = self.on_click.add(eval(self.string_variables(values.on_click, {object_name : object_name})), values); - else - self.on_click.update(values.i, date); - values.last_used = date; - }; - - values.type != "block" && shapes[values.type](context, values); - - values.type != "cache" && values.childs && draw(context, values.childs, values.x, values.y); - - context.translate(-sub_x, -sub_y); - context.restore(); - - }; - }); - - this.get_real_fps = this.get_real_frames_per_second = () => frames_times_summatory ? 1000 / (frames_times_summatory / frames_times.length) : 0; - - this.threads_add = callback => { - - let i = 0; - const l = threads.length; - - for(; i < l; i ++) - if(!threads[i]) - break; - - threads[i] = callback; - - return i; - }; - - this.threads_remove = i => threads[i] = null; - - this.get_cells_x = () => number_of_cells.x; - this.get_cells_y = () => number_of_cells.y; - - this.extends = object => { - for(const key in self) - if(object[key] === undefined) - object[key] = self[key]; - }; - - const on_click = (canvas, event, action) => { - - switch(action){ - case "click": - self.on_click.execute(properties => ( - event.clientX >= properties.context_x + (properties.x * cell_size) && - event.clientY >= properties.context_y + (properties.y * cell_size) && - event.clientX <= properties.context_x + ((properties.x + properties.width) * cell_size) && - event.clientY <= properties.context_y + ((properties.y + properties.height) * cell_size) - ), canvas, event); - break; - }; - - }; - - construct(); - -}; \ No newline at end of file diff --git a/Public/test/index.anp.html b/Public/test/index.anp.html deleted file mode 100755 index a95e982..0000000 --- a/Public/test/index.anp.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - Kanvas - Test - - - - - - - - - - - - diff --git a/Public/test/index.html b/Public/test/index.html index a72a60c..2b80685 100755 --- a/Public/test/index.html +++ b/Public/test/index.html @@ -56,6 +56,8 @@ /** @type {number} */ const v = 5; + console.log("PASA A"); + /** @type {Kanvas} */ const kanvas = new Kanvas({ position : "body", @@ -64,6 +66,7 @@ // threads_mode : Kanvas.THREADS_MODE_TIMEOUT, // context : "webgl", on_ready : () => { + console.log("PASA B"); [ { diff --git a/Public/test/shadow.html b/Public/test/shadow.html deleted file mode 100644 index 26e0594..0000000 --- a/Public/test/shadow.html +++ /dev/null @@ -1,51 +0,0 @@ - - \ No newline at end of file diff --git a/Public/test/x.html b/Public/test/x.html deleted file mode 100644 index 09fbd40..0000000 --- a/Public/test/x.html +++ /dev/null @@ -1,20 +0,0 @@ - - \ No newline at end of file diff --git a/Public/test/y.html b/Public/test/y.html deleted file mode 100644 index aedcd35..0000000 --- a/Public/test/y.html +++ /dev/null @@ -1,18 +0,0 @@ - \ No newline at end of file diff --git a/version b/version index e8f89e5..342a3d5 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.0.4.1 \ No newline at end of file +0.0.4.2 \ No newline at end of file