<commit_before>// --------------------------------------------------------------------------------
// Copyright (c) 2015 Ruggero Enrico Visintin
//
// 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.
// --------------------------------------------------------------------------------

console.log("SparkViewer.js included");

JRV.setBasePath("src/js/");

JRV.include("core/Renderer.js");
JRV.include("core/math/Matrix4.js");
JRV.include("core/RendererUtils.js");
JRV.include("core/RenderMaterial.js");
JRV.include("core/RenderMesh.js");
JRV.include("core/RenderModel.js");
JRV.include("core/math/Vector3.js");

SparkPreviewerMain();

if (JRV.isMobile.any() && JRV.supportTouch()) {
    JRV.include("core/input/MobileInputManager.js");
} else {
    if (JRV.supportMouse()) {
        JRV.include("core/input/PcInputManager.js");
    } else if(JRV.supportTouch()) {
        JRV.include("core/input/MobileInputManager.js");
    }
}

JRV.include("core/Camera.js");
JRV.include("core/utils/ShapeGenerator.js");

function Application(canvas, debugCanvas) {
	var mCanvas = canvas;
	var renderer;
	var debugRenderer;

	var inputManager;

    var backgroundColor;
    var renderModel;

    var litShaderProgram;
    var normalShaderProgram;
    var lightShaderProgram;

    var mCurrentShaderProgram;

	var mModelViewMatrix;
	var mArcballCamera;

	var running;
	var mFps;
	var mFrameTime;
	var load = false;

	var texture;

	this.init = function () {
        console.log("mobile: " + JRV.isMobile.any());

        renderer = new Renderer();
        renderer.initWebGL(mCanvas);

        debugRenderer = debugCanvas.getContext("2d");

        debugRenderer.fillStyle = "white";
        debugRenderer.font = "11px Lucida Console";

        mArcballCamera = new ArcballCamera();
        mArcballCamera.setViewport(45, mCanvas.clientWidth / mCanvas.clientHeight);

        initBackground();
        initShaderPrograms();
        initDefaultModel();
        initMatrices();

        renderer.program = litShaderProgram;
        renderer.init();

        if (JRV.isMobile.any() && JRV.supportTouch()) {
            inputManager = new MobileInputManager(mCanvas);
        } else {
            if (JRV.supportMouse()) {
                inputManager = new PcInputManager(mCanvas);
            } else if(supportTouch()){
                inputManager = new MobileInputManager(mCanvas);
            }
        }

        inputManager.init();
    };

    this.run = function () {
		running = true;
        runLoop();
    };

	this.stop = function () {
		running = false;
	};

	var initMatrices = function () {
	    mModelViewMatrix = Matrix4.create();
	};

	var initBackground = function() {
		backgroundColor = Vector3.create(1.0, 1.0, 1.0);
	};

	var initShaderPrograms = function () {
	    initShaderFromFile("src/glsl/global.vertex", "src/glsl/diffuse_lit.fragment", renderer.getGfx(), function (result) {
	        litShaderProgram = result;
	        mCurrentShaderProgram = litShaderProgram;
	    });

	    initShaderFromFile("src/glsl/global.vertex", "src/glsl/diffuse_lit_hair.fragment", renderer.getGfx(), function (result) {
	        lightShaderProgram = result;
	    });

	    initShaderFromFile("src/glsl/global.vertex", "src/glsl/normals.fragment", renderer.getGfx(), function (result) {
	        normalShaderProgram = result;
	    });

	};

	var initDefaultModel = function() {
	    renderModel = new RenderModel();
	    renderModel.loadFromObj("Edward_Kenway/Edward_Kenway.obj", renderer.getGfx(), function () {
	    //renderModel.loadFromObj("modello_prova/Lara_Croft.obj", renderer.getGfx(), function () {
	        var vbo = renderer.getGfx().createBuffer();

	        renderer.getGfx().bindBuffer(renderer.getGfx().ARRAY_BUFFER, vbo);
	        renderer.getGfx().bufferData(renderer.getGfx().ARRAY_BUFFER, new Float32Array(renderModel.getRenderMesh().getVerticesSet()), renderer.getGfx().STATIC_DRAW);

	        renderModel.getRenderMesh().setVertexBufferHandle(vbo);
	        load = true;
	    });
	};

	lastLoop = new Date();

	var runLoop = function () {
	    var thisLoop = new Date;

	    mFrameTime = thisLoop - lastLoop;
	    mFps = Math.round(1000 / mFrameTime);

	    updateInput();
	    updateRendering();

        debugRenderer.clearRect(0, 0, 300, 70);
        debugRenderer.fillText("Fps: " + mFps, 10, 10);
        debugRenderer.fillText("Frame Time: " + mFrameTime, 10, 30);

        if (load == false) {
            debugRenderer.fillText("Loading", 10, 50);
        }

	    if (running) {
			window.requestAnimationFrame(runLoop);
		} else {
		    return;
		}

		lastLoop = thisLoop;
	};

	window.onresize = function () {
	    console.log("Resizing");
	    mArcballCamera.setViewport(45, mCanvas.clientWidth / mCanvas.clientHeight);
	};

	window.onkeydown = function (event) {
	    console.log("pressed: " + event.keyCode);

	    if (event.keyCode == 49) {
	        mCurrentShaderProgram = litShaderProgram;
	    } else if (event.keyCode == 50) {
	        mCurrentShaderProgram = normalShaderProgram;
	    }
	}

	var updateRendering = function()
	{
	    var mvp = Matrix4.create();
	    var camMatrices = mArcballCamera.updateMatrices();

	    Matrix4.multiply(camMatrices[0], camMatrices[1], mvp);
	    Matrix4.multiply(mvp, mModelViewMatrix, mvp);

	    if (load && mCurrentShaderProgram) {
            renderer.startFrame(mCurrentShaderProgram);

            renderer.getGfx().depthMask(true);
	        renderer.getGfx().depthFunc(renderer.getGfx().LESS);

	            for (var i = 0; i < renderModel.getOpaqueMaterials().length; i++) {

	                var drawCall = new DrawCall();
	                drawCall.vbo = renderModel.getRenderMesh().getVertexBufferHandle();
	                drawCall.shaderProgram = mCurrentShaderProgram;

	                drawCall.verticesNumber = (renderModel.getOpaqueMaterials()[i].getEndIndex()) * 3;
	                drawCall.verticesStart = (renderModel.getOpaqueMaterials()[i].getStartIndex()) * 3;
	                drawCall.matrixMVP = mvp;

	                drawCall.mvpLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "modelViewProjectionMatrix");
	                drawCall.textureHandle = renderModel.getOpaqueMaterials()[i].getDiffuseTextureHandle();
	                drawCall.textureLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "sampler");
	                drawCall.alphaLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "alpha");

	                drawCall.opacity = renderModel.getOpaqueMaterials()[i].getOpacity();

	                renderer.render(0, drawCall);
	            }

	            //renderer.getGfx().enable(renderer.getGfx().BLEND);
	            //renderer.getGfx().blendFuncSeparate(renderer.getGfx().SRC_ALPHA, renderer.getGfx().ONE_MINUS_SRC_ALPHA, renderer.getGfx().ONE, renderer.getGfx().ONE_MINUS_SRC_ALPHA)

                for (var i = 0; i < renderModel.getTransparentMaterials().length; i++) {
	                var drawCall = new DrawCall();
	                drawCall.vbo = renderModel.getRenderMesh().getVertexBufferHandle();
	                drawCall.shaderProgram = mCurrentShaderProgram;

	                drawCall.verticesNumber = renderModel.getTransparentMaterials()[i].getEndIndex() * 3;
	                drawCall.verticesStart = renderModel.getTransparentMaterials()[i].getStartIndex() * 3;
	                drawCall.matrixMVP = mvp;

	                drawCall.mvpLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "modelViewProjectionMatrix");
	                drawCall.textureHandle = renderModel.getTransparentMaterials()[i].getDiffuseTextureHandle();
	                drawCall.textureLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "sampler");
	                drawCall.alphaLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "alpha");

	                drawCall.opacity = renderModel.getTransparentMaterials()[i].getOpacity();

	                renderer.render(0, drawCall);
	            }

	            //renderer.endFrame();
	            //renderer.getGfx().disable(renderer.getGfx().BLEND);

	            renderer.getGfx().useProgram(lightShaderProgram);

	            renderer.getGfx().depthMask(false);

	            renderer.getGfx().enable(renderer.getGfx().BLEND);
	            renderer.getGfx().blendFunc(renderer.getGfx().SRC_ALPHA, renderer.getGfx().ONE_MINUS_SRC_ALPHA);

	            for (var i = 0; i < renderModel.getTransparentMaterials().length; i++) {
	                var drawCall = new DrawCall();
	                drawCall.vbo = renderModel.getRenderMesh().getVertexBufferHandle();
	                drawCall.shaderProgram = lightShaderProgram;

	                drawCall.verticesNumber = renderModel.getTransparentMaterials()[i].getEndIndex() * 3;
	                drawCall.verticesStart = renderModel.getTransparentMaterials()[i].getStartIndex() * 3;
	                drawCall.matrixMVP = mvp;

	                drawCall.mvpLocation = renderer.getGfx().getUniformLocation(lightShaderProgram, "modelViewProjectionMatrix");
	                drawCall.textureHandle = renderModel.getTransparentMaterials()[i].getDiffuseTextureHandle();
	                drawCall.textureLocation = renderer.getGfx().getUniformLocation(lightShaderProgram, "sampler");
	                drawCall.alphaLocation = renderer.getGfx().getUniformLocation(lightShaderProgram, "alpha");

	                drawCall.opacity = renderModel.getTransparentMaterials()[i].getOpacity();

	                renderer.render(0, drawCall);
	            }

	            renderer.endFrame();
	            renderer.getGfx().disable(renderer.getGfx().BLEND);

            }

	    }

	var updateInput = function()
	{
	    if (inputManager.isLeftMouseDown()) {
	        var verticalDelta = inputManager.getMouseVerticalDelta();
	        var horizontalDelta = inputManager.getMouseHorizontalDelta();

            mArcballCamera.rotateY(verticalDelta * 0.02);
            mArcballCamera.rotateX(horizontalDelta * 0.02);
	    } else if (inputManager.isRightMouseDown()) {
	        var horizontalDelta = inputManager.getMouseHorizontalDelta();
	        var verticalDelta = inputManager.getMouseVerticalDelta();

	        mArcballCamera.translateX(horizontalDelta * 0.05);
	        mArcballCamera.translateY(-verticalDelta * 0.05);
	    }

	    if (inputManager.getWheelDelta() != 0) {
	        mArcballCamera.moveRadius(-inputManager.getWheelDelta());
	    }

	    inputManager.postUpdate();
	}

	return this;
}

var APPLICATION;

function SparkPreviewerMain() {
    window.onload = function () {
        var debugCanvas = document.getElementById("sparkViewer").cloneNode();

        debugCanvas.id = "sparkDebugger";
        debugCanvas.style.zIndex = "100";
        debugCanvas.style.position = "absolute";
        debugCanvas.style.left = "0";
        debugCanvas.style.top = "0";
        debugCanvas.style.pointerEvents = "none";

        document.body.appendChild(debugCanvas);

        APPLICATION = new Application(document.getElementById("sparkViewer"), debugCanvas);
        APPLICATION.init();
        APPLICATION.run();
    }

    return 0;
}
<commit_msg>Update SparkPreviewer.js<commit_after>// --------------------------------------------------------------------------------
// Copyright (c) 2015 Ruggero Enrico Visintin
//
// 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.
// --------------------------------------------------------------------------------

console.log("SparkViewer.js included");

JRV.setBasePath("src/js/");

JRV.include("core/Renderer.js");
JRV.include("core/math/Matrix4.js");
JRV.include("core/RendererUtils.js");
JRV.include("core/RenderMaterial.js");
JRV.include("core/RenderMesh.js");
JRV.include("core/RenderModel.js");
JRV.include("core/math/Vector3.js");

SparkPreviewerMain();

if (JRV.isMobile.any() && JRV.supportTouch()) {
    JRV.include("core/input/MobileInputManager.js");
} else {
    if (JRV.supportMouse()) {
        JRV.include("core/input/PcInputManager.js");
    } else if(JRV.supportTouch()) {
        JRV.include("core/input/MobileInputManager.js");
    }
}

JRV.include("core/Camera.js");
JRV.include("core/utils/ShapeGenerator.js");

function Application(canvas, debugCanvas) {
	var mCanvas = canvas;
	var renderer;
	var debugRenderer;

	var inputManager;

    var backgroundColor;
    var renderModel;

    var litShaderProgram;
    var normalShaderProgram;
    var lightShaderProgram;

    var mCurrentShaderProgram;

	var mModelViewMatrix;
	var mArcballCamera;

	var running;
	var mFps;
	var mFrameTime;
	var load = false;

	var texture;

	this.init = function () {
        console.log("mobile: " + JRV.isMobile.any());

        renderer = new Renderer();
        renderer.initWebGL(mCanvas);

        debugRenderer = debugCanvas.getContext("2d");

        debugRenderer.fillStyle = "white";
        debugRenderer.font = "11px Lucida Console";

        mArcballCamera = new ArcballCamera();
        mArcballCamera.setViewport(45, mCanvas.clientWidth / mCanvas.clientHeight);

        initBackground();
        initShaderPrograms();
        initDefaultModel();
        initMatrices();

        renderer.program = litShaderProgram;
        renderer.init();

        if (JRV.isMobile.any() && JRV.supportTouch()) {
            inputManager = new MobileInputManager(mCanvas);
        } else {
            if (JRV.supportMouse()) {
                inputManager = new PcInputManager(mCanvas);
            } else if(supportTouch()){
                inputManager = new MobileInputManager(mCanvas);
            }
        }

        inputManager.init();
    };

    this.run = function () {
		running = true;
        runLoop();
    };

	this.stop = function () {
		running = false;
	};

	var initMatrices = function () {
	    mModelViewMatrix = Matrix4.create();
	};

	var initBackground = function() {
		backgroundColor = Vector3.create(1.0, 1.0, 1.0);
	};

	var initShaderPrograms = function () {
	    initShaderFromFile("src/glsl/global.vertex", "src/glsl/diffuse_lit.fragment", renderer.getGfx(), function (result) {
	        litShaderProgram = result;
	        mCurrentShaderProgram = litShaderProgram;
	    });

	    initShaderFromFile("src/glsl/global.vertex", "src/glsl/diffuse_lit_hair.fragment", renderer.getGfx(), function (result) {
	        lightShaderProgram = result;
	    });

	    initShaderFromFile("src/glsl/global.vertex", "src/glsl/normals.fragment", renderer.getGfx(), function (result) {
	        normalShaderProgram = result;
	    });

	};

	var initDefaultModel = function() {
	    renderModel = new RenderModel();
	    //renderModel.loadFromObj("Edward_Kenway/Edward_Kenway.obj", renderer.getGfx(), function () {
	    renderModel.loadFromObj("modello_prova/Lara_Croft.obj", renderer.getGfx(), function () {
	        var vbo = renderer.getGfx().createBuffer();

	        renderer.getGfx().bindBuffer(renderer.getGfx().ARRAY_BUFFER, vbo);
	        renderer.getGfx().bufferData(renderer.getGfx().ARRAY_BUFFER, new Float32Array(renderModel.getRenderMesh().getVerticesSet()), renderer.getGfx().STATIC_DRAW);

	        renderModel.getRenderMesh().setVertexBufferHandle(vbo);
	        load = true;
	    });
	};

	lastLoop = new Date();

	var runLoop = function () {
	    var thisLoop = new Date;

	    mFrameTime = thisLoop - lastLoop;
	    mFps = Math.round(1000 / mFrameTime);

	    updateInput();
	    updateRendering();

        debugRenderer.clearRect(0, 0, 300, 70);
        debugRenderer.fillText("Fps: " + mFps, 10, 10);
        debugRenderer.fillText("Frame Time: " + mFrameTime, 10, 30);

        if (load == false) {
            debugRenderer.fillText("Loading", 10, 50);
        }

	    if (running) {
			window.requestAnimationFrame(runLoop);
		} else {
		    return;
		}

		lastLoop = thisLoop;
	};

	window.onresize = function () {
	    console.log("Resizing");
	    mArcballCamera.setViewport(45, mCanvas.clientWidth / mCanvas.clientHeight);
	};

	window.onkeydown = function (event) {
	    console.log("pressed: " + event.keyCode);

	    if (event.keyCode == 49) {
	        mCurrentShaderProgram = litShaderProgram;
	    } else if (event.keyCode == 50) {
	        mCurrentShaderProgram = normalShaderProgram;
	    }
	}

	var updateRendering = function()
	{
	    var mvp = Matrix4.create();
	    var camMatrices = mArcballCamera.updateMatrices();

	    Matrix4.multiply(camMatrices[0], camMatrices[1], mvp);
	    Matrix4.multiply(mvp, mModelViewMatrix, mvp);

	    if (load && mCurrentShaderProgram) {
            renderer.startFrame(mCurrentShaderProgram);

            renderer.getGfx().depthMask(true);
	        renderer.getGfx().depthFunc(renderer.getGfx().LESS);

	            for (var i = 0; i < renderModel.getOpaqueMaterials().length; i++) {

	                var drawCall = new DrawCall();
	                drawCall.vbo = renderModel.getRenderMesh().getVertexBufferHandle();
	                drawCall.shaderProgram = mCurrentShaderProgram;

	                drawCall.verticesNumber = (renderModel.getOpaqueMaterials()[i].getEndIndex()) * 3;
	                drawCall.verticesStart = (renderModel.getOpaqueMaterials()[i].getStartIndex()) * 3;
	                drawCall.matrixMVP = mvp;

	                drawCall.mvpLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "modelViewProjectionMatrix");
	                drawCall.textureHandle = renderModel.getOpaqueMaterials()[i].getDiffuseTextureHandle();
	                drawCall.textureLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "sampler");
	                drawCall.alphaLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "alpha");

	                drawCall.opacity = renderModel.getOpaqueMaterials()[i].getOpacity();

	                renderer.render(0, drawCall);
	            }

	            //renderer.getGfx().enable(renderer.getGfx().BLEND);
	            //renderer.getGfx().blendFuncSeparate(renderer.getGfx().SRC_ALPHA, renderer.getGfx().ONE_MINUS_SRC_ALPHA, renderer.getGfx().ONE, renderer.getGfx().ONE_MINUS_SRC_ALPHA)

                for (var i = 0; i < renderModel.getTransparentMaterials().length; i++) {
	                var drawCall = new DrawCall();
	                drawCall.vbo = renderModel.getRenderMesh().getVertexBufferHandle();
	                drawCall.shaderProgram = mCurrentShaderProgram;

	                drawCall.verticesNumber = renderModel.getTransparentMaterials()[i].getEndIndex() * 3;
	                drawCall.verticesStart = renderModel.getTransparentMaterials()[i].getStartIndex() * 3;
	                drawCall.matrixMVP = mvp;

	                drawCall.mvpLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "modelViewProjectionMatrix");
	                drawCall.textureHandle = renderModel.getTransparentMaterials()[i].getDiffuseTextureHandle();
	                drawCall.textureLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "sampler");
	                drawCall.alphaLocation = renderer.getGfx().getUniformLocation(mCurrentShaderProgram, "alpha");

	                drawCall.opacity = renderModel.getTransparentMaterials()[i].getOpacity();

	                renderer.render(0, drawCall);
	            }

	            //renderer.endFrame();
	            //renderer.getGfx().disable(renderer.getGfx().BLEND);

	            renderer.getGfx().useProgram(lightShaderProgram);

	            renderer.getGfx().depthMask(false);

	            renderer.getGfx().enable(renderer.getGfx().BLEND);
	            renderer.getGfx().blendFunc(renderer.getGfx().SRC_ALPHA, renderer.getGfx().ONE_MINUS_SRC_ALPHA);

	            for (var i = 0; i < renderModel.getTransparentMaterials().length; i++) {
	                var drawCall = new DrawCall();
	                drawCall.vbo = renderModel.getRenderMesh().getVertexBufferHandle();
	                drawCall.shaderProgram = lightShaderProgram;

	                drawCall.verticesNumber = renderModel.getTransparentMaterials()[i].getEndIndex() * 3;
	                drawCall.verticesStart = renderModel.getTransparentMaterials()[i].getStartIndex() * 3;
	                drawCall.matrixMVP = mvp;

	                drawCall.mvpLocation = renderer.getGfx().getUniformLocation(lightShaderProgram, "modelViewProjectionMatrix");
	                drawCall.textureHandle = renderModel.getTransparentMaterials()[i].getDiffuseTextureHandle();
	                drawCall.textureLocation = renderer.getGfx().getUniformLocation(lightShaderProgram, "sampler");
	                drawCall.alphaLocation = renderer.getGfx().getUniformLocation(lightShaderProgram, "alpha");

	                drawCall.opacity = renderModel.getTransparentMaterials()[i].getOpacity();

	                renderer.render(0, drawCall);
	            }

	            renderer.endFrame();
	            renderer.getGfx().disable(renderer.getGfx().BLEND);

            }

	    }

	var updateInput = function()
	{
	    if (inputManager.isLeftMouseDown()) {
	        var verticalDelta = inputManager.getMouseVerticalDelta();
	        var horizontalDelta = inputManager.getMouseHorizontalDelta();

            mArcballCamera.rotateY(verticalDelta * 0.02);
            mArcballCamera.rotateX(horizontalDelta * 0.02);
	    } else if (inputManager.isRightMouseDown()) {
	        var horizontalDelta = inputManager.getMouseHorizontalDelta();
	        var verticalDelta = inputManager.getMouseVerticalDelta();

	        mArcballCamera.translateX(horizontalDelta * 0.05);
	        mArcballCamera.translateY(-verticalDelta * 0.05);
	    }

	    if (inputManager.getWheelDelta() != 0) {
	        mArcballCamera.moveRadius(-inputManager.getWheelDelta());
	    }

	    inputManager.postUpdate();
	}

	return this;
}

var APPLICATION;

function SparkPreviewerMain() {
    window.onload = function () {
        var debugCanvas = document.getElementById("sparkViewer").cloneNode();

        debugCanvas.id = "sparkDebugger";
        debugCanvas.style.zIndex = "100";
        debugCanvas.style.position = "absolute";
        debugCanvas.style.left = "0";
        debugCanvas.style.top = "0";
        debugCanvas.style.pointerEvents = "none";

        document.body.appendChild(debugCanvas);

        APPLICATION = new Application(document.getElementById("sparkViewer"), debugCanvas);
        APPLICATION.init();
        APPLICATION.run();
    }

    return 0;
}
<|endoftext|>


<commit_before>"use strict";

function shuffleArray(array) {
  for (let i = array.length - 1; i > 0; -- i) {
      let j = Math.floor(Math.random() * (i + 1));
      [array[i], array[j]] = [array[j], array[i]];
  }
  return array;
}

const iterations = 80;
const threshold = 100;
function getFractalValue(f, [zr, zi]) {
  let [znr, zni] = [zr, zi], i, d2;
  for (i = 0; i < iterations; ++ i) {
    d2 = Math.pow(znr, 2) + Math.pow(zni, 2);
    if (d2 >= Math.pow(threshold, 2)) {
      break;
    }
    [znr, zni] = f([znr, zni]);
  }
  return [i + 1 / d2, i / iterations];
}

function quadratic([cr, ci]) {
  return ([a, b]) => [Math.pow(a, 2) - Math.pow(b, 2) + cr, 2 * a * b + ci];
}

function complexpow([a, b], n) {
  let [A, B] = [1, 0];
  for (let i = 0; i < n; ++ i) {
    [A, B] = [A * a - B * b, a * B + A * b];
  }
  return [A, B];
}

function complexp([a, b]) {
  return [Math.exp(a) * Math.cos(b), Math.exp(a) * Math.sin(b)];
}

function complexadd([a, b], [c, d]) {
  return [a + c, b + d];
}

function complexrandom(radiusOuter, radiusInner = 0) {
  const angle = Math.random() * 2 * Math.PI;
  const distance = radiusInner + Math.random() * (radiusOuter - radiusInner);
  return [Math.cos(angle) * distance, Math.sin(angle) * distance];
}

function round3(x) {
  return Math.round(x * 1000) / 1000;
}

function randomFractal() {
  const [cr, ci] = complexrandom(1, 0.5);
  return [quadratic, [round3(cr), round3(ci)], [0, -0.5], round3(0.8 + Math.random() * 0.4), 1];
}

const fractalLibrary = [
  [quadratic, [-0.7269, 0.1889], [0.6, -1.1], 0.5, 1],
  [quadratic, [0.285, 0.01], [-0.3, -0.4], 1.2, 1],
  [quadratic, [-0.8, 0.156], [0.5, -0.6], 1, 2],
  [quadratic,[-0.609, 0.456],[0.6, -0.3], 1.897, 1],
  [quadratic, [-0.825, -0.139], [0.118, 0.113], 1.376, 1],
  [quadratic, [-0.132, -0.803], [-0.048, 0.0193],1.93, 3],
  [quadratic, [-0.91, -0.26], [0.509, 0.091], 1.949, 1],
  [quadratic, [-0.518, -0.466], [-0.48, -0.709], 0.5, 2],
  [quadratic, [-0.15, -0.707], [0, 0], 0.5, 3],
  [quadratic, [-0.69, -0.312], [0, 0], 0.5, 1],
  [quadratic, [-0.299, -0.653], [0, 0], 0.5, 1],
  [quadratic, [-0.266, -0.802], [0, 0], 1.5, 1],
  [quadratic, [-0.19, 0.64], [0.2, -0.1], 1.5, 1],
  [quadratic, [0.311, -0.137], [0.8, 0], 1.5, 3],
  [quadratic, [-0.771, -0.212], [0,0], 2, 1],
  [quadratic, [-0.77, -0.166], [0, -0.5], 1, 1],
  [quadratic, [-0.235, 0.648], [0, -1], 0.926, 1],
  [quadratic, [-0.192, -0.832], [0, -0.5], 1.002, 1],
  [quadratic, [-0.756, -0.082], [0, -0.5], 1.145, 1],
  [quadratic, [-0.971, -0.017], [-0.3, -0.5], 1.104, 4],
  [quadratic, [-0.427, -0.56], [0, -0.5], 1.089, 2],
  [quadratic, [0.096, -0.657], [0, -0.5], 0.839, 1],
  [quadratic, [-0.536, 0.519], [0, -0.5], 1.011, 1],
  [quadratic, [-0.274, -0.655], [0, -0.5], 0.972, 1],
  [quadratic, [0.119, 0.606], [0, -0.5], 0.962, 1],
  [quadratic, [-0.105, -0.704], [-0.8, -0.5], 0.818, 4],
  [quadratic, [-0.883, -0.211], [0, -0.5], 0.866, 1],
  [quadratic, [-0.109, -0.576], [0, -0.5], 1.167, 1],
  [quadratic, [-0.676, -0.322], [0, -0.5], 1.195, 1],
];
{
  const randomProportion = 0.5;
  const additions = fractalLibrary.length > 0 ? Math.round((randomProportion * fractalLibrary.length) / (1 - randomProportion)) : 1;
  for (let i = 0; i < additions; ++ i) {
    fractalLibrary.push(randomFractal);
  }
}

// How often to refresh the fractal (in seconds)
const refresh = 2.5 * 60;
// How long the fade out takes (in seconds)
const vanish = 0.8, fade = 8;
// Maximum pixel opacity
const alpha = 0.6;
// How many steps to run in each frame (to get around the 4 ms setInterval timeout)
const speedup = 1;
// What detail (in stages) is the minimum in order to not bail out early on a fractal
const bailout = 5;

module.exports = () => {
  for (const canvas of document.querySelectorAll(".fractal-canvas")) {
    let cr, ci, or, oi, scale, vr, vi, l, fractal;
    let index = fractalLibrary.length;
    function pickNextFractal() {
      if (index === fractalLibrary.length) {
        const previous = fractalLibrary[fractalLibrary.length - 1];
        shuffleArray(fractalLibrary);
        if (fractalLibrary[0] === previous) {
          // Make sure we never pick the same fractal twice in a row (unless there's only one fractal in our library).
          fractalLibrary.reverse();
        }
        index = 0;
      }
      let next = fractalLibrary[index ++];
      if (typeof next === "function") {
        next = next();
      }
      let f;
      [f, [cr, ci], [or, oi], scale, l] = next;
      console.log(JSON.stringify([f, [cr, ci], [or, oi], scale, l]).replace(/,/g, ", ").replace("null", "quadratic"));
      // Viewpoint origin
      [vr, vi] = [-(cr + or), -(ci + oi)];
      // Fractal function
      fractal = f([cr, ci]);
    }

    let restart = null;
    function newFractal(clearQuickly = false) {
      if (restart !== null) {
        clearTimeout(restart);
      }
      restart = null;
      canvas.classList.add(clearQuickly ? "vanish" : "fade");
      setTimeout(() => {
        context.clearRect(0, 0, width, height);
        canvas.classList.remove(clearQuickly ? "vanish" : "fade");
        begin();
      }, (clearQuickly ? vanish : fade) * 1000);
    }

    canvas.classList.add("fractal-canvas");
    canvas.addEventListener("click", event => {
      if (event.button === 0) {
        newFractal(true);
      }
    });
    const size = Math.max(window.innerWidth, window.innerHeight) * window.devicePixelRatio;
    const [width, height] = [size, size];
    const [wlimit, hlimit] = [window.innerWidth * window.devicePixelRatio, window.innerHeight * window.devicePixelRatio];
    [canvas.width, canvas.height] = [width, height];
    canvas.style.width = "100%";
    canvas.style.imageRendering = "pixelated";
    const context = canvas.getContext("2d");
    context.fillStyle = "white";

    let regions, next, depth, minValue, maxValue, bail;
    function begin() {
      pickNextFractal();
      regions = [[0, 0, width, height, NaN, 0]], next = [], depth = 0, minValue = 1, maxValue = 0, bail = 0;
      restart = setTimeout(newFractal, refresh * 1000);
    }
    function pushNextRegions(newRegions, cs, stg) {
      for (const [x, y, w, h] of newRegions) {
        if (w >= 1 && h >= 1 && x < wlimit && y < hlimit) {
          next.push([x, y, w, h, cs, stg]);
        }
      }
    }

    begin();

    const stages = 4;

    let interval = setInterval(() => {
      if (typeof fractal === "undefined") {
        return;
      }
      let another = 0;
      for (let t = 0; t < speedup + another; ++ t) {
        if (regions.length === 0) {
          ++ depth;
          if (next.length === 0 || (depth > 4 && (minValue > 0.95 || maxValue < 0.5))) {
            ++ bail;
          }
          if (bail > 8) {
            if (restart !== null) {
              const clearQuickly = depth < stages || minValue > 0.95 || maxValue < 0.5;
              newFractal(clearQuickly);
            }
            next = [];
          }
          if (next.length === 0) {
            return;
          }
          regions = shuffleArray(next);
          next = [];
        }
        const [x, y, w, h, cs, u] = regions.shift();
        const [checksum, value] = getFractalValue(fractal, [((x + w / 2) / width - 0.5) * 2 / scale + vr, ((y + h / 2) / height - 0.5) * 2 / scale + vi]);
        if (value > maxValue) maxValue = value;
        if (value < minValue) minValue = value;
        let stagnation = Math.round(checksum * 1000) === Math.round(cs * 1000) ? u + 1 : 0;
        if (u > 0) {
          ++ another;
        }
        if (w < width / 2 && h < height / 2) {
          // Avoid drawing when nothing has changed, or when the regions are too large, where it can lead to an unpleasant flicker.
          context.globalAlpha = value * alpha;
          context.clearRect(x, y, w, h);
          context.fillRect(x, y, w, h);
        }
        if (stagnation > l) {
          // We want to be able to simply cancel iterating any farther on this region, but this can occasionally lead to blocky artefacts, so we try an additional sanity test here.
          const prev = Math.round(checksum * 1000);
          const checks = [
            getFractalValue(fractal, [((x) / width - 0.5) * 2 / scale + vr, ((y) / height - 0.5) * 2 / scale + vi]),
            getFractalValue(fractal, [((x) / width - 0.5) * 2 / scale + vr, ((y + h) / height - 0.5) * 2 / scale + vi]),
            getFractalValue(fractal, [((x + w) / width - 0.5) * 2 / scale + vr, ((y) / height - 0.5) * 2 / scale + vi]),
            getFractalValue(fractal, [((x + w) / width - 0.5) * 2 / scale + vr, ((y + h) / height - 0.5) * 2 / scale + vi])
          ];
          for (let check of checks) {
            if (Math.round(check[0] * 1000) !== prev) {
              stagnation = l;
            }
          }
        }
        if (stagnation <= l && (w > 1 || h > 1)) {
          const [nw, nh] = [w / 2, h / 2];
          const [[_nw, nw_], [_nh, nh_]]  = [[Math.floor(nw), Math.ceil(nw)], [Math.floor(nh), Math.ceil(nh)]];
          pushNextRegions([
            [x, y, nw_, nh_],
            [x + nw_, y, _nw, nh_],
            [x, y + nh_, nw_, _nh],
            [x + nw_, y + nh_, _nw, _nh]
          ], checksum, stagnation);
        }
      }
    }, 0);
  }
};<commit_msg>Handle edge case with no random fractals<commit_after>"use strict";

function shuffleArray(array) {
  for (let i = array.length - 1; i > 0; -- i) {
      let j = Math.floor(Math.random() * (i + 1));
      [array[i], array[j]] = [array[j], array[i]];
  }
  return array;
}

const iterations = 80;
const threshold = 100;
function getFractalValue(f, [zr, zi]) {
  let [znr, zni] = [zr, zi], i, d2;
  for (i = 0; i < iterations; ++ i) {
    d2 = Math.pow(znr, 2) + Math.pow(zni, 2);
    if (d2 >= Math.pow(threshold, 2)) {
      break;
    }
    [znr, zni] = f([znr, zni]);
  }
  return [i + 1 / d2, i / iterations];
}

function quadratic([cr, ci]) {
  return ([a, b]) => [Math.pow(a, 2) - Math.pow(b, 2) + cr, 2 * a * b + ci];
}

function complexpow([a, b], n) {
  let [A, B] = [1, 0];
  for (let i = 0; i < n; ++ i) {
    [A, B] = [A * a - B * b, a * B + A * b];
  }
  return [A, B];
}

function complexp([a, b]) {
  return [Math.exp(a) * Math.cos(b), Math.exp(a) * Math.sin(b)];
}

function complexadd([a, b], [c, d]) {
  return [a + c, b + d];
}

function complexrandom(radiusOuter, radiusInner = 0) {
  const angle = Math.random() * 2 * Math.PI;
  const distance = radiusInner + Math.random() * (radiusOuter - radiusInner);
  return [Math.cos(angle) * distance, Math.sin(angle) * distance];
}

function round3(x) {
  return Math.round(x * 1000) / 1000;
}

function randomFractal() {
  const [cr, ci] = complexrandom(1, 0.5);
  return [quadratic, [round3(cr), round3(ci)], [0, -0.5], round3(0.8 + Math.random() * 0.4), 1];
}

const fractalLibrary = [
  [quadratic, [-0.7269, 0.1889], [0.6, -1.1], 0.5, 1],
  [quadratic, [0.285, 0.01], [-0.3, -0.4], 1.2, 1],
  [quadratic, [-0.8, 0.156], [0.5, -0.6], 1, 2],
  [quadratic,[-0.609, 0.456],[0.6, -0.3], 1.897, 1],
  [quadratic, [-0.825, -0.139], [0.118, 0.113], 1.376, 1],
  [quadratic, [-0.132, -0.803], [-0.048, 0.0193],1.93, 3],
  [quadratic, [-0.91, -0.26], [0.509, 0.091], 1.949, 1],
  [quadratic, [-0.518, -0.466], [-0.48, -0.709], 0.5, 2],
  [quadratic, [-0.15, -0.707], [0, 0], 0.5, 3],
  [quadratic, [-0.69, -0.312], [0, 0], 0.5, 1],
  [quadratic, [-0.299, -0.653], [0, 0], 0.5, 1],
  [quadratic, [-0.266, -0.802], [0, 0], 1.5, 1],
  [quadratic, [-0.19, 0.64], [0.2, -0.1], 1.5, 1],
  [quadratic, [0.311, -0.137], [0.8, 0], 1.5, 3],
  [quadratic, [-0.771, -0.212], [0,0], 2, 1],
  [quadratic, [-0.77, -0.166], [0, -0.5], 1, 1],
  [quadratic, [-0.235, 0.648], [0, -1], 0.926, 1],
  [quadratic, [-0.192, -0.832], [0, -0.5], 1.002, 1],
  [quadratic, [-0.756, -0.082], [0, -0.5], 1.145, 1],
  [quadratic, [-0.971, -0.017], [-0.3, -0.5], 1.104, 4],
  [quadratic, [-0.427, -0.56], [0, -0.5], 1.089, 2],
  [quadratic, [0.096, -0.657], [0, -0.5], 0.839, 1],
  [quadratic, [-0.536, 0.519], [0, -0.5], 1.011, 1],
  [quadratic, [-0.274, -0.655], [0, -0.5], 0.972, 1],
  [quadratic, [0.119, 0.606], [0, -0.5], 0.962, 1],
  [quadratic, [-0.105, -0.704], [-0.8, -0.5], 0.818, 4],
  [quadratic, [-0.883, -0.211], [0, -0.5], 0.866, 1],
  [quadratic, [-0.109, -0.576], [0, -0.5], 1.167, 1],
  [quadratic, [-0.676, -0.322], [0, -0.5], 1.195, 1],
];
{
  const randomProportion = 0.5;
  const additions = randomProportion > 0 ? (fractalLibrary.length > 0 ? Math.round((randomProportion * fractalLibrary.length) / (1 - randomProportion)) : 1) : 0;
  for (let i = 0; i < additions; ++ i) {
    fractalLibrary.push(randomFractal);
  }
}

// How often to refresh the fractal (in seconds)
const refresh = 2.5 * 60;
// How long the fade out takes (in seconds)
const vanish = 0.8, fade = 8;
// Maximum pixel opacity
const alpha = 0.6;
// How many steps to run in each frame (to get around the 4 ms setInterval timeout)
const speedup = 1;
// What detail (in stages) is the minimum in order to not bail out early on a fractal
const bailout = 5;

module.exports = () => {
  for (const canvas of document.querySelectorAll(".fractal-canvas")) {
    let cr, ci, or, oi, scale, vr, vi, l, fractal;
    let index = fractalLibrary.length;
    function pickNextFractal() {
      if (index === fractalLibrary.length) {
        const previous = fractalLibrary[fractalLibrary.length - 1];
        shuffleArray(fractalLibrary);
        if (fractalLibrary[0] === previous) {
          // Make sure we never pick the same fractal twice in a row (unless there's only one fractal in our library).
          fractalLibrary.reverse();
        }
        index = 0;
      }
      let next = fractalLibrary[index ++];
      if (typeof next === "function") {
        next = next();
      }
      let f;
      [f, [cr, ci], [or, oi], scale, l] = next;
      console.log(JSON.stringify([f, [cr, ci], [or, oi], scale, l]).replace(/,/g, ", ").replace("null", "quadratic"));
      // Viewpoint origin
      [vr, vi] = [-(cr + or), -(ci + oi)];
      // Fractal function
      fractal = f([cr, ci]);
    }

    let restart = null;
    function newFractal(clearQuickly = false) {
      if (restart !== null) {
        clearTimeout(restart);
      }
      restart = null;
      canvas.classList.add(clearQuickly ? "vanish" : "fade");
      setTimeout(() => {
        context.clearRect(0, 0, width, height);
        canvas.classList.remove(clearQuickly ? "vanish" : "fade");
        begin();
      }, (clearQuickly ? vanish : fade) * 1000);
    }

    canvas.classList.add("fractal-canvas");
    canvas.addEventListener("click", event => {
      if (event.button === 0) {
        newFractal(true);
      }
    });
    const size = Math.max(window.innerWidth, window.innerHeight) * window.devicePixelRatio;
    const [width, height] = [size, size];
    const [wlimit, hlimit] = [window.innerWidth * window.devicePixelRatio, window.innerHeight * window.devicePixelRatio];
    [canvas.width, canvas.height] = [width, height];
    canvas.style.width = "100%";
    canvas.style.imageRendering = "pixelated";
    const context = canvas.getContext("2d");
    context.fillStyle = "white";

    let regions, next, depth, minValue, maxValue, bail;
    function begin() {
      pickNextFractal();
      regions = [[0, 0, width, height, NaN, 0]], next = [], depth = 0, minValue = 1, maxValue = 0, bail = 0;
      restart = setTimeout(newFractal, refresh * 1000);
    }
    function pushNextRegions(newRegions, cs, stg) {
      for (const [x, y, w, h] of newRegions) {
        if (w >= 1 && h >= 1 && x < wlimit && y < hlimit) {
          next.push([x, y, w, h, cs, stg]);
        }
      }
    }

    begin();

    const stages = 4;

    let interval = setInterval(() => {
      if (typeof fractal === "undefined") {
        return;
      }
      let another = 0;
      for (let t = 0; t < speedup + another; ++ t) {
        if (regions.length === 0) {
          ++ depth;
          if (next.length === 0 || (depth > 4 && (minValue > 0.95 || maxValue < 0.5))) {
            ++ bail;
          }
          if (bail > 8) {
            if (restart !== null) {
              const clearQuickly = depth < stages || minValue > 0.95 || maxValue < 0.5;
              newFractal(clearQuickly);
            }
            next = [];
          }
          if (next.length === 0) {
            return;
          }
          regions = shuffleArray(next);
          next = [];
        }
        const [x, y, w, h, cs, u] = regions.shift();
        const [checksum, value] = getFractalValue(fractal, [((x + w / 2) / width - 0.5) * 2 / scale + vr, ((y + h / 2) / height - 0.5) * 2 / scale + vi]);
        if (value > maxValue) maxValue = value;
        if (value < minValue) minValue = value;
        let stagnation = Math.round(checksum * 1000) === Math.round(cs * 1000) ? u + 1 : 0;
        if (u > 0) {
          ++ another;
        }
        if (w < width / 2 && h < height / 2) {
          // Avoid drawing when nothing has changed, or when the regions are too large, where it can lead to an unpleasant flicker.
          context.globalAlpha = value * alpha;
          context.clearRect(x, y, w, h);
          context.fillRect(x, y, w, h);
        }
        if (stagnation > l) {
          // We want to be able to simply cancel iterating any farther on this region, but this can occasionally lead to blocky artefacts, so we try an additional sanity test here.
          const prev = Math.round(checksum * 1000);
          const checks = [
            getFractalValue(fractal, [((x) / width - 0.5) * 2 / scale + vr, ((y) / height - 0.5) * 2 / scale + vi]),
            getFractalValue(fractal, [((x) / width - 0.5) * 2 / scale + vr, ((y + h) / height - 0.5) * 2 / scale + vi]),
            getFractalValue(fractal, [((x + w) / width - 0.5) * 2 / scale + vr, ((y) / height - 0.5) * 2 / scale + vi]),
            getFractalValue(fractal, [((x + w) / width - 0.5) * 2 / scale + vr, ((y + h) / height - 0.5) * 2 / scale + vi])
          ];
          for (let check of checks) {
            if (Math.round(check[0] * 1000) !== prev) {
              stagnation = l;
            }
          }
        }
        if (stagnation <= l && (w > 1 || h > 1)) {
          const [nw, nh] = [w / 2, h / 2];
          const [[_nw, nw_], [_nh, nh_]]  = [[Math.floor(nw), Math.ceil(nw)], [Math.floor(nh), Math.ceil(nh)]];
          pushNextRegions([
            [x, y, nw_, nh_],
            [x + nw_, y, _nw, nh_],
            [x, y + nh_, nw_, _nh],
            [x + nw_, y + nh_, _nw, _nh]
          ], checksum, stagnation);
        }
      }
    }, 0);
  }
};<|endoftext|>


<commit_before>import CoreFeature from '../CoreFeature.js';
import CellComponent from './CellComponent.js';

export default class Cell extends CoreFeature{
	constructor(column, row){
		super(column.table);

		this.table = column.table;
		this.column = column;
		this.row = row;
		this.element = null;
		this.value = null;
		this.initialValue;
		this.oldValue = null;
		this.modules = {};

		this.height = null;
		this.width = null;
		this.minWidth = null;

		this.component = null;

		this.loaded = false; //track if the cell has been added to the DOM yet

		this.build();
	}

	//////////////// Setup Functions /////////////////
	//generate element
	build(){
		this.generateElement();

		this.setWidth();

		this._configureCell();

		this.setValueActual(this.column.getFieldValue(this.row.data));

		this.initialValue = this.value;
	}

	generateElement(){
		this.element = document.createElement('div');
		this.element.className = "tabulator-cell";
		this.element.setAttribute("role", "gridcell");
		this.element = this.element;
	}

	_configureCell(){
		var element = this.element,
		field = this.column.getField(),
		vertAligns = {
			top:"flex-start",
			bottom:"flex-end",
			middle:"center",
		},
		hozAligns = {
			left:"flex-start",
			right:"flex-end",
			center:"center",
		};

		//set text alignment
		element.style.textAlign = this.column.hozAlign;

		if(this.column.vertAlign){
			element.style.display = "inline-flex";

			element.style.alignItems = vertAligns[this.column.vertAlign] || "";

			if(this.column.hozAlign){
				element.style.justifyContent = hozAligns[this.column.hozAlign] || "";
			}
		}

		if(field){
			element.setAttribute("tabulator-field", field);
		}

		//add class to cell if needed
		if(this.column.definition.cssClass){
			var classNames = this.column.definition.cssClass.split(" ")
			classNames.forEach((className) => {
				element.classList.add(className)
			});
		}

		//update tooltip on mouse enter
		if (this.table.options.tooltipGenerationMode === "hover"){
			element.addEventListener("mouseenter", (e) => {
				this._generateTooltip();
			});
		}

		this.dispatch("cell-init", this);

		//hide cell if not visible
		if(!this.column.visible){
			this.hide();
		}
	}

	//generate cell contents
	_generateContents(){
		var val;

		val = this.chain("cell-format", this, null, () => {
			return this.element.innerHTML = this.value;
		});

		switch(typeof val){
			case "object":
			if(val instanceof Node){

				//clear previous cell contents
				while(this.element.firstChild) this.element.removeChild(this.element.firstChild);

				this.element.appendChild(val);
			}else{
				this.element.innerHTML = "";

				if(val != null){
					console.warn("Format Error - Formatter has returned a type of object, the only valid formatter object return is an instance of Node, the formatter returned:", val);
				}
			}
			break;
			case "undefined":
			case "null":
			this.element.innerHTML = "";
			break;
			default:
			this.element.innerHTML = val;
		}
	}

	cellRendered(){
		this.dispatch("cell-rendered", this);
	}

	//generate tooltip text
	_generateTooltip(){
		var tooltip = this.column.tooltip;

		if(tooltip){
			if(tooltip === true){
				tooltip = this.value;
			}else if(typeof(tooltip) == "function"){
				tooltip = tooltip(this.getComponent());

				if(tooltip === false){
					tooltip = "";
				}
			}

			if(typeof tooltip === "undefined"){
				tooltip = "";
			}

			this.element.setAttribute("title", tooltip);
		}else{
			this.element.setAttribute("title", "");
		}
	}

	//////////////////// Getters ////////////////////
	getElement(containerOnly){
		if(!this.loaded){
			this.loaded = true;
			if(!containerOnly){
				this.layoutElement();
			}
		}

		return this.element;
	}

	getValue(){
		return this.value;
	}

	getOldValue(){
		return this.oldValue;
	}

	//////////////////// Actions ////////////////////
	setValue(value, mutate){
		var changed = this.setValueProcessData(value, mutate);

		if(changed){
			this.dispatch("cell-value-updated", this);

			this.cellRendered();

			this.dispatchExternal("cellEdited", this.getComponent());

			if(this.subscribedExternal("dataChanged")){
				this.dispatchExternal("dataChanged", this.table.rowManager.getData());
			}
		}
	}

	setValueProcessData(value, mutate){
		var changed = false;

		if(this.value != value){

			changed = true;

			if(mutate){
				value = this.chain("cell-value-changing", [this, value], null, value);
			}
		}

		this.setValueActual(value);

		if(changed){
			this.dispatch("cell-value-changed", this);
		}

		return changed;
	}

	setValueActual(value){
		this.oldValue = this.value;

		this.value = value;

		this.dispatch("cell-value-save-before", this);

		this.column.setFieldValue(this.row.data, value);

		this.dispatch("cell-value-save-after", this);

		if(this.loaded){
			this.layoutElement();
		}
	}

	layoutElement(){
		this._generateContents();
		this._generateTooltip();

		this.dispatch("cell-layout", this);
	}

	setWidth(){
		this.width = this.column.width;
		this.element.style.width = this.column.widthStyled;
	}

	clearWidth(){
		this.width = "";
		this.element.style.width = "";
	}

	getWidth(){
		return this.width || this.element.offsetWidth;
	}

	setMinWidth(){
		this.minWidth = this.column.minWidth;
		this.element.style.minWidth = this.column.minWidthStyled;
	}

	setMaxWidth(){
		this.maxWidth = this.column.maxWidth;
		this.element.style.maxWidth = this.column.maxWidthStyled;
	}

	checkHeight(){
		// var height = this.element.css("height");
		this.row.reinitializeHeight();
	}

	clearHeight(){
		this.element.style.height = "";
		this.height = null;
	}

	setHeight(){
		this.height = this.row.height;
		this.element.style.height =  this.row.heightStyled;
	}

	getHeight(){
		return this.height || this.element.offsetHeight;
	}

	show(){
		this.element.style.display = this.column.vertAlign ? "inline-flex" : "";
	}

	hide(){
		this.element.style.display = "none";
	}

	delete(){
		this.dispatch("cell-delete", this);

		if(!this.table.rowManager.redrawBlock && this.element.parentNode){
			this.element.parentNode.removeChild(this.element);
		}

		this.element = false;
		this.column.deleteCell(this);
		this.row.deleteCell(this);
		this.calcs = {};
	}

	getIndex(){
		return this.row.getCellIndex(this);
	}

	//////////////// Object Generation /////////////////
	getComponent(){
		if(!this.component){
			this.component = new CellComponent(this);
		}

		return this.component;
	}
}<commit_msg>Callback the cellEdited function on the definition if it exists (#3513)<commit_after>import CoreFeature from '../CoreFeature.js';
import CellComponent from './CellComponent.js';

export default class Cell extends CoreFeature{
	constructor(column, row){
		super(column.table);

		this.table = column.table;
		this.column = column;
		this.row = row;
		this.element = null;
		this.value = null;
		this.initialValue;
		this.oldValue = null;
		this.modules = {};

		this.height = null;
		this.width = null;
		this.minWidth = null;

		this.component = null;

		this.loaded = false; //track if the cell has been added to the DOM yet

		this.build();
	}

	//////////////// Setup Functions /////////////////
	//generate element
	build(){
		this.generateElement();

		this.setWidth();

		this._configureCell();

		this.setValueActual(this.column.getFieldValue(this.row.data));

		this.initialValue = this.value;
	}

	generateElement(){
		this.element = document.createElement('div');
		this.element.className = "tabulator-cell";
		this.element.setAttribute("role", "gridcell");
		this.element = this.element;
	}

	_configureCell(){
		var element = this.element,
		field = this.column.getField(),
		vertAligns = {
			top:"flex-start",
			bottom:"flex-end",
			middle:"center",
		},
		hozAligns = {
			left:"flex-start",
			right:"flex-end",
			center:"center",
		};

		//set text alignment
		element.style.textAlign = this.column.hozAlign;

		if(this.column.vertAlign){
			element.style.display = "inline-flex";

			element.style.alignItems = vertAligns[this.column.vertAlign] || "";

			if(this.column.hozAlign){
				element.style.justifyContent = hozAligns[this.column.hozAlign] || "";
			}
		}

		if(field){
			element.setAttribute("tabulator-field", field);
		}

		//add class to cell if needed
		if(this.column.definition.cssClass){
			var classNames = this.column.definition.cssClass.split(" ")
			classNames.forEach((className) => {
				element.classList.add(className)
			});
		}

		//update tooltip on mouse enter
		if (this.table.options.tooltipGenerationMode === "hover"){
			element.addEventListener("mouseenter", (e) => {
				this._generateTooltip();
			});
		}

		this.dispatch("cell-init", this);

		//hide cell if not visible
		if(!this.column.visible){
			this.hide();
		}
	}

	//generate cell contents
	_generateContents(){
		var val;

		val = this.chain("cell-format", this, null, () => {
			return this.element.innerHTML = this.value;
		});

		switch(typeof val){
			case "object":
			if(val instanceof Node){

				//clear previous cell contents
				while(this.element.firstChild) this.element.removeChild(this.element.firstChild);

				this.element.appendChild(val);
			}else{
				this.element.innerHTML = "";

				if(val != null){
					console.warn("Format Error - Formatter has returned a type of object, the only valid formatter object return is an instance of Node, the formatter returned:", val);
				}
			}
			break;
			case "undefined":
			case "null":
			this.element.innerHTML = "";
			break;
			default:
			this.element.innerHTML = val;
		}
	}

	cellRendered(){
		this.dispatch("cell-rendered", this);
	}

	//generate tooltip text
	_generateTooltip(){
		var tooltip = this.column.tooltip;

		if(tooltip){
			if(tooltip === true){
				tooltip = this.value;
			}else if(typeof(tooltip) == "function"){
				tooltip = tooltip(this.getComponent());

				if(tooltip === false){
					tooltip = "";
				}
			}

			if(typeof tooltip === "undefined"){
				tooltip = "";
			}

			this.element.setAttribute("title", tooltip);
		}else{
			this.element.setAttribute("title", "");
		}
	}

	//////////////////// Getters ////////////////////
	getElement(containerOnly){
		if(!this.loaded){
			this.loaded = true;
			if(!containerOnly){
				this.layoutElement();
			}
		}

		return this.element;
	}

	getValue(){
		return this.value;
	}

	getOldValue(){
		return this.oldValue;
	}

	//////////////////// Actions ////////////////////
	setValue(value, mutate){
		var changed = this.setValueProcessData(value, mutate);

		if(changed){
			this.dispatch("cell-value-updated", this);

			this.cellRendered();

			if(this.column.definition.cellEdited){
				this.column.definition.cellEdited.call(this.table, this.getComponent());
			}

			this.dispatchExternal("cellEdited", this.getComponent());

			if(this.subscribedExternal("dataChanged")){
				this.dispatchExternal("dataChanged", this.table.rowManager.getData());
			}
		}
	}

	setValueProcessData(value, mutate){
		var changed = false;

		if(this.value != value){

			changed = true;

			if(mutate){
				value = this.chain("cell-value-changing", [this, value], null, value);
			}
		}

		this.setValueActual(value);

		if(changed){
			this.dispatch("cell-value-changed", this);
		}

		return changed;
	}

	setValueActual(value){
		this.oldValue = this.value;

		this.value = value;

		this.dispatch("cell-value-save-before", this);

		this.column.setFieldValue(this.row.data, value);

		this.dispatch("cell-value-save-after", this);

		if(this.loaded){
			this.layoutElement();
		}
	}

	layoutElement(){
		this._generateContents();
		this._generateTooltip();

		this.dispatch("cell-layout", this);
	}

	setWidth(){
		this.width = this.column.width;
		this.element.style.width = this.column.widthStyled;
	}

	clearWidth(){
		this.width = "";
		this.element.style.width = "";
	}

	getWidth(){
		return this.width || this.element.offsetWidth;
	}

	setMinWidth(){
		this.minWidth = this.column.minWidth;
		this.element.style.minWidth = this.column.minWidthStyled;
	}

	setMaxWidth(){
		this.maxWidth = this.column.maxWidth;
		this.element.style.maxWidth = this.column.maxWidthStyled;
	}

	checkHeight(){
		// var height = this.element.css("height");
		this.row.reinitializeHeight();
	}

	clearHeight(){
		this.element.style.height = "";
		this.height = null;
	}

	setHeight(){
		this.height = this.row.height;
		this.element.style.height =  this.row.heightStyled;
	}

	getHeight(){
		return this.height || this.element.offsetHeight;
	}

	show(){
		this.element.style.display = this.column.vertAlign ? "inline-flex" : "";
	}

	hide(){
		this.element.style.display = "none";
	}

	delete(){
		this.dispatch("cell-delete", this);

		if(!this.table.rowManager.redrawBlock && this.element.parentNode){
			this.element.parentNode.removeChild(this.element);
		}

		this.element = false;
		this.column.deleteCell(this);
		this.row.deleteCell(this);
		this.calcs = {};
	}

	getIndex(){
		return this.row.getCellIndex(this);
	}

	//////////////// Object Generation /////////////////
	getComponent(){
		if(!this.component){
			this.component = new CellComponent(this);
		}

		return this.component;
	}
}<|endoftext|>


<commit_before>import DomHelper from "../helper/domHelper";

export default class Behavior {
    /**
     * @returns {{hover: string, click: string}}
     */
    static mouseEvents() {
        return {
            'hover': 'mouseenter',
            'click': 'click'
        };
    }

    /**
     * @param {string} triggerEvent
     * @param {jQuery} $image
     */
    constructor($image, triggerEvent) {
        this.$image = $image;
        this.triggerEvent = triggerEvent;
        this.enabled = false;
    }

    bindAll() {
        if (this.enabled === false) {
            this.enabled = true;
        }

        this.bindSceneEvents();
        this.bindItemsEvents();
        this.bindHotspotsEvents();
    }

    unbindAll() {
        if (this.enabled === true) {
            this.enabled = false;
        }

        this.$image.off();
    }

    bindHostpotMouseLeave($hotspot) {
        $hotspot.on('mouseleave', function(event) {
            const $relatedTarget = $(event.relatedTarget);
            // If parent has class "item", it enters container so there is no need to hide it
            if ($relatedTarget.parent() && $relatedTarget.parent().hasClass('item')) {
                return;
            }

            const container = DomHelper.retrieveContainerFromHotspot($hotspot[0]);
            if (container.classList.contains('behavior-sticky')) {
                return;
            }

            DomHelper.hideElement(container);
        });
    }

    /**
     * @param {HTMLElement} hotspot
     */
    unbindHotspotMouseLeave(hotspot) {
        hotspot.removeEventListener('mouseleave', function() {});
    }

    bindSceneEvents() {
        // Mouse enters scene -> show all hotspots and share box
        this.$image.on('mouseenter', function() {
            const $hotspots = $(this).find('.hotspot');
            $.each($hotspots, function() {
                $(this).fadeIn();
            });

            const $shareBox = $(this).find('.social-share-box');
            setTimeout(() => {
                $shareBox.css('display', 'flex');
            }, 100);
        });

        // Mouse leaves scene -> hide all hotspots, containers and share box
        this.$image.on('mouseleave', function() {
            const $elements = $(this).find('.hotspot, .item');
            $.each($elements, function() {
                DomHelper.hideElement($(this)[0]);
            });

            const $shareBox = $(this).find('.social-share-box');
            DomHelper.hideElement($shareBox[0]);
        });
    }

    bindStickyItemsEvents() {
        this.$image.find('.item').each(function() {
            let $container = $(this);
            if (!$container[0].classList.contains('behavior-sticky')) {
                return;
            }

            // Bind event to hide the related sticky container when close button is clicked
            $container.on('click', '.close-button' , function() {
                DomHelper.hideElement($container[0]);
            });
        });
    }

    /**
     * Initialize events on each item
     */
    bindItemsEvents() {
        let that = this;

        that.$image.find('.hotspot').each(function() {
            const $hotspot = $(this);
            const $container = $(DomHelper.retrieveContainerFromHotspot($hotspot[0]));

            if ($container[0].classList.contains('behavior-sticky')) {
                return;
            }

            that.bindHostpotMouseLeave($hotspot);
            $container.on('mouseenter', function() {
                that.unbindHotspotMouseLeave($hotspot[0]);
            });

            // Bind event to hide the related container when mouse leaves it
            $container.on('mouseleave', function(event) {
                const $relatedTarget = $(event.relatedTarget);
                // If related target has class "hotpost", it enters hotspot so there is no need to hide the container
                if ($relatedTarget.hasClass('hotspot')) {
                    return;
                }

                DomHelper.hideElement($(this)[0]);
                that.bindHostpotMouseLeave($hotspot);
            });
        });

        this.bindStickyItemsEvents();
    }

    /**
     * Initialize events on each hotspot
     */
    bindHotspotsEvents() {
        let that = this;

        that.$image.on(Behavior.mouseEvents()[this.triggerEvent], '.hotspot', function(event) {
            const $hotspot = $(this);
            const $relatedTarget = $(event.relatedTarget);
            if ($relatedTarget.parent() && $relatedTarget.parent().hasClass('item')) {
                // If parent has class "item", it only re-enters from item
                return that.bindHostpotMouseLeave($hotspot);
            }

            // Hide all other containers that are not sticky
            const $containers = that.$image.find('.item').not('.behavior-sticky');
            $.each($containers, function() {
                DomHelper.hideElement($(this)[0]);
            });

            // Finally, show the related item
            const container = DomHelper.retrieveContainerFromHotspot($hotspot[0]);
            DomHelper.showElement(container);
        });
    }
}
<commit_msg>fixed error when share box is hidden - issue #8<commit_after>import DomHelper from "../helper/domHelper";

export default class Behavior {
    /**
     * @returns {{hover: string, click: string}}
     */
    static mouseEvents() {
        return {
            'hover': 'mouseenter',
            'click': 'click'
        };
    }

    /**
     * @param {string} triggerEvent
     * @param {jQuery} $image
     */
    constructor($image, triggerEvent) {
        this.$image = $image;
        this.triggerEvent = triggerEvent;
        this.enabled = false;
    }

    bindAll() {
        if (this.enabled === false) {
            this.enabled = true;
        }

        this.bindSceneEvents();
        this.bindItemsEvents();
        this.bindHotspotsEvents();
    }

    unbindAll() {
        if (this.enabled === true) {
            this.enabled = false;
        }

        this.$image.off();
    }

    bindHostpotMouseLeave($hotspot) {
        $hotspot.on('mouseleave', function(event) {
            const $relatedTarget = $(event.relatedTarget);
            // If parent has class "item", it enters container so there is no need to hide it
            if ($relatedTarget.parent() && $relatedTarget.parent().hasClass('item')) {
                return;
            }

            const container = DomHelper.retrieveContainerFromHotspot($hotspot[0]);
            if (container.classList.contains('behavior-sticky')) {
                return;
            }

            DomHelper.hideElement(container);
        });
    }

    /**
     * @param {HTMLElement} hotspot
     */
    unbindHotspotMouseLeave(hotspot) {
        hotspot.removeEventListener('mouseleave', function() {});
    }

    bindSceneEvents() {
        // Mouse enters scene -> show all hotspots and share box (if exists)
        this.$image.on('mouseenter', function() {
            const $hotspots = $(this).find('.hotspot');
            $.each($hotspots, function() {
                $(this).fadeIn();
            });

            const $shareBox = $(this).find('.social-share-box');
            if (!$shareBox.length) {
                return;
            }

            setTimeout(() => {
                $shareBox.css('display', 'flex');
            }, 100);
        });

        // Mouse leaves scene -> hide all hotspots, containers and share box (if exists)
        this.$image.on('mouseleave', function() {
            const $elements = $(this).find('.hotspot, .item');
            $.each($elements, function() {
                DomHelper.hideElement($(this)[0]);
            });

            const $shareBox = $(this).find('.social-share-box');
            if (!$shareBox.length) {
                return;
            }

            DomHelper.hideElement($shareBox[0]);
        });
    }

    bindStickyItemsEvents() {
        this.$image.find('.item').each(function() {
            let $container = $(this);
            if (!$container[0].classList.contains('behavior-sticky')) {
                return;
            }

            // Bind event to hide the related sticky container when close button is clicked
            $container.on('click', '.close-button' , function() {
                DomHelper.hideElement($container[0]);
            });
        });
    }

    /**
     * Initialize events on each item
     */
    bindItemsEvents() {
        let that = this;

        that.$image.find('.hotspot').each(function() {
            const $hotspot = $(this);
            const $container = $(DomHelper.retrieveContainerFromHotspot($hotspot[0]));

            if ($container[0].classList.contains('behavior-sticky')) {
                return;
            }

            that.bindHostpotMouseLeave($hotspot);
            $container.on('mouseenter', function() {
                that.unbindHotspotMouseLeave($hotspot[0]);
            });

            // Bind event to hide the related container when mouse leaves it
            $container.on('mouseleave', function(event) {
                const $relatedTarget = $(event.relatedTarget);
                // If related target has class "hotpost", it enters hotspot so there is no need to hide the container
                if ($relatedTarget.hasClass('hotspot')) {
                    return;
                }

                DomHelper.hideElement($(this)[0]);
                that.bindHostpotMouseLeave($hotspot);
            });
        });

        this.bindStickyItemsEvents();
    }

    /**
     * Initialize events on each hotspot
     */
    bindHotspotsEvents() {
        let that = this;

        that.$image.on(Behavior.mouseEvents()[this.triggerEvent], '.hotspot', function(event) {
            const $hotspot = $(this);
            const $relatedTarget = $(event.relatedTarget);
            if ($relatedTarget.parent() && $relatedTarget.parent().hasClass('item')) {
                // If parent has class "item", it only re-enters from item
                return that.bindHostpotMouseLeave($hotspot);
            }

            // Hide all other containers that are not sticky
            const $containers = that.$image.find('.item').not('.behavior-sticky');
            $.each($containers, function() {
                DomHelper.hideElement($(this)[0]);
            });

            // Finally, show the related item
            const container = DomHelper.retrieveContainerFromHotspot($hotspot[0]);
            DomHelper.showElement(container);
        });
    }
}
<|endoftext|>


<commit_before>(function() { //IIFE

    var DJANGO_SERVER_URL = "https://cryptic-citadel-5628.herokuapp.com/api";
    var FIREBASE_SERVER_URL = "https://tanks-for-waiting.firebaseio.com";

    angular.module('tanks-for-waiting').controller('GameController', GameController);
    GameController.$inject = ['$scope', '$http', '$firebaseObject', '$interval'];

    function GameController($scope, $http, $firebaseObject, $interval) {

        var firebaseref = null;
        var playerID = null; //player_id stored here
        var gameID = null; //game_id stored here
        $scope.gameRunning = false;
        $scope.score = 0;
        /*
        *This begins the process of game selection.
        POST to /players/ for player_id
        Returns player_id
        Stores player_id
        POST to games/player_id
        Returns game_id
        Stores game_id
        Starts game
        */
        $scope.startGame = function() {
            $http.post(DJANGO_SERVER_URL + "/players/")
                .then(function(response) {
                    playerID = response.data;
                    //this is where I would display the tutorial
                    $http.post(DJANGO_SERVER_URL + "/game/" + playerID)
                        .then(function(response) {
                                gameID = response.data;
                                firebaseref = new Firebase (FIREBASE_SERVER_URL + "/games/" + gameID); //websocket to firebase api
                                $scope.game = $firsebaseObject (firebaseref); //websocket to firebase api
                                // $scope.gameRunning = true;
                                // new Game("screen");
                            },
                            function(errobj) {
                                alert("Game request failed: " + JSON.stringify(errobj));
                            });
                }, function(errobj) {
                  $scope.gameRunning = true;
                  new Game("screen");
                    // alert("Player request failed: " + JSON.stringify(errobj));
                });
            console.log("click");
        };

        var Game = function(canvasId) { //holds all the main game code
            var canvas = document.getElementById(canvasId); //get the canvas into my game
            var screen = canvas.getContext('2d'); //var screen will allow me to draw to the canvas. "2d" leads to the creation of a CanvasRenderingContext2D object representing a two-dimensional rendering context.
            var gameSize = {
                x: canvas.width,
                y: canvas.height
            }; // stores the width and height of the canvas for later use for placing entities on the canvas

            this.tanks = [new Player(this, gameSize)]; //will hold all of the tanks in the game
            this.targets = [new Target(this, gameSize),
                new Target(this, gameSize),
                new Target(this, gameSize),
                new Target(this, gameSize),
                new Target(this, gameSize)
            ];
            var self = this;
            // var framesPerSecond = function() { // framesPerSecond is going to get run about 60 times a second and it's responsible for running all the main game logic
            //     self.update(); //updates the screen
            //     self.draw(screen, gameSize); //based upon what's happening in the game
            //     requestAnimationFrame(framesPerSecond); // and then asks to run framesPerSecond again
            //     // console.log("hello"); // uncomment the console log to see this 60fps in action
            // };
            //
            // framesPerSecond();
            $interval(function() {
              self.update(); //updates the screen
              self.draw(screen, gameSize); //based upon what's happening in the game
            }, 16.7);
        };

        Game.prototype = { //gives Game a prototype
            update: function() { //updates the movement of all the on screen entities
                for (var i = 0; i < this.tanks.length; i++) {
                    this.tanks[i].update();
                }
                var thisPlayer = this.tanks[0];
                for (i = 0; i < this.targets.length; i++) {
                  if (colliding(thisPlayer, this.targets[i])) {
                    console.log("HIT!");
                    $scope.score += 1;
                  }
                }
            },

            draw: function(screen, gameSize) {
                screen.clearRect(0, 0, gameSize.x, gameSize.y);
                for (var i = 0; i < this.tanks.length; i++) {
                    drawTank(screen, this.tanks[i]);
                    // drawTarget(screen, this.tanks[i]);
                    if (i === 0) {
                        if (this.tanks[i].keyboarder.isDown(this.tanks[i].keyboarder.KEYS.LEFT)) {
                            drawDrillHeadLeft(screen, this.tanks[i]);
                        } else if (this.tanks[i].keyboarder.isDown(this.tanks[i].keyboarder.KEYS.RIGHT)) {
                            drawDrillHeadRight(screen, this.tanks[i]);
                        } else if (this.tanks[i].keyboarder.isDown(this.tanks[i].keyboarder.KEYS.UP)) {
                            drawDrillHeadUp(screen, this.tanks[i]);
                        } else if (this.tanks[i].keyboarder.isDown(this.tanks[i].keyboarder.KEYS.DOWN)) {
                            drawDrillHeadDown(screen, this.tanks[i]);
                        }
                    }
                }
                for (i = 0; i < this.targets.length; i++) {
                    drawTarget(screen, this.targets[i]);
                    // drawTarget(screen, this.tanks[i]);

                }
            },

            addBody: function(body) { //takes a body and pushes it to the tanks array
                this.tanks.push(body); // example; this.game.addBody(varNameOfBody);
            }
        };
        var Player = function(game, gameSize) {
            this.game = game;
            this.size = {
                x: 16,
                y: 16
            }; //player size
            this.center = {
                x: gameSize.x / 2,
                y: gameSize.y - this.size.x
            }; //tells the game where the player is at the moment, starting at half way through the screen and just above the bottom
            this.keyboarder = new Keyboarder();
        };

        Player.prototype = {
            update: function() {
                if (this.keyboarder.isDown(this.keyboarder.KEYS.LEFT)) {
                    if (this.center.x <= 10) {
                        this.center.x = 8;
                    } else {
                        this.center.x -= 2;
                    }
                }
                if (this.keyboarder.isDown(this.keyboarder.KEYS.RIGHT)) {
                    if (this.center.x >= 490) {
                        this.center.x = 492;
                    } else {
                        this.center.x += 2;
                    }
                }
                if (this.keyboarder.isDown(this.keyboarder.KEYS.UP)) {
                    if (this.center.y <= 10) {
                        this.center.y = 8;
                    } else {
                        this.center.y -= 2;
                    }
                }
                if (this.keyboarder.isDown(this.keyboarder.KEYS.DOWN)) {
                    if (this.center.y >= 490) {
                        this.center.y = 492;
                    } else {
                        this.center.y += 2;
                    }
                }
            }
        };

        var Target = function(game, gameSize) {
            this.game = game;
            this.size = {
                x: 10,
                y: 10
            }; //player size
            this.center = {
                x: Math.random() * gameSize.x,
                y: Math.random() * gameSize.y
            }; //tells the game where the player is at the moment, starting at half way through the screen and just above the bottom
        };

        Target.prototype = {
            update: function() {
                console.log("helllo");
            }
        };

        var drawTank = function(screen, body) {
            //tank body
            screen.fillRect(body.center.x - body.size.x / 2, //x coordinate
                body.center.y - body.size.y / 2, // y coordinate
                body.size.x, body.size.y); //width and hieght
        };

        var drawDrillHeadLeft = function(screen, body) {
            screen.fillRect(body.center.x - body.size.x / 2 - 4, body.center.y - 2, 4, 4);
        };

        var drawDrillHeadRight = function(screen, body) {
            screen.fillRect(body.center.x + body.size.x / 2, body.center.y - 2, 4, 4);
        };

        var drawDrillHeadUp = function(screen, body) {
            screen.fillRect(body.center.x - 2, body.center.y - body.size.y / 2 - 4, 4, 4);
        };

        var drawDrillHeadDown = function(screen, body) {
            screen.fillRect(body.center.x - 2, body.center.y + body.size.y / 2, 4, 4);
        };

        var drawTarget = function(screen, target) {
            screen.fillRect(target.center.x - target.size.x / 2, //x coordinate
                target.center.y - target.size.y / 2, // y coordinate
                target.size.x, target.size.y);
        };

        var Keyboarder = function() { //handles keyboard input
            var keyState = {}; //records if any key that's been pressed is pressed or released

            window.onkeydown = function(e) {
                keyState[e.keyCode] = true;
            };

            window.onkeyup = function(e) {
                keyState[e.keyCode] = false;
            };

            this.isDown = function(keyCode) {
                return keyState[keyCode] === true;
            };

            this.KEYS = {
                LEFT: 37,
                UP: 38,
                RIGHT: 39,
                DOWN: 40,
                SPACE: 32
            };
        };

        var colliding = function(b1, b2) {
          return !(b1 === b2 ||
                   b1.center.x + b1.size.x /2 < b2.center.x - b2.size.x / 2 ||
                   b1.center.y + b1.size.y /2 < b2.center.y - b2.size.y / 2 ||
                   b1.center.x - b1.size.x /2 > b2.center.x + b2.size.x / 2 ||
                   b1.center.y - b1.size.y /2 > b2.center.y + b2.size.y / 2);
        };
    }
})(); // End of IIFE
<commit_msg>target is removed after being hit<commit_after>(function() { //IIFE

    var DJANGO_SERVER_URL = "https://cryptic-citadel-5628.herokuapp.com/api";
    var FIREBASE_SERVER_URL = "https://tanks-for-waiting.firebaseio.com";

    angular.module('tanks-for-waiting').controller('GameController', GameController);
    GameController.$inject = ['$scope', '$http', '$firebaseObject', '$interval'];

    function GameController($scope, $http, $firebaseObject, $interval) {

        var firebaseref = null;
        var playerID = null; //player_id stored here
        var gameID = null; //game_id stored here
        $scope.gameRunning = false;
        $scope.score = 0;
        /*
        *This begins the process of game selection.
        POST to /players/ for player_id
        Returns player_id
        Stores player_id
        POST to games/player_id
        Returns game_id
        Stores game_id
        Starts game
        */
        $scope.startGame = function() {
            $http.post(DJANGO_SERVER_URL + "/players/")
                .then(function(response) {
                    playerID = response.data;
                    //this is where I would display the tutorial
                    $http.post(DJANGO_SERVER_URL + "/game/" + playerID)
                        .then(function(response) {
                                gameID = response.data;
                                firebaseref = new Firebase (FIREBASE_SERVER_URL + "/games/" + gameID); //websocket to firebase api
                                $scope.game = $firsebaseObject (firebaseref); //websocket to firebase api
                                // $scope.gameRunning = true;
                                // new Game("screen");
                            },
                            function(errobj) {
                                alert("Game request failed: " + JSON.stringify(errobj));
                            });
                }, function(errobj) {
                  $scope.gameRunning = true;
                  new Game("screen");
                    // alert("Player request failed: " + JSON.stringify(errobj));
                });
            console.log("click");
        };

        var Game = function(canvasId) { //holds all the main game code
            var canvas = document.getElementById(canvasId); //get the canvas into my game
            var screen = canvas.getContext('2d'); //var screen will allow me to draw to the canvas. "2d" leads to the creation of a CanvasRenderingContext2D object representing a two-dimensional rendering context.
            var gameSize = {
                x: canvas.width,
                y: canvas.height
            }; // stores the width and height of the canvas for later use for placing entities on the canvas

            this.tanks = [new Player(this, gameSize)]; //will hold all of the tanks in the game
            this.targets = [new Target(this, gameSize),
                new Target(this, gameSize),
                new Target(this, gameSize),
                new Target(this, gameSize),
                new Target(this, gameSize)
            ];
            var self = this;
            // var framesPerSecond = function() { // framesPerSecond is going to get run about 60 times a second and it's responsible for running all the main game logic
            //     self.update(); //updates the screen
            //     self.draw(screen, gameSize); //based upon what's happening in the game
            //     requestAnimationFrame(framesPerSecond); // and then asks to run framesPerSecond again
            //     // console.log("hello"); // uncomment the console log to see this 60fps in action
            // };
            //
            // framesPerSecond();
            $interval(function() {
              self.update(); //updates the screen
              self.draw(screen, gameSize); //based upon what's happening in the game
            }, 16.7);
        };

        Game.prototype = { //gives Game a prototype
            update: function() { //updates the movement of all the on screen entities
                for (var i = 0; i < this.tanks.length; i++) {
                    this.tanks[i].update();
                }
                var thisPlayer = this.tanks[0];
                for (i = 0; i < this.targets.length; i++) {
                  if (colliding(thisPlayer, this.targets[i])) {
                    console.log("HIT!");
                    $scope.score += 1;
                    this.targets.splice(i, 1);
                  }
                }
            },

            draw: function(screen, gameSize) {
                screen.clearRect(0, 0, gameSize.x, gameSize.y);
                for (var i = 0; i < this.tanks.length; i++) {
                    drawTank(screen, this.tanks[i]);
                    // drawTarget(screen, this.tanks[i]);
                    if (i === 0) {
                        if (this.tanks[i].keyboarder.isDown(this.tanks[i].keyboarder.KEYS.LEFT)) {
                            drawDrillHeadLeft(screen, this.tanks[i]);
                        } else if (this.tanks[i].keyboarder.isDown(this.tanks[i].keyboarder.KEYS.RIGHT)) {
                            drawDrillHeadRight(screen, this.tanks[i]);
                        } else if (this.tanks[i].keyboarder.isDown(this.tanks[i].keyboarder.KEYS.UP)) {
                            drawDrillHeadUp(screen, this.tanks[i]);
                        } else if (this.tanks[i].keyboarder.isDown(this.tanks[i].keyboarder.KEYS.DOWN)) {
                            drawDrillHeadDown(screen, this.tanks[i]);
                        }
                    }
                }
                for (i = 0; i < this.targets.length; i++) {
                    drawTarget(screen, this.targets[i]);
                    // drawTarget(screen, this.tanks[i]);

                }
            },

            addBody: function(body) { //takes a body and pushes it to the tanks array
                this.tanks.push(body); // example; this.game.addBody(varNameOfBody);
            }
        };
        var Player = function(game, gameSize) {
            this.game = game;
            this.size = {
                x: 16,
                y: 16
            }; //player size
            this.center = {
                x: gameSize.x / 2,
                y: gameSize.y - this.size.x
            }; //tells the game where the player is at the moment, starting at half way through the screen and just above the bottom
            this.keyboarder = new Keyboarder();
        };

        Player.prototype = {
            update: function() {
                if (this.keyboarder.isDown(this.keyboarder.KEYS.LEFT)) {
                    if (this.center.x <= 10) {
                        this.center.x = 8;
                    } else {
                        this.center.x -= 2;
                    }
                }
                if (this.keyboarder.isDown(this.keyboarder.KEYS.RIGHT)) {
                    if (this.center.x >= 490) {
                        this.center.x = 492;
                    } else {
                        this.center.x += 2;
                    }
                }
                if (this.keyboarder.isDown(this.keyboarder.KEYS.UP)) {
                    if (this.center.y <= 10) {
                        this.center.y = 8;
                    } else {
                        this.center.y -= 2;
                    }
                }
                if (this.keyboarder.isDown(this.keyboarder.KEYS.DOWN)) {
                    if (this.center.y >= 490) {
                        this.center.y = 492;
                    } else {
                        this.center.y += 2;
                    }
                }
            }
        };

        var Target = function(game, gameSize) {
            this.game = game;
            this.size = {
                x: 10,
                y: 10
            }; //player size
            this.center = {
                x: Math.random() * gameSize.x,
                y: Math.random() * gameSize.y
            }; //tells the game where the player is at the moment, starting at half way through the screen and just above the bottom
        };

        Target.prototype = {
            update: function() {
                console.log("helllo");
            }
        };

        var drawTank = function(screen, body) {
            //tank body
            screen.fillRect(body.center.x - body.size.x / 2, //x coordinate
                body.center.y - body.size.y / 2, // y coordinate
                body.size.x, body.size.y); //width and hieght
        };

        var drawDrillHeadLeft = function(screen, body) {
            screen.fillRect(body.center.x - body.size.x / 2 - 4, body.center.y - 2, 4, 4);
        };

        var drawDrillHeadRight = function(screen, body) {
            screen.fillRect(body.center.x + body.size.x / 2, body.center.y - 2, 4, 4);
        };

        var drawDrillHeadUp = function(screen, body) {
            screen.fillRect(body.center.x - 2, body.center.y - body.size.y / 2 - 4, 4, 4);
        };

        var drawDrillHeadDown = function(screen, body) {
            screen.fillRect(body.center.x - 2, body.center.y + body.size.y / 2, 4, 4);
        };

        var drawTarget = function(screen, target) {
            screen.fillRect(target.center.x - target.size.x / 2, //x coordinate
                target.center.y - target.size.y / 2, // y coordinate
                target.size.x, target.size.y);
        };

        var Keyboarder = function() { //handles keyboard input
            var keyState = {}; //records if any key that's been pressed is pressed or released

            window.onkeydown = function(e) {
                keyState[e.keyCode] = true;
            };

            window.onkeyup = function(e) {
                keyState[e.keyCode] = false;
            };

            this.isDown = function(keyCode) {
                return keyState[keyCode] === true;
            };

            this.KEYS = {
                LEFT: 37,
                UP: 38,
                RIGHT: 39,
                DOWN: 40,
                SPACE: 32
            };
        };

        var colliding = function(b1, b2) {
          return !(b1 === b2 ||
                   b1.center.x + b1.size.x /2 < b2.center.x - b2.size.x / 2 ||
                   b1.center.y + b1.size.y /2 < b2.center.y - b2.size.y / 2 ||
                   b1.center.x - b1.size.x /2 > b2.center.x + b2.size.x / 2 ||
                   b1.center.y - b1.size.y /2 > b2.center.y + b2.size.y / 2);
        };
    }
})(); // End of IIFE
<|endoftext|>


<commit_before>'use strict';
/**
 * @author Rafael Violato (http://rviolato.com)
 */

(function(){

	angular.module('pg-ng-dropdown', [])
		.directive('pgNgDropdown', dropdownDirective);

	dropdownDirective.$inject = ['$timeout', '$document'];

	function dropdownDirective($timeout, $document){

		var template = [

			'
',
				'
',
						'',
						'',
						'',
						'',
						'
',
							'

',
						'
',
				'
',
				'
',
					'
',
						'',
						'',
						'',
						'',
					'
',
				'
',
		    '
',

		].join('');

		var directive = {

			scope: {
				data: '=options',
				image: '@imageOptions',
				imageProperty: '@',
				value: '@selected',
				name: '@',
				textProperty: '@',
				openedClass: '@',
				selectedClass: '@',
				onchange: '&',
			},
			restrict: 'AEC',
			compile: compile,
			controller: controller,
			controllerAs: 'ctrl',
			bindToController: true,
			replace: true,
			template: template,

		};

		return directive;

		function compile($element, attrs){

			attrs.value = attrs.value || 0;
			attrs.textProperty = attrs.textProperty || 'text';
			attrs.imageProperty = attrs.imagetProperty || 'image';

			return {
				post: postLink,
			};

		}

		function controller($scope){

			var vm = this;

			vm.opened = false;

			vm.selectOption = selectOption;
			vm.open = open;
			vm.close = close;
			vm.toggle = toggle;

			if((typeof vm.value) === 'number'){

				vm.data[vm.value].selected = true;

			}

			function selectOption(_index){

				if(_index !== parseInt(vm.value)){

					var _pastSelected = vm.value;

					_index = parseInt(_index);

					vm.value = _index;
					vm.data[_index].selected = true;

					if(vm.data[_pastSelected]){

						delete vm.data[_pastSelected].selected;

					}

					vm.onchange();

					$scope.$broadcast('option-selected', {index: _index, pastIndex: _pastSelected});

				}

			}

			function toggle(){

				if(vm.opened){

					vm.opened = false;
					$scope.$broadcast('close-dropdown');

				}else{

					vm.opened = true;
					$scope.$broadcast('open-dropdown');

				}

			}

			function open(){

				vm.opened = true;
				$scope.$broadcast('open-dropdown');

			}

			function close(){

				vm.opened = false;
				$scope.$broadcast('close-dropdown');

			}

		}

		function postLink($scope, $element, attrs, ctrl){

			var options;
			var openedClass = 'opened';
			var selectedClass = 'selected';
			var eventId = Math.round(Math.random() * 1000);

			if(ctrl.openedClass){
				var openedClass = ctrl.openedClass;
			}

			if(ctrl.selectedClass){
				var selectedClass = ctrl.selectedClass;
			}

			$scope.$on('open-dropdown', open);
			$scope.$on('close-dropdown', close);
			$scope.$on('option-selected', select);
			$scope.$on('option-selected', ctrl.close);
			$scope.$on('dropdown-open', openEvt);
			$scope.$on('dropdown-close', closeEvt);
			$scope.$on('select-option', selectEvt);
			$scope.$on('$destroy', destroy);

			$element.on('click', elementClick);
			$document.on('click', ctrl.close);

			//init
			$timeout(function(){

				options = $element.find('li');
				options.eq(ctrl.value).addClass(selectedClass);

			});

			function select($evt, data){

				options.eq(data.index).addClass(selectedClass);
				options.eq(data.pastIndex).removeClass(selectedClass);

			}

			function open(){

				$element.addClass(openedClass);

			}

			function close(){

				$element.removeClass(openedClass);

			}

			function elementClick(evt){

				evt.stopPropagation();

			}

			function selectEvt($evt, data){

				if(ctrl.name === data.name){

					$scope.$apply(function(){

						ctrl.selectOption(data.index);

					});

				}

			}

			function openEvt($evt, data){

				if(ctrl.name === data.name){

					ctrl.open();

				}

			}

			function closeEvt($evt, data){

				if(ctrl.name === data.name){

					ctrl.close();

				}

			}

			function destroy(){

				$document.off('click');

			}

		}

	}

})();<commit_msg>Improve scope events names and unregisters upon directive destroy<commit_after>'use strict';
/**
 * @author Rafael Violato (http://rviolato.com)
 */

(function(){

	angular.module('pg-ng-dropdown', [])
		.directive('pgNgDropdown', dropdownDirective);

	dropdownDirective.$inject = ['$timeout', '$document'];

	function dropdownDirective($timeout, $document){

		var template = [

			'
',
				'
',
						'',
						'',
						'',
						'',
						'
',
							'

',
						'
',
				'
',
				'
',
					'
',
						'',
						'',
						'',
						'',
					'
',
				'
',
		    '
',

		].join('');

		var directive = {

			scope: {
				data: '=options',
				image: '@imageOptions',
				imageProperty: '@',
				value: '@selected',
				name: '@',
				textProperty: '@',
				openedClass: '@',
				selectedClass: '@',
				onchange: '&',
			},
			restrict: 'AEC',
			compile: compile,
			controller: controller,
			controllerAs: 'ctrl',
			bindToController: true,
			replace: true,
			template: template,

		};

		return directive;

		function compile($element, attrs){

			attrs.value = attrs.value || 0;
			attrs.textProperty = attrs.textProperty || 'text';
			attrs.imageProperty = attrs.imagetProperty || 'image';

			return {
				post: postLink,
			};

		}

		function controller($scope){

			var vm = this;

			vm.opened = false;

			vm.selectOption = selectOption;
			vm.open = open;
			vm.close = close;
			vm.toggle = toggle;

			if((typeof vm.value) === 'number'){

				vm.data[vm.value].selected = true;

			}

			function selectOption(_index){

				if(_index !== parseInt(vm.value)){

					var _pastSelected = vm.value;

					_index = parseInt(_index);

					vm.value = _index;
					vm.data[_index].selected = true;

					if(vm.data[_pastSelected]){

						delete vm.data[_pastSelected].selected;

					}

					vm.onchange();

					$scope.$broadcast('pg-option-selected', {index: _index, pastIndex: _pastSelected});

				}

			}

			function toggle(){

				if(vm.opened){

					vm.opened = false;
					$scope.$broadcast('pg-close-dropdown');

				}else{

					vm.opened = true;
					$scope.$broadcast('pg-open-dropdown');

				}

			}

			function open(){

				vm.opened = true;
				$scope.$broadcast('pg-open-dropdown');

			}

			function close(){

				vm.opened = false;
				$scope.$broadcast('pg-close-dropdown');

			}

		}

		function postLink($scope, $element, attrs, ctrl){

			var options;
			var openedClass = 'opened';
			var selectedClass = 'selected';
			var eventId = Math.round(Math.random() * 1000);

			if(ctrl.openedClass){
				var openedClass = ctrl.openedClass;
			}

			if(ctrl.selectedClass){
				var selectedClass = ctrl.selectedClass;
			}

			var $open = $scope.$on('pg-open-dropdown', open);
			var $close = $scope.$on('pg-close-dropdown', close);
			var $openThis = $scope.$on('pg-dropdown-open', openEvt);
			var $closeThis = $scope.$on('pg-dropdown-close', closeEvt);
			var $selectThis = $scope.$on('pg-select-option', selectEvt);
			var $select = $scope.$on('pg-option-selected', function($evt, data){

				select($evt, data);
				ctrl.close();

			});

			$element.on('click', elementClick);
			$document.on('click', ctrl.close);
			$scope.$on('$destroy', destroy);

			//init
			$timeout(function(){

				options = $element.find('li');
				options.eq(ctrl.value).addClass(selectedClass);

			});

			function select($evt, data){

				options.eq(data.index).addClass(selectedClass);
				options.eq(data.pastIndex).removeClass(selectedClass);

			}

			function open(){

				$element.addClass(openedClass);

			}

			function close(){

				$element.removeClass(openedClass);

			}

			function elementClick(evt){

				evt.stopPropagation();

			}

			function selectEvt($evt, data){

				if(ctrl.name === data.name){

					$scope.$apply(function(){

						ctrl.selectOption(data.index);

					});

				}

			}

			function openEvt($evt, data){

				if(ctrl.name === data.name){

					ctrl.open();

				}

			}

			function closeEvt($evt, data){

				if(ctrl.name === data.name){

					ctrl.close();

				}

			}

			function destroy(){

				$document.off('click');
				$open();
				$close();
				$select();
				$closeThis();
				$openThis();
				$selectThis

			}

		}

	}

})();<|endoftext|>