"use strict";
import {Pointer} from "./input/Pointer.js";
/**
* The renderer is resposible for drawing the structure into the canvas element.
*
* Its also resposible for managing the canvas state.
*
* @class
*/
function Renderer(canvas)
{
/**
* Canvas DOM element, has to be managed by the user.
*/
this.canvas = canvas;
/**
* Canvas 2D rendering context used to draw content.
*/
this.context = canvas.getContext("2d");
this.context.imageSmoothingEnabled = true;
this.context.globalCompositeOperation = "source-over";
/**
* Pointer input handler object.
*/
this.pointer = new Pointer();
this.pointer.setCanvas(canvas);
}
/**
* Update the renderer state, update the input handlers, calculate the object and viewport transformation matrices.
*
* Render the object using the viewport into a canvas element.
*
* The canvas state is saved and restored for each individual object, ensuring that the code of one object does not affect another one.
*
* Should be called at a fixed rate preferably using the requestAnimationFrame() method.
*
* @param object Object to be updated.
* @param viewport Viewport to be updated (should be the one where the objects will be rendered after).
*/
Renderer.prototype.update = function(object, viewport)
{
// Get objects to be rendered
var objects = []
object.traverse(function(child)
{
if(child.visible)
{
objects.push(child);
}
});
// Sort objects by layer
objects.sort(function(a, b)
{
return b.layer - a.layer;
});
// Pointer object update
var pointer = this.pointer;
pointer.update();
// Viewport transform matrix
viewport.updateControls(pointer);
viewport.updateMatrix();
// Project pointer coordinates
var point = pointer.position.clone();
var viewportPoint = viewport.inverseMatrix.transformPoint(point);
// Object transformation matrices
for(var i = 0; i < objects.length; i++)
{
var child = objects[i];
var childPoint = child.inverseGlobalMatrix.transformPoint(viewportPoint);
// Check if the pointer pointer is inside
if(child.isInside(childPoint))
{
// Pointer enter
if(!child.pointerInside && child.onPointerEnter !== null)
{
child.onPointerEnter(pointer, viewport);
}
// Pointer over
if(child.onPointerOver !== null)
{
child.onPointerOver(pointer, viewport);
}
// Pointer just pressed
if(pointer.buttonJustPressed(Pointer.LEFT))
{
if(child.onButtonDown !== null)
{
child.onButtonDown(pointer, viewport);
}
if(child.draggable)
{
child.beingDragged = true;
break;
}
}
// Pointer pressed
if(pointer.buttonPressed(Pointer.LEFT) && child.onButtonPressed !== null)
{
child.onButtonPressed(pointer, viewport);
}
// Just released
if(pointer.buttonJustReleased(Pointer.LEFT) && child.onButtonUp !== null)
{
child.onButtonUp(pointer, viewport);
}
child.pointerInside = true;
}
else if(child.pointerInside)
{
// Pointer leave
if(child.onPointerLeave !== null)
{
child.onPointerLeave(pointer, viewport);
}
child.pointerInside = false;
}
// Stop object drag
if(pointer.buttonJustReleased(Pointer.LEFT))
{
if(child.draggable)
{
child.beingDragged = false;
}
}
}
// Pointer drag event
for(var i = 0; i < objects.length; i++)
{
var child = objects[i];
if(child.beingDragged)
{
var matrix = viewport.inverseMatrix.clone();
matrix.multiply(child.inverseGlobalMatrix);
matrix.setPosition(0, 0);
var delta = matrix.transformPoint(pointer.delta);
child.position.add(delta);
if(child.onPointerDrag !== null)
{
child.onPointerDrag(pointer, viewport, delta);
}
}
// On update
if(child.onUpdate !== null)
{
child.onUpdate();
}
child.updateMatrix();
}
// Sort objects by layer
objects.sort(function(a, b)
{
return a.layer - b.layer;
});
// Render the content
var context = this.context;
// Clear canvas
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Set viewport matrix transform
viewport.matrix.setContextTransform(context);
// Render into the canvas
for(var i = 0; i < objects.length; i++)
{
context.save();
objects[i].globalMatrix.tranformContext(context);
objects[i].draw(context);
context.restore();
}
};
export {Renderer};