#wip(js): Building new models version.
This commit is contained in:
parent
a1dbed7503
commit
a6cdaf3309
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,4 +9,5 @@ html.files.json
|
|||||||
/Python/Abstracts/AnPMap.py
|
/Python/Abstracts/AnPMap.py
|
||||||
/Python/Abstracts/Applications.py
|
/Python/Abstracts/Applications.py
|
||||||
__pycache__
|
__pycache__
|
||||||
.sass-cache
|
.sass-cache
|
||||||
|
*.deleted.*
|
||||||
File diff suppressed because it is too large
Load Diff
601
Public/ecma/Modules/Parallax.ecma.js
Normal file
601
Public/ecma/Modules/Parallax.ecma.js
Normal file
@ -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.<string, any|null>|Array.<any|null>)} [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.<number, number>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.get = () => [self.get_x(), self.get_y()];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class
|
||||||
|
* @constructor
|
||||||
|
* @param {!Kanvas} kanvas
|
||||||
|
* @param {?Parallax.Class} [parent = null]
|
||||||
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [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.<Object.<string, any|null>|Array.<any|null>|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.<number, number>} */
|
||||||
|
this.framed_in = Kanvas.get_value("framed_in", inputs, [1, 1]);
|
||||||
|
/** @type {boolean} */
|
||||||
|
this.repeated = !!Kanvas.get_value("repeated", inputs, false);
|
||||||
|
/** @type {Array.<Array.<number, number, number, number, Array.<number>, 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.<number, number>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.get_frame_position = i => [i % self.framed_in[Parallax.X], i / self.framed_in[Parallax.Y] >> 0];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!(Object.<string, any|null>|Kanvas.ObjectBase)} item
|
||||||
|
* @returns {Array.<Array.<number, number>, Array.<number, number>>}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const get_item_range_position = item => {
|
||||||
|
|
||||||
|
/** @type {Array.<Array.<number, number>, Array.<number, number>>} */
|
||||||
|
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.<number>} ks
|
||||||
|
* @returns {void}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.recalculate_items_in_frames = (ks = []) => {
|
||||||
|
|
||||||
|
/** @type {Array.<number, number>} */
|
||||||
|
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.<number, number>, Array.<number, number>>} */
|
||||||
|
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.<string, any|null>|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.<Parallax.Stage|null>} */
|
||||||
|
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.<number>} */
|
||||||
|
// 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.<number, number, number>} */
|
||||||
|
Parallax.FRAMES_BROTHERS = [-1, 0, 1];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?any} item
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
Parallax.is_stage = item => item instanceof Parallax.Stage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!(Object.<string, any|null>|Array.<any|null>|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.<number, number>} range
|
||||||
|
* @param {!number} limit
|
||||||
|
* @returns {Array.<number>}
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
Parallax.get_range_positions = (range, limit) => {
|
||||||
|
|
||||||
|
/** @type {Array.<number>} */
|
||||||
|
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;
|
||||||
104
Public/ecma/t.js
104
Public/ecma/t.js
@ -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.<string, number>} */
|
|
||||||
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();
|
|
||||||
@ -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();
|
|
||||||
|
|
||||||
};
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -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();
|
|
||||||
|
|
||||||
};
|
|
||||||
@ -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();
|
|
||||||
|
|
||||||
};
|
|
||||||
@ -1,456 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import("../../../AnP/Public/ecma/AnP.ecma.js").AnP} AnP
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constructor
|
|
||||||
* @param {!AnP} anp
|
|
||||||
* @param {!(Object.<string, any|null>|Array.<Object.<string, any|null>>)} [inputs]
|
|
||||||
* @param {!anp_default_callback} [callback]
|
|
||||||
* @returns {void}
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
const Kanvas = function(anp, inputs, callback){
|
|
||||||
|
|
||||||
/** @type {Kanvas} */
|
|
||||||
const self = this,
|
|
||||||
/** @type {Object.<string, any|null>} */
|
|
||||||
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.<string, number>} */
|
|
||||||
screen = {x : 0, y : 0, quality : 0},
|
|
||||||
/** @type {Object.<string, number>} */
|
|
||||||
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.<Kanvas.prototype.ObjectBase|Object.<string, any|null>|Array.<any|null>|null>} */
|
|
||||||
this.map = [];
|
|
||||||
/** @type {Object.<string, number>} */
|
|
||||||
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.<number>}
|
|
||||||
* @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.<number>} */
|
|
||||||
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.<Array.<any|null>|Object.<string, any|null>|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.<string, any|null>} inputs
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constructor
|
|
||||||
* @callback kanvas_object_callback
|
|
||||||
* @param {!(Object.<string, any|null>|Object.<any|null>)} inputs
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {!Array.<string>} keys
|
|
||||||
* @param {!(Object.<string, any|null>|Array.<any|null>>)} 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.<string, string>} */
|
|
||||||
const object_synonyms = {
|
|
||||||
rectangle : "Rectangle",
|
|
||||||
image : "Image",
|
|
||||||
text : "Text",
|
|
||||||
image : "Image"
|
|
||||||
};
|
|
||||||
|
|
||||||
/** @type {Object.<string, kanvas_object_callback>} */
|
|
||||||
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>|string)} keys
|
|
||||||
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
|
||||||
* @returns {Object.<string, any|null>}
|
|
||||||
* @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.<string, any|null>} 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.<Array.<any>|Object.<string, any|null>|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 = () => {};
|
|
||||||
|
|
||||||
};
|
|
||||||
@ -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();
|
|
||||||
|
|
||||||
};
|
|
||||||
@ -1,87 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<title>Kanvas - Test</title>
|
|
||||||
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
|
|
||||||
<style data-type="text/css" data-language="CSS3" data-rel="stylesheet" charset="utf-8">
|
|
||||||
|
|
||||||
html,body{
|
|
||||||
height : 100%;
|
|
||||||
margin : 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
body{overflow : hidden;}
|
|
||||||
|
|
||||||
.kanvas{
|
|
||||||
position : absolute;
|
|
||||||
top : 0px;
|
|
||||||
left : 0px;
|
|
||||||
width : 100%;
|
|
||||||
height : 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fps{
|
|
||||||
position : absolute;
|
|
||||||
top : 0px;
|
|
||||||
right : 0px;
|
|
||||||
margin : 10px;
|
|
||||||
font-weight : 900;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script data-type="text/javascript" data-language="ECMAScript 2015" src="/ecma/version/20230707/Kanvas.ecma.js" data-crossorigin="anonymous" charset="utf-8"></script>
|
|
||||||
|
|
||||||
<script type="module" data-type="text/javascript" data-language="ECMAScript 2015" charset="utf-8">
|
|
||||||
|
|
||||||
kanvas = new Kanvas({
|
|
||||||
position : "body",
|
|
||||||
quality : 1,
|
|
||||||
frames_per_second : 60
|
|
||||||
});
|
|
||||||
|
|
||||||
kanvas.map.push(
|
|
||||||
{type : "cache", name : "main_test", x : -20, y : -20, width : 40, height : 40, childs : [
|
|
||||||
{type : "image", url : "/data/test/hqdefault.jpg", x : -10, y : -10, width : 20, height : 20, cut_x : 100, cut_width : 100, rotate : -15},
|
|
||||||
{type : "rectangle", x : -2, y : -1, width : 4, height : 2, background : [0, 0, 4, 0, [
|
|
||||||
[0, "#F00"],
|
|
||||||
[1, "#00F"]
|
|
||||||
]], rotate : 45, border_color : "#00F", childs : [
|
|
||||||
{type : "rectangle", x : -.5, y : -.5, width : 1, height : 1, background : "#F88", rotate : -35, margin_x : 2, margin_y : 1}
|
|
||||||
]},
|
|
||||||
{type : "cache", name : "test_cache", childs : []}
|
|
||||||
]},
|
|
||||||
{type : "text", background : "#080", border_color : "#F00", text : "Hola, esto es una prueba xD", x : 20, y : 20, size : 5, baseline : "bottom", align : "right", shadow : [
|
|
||||||
[0, 0, 5, "#000"],
|
|
||||||
[1, 1, 2, "#800"]
|
|
||||||
]}
|
|
||||||
);
|
|
||||||
|
|
||||||
with(kanvas.map[1]){
|
|
||||||
align = "left";
|
|
||||||
baseline = "top";
|
|
||||||
};
|
|
||||||
|
|
||||||
kanvas.on_ready.add(() => {
|
|
||||||
|
|
||||||
kanvas.threads_add(() => {
|
|
||||||
kanvas.map[1].text = kanvas.get_real_fps().toFixed(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
kanvas.on_screen_change.add(() => {
|
|
||||||
console.log("PASA");
|
|
||||||
with(kanvas.map[1]){
|
|
||||||
x = -kanvas.cells_x;
|
|
||||||
y = -kanvas.cells_y;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body></body>
|
|
||||||
</html>
|
|
||||||
@ -56,6 +56,8 @@
|
|||||||
/** @type {number} */
|
/** @type {number} */
|
||||||
const v = 5;
|
const v = 5;
|
||||||
|
|
||||||
|
console.log("PASA A");
|
||||||
|
|
||||||
/** @type {Kanvas} */
|
/** @type {Kanvas} */
|
||||||
const kanvas = new Kanvas({
|
const kanvas = new Kanvas({
|
||||||
position : "body",
|
position : "body",
|
||||||
@ -64,6 +66,7 @@
|
|||||||
// threads_mode : Kanvas.THREADS_MODE_TIMEOUT,
|
// threads_mode : Kanvas.THREADS_MODE_TIMEOUT,
|
||||||
// context : "webgl",
|
// context : "webgl",
|
||||||
on_ready : () => {
|
on_ready : () => {
|
||||||
|
console.log("PASA B");
|
||||||
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,51 +0,0 @@
|
|||||||
<canvas id="mainCanvas" width="800" height="600"></canvas>
|
|
||||||
<script>
|
|
||||||
const mainCanvas = document.getElementById("mainCanvas");
|
|
||||||
const mainCtx = mainCanvas.getContext("2d");
|
|
||||||
|
|
||||||
// Crear un canvas temporal para la forma base
|
|
||||||
function createBaseShapeCanvas(width, height, drawShapeCallback) {
|
|
||||||
const tempCanvas = document.createElement("canvas");
|
|
||||||
tempCanvas.width = width;
|
|
||||||
tempCanvas.height = height;
|
|
||||||
|
|
||||||
const tempCtx = tempCanvas.getContext("2d");
|
|
||||||
drawShapeCallback(tempCtx); // Dibujar la forma en el canvas temporal
|
|
||||||
|
|
||||||
return tempCanvas;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dibujar la forma base con diferentes configuraciones de sombra
|
|
||||||
function drawShapesWithShadows(baseCanvas) {
|
|
||||||
const shadows = [
|
|
||||||
{ shadowColor: "rgba(0, 0, 0, 0.5)", shadowBlur: 10, x: 50, y: 50 },
|
|
||||||
{ shadowColor: "rgba(255, 0, 0, 0.5)", shadowBlur: 20, x: 50, y: 50 },
|
|
||||||
{ shadowColor: "rgba(0, 0, 255, 0.7)", shadowBlur: 15, x: 50, y: 50 },
|
|
||||||
];
|
|
||||||
|
|
||||||
shadows.forEach(({ shadowColor, shadowBlur, x, y }, i) => {
|
|
||||||
mainCtx.save(); // Guardar estado actual del contexto principal
|
|
||||||
|
|
||||||
mainCtx.shadowColor = shadowColor;
|
|
||||||
mainCtx.shadowBlur = shadowBlur;
|
|
||||||
mainCtx.shadowOffsetX = i * 10 - 10; // Opcional: ajustar según el efecto deseado
|
|
||||||
mainCtx.shadowOffsetY = i * 10 - 10;
|
|
||||||
|
|
||||||
// Dibujar la forma base con la sombra configurada
|
|
||||||
mainCtx.drawImage(baseCanvas, x, y);
|
|
||||||
|
|
||||||
mainCtx.restore(); // Restaurar estado para evitar que las sombras se mezclen
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crear la forma base
|
|
||||||
const baseShapeCanvas = createBaseShapeCanvas(100, 100, (ctx) => {
|
|
||||||
ctx.fillStyle = "green";
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(50, 50, 50, 0, Math.PI * 2); // Un círculo
|
|
||||||
ctx.fill();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Dibujar la forma base con diferentes sombras
|
|
||||||
drawShapesWithShadows(baseShapeCanvas);
|
|
||||||
</script>
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
<canvas id="mainCanvas"></canvas>
|
|
||||||
<script>
|
|
||||||
|
|
||||||
function x(){
|
|
||||||
|
|
||||||
const body = document.querySelector("body"),
|
|
||||||
canvas = document.querySelector("canvas"),
|
|
||||||
context = canvas.getContext("2d");
|
|
||||||
|
|
||||||
canvas.setAttribute("width", body.offsetWidth);
|
|
||||||
canvas.setAttribute("height", body.offsetHeight);
|
|
||||||
|
|
||||||
context.clearRect(0, 0, body.offsetWidth, body.offsetHeight);
|
|
||||||
|
|
||||||
requestAnimationFrame(x);
|
|
||||||
};
|
|
||||||
|
|
||||||
requestAnimationFrame(x);
|
|
||||||
|
|
||||||
</script>
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
<script>
|
|
||||||
|
|
||||||
// function cosa(){
|
|
||||||
// console.log("PASA");
|
|
||||||
// requestAnimationFrame(cosa);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// requestAnimationFrame(cosa);
|
|
||||||
|
|
||||||
console.log("Primero");
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
console.log("Segundo (callback de setTimeout)");
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
console.log("Tercero");
|
|
||||||
|
|
||||||
</script>
|
|
||||||
Loading…
Reference in New Issue
Block a user