/* * Concrete v3.0.6 * A lightweight Html5 Canvas framework that enables hit detection, layering, multi buffering, * pixel ratio management, exports, and image downloads * Release Date: 6-29-2020 * https://github.com/ericdrowell/concrete * Licensed under the MIT or GPL Version 2 licenses. * * Copyright (C) 2020 Eric Rowell @ericdrowell * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ var Concrete = {}, idCounter = 0; Concrete.PIXEL_RATIO = (function () { return (window && window.devicePixelRatio) || 1; })(); Concrete.viewports = []; ////////////////////////////////////////////////////////////// VIEWPORT ////////////////////////////////////////////////////////////// /** * Concrete Viewport constructor * @param {Object} config * @param {Integer} config.width - viewport width in pixels * @param {Integer} config.height - viewport height in pixels */ Concrete.Viewport = function(config) { if (!config) { config = {}; } this.container = config.container; this.layers = []; this.id = idCounter++; this.scene = new Concrete.Scene(); this.setSize(config.width || 0, config.height || 0); // clear container config.container.innerHTML = ''; config.container.appendChild(this.scene.canvas); Concrete.viewports.push(this); }; Concrete.Viewport.prototype = { /** * add layer * @param {Concrete.Layer} layer * @returns {Concrete.Viewport} */ add: function(layer) { this.layers.push(layer); layer.setSize(layer.width || this.width, layer.height || this.height); layer.viewport = this; return this; }, /** * set viewport size * @param {Integer} width - viewport width in pixels * @param {Integer} height - viewport height in pixels * @returns {Concrete.Viewport} */ setSize: function(width, height) { this.width = width; this.height = height; this.scene.setSize(width, height); this.layers.forEach(function(layer) { layer.setSize(width, height); }); return this; }, /** * get key associated to coordinate. This can be used for mouse interactivity. * @param {Number} x * @param {Number} y * @returns {Integer} integer - returns -1 if no pixel is there */ getIntersection: function(x, y) { var layers = this.layers, len = layers.length, n, layer, key; for (n=len-1; n>=0; n--) { layer = layers[n]; key = layer.hit.getIntersection(x, y); if (key >= 0) { return key; } } return -1; }, /** * get viewport index from all Concrete viewports * @returns {Integer} */ getIndex: function() { var viewports = Concrete.viewports, len = viewports.length, n = 0, viewport; for (n=0; n 0) { // swap layers[index] = layers[index-1]; layers[index-1] = this; } return this; }, /** * move to top * @returns {Concrete.Layer} */ moveToTop: function() { var index = this.getIndex(), viewport = this.viewport, layers = viewport.layers; layers.splice(index, 1); layers.push(this); }, /** * move to bottom * @returns {Concrete.Layer} */ moveToBottom: function() { var index = this.getIndex(), viewport = this.viewport, layers = viewport.layers; layers.splice(index, 1); layers.unshift(this); return this; }, /** * get layer index from viewport layers * @returns {Number|null} */ getIndex: function() { var layers = this.viewport.layers, len = layers.length, n = 0, layer; for (n=0; n this.width || y > this.height) { return -1; } // 2d if (this.contextType === '2d') { data = context.getImageData(x, y, 1, 1).data; if (data[3] < 255) { return -1; } } // webgl else { data = new Uint8Array(4); context.readPixels(x*Concrete.PIXEL_RATIO, (this.height - y - 1)*Concrete.PIXEL_RATIO, 1, 1, context.RGBA, context.UNSIGNED_BYTE, data); if (data[0] === 255 && data[1] === 255 && data[2] === 255) { return -1; } } return this.rgbToInt(data); }, /** * get canvas formatted color string from data index * @param {Number} index * @returns {String} */ getColorFromIndex: function(index) { var rgb = this.intToRGB(index); return 'rgb(' + rgb[0] + ', ' + rgb[1] + ', ' + rgb[2] + ')'; }, /** * converts rgb array to integer value * @param {Array.} */ intToRGB: function(number) { var r = (number & 0xff0000) >> 16; var g = (number & 0x00ff00) >> 8; var b = (number & 0x0000ff); return [r, g, b]; }, }; // export (function (global) { 'use strict'; // AMD support if (typeof define === 'function' && define.amd) { define(function () { return Concrete; }); // CommonJS and Node.js module support. } else if (typeof exports !== 'undefined') { // Support Node.js specific `module.exports` (which can be a function) if (typeof module !== 'undefined' && module.exports) { exports = module.exports = Concrete; } // But always support CommonJS module 1.1.1 spec (`exports` cannot be a function) exports.Concrete = Concrete; } else { global.Concrete = Concrete; } })(this);