Compare commits

...

13 Commits

5 changed files with 203 additions and 46 deletions

3
.gitignore vendored
View File

@ -59,3 +59,6 @@ typings/
/public/uploads /public/uploads
/package-lock.json /package-lock.json
# WebStorm config files
/.idea/

View File

@ -1,9 +1,10 @@
body { body {
position: relative; position: relative;
margin: 0px; margin: 0px;
height: calc(var(--vh, 1vh) * 100); /* height: calc(var(--vh, 1vh) * 100);*/
height: 10000px;
width: 100%; width: 100%;
overflow: hidden; overflow: scroll;
} }
#whiteboardContainer { #whiteboardContainer {

View File

@ -38,11 +38,8 @@
</head> </head>
<body> <body>
<!---Whiteboard container -!-->
<div id="whiteboardContainer"></div>
<!---Toolbar -!--> <!---Toolbar -!-->
<div id="toolbar" style="position: absolute; top: 10px; left: 10px;"> <div id="toolbar" style="position: -webkit-sticky; position: sticky; top: 10px; left: 10px; z-index: 1;">
<div class="btn-group"> <div class="btn-group">
<button id="whiteboardTrashBtn" title="Clear the whiteboard" type="button" class="whiteboardBtn"> <button id="whiteboardTrashBtn" title="Clear the whiteboard" type="button" class="whiteboardBtn">
<i class="fa fa-trash"></i> <i class="fa fa-trash"></i>
@ -125,14 +122,21 @@
</div> </div>
<div class="btn-group"> <div class="btn-group">
<button id="addImgToCanvasBtn" title="Upload Image to whiteboard" type="button" class="whiteboardBtn"> <button id="addImgToCanvasBtn" title="Upload Image to whiteboard" type="button" class="whiteboardBtn">
<i class="fas fa-image"></i> <i class="fas fa-image"></i>
<i style="position: absolute; top: 3px; left: 2px; color: #000000; font-size: 0.5em; " <i style="position: absolute; top: 3px; left: 2px; color: #000000; font-size: 0.5em; "
class="fas fa-upload"></i> class="fas fa-upload"></i>
</button> </button>
<button style="position: relative;" id="uploadJsonBtn" title="Load saved JSON to whiteboard" type="button" <button style="position: relative;" id="addPageBtn" title="Add a page to this canvas" type="button" class="whiteboardBtn">
class="whiteboardBtn">
<i class="far fa-file-alt"></i>
<i style="position: absolute; top: 3px; left: 2px; color: #000000; font-size: 0.5em; "
class="fas fa-upload"></i>
</button>
<button style="position: relative;" id="uploadJsonBtn" title="Load saved JSON to whiteboard" type="button" class="whiteboardBtn">
<i class="far fa-file-alt"></i> <i class="far fa-file-alt"></i>
<i style="position: absolute; top: 3px; left: 2px; color: #000000; font-size: 0.5em; " <i style="position: absolute; top: 3px; left: 2px; color: #000000; font-size: 0.5em; "
@ -151,6 +155,11 @@
<i id="maxBtn" style="position:relative; left:-5px; display: none;" class="fas fa-angle-right"></i> <i id="maxBtn" style="position:relative; left:-5px; display: none;" class="fas fa-angle-right"></i>
</button> </button>
</div> </div>
</div>
<!---Whiteboard container -!-->
<div id="whiteboardContainer" style="z-index: 0;"></div>
</body> </body>
</html> </html>

View File

@ -56,6 +56,11 @@ signaling_socket.on('connect', function () {
whiteboard.updateSmallestScreenResolution(widthHeight["w"], widthHeight["h"]); whiteboard.updateSmallestScreenResolution(widthHeight["w"], widthHeight["h"]);
}); });
signaling_socket.on('updateBiggestScreenResolution', function (widthHeight) {
//whiteboard.updateSmallestScreenResolution(widthHeight["w"], widthHeight["h"]);
// todo: implement biggest resolution check & update
});
signaling_socket.emit('joinWhiteboard', { wid: whiteboardId, at: accessToken, windowWidthHeight: { w: $(window).width(), h: $(window).height() } }); signaling_socket.emit('joinWhiteboard', { wid: whiteboardId, at: accessToken, windowWidthHeight: { w: $(window).width(), h: $(window).height() } });
}); });
@ -379,6 +384,11 @@ $(document).ready(function () {
}) })
}); });
// add page
$("#addPageBtn").click(function () {
whiteboard.addPage();
});
// upload json containing steps // upload json containing steps
$("#uploadJsonBtn").click(function () { $("#uploadJsonBtn").click(function () {
$("#myFile").click(); $("#myFile").click();

View File

@ -1,4 +1,9 @@
let biggestWidth = 1920;
let biggestHeight = 10000;
let pages = 1;
var whiteboard = { var whiteboard = {
isMultiTouch: false,
canvas: null, canvas: null,
ctx: null, ctx: null,
drawcolor: "black", drawcolor: "black",
@ -43,22 +48,49 @@ var whiteboard = {
this.settings["username"] = this.settings["username"].replace(/[^0-9a-z]/gi, ''); this.settings["username"] = this.settings["username"].replace(/[^0-9a-z]/gi, '');
this.settings["whiteboardId"] = this.settings["whiteboardId"].replace(/[^0-9a-z]/gi, ''); this.settings["whiteboardId"] = this.settings["whiteboardId"].replace(/[^0-9a-z]/gi, '');
var width = biggestWidth;
var height = biggestHeight;
/*var width = $(window).width();
if(width > biggestWidth)
{
biggestWidth = width;
}
else
{
width = biggestWidth;
}
var height = $(window).height();
console.info("height: " + height);
if(height > biggestHeight)
{
biggestHeight = height;
}
else
{
height = biggestHeight;
}*/
//console.info("height new: " + height);
//_this.sendFunction({ "t": "refreshEveryoneScreenSize" });
//background grid (repeating image) and smallest screen indication //background grid (repeating image) and smallest screen indication
_this.backgroundGrid = $('<div style="position: absolute; left:0px; top:0; opacity: 0.2; background-image:url(\'' + _this.settings["backgroundGridUrl"] + '\'); height: 100%; width: 100%;"></div>'); _this.backgroundGrid = $('<div style="position: absolute; left:0px; top:0; opacity: 0.2; background-image:url(\'' + _this.settings["backgroundGridUrl"] + '\'); height: ' + height + 'px; width: ' + width + 'px;"></div>');
// container for background images // container for background images
_this.imgContainer = $('<div style="position: absolute; left:0px; top:0; height: 100%; width: 100%;"></div>'); _this.imgContainer = $('<div style="position: absolute; left:0px; top:0; height: ' + height + 'px; width: ' + width + 'px;"></div>');
// whiteboard canvas // whiteboard canvas
_this.canvasElement = $('<canvas id="whiteboardCanvas" style="position: absolute; left:0px; top:0; cursor:crosshair;"></canvas>'); _this.canvasElement = $('<canvas id="whiteboardCanvas" style="position: absolute; left:0px; top:0; cursor:crosshair;"></canvas>');
// SVG container holding drawing or moving previews // SVG container holding drawing or moving previews
_this.svgContainer = $('<svg style="position: absolute; top:0px; left:0px;" width="100%" height="100%"></svg>'); _this.svgContainer = $('<svg style="position: absolute; top: 0px; left:0px; width:' + width + 'px; height: ' + height + 'px;"></svg>');
// drag and drop indicator, hidden by default // drag and drop indicator, hidden by default
_this.dropIndicator = $('<div style="position:absolute; height: 100%; width: 100%; border: 7px dashed gray; text-align: center; top: 0px; left: 0px; color: gray; font-size: 23em; display: none;"><i class="far fa-plus-square" aria-hidden="true"></i></div>') _this.dropIndicator = $('<div style="position:absolute; height: ' + height + 'px; width: ' + width + 'px; border: 7px dashed gray; text-align: center; top: 0px; left: 0px; color: gray; font-size: 23em; display: none;"><i class="far fa-plus-square" aria-hidden="true"></i></div>')
// container for other users cursors // container for other users cursors
_this.cursorContainer = $('<div style="position: absolute; left:0px; top:0; height: 100%; width: 100%;"></div>'); _this.cursorContainer = $('<div style="position: absolute; left:0px; top:0; height: ' + height + 'px; width: ' + width + 'px;"></div>');
// container for texts by users // container for texts by users
_this.textContainer = $('<div class="textcontainer" style="position: absolute; left:0px; top:0; height: 100%; width: 100%; cursor:text;"></div>'); _this.textContainer = $('<div class="textcontainer" style="position: absolute; left:0px; top:0; height: ' + height + 'px; width: ' + width + 'px; cursor:text;"></div>');
// mouse overlay for draw callbacks // mouse overlay for draw callbacks
_this.mouseOverlay = $('<div style="cursor:none; position: absolute; left:0px; top:0; height: 100%; width: 100%;"></div>'); _this.mouseOverlay = $('<div style="cursor:none; position: absolute; left:0px; top:0; height: ' + height + 'px; width: ' + width + 'px;"></div>');
$(whiteboardContainer).append(_this.backgroundGrid) $(whiteboardContainer).append(_this.backgroundGrid)
.append(_this.imgContainer) .append(_this.imgContainer)
@ -69,27 +101,43 @@ var whiteboard = {
.append(_this.textContainer) .append(_this.textContainer)
.append(_this.mouseOverlay); .append(_this.mouseOverlay);
this.canvas = $("#whiteboardCanvas")[0]; this.canvas = $("#whiteboardCanvas")[0];
this.canvas.height = $(window).height(); this.canvas.width = biggestWidth * pages;
this.canvas.width = $(window).width(); this.canvas.height = biggestHeight * pages;
this.ctx = this.canvas.getContext("2d"); this.ctx = this.canvas.getContext("2d");
this.oldGCO = this.ctx.globalCompositeOperation; this.oldGCO = this.ctx.globalCompositeOperation;
$(window).resize(function () { //Handel resize $(window).resize(function () { //Handle resize
var dbCp = JSON.parse(JSON.stringify(_this.drawBuffer)); //Copy the buffer var dbCp = JSON.parse(JSON.stringify(_this.drawBuffer)); //Copy the buffer
_this.canvas.width = $(window).width(); _this.canvas.width = biggestWidth * pages;
_this.canvas.height = $(window).height(); //Set new canvas height _this.canvas.height = biggestHeight * pages; //Set new canvas height
_this.drawBuffer = []; _this.drawBuffer = [];
_this.loadData(dbCp); //draw old content in _this.loadData(dbCp); //draw old content in
}); });
$(_this.mouseOverlay).on( "mousedown touchstart", function (e) { $(_this.mouseOverlay).on( "mousedown touchstart", function (e) {
if (_this.imgDragActive || _this.drawFlag) { if (_this.imgDragActive || _this.drawFlag) {
return; return;
} }
var loc;
if(e.type === "touchstart")
{
loc = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
if (e.touches.length > 1) {
_this.isMultiTouch = true;
return; // if more than one finger is touching the screen, dont draw
}
}
else
{
loc = e;
}
_this.drawFlag = true; _this.drawFlag = true;
_this.prevX = (e.offsetX || e.pageX - $(e.target).offset().left) + 1; _this.prevX = (loc.offsetX || loc.pageX - $(e.target).offset().left) + 1;
_this.prevY = (e.offsetY || e.pageY - $(e.target).offset().top) + 1; _this.prevY = (loc.offsetY || loc.pageY - $(e.target).offset().top) + 1;
if (!_this.prevX || !_this.prevY || (_this.prevX == 1 && _this.prevY == 1)) { if (!_this.prevX || !_this.prevY || (_this.prevX == 1 && _this.prevY == 1)) {
var touche = e.touches[0]; var touche = e.touches[0];
_this.prevX = touche.clientX - $(_this.mouseOverlay).offset().left + 1; _this.prevX = touche.clientX - $(_this.mouseOverlay).offset().left + 1;
@ -101,7 +149,11 @@ var whiteboard = {
_this.penSmoothLastCoords = [_this.prevX, _this.prevY, _this.prevX, _this.prevY, _this.prevX, _this.prevY] _this.penSmoothLastCoords = [_this.prevX, _this.prevY, _this.prevX, _this.prevY, _this.prevX, _this.prevY]
} else if (_this.tool === "eraser") { } else if (_this.tool === "eraser") {
_this.drawEraserLine(_this.prevX, _this.prevY, _this.prevX, _this.prevY, _this.thickness); _this.drawEraserLine(_this.prevX, _this.prevY, _this.prevX, _this.prevY, _this.thickness);
_this.sendFunction({ "t": _this.tool, "d": [_this.prevX, _this.prevY, _this.prevX, _this.prevY], "th": _this.thickness }); _this.sendFunction({
"t": _this.tool,
"d": [_this.prevX, _this.prevY, _this.prevX, _this.prevY],
"th": _this.thickness
});
} else if (_this.tool === "line") { } else if (_this.tool === "line") {
_this.startCoords = [_this.prevX, _this.prevY]; _this.startCoords = [_this.prevX, _this.prevY];
_this.svgLine = document.createElementNS(svgns, 'line'); _this.svgLine = document.createElementNS(svgns, 'line');
@ -137,39 +189,82 @@ var whiteboard = {
} }
}); });
_this.textContainer.on("mousemove touchmove", function (e) { _this.textContainer.on("mousemove touchmove", function (e) {
var loc;
if(e.type === "touchmove")
{
loc = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
if (e.touches.length > 1) {
_this.isMultiTouch = true;
return; // if more than one finger is touching the screen, dont draw
}
}
else
{
loc = e;
}
var currX = (loc.offsetX || loc.pageX - $(e.target).offset().left);
var currY = (loc.offsetY || loc.pageY - $(e.target).offset().top);
e.preventDefault(); e.preventDefault();
if (_this.imgDragActive || !$(e.target).hasClass("textcontainer")) { if (_this.imgDragActive || !$(e.target).hasClass("textcontainer")) {
return; return;
} }
var currX = (e.offsetX || e.pageX - $(e.target).offset().left); _this.sendFunction({
var currY = (e.offsetY || e.pageY - $(e.target).offset().top); "t": "cursor",
_this.sendFunction({ "t": "cursor", "event": "move", "d": [currX, currY], "username": _this.settings.username }); "event": "move",
}) "d": [currX, currY],
"username": _this.settings.username
});
});
_this.mouseOverlay.on("mousemove touchmove", function (e) { _this.mouseOverlay.on("mousemove touchmove", function (e) {
e.preventDefault();
_this.triggerMouseMove(e); _this.triggerMouseMove(e);
}); });
_this.mouseOverlay.on("mouseup touchend touchcancel", function (e) { _this.mouseOverlay.on("mouseup touchend touchcancel", function (e) {
var isTouch = false;
var loc;
if(e.type === "touchend" || e.type === "touchcancel")
{
isTouch = true;
loc = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
}
else
{
loc = e;
}
if (_this.imgDragActive) { if (_this.imgDragActive) {
return; return;
} }
_this.drawFlag = false; _this.drawFlag = false;
_this.drawId++; _this.drawId++;
_this.ctx.globalCompositeOperation = _this.oldGCO; _this.ctx.globalCompositeOperation = _this.oldGCO;
var currX = (e.offsetX || e.pageX - $(e.target).offset().left); var currX = (loc.offsetX || loc.pageX - $(e.target).offset().left);
var currY = (e.offsetY || e.pageY - $(e.target).offset().top); var currY = (loc.offsetY || loc.pageY - $(e.target).offset().top);
if (!currX || !currY) { if (!currX || !currY) {
currX = _this.latestTouchCoods[0]; currX = _this.latestTouchCoods[0];
currY = _this.latestTouchCoods[1]; currY = _this.latestTouchCoods[1];
_this.sendFunction({"t": "cursor", "event": "out", "username": _this.settings.username}); _this.sendFunction({"t": "cursor", "event": "out", "username": _this.settings.username});
} }
if(isTouch)
{
if (_this.isMultiTouch) {
if (e.touches.length === 0) {
_this.isMultiTouch = false;
}
return; // if more than one finger is touching the screen, dont draw
}
}
if (_this.tool === "line") { if (_this.tool === "line") {
if (_this.pressedKeys.shift) { if (_this.pressedKeys.shift) {
var angs = _this.getRoundedAngles(currX, currY); var angs = _this.getRoundedAngles(currX, currY);
@ -177,7 +272,12 @@ var whiteboard = {
currY = angs.y; currY = angs.y;
} }
_this.drawPenLine(currX, currY, _this.startCoords[0], _this.startCoords[1], _this.drawcolor, _this.thickness); _this.drawPenLine(currX, currY, _this.startCoords[0], _this.startCoords[1], _this.drawcolor, _this.thickness);
_this.sendFunction({ "t": _this.tool, "d": [currX, currY, _this.startCoords[0], _this.startCoords[1]], "c": _this.drawcolor, "th": _this.thickness }); _this.sendFunction({
"t": _this.tool,
"d": [currX, currY, _this.startCoords[0], _this.startCoords[1]],
"c": _this.drawcolor,
"th": _this.thickness
});
_this.svgContainer.find("line").remove(); _this.svgContainer.find("line").remove();
} else if (_this.tool === "pen") { } else if (_this.tool === "pen") {
_this.pushPointSmoothPen(currX, currY); _this.pushPointSmoothPen(currX, currY);
@ -190,14 +290,24 @@ var whiteboard = {
} }
} }
_this.drawRec(_this.startCoords[0], _this.startCoords[1], currX, currY, _this.drawcolor, _this.thickness); _this.drawRec(_this.startCoords[0], _this.startCoords[1], currX, currY, _this.drawcolor, _this.thickness);
_this.sendFunction({ "t": _this.tool, "d": [_this.startCoords[0], _this.startCoords[1], currX, currY], "c": _this.drawcolor, "th": _this.thickness }); _this.sendFunction({
"t": _this.tool,
"d": [_this.startCoords[0], _this.startCoords[1], currX, currY],
"c": _this.drawcolor,
"th": _this.thickness
});
_this.svgContainer.find("rect").remove(); _this.svgContainer.find("rect").remove();
} else if (_this.tool === "circle") { } else if (_this.tool === "circle") {
var a = currX - _this.startCoords[0]; var a = currX - _this.startCoords[0];
var b = currY - _this.startCoords[1]; var b = currY - _this.startCoords[1];
var r = Math.sqrt(a * a + b * b); var r = Math.sqrt(a * a + b * b);
_this.drawCircle(_this.startCoords[0], _this.startCoords[1], r, _this.drawcolor, _this.thickness); _this.drawCircle(_this.startCoords[0], _this.startCoords[1], r, _this.drawcolor, _this.thickness);
_this.sendFunction({ "t": _this.tool, "d": [_this.startCoords[0], _this.startCoords[1], r], "c": _this.drawcolor, "th": _this.thickness }); _this.sendFunction({
"t": _this.tool,
"d": [_this.startCoords[0], _this.startCoords[1], r],
"c": _this.drawcolor,
"th": _this.thickness
});
_this.svgContainer.find("circle").remove(); _this.svgContainer.find("circle").remove();
} else if (_this.tool === "recSelect") { } else if (_this.tool === "recSelect") {
_this.imgDragActive = true; _this.imgDragActive = true;
@ -250,7 +360,6 @@ var whiteboard = {
_this.svgContainer.find("rect").remove(); _this.svgContainer.find("rect").remove();
} }
}); });
_this.mouseOverlay.on("mouseout", function (e) { _this.mouseOverlay.on("mouseout", function (e) {
_this.triggerMouseOut(); _this.triggerMouseOut();
}); });
@ -269,6 +378,7 @@ var whiteboard = {
_this.addTextBox(_this.drawcolor, fontsize, currX, currY, txId, true); _this.addTextBox(_this.drawcolor, fontsize, currX, currY, txId, true);
}); });
}, },
getRoundedAngles: function (currX, currY) { //For drawing lines at 0,45,90° .... getRoundedAngles: function (currX, currY) { //For drawing lines at 0,45,90° ....
var _this = this; var _this = this;
var x = currX - _this.startCoords[0]; var x = currX - _this.startCoords[0];
@ -291,18 +401,33 @@ var whiteboard = {
return { "x": currX, "y": currY }; return { "x": currX, "y": currY };
}, },
triggerMouseMove: function (e) { triggerMouseMove: function (e) {
var _this = this; var _this = this;
var loc;
if(e.type === "touchmove")
{
loc = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
if (e.touches.length > 1) {
_this.isMultiTouch = true;
return; // if more than one finger is touching the screen, dont draw
}
}
else
{
loc = e;
}
e.preventDefault();
if (_this.imgDragActive) { if (_this.imgDragActive) {
return; return;
} }
var currX = e.currX || (e.offsetX || e.pageX - $(e.target).offset().left);
var currY = e.currY || (e.offsetY || e.pageY - $(e.target).offset().top); var currX = loc.offsetX || loc.pageX - $(e.target).offset().left;
var currY = loc.offsetY || loc.pageY - $(e.target).offset().top;
window.requestAnimationFrame(function () { window.requestAnimationFrame(function () {
if ((!currX || !currY) && e.touches && e.touches[0]) {
var touche = e.touches[0];
currX = touche.clientX - $(_this.mouseOverlay).offset().left;
currY = touche.clientY - $(_this.mouseOverlay).offset().top;
}
_this.latestTouchCoods = [currX, currY]; _this.latestTouchCoods = [currX, currY];
if (_this.drawFlag) { if (_this.drawFlag) {
@ -533,6 +658,10 @@ var whiteboard = {
_this.drawBuffer = []; _this.drawBuffer = [];
_this.drawId = 0; _this.drawId = 0;
}, },
addPage: function () {
pages += 1;
},
setStrokeThickness(thickness) { setStrokeThickness(thickness) {
var _this = this; var _this = this;
_this.thickness = thickness; _this.thickness = thickness;
@ -909,6 +1038,11 @@ var whiteboard = {
if (["line", "pen", "rect", "circle", "eraser", "addImgBG", "recSelect", "eraseRec", "addTextBox", "setTextboxText", "removeTextbox", "setTextboxPosition", "setTextboxFontSize", "setTextboxFontColor"].includes(tool)) { if (["line", "pen", "rect", "circle", "eraser", "addImgBG", "recSelect", "eraseRec", "addTextBox", "setTextboxText", "removeTextbox", "setTextboxPosition", "setTextboxFontSize", "setTextboxFontColor"].includes(tool)) {
_this.drawBuffer.push(content); _this.drawBuffer.push(content);
} }
/*if(["refreshEveryoneScreenSize"].includes(tool)) {
console.info("refreshing size: " + biggestWidth + ", " + biggestHeight);
_this.canvas.width = biggestWidth * pages;
_this.canvas.height = biggestHeight * pages;
}*/
}, },
refreshCursorAppearance() { //Set cursor depending on current active tool refreshCursorAppearance() { //Set cursor depending on current active tool
var _this = this; var _this = this;