1
0
Fork 0
Nibriboard/Nibriboard/ClientFiles/Pencil.js

228 lines
6.3 KiB
JavaScript
Raw Normal View History

"use strict";
import cuid from "cuid";
import { simplify_line } from "visvalingam-simplifier";
2017-04-14 19:22:01 +00:00
import Vector from './Utilities/Vector';
import Mouse from './Utilities/Mouse';
class Pencil
{
/**
* Creates a new Pencil class instance.
* @param {RippleLink} inRippleLink The connection to the nibri server.
* @return {Pencil} A new Pencil class instance.
*/
constructor(inRippleLink, inBoardWindow, inCanvas)
{
2017-04-15 12:13:07 +00:00
this.boardWindow = inBoardWindow;
2017-04-14 19:22:01 +00:00
// The time, in milliseconds, between pushes of the line to the server.
this.pushDelay = 200;
2017-04-15 12:13:07 +00:00
// The current line width
this.currentLineWidth = 3;
// The current line colour
this.currentColour = "black";
2017-04-14 19:22:01 +00:00
/**
* The ripple link connection to the server.
* @type {RippleLink}
*/
this.rippleLink = inRippleLink;
/**
* The mouse information.
* @type {Mouse}
*/
this.mouse = new Mouse();
2017-10-29 21:26:49 +00:00
/** The id of the current line-in-progress.*/
2017-04-14 19:22:01 +00:00
this.currentLineId = cuid();
2017-10-29 21:26:49 +00:00
/** Holds the (unsimplified) line segments before the pencil is lifted. */
2017-04-14 19:22:01 +00:00
this.currentLineSegments = [];
/** Holds the (simplified) line segment befoer the pencil is lifted. */
this.currentSimplifiedLineSegments = [];
2017-04-14 19:22:01 +00:00
// The segments of the (unsimplified) line that haven't yet been sent
// to the server.
this.unsentSegments = [];
2017-04-14 19:22:01 +00:00
// The time of the last push of the line to the server.
this.lastServerPush = 0;
this.canvas = inCanvas;
2017-04-28 11:42:34 +00:00
// Event Listeners
document.addEventListener("mousedown", this.handleMouseDown.bind(this));
document.addEventListener("mousemove", this.handleMouseMove.bind(this));
document.addEventListener("mouseup", this.handleMouseUp.bind(this));
2017-04-28 11:42:34 +00:00
this.setupInterfaceBindings(this.boardWindow.interface);
// Whether the pencil is on the board at the moment.
this.pencilDown = false;
}
setupInterfaceBindings(inInterface)
{
// Snag the initial colour from the interface
2017-11-14 15:16:22 +00:00
this.currentColour = inInterface.brushIndicator.colour;
// Listen for future colour updates
inInterface.on("colourchange", (function(event) {
2017-04-28 11:42:34 +00:00
this.currentColour = event.newColour;
}).bind(this))
// Look up the initial line with in the interface
this.currentLineWidth = inInterface.brushIndicator.width;
// Listen for future updates fromt he interface
inInterface.on("brushwidthchange", (function(event) {
this.currentLineWidth = event.newWidth;
}).bind(this))
2017-04-14 19:22:01 +00:00
}
handleMouseDown(event) {
if(event.target != this.canvas)
return;
switch(this.boardWindow.interface.currentTool)
{
case "brush": // Put the pencil down and start the new line
this.pencilDown = true;
console.log(`Starting line with id ${this.currentLineId}.`);
this.rippleLink.send({
Event: "LineStart",
LineId: this.currentLineId,
LineColour: this.currentColour,
LineWidth: this.currentLineWidth
});
break;
}
}
handleMouseMove(event) {
// Don't handle mouse movements on anything other than the canvas itself
if(event.target != this.canvas)
return;
// Don't draw anything if the left mouse button isn't down
if(/*!this.mouse.leftDown || (is this really needed?)*/ !this.pencilDown)
return;
switch(this.boardWindow.interface.currentTool)
{
case "brush":
// The server only supports ints atm, so we have to round here :-(
// TODO: Lift this limit
var nextPoint = new Vector(
Math.floor((event.clientX / this.boardWindow.viewport.zoomLevel) + this.boardWindow.viewport.x),
Math.floor((event.clientY / this.boardWindow.viewport.zoomLevel) + this.boardWindow.viewport.y)
);
this.unsentSegments.push(nextPoint);
this.currentLineSegments.push(nextPoint);
this.recalculateSimplifiedLine();
var timeSinceLastPush = new Date() - this.lastServerPush;
if(timeSinceLastPush > this.pushDelay)
this.sendUnsent();
break;
case "pan":
// handled by BoardWindow.handleCanvasMovement(event)
break;
case "pointer":
// Don't need to do anything here!
break;
default:
console.warn(`Unknown tool ${this.boardWindow.interface.currentTool}.`);
break;
}
2017-04-14 19:22:01 +00:00
}
handleMouseUp(event) {
2017-06-26 15:57:26 +00:00
// Don't do anything at all if the brush tool isn't selected
if(this.boardWindow.interface.currentTool !== "brush")
return;
// Ignore it if the ctrl key is held down - see above
if(this.boardWindow.keyboard.DownKeys.includes(17))
return;
2017-04-16 15:51:52 +00:00
this.sendUnsent();
// Tell the server that the line is complete
this.rippleLink.send({
Event: "LineComplete",
LineId: this.currentLineId
});
this.pencilDown = false;
2017-04-15 12:13:07 +00:00
// Reset the current line segments
2017-04-14 19:22:01 +00:00
this.currentLineSegments = [];
this.currentSimplifiedLineSegments = [];
2017-04-14 19:22:01 +00:00
// Regenerate the line id
this.currentLineId = cuid();
}
/**
* Send the unsent segments of the line to the server and reset the line
* unsent segments buffer.
*/
sendUnsent() {
2017-04-23 17:16:18 +00:00
// Don't bother if there aren't any segments to push
if(this.unsentSegments.length == 0)
return;
2017-04-14 19:22:01 +00:00
// It's time for another push of the line to the server
this.rippleLink.send({
Event: "LinePart",
Points: this.unsentSegments,
LineId: this.currentLineId
});
// Reset the unsent segments buffer
this.unsentSegments = [];
2017-04-23 17:16:18 +00:00
// Update the time we last pushed to the server
this.lastServerPush = +new Date();
2017-04-14 19:22:01 +00:00
}
/**
* Recalculates the simplified line points array.
*/
recalculateSimplifiedLine()
{
2017-11-14 15:03:39 +00:00
this.currentSimplifiedLineSegments = simplify_line(this.currentLineSegments, 6);
}
/**
* Renders the line that is currently being drawn to the screen.
* @param {HTMLCanvasElement} canvas The canvas to draw to.
* @param {CanvasRenderingContext2D} context The rendering context to use to draw to the canvas.
*/
2017-06-12 19:46:50 +00:00
render(canvas, context) {
if(this.currentSimplifiedLineSegments.length == 0)
2017-04-15 12:13:07 +00:00
return;
context.save();
2017-04-15 12:13:07 +00:00
context.beginPath();
context.moveTo(this.currentSimplifiedLineSegments[0].x, this.currentSimplifiedLineSegments[0].y);
for(let i = 1; i < this.currentSimplifiedLineSegments.length; i++) {
context.lineTo(this.currentSimplifiedLineSegments[i].x, this.currentSimplifiedLineSegments[i].y);
2017-04-15 12:13:07 +00:00
}
context.lineWidth = this.currentLineWidth;
2017-04-15 12:13:07 +00:00
context.strokeStyle = this.currentColour;
context.lineCap = "round";
context.lineJoin = "round";
context.stroke();
2017-04-15 12:13:07 +00:00
context.restore();
}
}
2017-04-15 12:13:07 +00:00
export default Pencil;