fix(ecma): Fixing the default Kanvas ECMA file.
This commit is contained in:
		
							parent
							
								
									1164a8db12
								
							
						
					
					
						commit
						b7cd867778
					
				
							
								
								
									
										747
									
								
								Public/ecma/Kanvas.ecma.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										747
									
								
								Public/ecma/Kanvas.ecma.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,747 @@
 | 
			
		||||
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();
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user