refacto: moved to src
This commit is contained in:
16
src/entry.js
Normal file
16
src/entry.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import "./keybinds";
|
||||
import "./whiteboard";
|
||||
import "./main";
|
||||
import "../assets/css/main.css"
|
||||
|
||||
//Set correct width height on mobile browsers
|
||||
const isChrome = /Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor);
|
||||
if (isChrome) {
|
||||
$('head').append('<meta name="viewport" content="width=device-width, initial-scale=0.52, maximum-scale=1" />');
|
||||
} else {
|
||||
$('head').append('<meta name="viewport" content="width=1400" />');
|
||||
}
|
||||
|
||||
if (module.hot) {
|
||||
module.hot.accept();
|
||||
}
|
||||
46
src/keybinds.js
Normal file
46
src/keybinds.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/* -----------
|
||||
KEYBINDINGS
|
||||
----------- */
|
||||
|
||||
//> defmod is "command" on OS X and "ctrl" elsewhere
|
||||
//Advanced Example: 'defmod-k j' -> For this to fire you have to first press both ctrl and k, and then j.
|
||||
|
||||
var keybinds = {
|
||||
// 'key(s)' : 'function',
|
||||
'defmod-shift-z' : 'clearWhiteboard',
|
||||
'defmod-z' : 'undoStep',
|
||||
'defmod-y' : 'redoStep',
|
||||
'defmod-x' : 'setTool_recSelect',
|
||||
'defmod-m' : 'setTool_mouse',
|
||||
'defmod-p' : 'setTool_pen',
|
||||
'defmod-l' : 'setTool_line',
|
||||
'defmod-r' : 'setTool_rect',
|
||||
'defmod-c' : 'setTool_circle',
|
||||
'defmod-shift-f' : 'toggleLineRecCircle',
|
||||
'defmod-shift-x' : 'togglePenEraser',
|
||||
'defmod-shift-r' : 'toggleMainColors',
|
||||
'defmod-a' : 'setTool_text',
|
||||
'defmod-e' : 'setTool_eraser',
|
||||
'defmod-up' : 'thickness_bigger',
|
||||
'defmod-down' : 'thickness_smaller',
|
||||
'defmod-shift-c' : 'openColorPicker',
|
||||
'defmod-shift-1' : 'setDrawColorBlack',
|
||||
'defmod-shift-2' : 'setDrawColorBlue',
|
||||
'defmod-shift-3' : 'setDrawColorGreen',
|
||||
'defmod-shift-4' : 'setDrawColorYellow',
|
||||
'defmod-shift-5' : 'setDrawColorRed',
|
||||
'defmod-s' : 'saveWhiteboardAsImage',
|
||||
'defmod-shift-k' : 'saveWhiteboardAsJson',
|
||||
'defmod-shift-i' : 'uploadWhiteboardToWebDav',
|
||||
'defmod-shift-j' : 'uploadJsonToWhiteboard',
|
||||
'defmod-shift-s' : 'shareWhiteboard',
|
||||
'tab' : 'hideShowControls',
|
||||
'up' : 'moveDraggableUp',
|
||||
'down' : 'moveDraggableDown',
|
||||
'left' : 'moveDraggableLeft',
|
||||
'right' : 'moveDraggableRight',
|
||||
'defmod-enter' : 'dropDraggable',
|
||||
'shift-enter' : 'addToBackground',
|
||||
'escape' : 'cancelAllActions',
|
||||
'del' : 'deleteSelection'
|
||||
}
|
||||
685
src/main.js
Normal file
685
src/main.js
Normal file
@@ -0,0 +1,685 @@
|
||||
import keymage from "keymage";
|
||||
|
||||
var whiteboardId = getQueryVariable("whiteboardid");
|
||||
var randomid = getQueryVariable("randomid");
|
||||
if (randomid && !whiteboardId) { //set random whiteboard on empty whiteboardid
|
||||
whiteboardId = Array(2).fill(null).map(() => Math.random().toString(36).substr(2)).join('');
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
urlParams.set('whiteboardid', whiteboardId);
|
||||
window.location.search = urlParams;
|
||||
}
|
||||
|
||||
whiteboardId = whiteboardId || "myNewWhiteboard";
|
||||
whiteboardId = unescape(encodeURIComponent(whiteboardId)).replace(/[^a-zA-Z0-9 ]/g, "");
|
||||
var myUsername = getQueryVariable("username");
|
||||
var accessToken = getQueryVariable("accesstoken");
|
||||
myUsername = myUsername || "unknown" + (Math.random() + "").substring(2, 6);
|
||||
accessToken = accessToken || "";
|
||||
var accessDenied = false;
|
||||
|
||||
// Custom Html Title
|
||||
var title = getQueryVariable("title");
|
||||
if (!title === false) {
|
||||
document.title = decodeURIComponent(title);
|
||||
}
|
||||
|
||||
var url = document.URL.substr(0, document.URL.lastIndexOf('/'));
|
||||
var signaling_socket = null;
|
||||
var urlSplit = url.split("/");
|
||||
var subdir = "";
|
||||
for (var i = 3; i < urlSplit.length; i++) {
|
||||
subdir = subdir + '/' + urlSplit[i];
|
||||
}
|
||||
if (subdir != "") {
|
||||
signaling_socket = io("", { "path": subdir + "/socket.io" }); //Connect even if we are in a subdir behind a reverse proxy
|
||||
} else {
|
||||
signaling_socket = io();
|
||||
}
|
||||
|
||||
signaling_socket.on('connect', function () {
|
||||
console.log("Websocket connected!");
|
||||
|
||||
signaling_socket.on('drawToWhiteboard', function (content) {
|
||||
whiteboard.handleEventsAndData(content, true);
|
||||
});
|
||||
|
||||
signaling_socket.on('refreshUserBadges', function () {
|
||||
whiteboard.refreshUserBadges();
|
||||
});
|
||||
|
||||
signaling_socket.on('wrongAccessToken', function () {
|
||||
if (!accessDenied) {
|
||||
accessDenied = true;
|
||||
showBasicAlert("Access denied! Wrong accessToken!")
|
||||
}
|
||||
});
|
||||
|
||||
signaling_socket.on('updateSmallestScreenResolution', function (widthHeight) {
|
||||
whiteboard.updateSmallestScreenResolution(widthHeight["w"], widthHeight["h"]);
|
||||
});
|
||||
|
||||
signaling_socket.emit('joinWhiteboard', { wid: whiteboardId, at: accessToken, windowWidthHeight: { w: $(window).width(), h: $(window).height() } });
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
if (getQueryVariable("webdav") == "true") {
|
||||
$("#uploadWebDavBtn").show();
|
||||
}
|
||||
whiteboard.loadWhiteboard("#whiteboardContainer", { //Load the whiteboard
|
||||
whiteboardId: whiteboardId,
|
||||
username: btoa(myUsername),
|
||||
sendFunction: function (content) {
|
||||
content["at"] = accessToken;
|
||||
signaling_socket.emit('drawToWhiteboard', content);
|
||||
}
|
||||
});
|
||||
|
||||
// request whiteboard from server
|
||||
$.get(subdir + "/loadwhiteboard", { wid: whiteboardId, at: accessToken }).done(function (data) {
|
||||
whiteboard.loadData(data)
|
||||
});
|
||||
|
||||
$(window).resize(function () {
|
||||
signaling_socket.emit('updateScreenResolution', { at: accessToken, windowWidthHeight: { w: $(window).width(), h: $(window).height() } });
|
||||
})
|
||||
|
||||
/*----------------/
|
||||
Whiteboard actions
|
||||
/----------------*/
|
||||
|
||||
//Handle key actions
|
||||
$(document).on("keydown", function (e) {
|
||||
if (e.which == 16) {
|
||||
whiteboard.pressedKeys["shift"] = true; //Used for straight lines...
|
||||
}
|
||||
//console.log(e.which);
|
||||
});
|
||||
$(document).on("keyup", function (e) {
|
||||
if (e.which == 16) {
|
||||
whiteboard.pressedKeys["shift"] = false;
|
||||
}
|
||||
});
|
||||
|
||||
var shortcutFunctions = {
|
||||
clearWhiteboard: function () { whiteboard.clearWhiteboard(); },
|
||||
undoStep: function () { whiteboard.undoWhiteboardClick(); },
|
||||
redoStep: function () { whiteboard.redoWhiteboardClick(); },
|
||||
setTool_mouse: function () { $(".whiteboardTool[tool=mouse]").click(); },
|
||||
setTool_recSelect: function () { $(".whiteboardTool[tool=recSelect]").click(); },
|
||||
setTool_pen: function () {
|
||||
$(".whiteboardTool[tool=pen]").click();
|
||||
whiteboard.redrawMouseCursor();
|
||||
},
|
||||
setTool_line: function () { $(".whiteboardTool[tool=line]").click(); },
|
||||
setTool_rect: function () { $(".whiteboardTool[tool=rect]").click(); },
|
||||
setTool_circle: function () { $(".whiteboardTool[tool=circle]").click(); },
|
||||
setTool_text: function () { $(".whiteboardTool[tool=text]").click(); },
|
||||
setTool_eraser: function () {
|
||||
$(".whiteboardTool[tool=eraser]").click();
|
||||
whiteboard.redrawMouseCursor();
|
||||
},
|
||||
thickness_bigger: function () {
|
||||
var thickness = parseInt($("#whiteboardThicknessSlider").val()) + 1;
|
||||
$("#whiteboardThicknessSlider").val(thickness);
|
||||
whiteboard.setStrokeThickness(thickness);
|
||||
whiteboard.redrawMouseCursor();
|
||||
},
|
||||
thickness_smaller: function () {
|
||||
var thickness = parseInt($("#whiteboardThicknessSlider").val()) - 1;
|
||||
$("#whiteboardThicknessSlider").val(thickness);
|
||||
whiteboard.setStrokeThickness(thickness);
|
||||
whiteboard.redrawMouseCursor();
|
||||
},
|
||||
openColorPicker: function () { $("#whiteboardColorpicker").click(); },
|
||||
saveWhiteboardAsImage: function () { $("#saveAsImageBtn").click(); },
|
||||
saveWhiteboardAsJson: function () { $("#saveAsJSONBtn").click(); },
|
||||
uploadWhiteboardToWebDav: function () { $("#uploadWebDavBtn").click(); },
|
||||
uploadJsonToWhiteboard: function () { $("#uploadJsonBtn").click(); },
|
||||
shareWhiteboard: function () { $("#shareWhiteboardBtn").click(); },
|
||||
hideShowControls: function () { $("#minMaxBtn").click(); },
|
||||
|
||||
setDrawColorBlack: function () {
|
||||
whiteboard.setDrawColor("black");
|
||||
whiteboard.redrawMouseCursor();
|
||||
$("#whiteboardColorpicker").css({ "background": "black" });
|
||||
},
|
||||
setDrawColorRed: function () {
|
||||
whiteboard.setDrawColor("red");
|
||||
whiteboard.redrawMouseCursor();
|
||||
$("#whiteboardColorpicker").css({ "background": "red" });
|
||||
},
|
||||
setDrawColorGreen: function () {
|
||||
whiteboard.setDrawColor("green");
|
||||
whiteboard.redrawMouseCursor();
|
||||
$("#whiteboardColorpicker").css({ "background": "green" });
|
||||
},
|
||||
setDrawColorBlue: function () {
|
||||
whiteboard.setDrawColor("blue");
|
||||
whiteboard.redrawMouseCursor();
|
||||
$("#whiteboardColorpicker").css({ "background": "blue" });
|
||||
},
|
||||
setDrawColorYellow: function () {
|
||||
whiteboard.setDrawColor("yellow");
|
||||
whiteboard.redrawMouseCursor();
|
||||
$("#whiteboardColorpicker").css({ "background": "yellow" });
|
||||
},
|
||||
|
||||
toggleLineRecCircle: function () {
|
||||
var activeTool = $(".whiteboardTool.active").attr("tool");
|
||||
if (activeTool == "line") {
|
||||
$(".whiteboardTool[tool=rect]").click();
|
||||
} else if (activeTool == "rect") {
|
||||
$(".whiteboardTool[tool=circle]").click();
|
||||
} else {
|
||||
$(".whiteboardTool[tool=line]").click();
|
||||
}
|
||||
},
|
||||
togglePenEraser: function () {
|
||||
var activeTool = $(".whiteboardTool.active").attr("tool");
|
||||
if (activeTool == "pen") {
|
||||
$(".whiteboardTool[tool=eraser]").click();
|
||||
} else {
|
||||
$(".whiteboardTool[tool=pen]").click();
|
||||
}
|
||||
},
|
||||
toggleMainColors: function () {
|
||||
var bgColor = $("#whiteboardColorpicker")[0].style.backgroundColor;
|
||||
if (bgColor == "blue") {
|
||||
shortcutFunctions.setDrawColorGreen();
|
||||
} else if (bgColor == "green") {
|
||||
shortcutFunctions.setDrawColorYellow();
|
||||
} else if (bgColor == "yellow") {
|
||||
shortcutFunctions.setDrawColorRed();
|
||||
} else if (bgColor == "red") {
|
||||
shortcutFunctions.setDrawColorBlack();
|
||||
} else {
|
||||
shortcutFunctions.setDrawColorBlue();
|
||||
}
|
||||
},
|
||||
|
||||
moveDraggableUp: function () {
|
||||
var elm = whiteboard.tool == "text" ? $("#" + whiteboard.latestActiveTextBoxId) : $(".dragMe")[0];
|
||||
var p = $(elm).position();
|
||||
$(elm).css({ top: p.top - 5, left: p.left })
|
||||
},
|
||||
moveDraggableDown: function () {
|
||||
var elm = whiteboard.tool == "text" ? $("#" + whiteboard.latestActiveTextBoxId) : $(".dragMe")[0];
|
||||
var p = $(elm).position();
|
||||
$(elm).css({ top: p.top + 5, left: p.left })
|
||||
},
|
||||
moveDraggableLeft: function () {
|
||||
var elm = whiteboard.tool == "text" ? $("#" + whiteboard.latestActiveTextBoxId) : $(".dragMe")[0];
|
||||
var p = $(elm).position();
|
||||
$(elm).css({ top: p.top, left: p.left - 5 })
|
||||
},
|
||||
moveDraggableRight: function () {
|
||||
var elm = whiteboard.tool == "text" ? $("#" + whiteboard.latestActiveTextBoxId) : $(".dragMe")[0];
|
||||
var p = $(elm).position();
|
||||
$(elm).css({ top: p.top, left: p.left + 5 })
|
||||
},
|
||||
dropDraggable: function () {
|
||||
$($(".dragMe")[0]).find('.addToCanvasBtn').click();
|
||||
},
|
||||
addToBackground: function () {
|
||||
$($(".dragMe")[0]).find('.addToBackgroundBtn').click();
|
||||
},
|
||||
cancelAllActions: function () { whiteboard.escKeyAction(); },
|
||||
deleteSelection: function () { whiteboard.delKeyAction(); },
|
||||
}
|
||||
|
||||
//Load keybindings from keybinds.js to given functions
|
||||
for (var i in keybinds) {
|
||||
if (shortcutFunctions[keybinds[i]]) {
|
||||
keymage(i, shortcutFunctions[keybinds[i]], { preventDefault: true });
|
||||
} else {
|
||||
console.error("function you want to keybind on key:", i, "named:", keybinds[i], "is not available!")
|
||||
}
|
||||
}
|
||||
|
||||
// whiteboard clear button
|
||||
$("#whiteboardTrashBtn").click(function () {
|
||||
$("#whiteboardTrashBtnConfirm").show().focus();
|
||||
$(this).css({ visibility: "hidden" });
|
||||
});
|
||||
|
||||
$("#whiteboardTrashBtnConfirm").mouseout(function () {
|
||||
$(this).hide();
|
||||
$("#whiteboardTrashBtn").css({ visibility: "inherit" });
|
||||
});
|
||||
|
||||
$("#whiteboardTrashBtnConfirm").click(function () {
|
||||
$(this).hide();
|
||||
$("#whiteboardTrashBtn").css({ visibility: "inherit" });
|
||||
whiteboard.clearWhiteboard();
|
||||
});
|
||||
|
||||
// undo button
|
||||
$("#whiteboardUndoBtn").click(function () {
|
||||
whiteboard.undoWhiteboardClick();
|
||||
});
|
||||
|
||||
// redo button
|
||||
$("#whiteboardRedoBtn").click(function () {
|
||||
whiteboard.redoWhiteboardClick();
|
||||
});
|
||||
|
||||
// switch tool
|
||||
$(".whiteboardTool").click(function () {
|
||||
$(".whiteboardTool").removeClass("active");
|
||||
$(this).addClass("active");
|
||||
var activeTool = $(this).attr("tool");
|
||||
whiteboard.setTool(activeTool);
|
||||
if (activeTool == "mouse" || activeTool == "recSelect") {
|
||||
$(".activeToolIcon").empty();
|
||||
} else {
|
||||
$(".activeToolIcon").html($(this).html()); //Set Active icon the same as the button icon
|
||||
}
|
||||
});
|
||||
|
||||
// upload image button
|
||||
$("#addImgToCanvasBtn").click(function () {
|
||||
showBasicAlert("Please drag the image into the browser.");
|
||||
});
|
||||
|
||||
// save image as png
|
||||
$("#saveAsImageBtn").click(function () {
|
||||
var imgData = whiteboard.getImageDataBase64();
|
||||
|
||||
var w = window.open('about:blank'); //Firefox will not allow downloads without extra window
|
||||
setTimeout(function () { //FireFox seems to require a setTimeout for this to work.
|
||||
var a = document.createElement('a');
|
||||
a.href = imgData;
|
||||
a.download = 'whiteboard.png';
|
||||
w.document.body.appendChild(a);
|
||||
a.click();
|
||||
w.document.body.removeChild(a);
|
||||
setTimeout(function () { w.close(); }, 100);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
// save image to json containing steps
|
||||
$("#saveAsJSONBtn").click(function () {
|
||||
var imgData = whiteboard.getImageDataJson();
|
||||
|
||||
var w = window.open('about:blank'); //Firefox will not allow downloads without extra window
|
||||
setTimeout(function () { //FireFox seems to require a setTimeout for this to work.
|
||||
var a = document.createElement('a');
|
||||
a.href = window.URL.createObjectURL(new Blob([imgData], { type: 'text/json' }));
|
||||
a.download = 'whiteboard.json';
|
||||
w.document.body.appendChild(a);
|
||||
a.click();
|
||||
w.document.body.removeChild(a);
|
||||
setTimeout(function () { w.close(); }, 100);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
$("#uploadWebDavBtn").click(function () {
|
||||
if ($(".webdavUploadBtn").length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var webdavserver = localStorage.getItem('webdavserver') || ""
|
||||
var webdavpath = localStorage.getItem('webdavpath') || "/"
|
||||
var webdavusername = localStorage.getItem('webdavusername') || ""
|
||||
var webdavpassword = localStorage.getItem('webdavpassword') || ""
|
||||
var webDavHtml = $('<div>' +
|
||||
'<table>' +
|
||||
'<tr>' +
|
||||
'<td>Server URL:</td>' +
|
||||
'<td><input class="webdavserver" type="text" value="' + webdavserver + '" placeholder="https://yourserver.com/remote.php/webdav/"></td>' +
|
||||
'<td></td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td>Path:</td>' +
|
||||
'<td><input class="webdavpath" type="text" placeholder="folder" value="' + webdavpath + '"></td>' +
|
||||
'<td style="font-size: 0.7em;"><i>path always have to start & end with "/"</i></td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td>Username:</td>' +
|
||||
'<td><input class="webdavusername" type="text" value="' + webdavusername + '" placeholder="username"></td>' +
|
||||
'<td style="font-size: 0.7em;"></td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td>Password:</td>' +
|
||||
'<td><input class="webdavpassword" type="password" value="' + webdavpassword + '" placeholder="password"></td>' +
|
||||
'<td style="font-size: 0.7em;"></td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td style="font-size: 0.7em;" colspan="3">Note: You have to generate and use app credentials if you have 2 Factor Auth activated on your dav/nextcloud server!</td>' +
|
||||
'</tr>' +
|
||||
'<tr>' +
|
||||
'<td></td>' +
|
||||
'<td colspan="2"><span class="loadingWebdavText" style="display:none;">Saving to webdav, please wait...</span><button class="modalBtn webdavUploadBtn"><i class="fas fa-upload"></i> Start Upload</button></td>' +
|
||||
'</tr>' +
|
||||
'</table>' +
|
||||
'</div>');
|
||||
webDavHtml.find(".webdavUploadBtn").click(function () {
|
||||
var webdavserver = webDavHtml.find(".webdavserver").val();
|
||||
localStorage.setItem('webdavserver', webdavserver);
|
||||
var webdavpath = webDavHtml.find(".webdavpath").val();
|
||||
localStorage.setItem('webdavpath', webdavpath);
|
||||
var webdavusername = webDavHtml.find(".webdavusername").val();
|
||||
localStorage.setItem('webdavusername', webdavusername);
|
||||
var webdavpassword = webDavHtml.find(".webdavpassword").val();
|
||||
localStorage.setItem('webdavpassword', webdavpassword);
|
||||
var base64data = whiteboard.getImageDataBase64();
|
||||
var webdavaccess = {
|
||||
webdavserver: webdavserver,
|
||||
webdavpath: webdavpath,
|
||||
webdavusername: webdavusername,
|
||||
webdavpassword: webdavpassword
|
||||
}
|
||||
webDavHtml.find(".loadingWebdavText").show();
|
||||
webDavHtml.find(".webdavUploadBtn").hide();
|
||||
saveWhiteboardToWebdav(base64data, webdavaccess, function (err) {
|
||||
if (err) {
|
||||
webDavHtml.find(".loadingWebdavText").hide();
|
||||
webDavHtml.find(".webdavUploadBtn").show();
|
||||
} else {
|
||||
webDavHtml.parents(".basicalert").remove();
|
||||
}
|
||||
});
|
||||
})
|
||||
showBasicAlert(webDavHtml, {
|
||||
header: "Save to Webdav",
|
||||
okBtnText: "cancel",
|
||||
headercolor: "#0082c9"
|
||||
})
|
||||
});
|
||||
|
||||
// upload json containing steps
|
||||
$("#uploadJsonBtn").click(function () {
|
||||
$("#myFile").click();
|
||||
});
|
||||
|
||||
$("#shareWhiteboardBtn").click(function () {
|
||||
var url = window.location.href;
|
||||
var s = url.indexOf("&username=") !== -1 ? "&username=" : "username="; //Remove username from url
|
||||
var urlSlpit = url.split(s);
|
||||
var urlStart = urlSlpit[0];
|
||||
if (urlSlpit.length > 1) {
|
||||
var endSplit = urlSlpit[1].split("&");
|
||||
endSplit = endSplit.splice(1, 1);
|
||||
urlStart += "&" + endSplit.join("&");
|
||||
}
|
||||
$("<textarea/>").appendTo("body").val(urlStart).select().each(function () {
|
||||
document.execCommand('copy');
|
||||
}).remove();
|
||||
showBasicAlert("Copied Whiteboard-URL to clipboard.", { hideAfter: 2 })
|
||||
});
|
||||
|
||||
var btnsMini = false;
|
||||
$("#minMaxBtn").click(function () {
|
||||
if (!btnsMini) {
|
||||
$("#toolbar").find(".btn-group:not(.minGroup)").hide();
|
||||
$(this).find("#minBtn").hide();
|
||||
$(this).find("#maxBtn").show();
|
||||
} else {
|
||||
$("#toolbar").find(".btn-group").show();
|
||||
$(this).find("#minBtn").show();
|
||||
$(this).find("#maxBtn").hide();
|
||||
}
|
||||
btnsMini = !btnsMini;
|
||||
})
|
||||
|
||||
// load json to whiteboard
|
||||
$("#myFile").on("change", function () {
|
||||
var file = document.getElementById("myFile").files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
try {
|
||||
var j = JSON.parse(e.target.result);
|
||||
whiteboard.loadJsonData(j);
|
||||
} catch (e) {
|
||||
showBasicAlert("File was not a valid JSON!");
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
$(this).val("");
|
||||
});
|
||||
|
||||
// On thickness slider change
|
||||
$("#whiteboardThicknessSlider").on("input", function () {
|
||||
whiteboard.setStrokeThickness($(this).val());
|
||||
});
|
||||
|
||||
// handle drag&drop
|
||||
var dragCounter = 0;
|
||||
$('#whiteboardContainer').on("dragenter", function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
dragCounter++;
|
||||
whiteboard.dropIndicator.show();
|
||||
});
|
||||
|
||||
$('#whiteboardContainer').on("dragleave", function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
dragCounter--;
|
||||
if (dragCounter === 0) {
|
||||
whiteboard.dropIndicator.hide();
|
||||
}
|
||||
});
|
||||
|
||||
$('#whiteboardContainer').on('drop', function (e) { //Handle drop
|
||||
if (e.originalEvent.dataTransfer) {
|
||||
if (e.originalEvent.dataTransfer.files.length) { //File from harddisc
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var filename = e.originalEvent.dataTransfer.files[0]["name"];
|
||||
if (isImageFileName(filename)) {
|
||||
var blob = e.originalEvent.dataTransfer.files[0];
|
||||
var reader = new window.FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
reader.onloadend = function () {
|
||||
base64data = reader.result;
|
||||
uploadImgAndAddToWhiteboard(base64data);
|
||||
}
|
||||
} else {
|
||||
showBasicAlert("File must be an image!");
|
||||
}
|
||||
} else { //File from other browser
|
||||
|
||||
var fileUrl = e.originalEvent.dataTransfer.getData('URL');
|
||||
var imageUrl = e.originalEvent.dataTransfer.getData('text/html');
|
||||
var rex = /src="?([^"\s]+)"?\s*/;
|
||||
var url = rex.exec(imageUrl);
|
||||
if (url && url.length > 1) {
|
||||
url = url[1];
|
||||
} else {
|
||||
url = "";
|
||||
}
|
||||
|
||||
isValidImageUrl(fileUrl, function (isImage) {
|
||||
if (isImage && isImageFileName(url)) {
|
||||
whiteboard.addImgToCanvasByUrl(fileUrl);
|
||||
} else {
|
||||
isValidImageUrl(url, function (isImage) {
|
||||
if (isImage) {
|
||||
if (isImageFileName(url) || url.startsWith("http")) {
|
||||
whiteboard.addImgToCanvasByUrl(url);
|
||||
} else {
|
||||
uploadImgAndAddToWhiteboard(url); //Last option maybe its base64
|
||||
}
|
||||
} else {
|
||||
showBasicAlert("Can only upload Imagedata!");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
dragCounter = 0;
|
||||
whiteboard.dropIndicator.hide();
|
||||
});
|
||||
|
||||
$('#whiteboardColorpicker').colorPicker({
|
||||
renderCallback: function (elm) {
|
||||
whiteboard.setDrawColor(elm.val());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//Prevent site from changing tab on drag&drop
|
||||
window.addEventListener("dragover", function (e) {
|
||||
e = e || event;
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
window.addEventListener("drop", function (e) {
|
||||
e = e || event;
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
|
||||
function uploadImgAndAddToWhiteboard(base64data) {
|
||||
var date = (+new Date());
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: document.URL.substr(0, document.URL.lastIndexOf('/')) + '/upload',
|
||||
data: {
|
||||
'imagedata': base64data,
|
||||
'whiteboardId': whiteboardId,
|
||||
'date': date,
|
||||
'at': accessToken
|
||||
},
|
||||
success: function (msg) {
|
||||
var filename = whiteboardId + "_" + date + ".png";
|
||||
whiteboard.addImgToCanvasByUrl(document.URL.substr(0, document.URL.lastIndexOf('/')) + "/uploads/" + filename); //Add image to canvas
|
||||
console.log("Image uploaded!");
|
||||
},
|
||||
error: function (err) {
|
||||
showBasicAlert("Failed to upload frame: " + JSON.stringify(err));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function saveWhiteboardToWebdav(base64data, webdavaccess, callback) {
|
||||
var date = (+new Date());
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: document.URL.substr(0, document.URL.lastIndexOf('/')) + '/upload',
|
||||
data: {
|
||||
'imagedata': base64data,
|
||||
'whiteboardId': whiteboardId,
|
||||
'date': date,
|
||||
'at': accessToken,
|
||||
'webdavaccess': JSON.stringify(webdavaccess)
|
||||
},
|
||||
success: function (msg) {
|
||||
showBasicAlert("Whiteboard was saved to Webdav!", {
|
||||
headercolor: "#5c9e5c"
|
||||
});
|
||||
console.log("Image uploaded for webdav!");
|
||||
callback();
|
||||
},
|
||||
error: function (err) {
|
||||
if (err.status == 403) {
|
||||
showBasicAlert("Could not connect to Webdav folder! Please check the credentials and paths and try again!");
|
||||
} else {
|
||||
showBasicAlert("Unknown Webdav error! ", err);
|
||||
}
|
||||
callback(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// verify if filename refers to an image
|
||||
function isImageFileName(filename) {
|
||||
var extension = filename.split(".")[filename.split(".").length - 1];
|
||||
var known_extensions = ["png", "jpg", "jpeg", "gif", "tiff", "bmp", "webp"];
|
||||
return known_extensions.includes(extension.toLowerCase());
|
||||
}
|
||||
|
||||
// verify if given url is url to an image
|
||||
function isValidImageUrl(url, callback) {
|
||||
var img = new Image();
|
||||
var timer = null;
|
||||
img.onerror = img.onabort = function () {
|
||||
clearTimeout(timer);
|
||||
callback(false);
|
||||
};
|
||||
img.onload = function () {
|
||||
clearTimeout(timer);
|
||||
callback(true);
|
||||
};
|
||||
timer = setTimeout(function () {
|
||||
callback(false);
|
||||
}, 2000);
|
||||
img.src = url;
|
||||
}
|
||||
|
||||
// handle pasting from clipboard
|
||||
window.addEventListener("paste", function (e) {
|
||||
if ($(".basicalert").length > 0) {
|
||||
return;
|
||||
}
|
||||
if (e.clipboardData) {
|
||||
var items = e.clipboardData.items;
|
||||
var imgItemFound = false;
|
||||
if (items) {
|
||||
// Loop through all items, looking for any kind of image
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
if (items[i].type.indexOf("image") !== -1) {
|
||||
imgItemFound = true;
|
||||
// We need to represent the image as a file,
|
||||
var blob = items[i].getAsFile();
|
||||
|
||||
var reader = new window.FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
reader.onloadend = function () {
|
||||
console.log("Uploading image!");
|
||||
base64data = reader.result;
|
||||
uploadImgAndAddToWhiteboard(base64data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!imgItemFound && whiteboard.tool != "text") {
|
||||
showBasicAlert("Please Drag&Drop the image into the Whiteboard. (Browsers don't allow copy+past from the filesystem directly)");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function showBasicAlert(html, newOptions) {
|
||||
var options = {
|
||||
header: "INFO MESSAGE",
|
||||
okBtnText: "Ok",
|
||||
headercolor: "#d25d5d",
|
||||
hideAfter: false
|
||||
}
|
||||
if (newOptions) {
|
||||
for (var i in newOptions) {
|
||||
options[i] = newOptions[i];
|
||||
}
|
||||
}
|
||||
var alertHtml = $('<div class="basicalert" style="position:absolute; top:0px; left:0px; width:100%; top:70px; font-family: monospace;">' +
|
||||
'<div style="width: 30%; margin: auto; background: #aaaaaa; border-radius: 5px; font-size: 1.2em; border: 1px solid gray;">' +
|
||||
'<div style="border-bottom: 1px solid #676767; background: ' + options["headercolor"] + '; padding-left: 5px; font-size: 0.8em;">' + options["header"] + '</div>' +
|
||||
'<div style="padding: 10px;" class="htmlcontent"></div>' +
|
||||
'<div style="height: 20px; padding: 10px;"><button class="modalBtn okbtn" style="float: right;">' + options["okBtnText"] + '</button></div>' +
|
||||
'</div>' +
|
||||
'</div>');
|
||||
alertHtml.find(".htmlcontent").append(html);
|
||||
$("body").append(alertHtml);
|
||||
alertHtml.find(".okbtn").click(function () {
|
||||
alertHtml.remove();
|
||||
})
|
||||
if (options.hideAfter) {
|
||||
setTimeout(function () {
|
||||
alertHtml.find(".okbtn").click();
|
||||
}, 1000 * options.hideAfter)
|
||||
}
|
||||
}
|
||||
|
||||
// get 'GET' parameter by variable name
|
||||
function getQueryVariable(variable) {
|
||||
var query = window.location.search.substring(1);
|
||||
var vars = query.split("&");
|
||||
for (var i = 0; i < vars.length; i++) {
|
||||
var pair = vars[i].split("=");
|
||||
if (pair[0] == variable) {
|
||||
return pair[1];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
981
src/whiteboard.js
Normal file
981
src/whiteboard.js
Normal file
@@ -0,0 +1,981 @@
|
||||
var whiteboard = {
|
||||
canvas: null,
|
||||
ctx: null,
|
||||
drawcolor: "black",
|
||||
tool: "pen",
|
||||
thickness: 4,
|
||||
prevX: null,
|
||||
prevY: null,
|
||||
latestTouchCoods: [],
|
||||
drawFlag: false,
|
||||
oldGCO: null,
|
||||
mouseover: false,
|
||||
lineCap: "round", //butt, square
|
||||
backgroundGrid: null,
|
||||
canvasElement: null,
|
||||
cursorContainer: null,
|
||||
imgContainer: null,
|
||||
svgContainer: null, //For draw prev
|
||||
mouseOverlay: null,
|
||||
ownCursor: null,
|
||||
startCoords: [],
|
||||
penSmoothLastCoords: [],
|
||||
svgLine: null,
|
||||
svgRect: null,
|
||||
svgCirle: null,
|
||||
drawBuffer: [],
|
||||
undoBuffer: [],
|
||||
drawId: 0, //Used for undo/redo functions
|
||||
imgDragActive: false,
|
||||
latestActiveTextBoxId: false, //The id of the latest clicked Textbox (for font and color change)
|
||||
pressedKeys: {},
|
||||
settings: {
|
||||
whiteboardId: "0",
|
||||
username: "unknown",
|
||||
sendFunction: null,
|
||||
backgroundGridUrl: './images/KtEBa2.png'
|
||||
},
|
||||
loadWhiteboard: function (whiteboardContainer, newSettings) {
|
||||
var svgns = "http://www.w3.org/2000/svg";
|
||||
var _this = this;
|
||||
for (var i in newSettings) {
|
||||
this.settings[i] = newSettings[i];
|
||||
}
|
||||
this.settings["username"] = this.settings["username"].replace(/[^0-9a-z]/gi, '');
|
||||
this.settings["whiteboardId"] = this.settings["whiteboardId"].replace(/[^0-9a-z]/gi, '');
|
||||
|
||||
//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>');
|
||||
// container for background images
|
||||
_this.imgContainer = $('<div style="position: absolute; left:0px; top:0; height: 100%; width: 100%;"></div>');
|
||||
// whiteboard canvas
|
||||
_this.canvasElement = $('<canvas id="whiteboardCanvas" style="position: absolute; left:0px; top:0; cursor:crosshair;"></canvas>');
|
||||
// SVG container holding drawing or moving previews
|
||||
_this.svgContainer = $('<svg style="position: absolute; top:0px; left:0px;" width="100%" height="100%"></svg>');
|
||||
// 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>')
|
||||
// container for other users cursors
|
||||
_this.cursorContainer = $('<div style="position: absolute; left:0px; top:0; height: 100%; width: 100%;"></div>');
|
||||
// container for texts by users
|
||||
_this.textContainer = $('<div class="textcontainer" style="position: absolute; left:0px; top:0; height: 100%; width: 100%; cursor:text;"></div>');
|
||||
// mouse overlay for draw callbacks
|
||||
_this.mouseOverlay = $('<div style="cursor:none; position: absolute; left:0px; top:0; height: 100%; width: 100%;"></div>');
|
||||
|
||||
$(whiteboardContainer).append(_this.backgroundGrid)
|
||||
.append(_this.imgContainer)
|
||||
.append(_this.canvasElement)
|
||||
.append(_this.svgContainer)
|
||||
.append(_this.dropIndicator)
|
||||
.append(_this.cursorContainer)
|
||||
.append(_this.textContainer)
|
||||
.append(_this.mouseOverlay);
|
||||
this.canvas = $("#whiteboardCanvas")[0];
|
||||
this.canvas.height = $(window).height();
|
||||
this.canvas.width = $(window).width();
|
||||
this.ctx = this.canvas.getContext("2d");
|
||||
this.oldGCO = this.ctx.globalCompositeOperation;
|
||||
|
||||
$(window).resize(function () { //Handel resize
|
||||
var dbCp = JSON.parse(JSON.stringify(_this.drawBuffer)); //Copy the buffer
|
||||
_this.canvas.width = $(window).width();
|
||||
_this.canvas.height = $(window).height(); //Set new canvas height
|
||||
_this.drawBuffer = [];
|
||||
_this.loadData(dbCp); //draw old content in
|
||||
});
|
||||
|
||||
$(_this.mouseOverlay).on("mousedown touchstart", function (e) {
|
||||
if (_this.imgDragActive || _this.drawFlag) {
|
||||
return;
|
||||
}
|
||||
|
||||
_this.drawFlag = true;
|
||||
_this.prevX = (e.offsetX || e.pageX - $(e.target).offset().left) + 1;
|
||||
_this.prevY = (e.offsetY || e.pageY - $(e.target).offset().top) + 1;
|
||||
if (!_this.prevX || !_this.prevY || (_this.prevX == 1 && _this.prevY == 1)) {
|
||||
var touche = e.touches[0];
|
||||
_this.prevX = touche.clientX - $(_this.mouseOverlay).offset().left + 1;
|
||||
_this.prevY = touche.clientY - $(_this.mouseOverlay).offset().top + 1;
|
||||
latestTouchCoods = [_this.prevX, _this.prevY];
|
||||
}
|
||||
|
||||
if (_this.tool === "pen") {
|
||||
_this.penSmoothLastCoords = [_this.prevX, _this.prevY, _this.prevX, _this.prevY, _this.prevX, _this.prevY]
|
||||
} else if (_this.tool === "eraser") {
|
||||
_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 });
|
||||
} else if (_this.tool === "line") {
|
||||
_this.startCoords = [_this.prevX, _this.prevY];
|
||||
_this.svgLine = document.createElementNS(svgns, 'line');
|
||||
_this.svgLine.setAttribute('stroke', 'gray');
|
||||
_this.svgLine.setAttribute('stroke-dasharray', '5, 5');
|
||||
_this.svgLine.setAttribute('x1', _this.prevX);
|
||||
_this.svgLine.setAttribute('y1', _this.prevY);
|
||||
_this.svgLine.setAttribute('x2', _this.prevX);
|
||||
_this.svgLine.setAttribute('y2', _this.prevY);
|
||||
_this.svgContainer.append(_this.svgLine);
|
||||
} else if (_this.tool === "rect" || _this.tool === "recSelect") {
|
||||
_this.svgContainer.find("rect").remove();
|
||||
_this.svgRect = document.createElementNS(svgns, 'rect');
|
||||
_this.svgRect.setAttribute('stroke', 'gray');
|
||||
_this.svgRect.setAttribute('stroke-dasharray', '5, 5');
|
||||
_this.svgRect.setAttribute('style', 'fill-opacity:0.0;');
|
||||
_this.svgRect.setAttribute('x', _this.prevX);
|
||||
_this.svgRect.setAttribute('y', _this.prevY);
|
||||
_this.svgRect.setAttribute('width', 0);
|
||||
_this.svgRect.setAttribute('height', 0);
|
||||
_this.svgContainer.append(_this.svgRect);
|
||||
_this.startCoords = [_this.prevX, _this.prevY];
|
||||
} else if (_this.tool === "circle") {
|
||||
_this.svgCirle = document.createElementNS(svgns, 'circle');
|
||||
_this.svgCirle.setAttribute('stroke', 'gray');
|
||||
_this.svgCirle.setAttribute('stroke-dasharray', '5, 5');
|
||||
_this.svgCirle.setAttribute('style', 'fill-opacity:0.0;');
|
||||
_this.svgCirle.setAttribute('cx', _this.prevX);
|
||||
_this.svgCirle.setAttribute('cy', _this.prevY);
|
||||
_this.svgCirle.setAttribute('r', 0);
|
||||
_this.svgContainer.append(_this.svgCirle);
|
||||
_this.startCoords = [_this.prevX, _this.prevY];
|
||||
}
|
||||
});
|
||||
|
||||
_this.textContainer.on("mousemove touchmove", function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (_this.imgDragActive || !$(e.target).hasClass("textcontainer")) {
|
||||
return;
|
||||
}
|
||||
|
||||
var currX = (e.offsetX || e.pageX - $(e.target).offset().left);
|
||||
var currY = (e.offsetY || e.pageY - $(e.target).offset().top);
|
||||
_this.sendFunction({ "t": "cursor", "event": "move", "d": [currX, currY], "username": _this.settings.username });
|
||||
})
|
||||
|
||||
_this.mouseOverlay.on("mousemove touchmove", function (e) {
|
||||
e.preventDefault();
|
||||
_this.triggerMouseMove(e);
|
||||
});
|
||||
|
||||
_this.mouseOverlay.on("mouseup touchend touchcancel", function (e) {
|
||||
if (_this.imgDragActive) {
|
||||
return;
|
||||
}
|
||||
_this.drawFlag = false;
|
||||
_this.drawId++;
|
||||
_this.ctx.globalCompositeOperation = _this.oldGCO;
|
||||
var currX = (e.offsetX || e.pageX - $(e.target).offset().left);
|
||||
var currY = (e.offsetY || e.pageY - $(e.target).offset().top);
|
||||
|
||||
if (!currX || !currY) {
|
||||
currX = _this.latestTouchCoods[0];
|
||||
currY = _this.latestTouchCoods[1];
|
||||
_this.sendFunction({ "t": "cursor", "event": "out", "username": _this.settings.username });
|
||||
}
|
||||
|
||||
if (_this.tool === "line") {
|
||||
if (_this.pressedKeys.shift) {
|
||||
var angs = _this.getRoundedAngles(currX, currY);
|
||||
currX = angs.x;
|
||||
currY = angs.y;
|
||||
}
|
||||
_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.svgContainer.find("line").remove();
|
||||
} else if (_this.tool === "pen") {
|
||||
_this.drawId--;
|
||||
_this.pushPointSmoothPen(currX, currY);
|
||||
_this.drawId++;
|
||||
} else if (_this.tool === "rect") {
|
||||
if (_this.pressedKeys.shift) {
|
||||
if ((currY - _this.startCoords[1]) * (currX - _this.startCoords[0]) > 0) {
|
||||
currY = _this.startCoords[1] + (currX - _this.startCoords[0]);
|
||||
} else {
|
||||
currY = _this.startCoords[1] - (currX - _this.startCoords[0]);
|
||||
}
|
||||
}
|
||||
_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.svgContainer.find("rect").remove();
|
||||
} else if (_this.tool === "circle") {
|
||||
var a = currX - _this.startCoords[0];
|
||||
var b = currY - _this.startCoords[1];
|
||||
var r = Math.sqrt(a * a + b * b);
|
||||
_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.svgContainer.find("circle").remove();
|
||||
} else if (_this.tool === "recSelect") {
|
||||
_this.imgDragActive = true;
|
||||
if (_this.pressedKeys.shift) {
|
||||
if ((currY - _this.startCoords[1]) * (currX - _this.startCoords[0]) > 0) {
|
||||
currY = _this.startCoords[1] + (currX - _this.startCoords[0]);
|
||||
} else {
|
||||
currY = _this.startCoords[1] - (currX - _this.startCoords[0]);
|
||||
}
|
||||
}
|
||||
|
||||
var width = Math.abs(_this.startCoords[0] - currX);
|
||||
var height = Math.abs(_this.startCoords[1] - currY);
|
||||
var left = _this.startCoords[0] < currX ? _this.startCoords[0] : currX;
|
||||
var top = _this.startCoords[1] < currY ? _this.startCoords[1] : currY;
|
||||
_this.mouseOverlay.css({ "cursor": "default" });
|
||||
var imgDiv = $('<div class="dragMe" style="position:absolute; left:' + left + 'px; top:' + top + 'px; width:' + width + 'px; border: 2px dotted gray; overflow: hidden; height:' + height + 'px;" cursor:move;">' +
|
||||
'<canvas style="cursor:move; position:absolute; top:0px; left:0px;" width="' + width + '" height="' + height + '"/>' +
|
||||
'<div style="position:absolute; right:5px; top:3px;">' +
|
||||
'<button draw="1" style="margin: 0px 0px; background: #03a9f4; padding: 5px; margin-top: 3px; color: white;" class="addToCanvasBtn btn btn-default">Drop</button> ' +
|
||||
'<button style="margin: 0px 0px; background: #03a9f4; padding: 5px; margin-top: 3px; color: white;" class="xCanvasBtn btn btn-default">x</button>' +
|
||||
'</div>' +
|
||||
'</div>');
|
||||
var dragCanvas = $(imgDiv).find("canvas");
|
||||
var dragOutOverlay = $('<div class="dragOutOverlay" style="position:absolute; left:' + left + 'px; top:' + top + 'px; width:' + width + 'px; height:' + height + 'px; background:white;"></div>');
|
||||
_this.mouseOverlay.append(dragOutOverlay);
|
||||
_this.mouseOverlay.append(imgDiv);
|
||||
|
||||
var destCanvasContext = dragCanvas[0].getContext('2d');
|
||||
destCanvasContext.drawImage(_this.canvas, left, top, width, height, 0, 0, width, height);
|
||||
imgDiv.find(".xCanvasBtn").click(function () {
|
||||
_this.imgDragActive = false;
|
||||
_this.refreshCursorAppearance();
|
||||
imgDiv.remove();
|
||||
dragOutOverlay.remove();
|
||||
});
|
||||
imgDiv.find(".addToCanvasBtn").click(function () {
|
||||
_this.imgDragActive = false;
|
||||
_this.refreshCursorAppearance();
|
||||
var p = imgDiv.position();
|
||||
var leftT = Math.round(p.left * 100) / 100;
|
||||
var topT = Math.round(p.top * 100) / 100;
|
||||
_this.drawId++;
|
||||
_this.sendFunction({ "t": _this.tool, "d": [left, top, leftT, topT, width, height] });
|
||||
_this.dragCanvasRectContent(left, top, leftT, topT, width, height);
|
||||
imgDiv.remove();
|
||||
dragOutOverlay.remove();
|
||||
});
|
||||
imgDiv.draggable();
|
||||
_this.svgContainer.find("rect").remove();
|
||||
}
|
||||
});
|
||||
|
||||
_this.mouseOverlay.on("mouseout", function (e) {
|
||||
_this.triggerMouseOut();
|
||||
});
|
||||
|
||||
_this.mouseOverlay.on("mouseover", function (e) {
|
||||
_this.triggerMouseOver();
|
||||
});
|
||||
|
||||
//On textcontainer click (Add a new textbox)
|
||||
_this.textContainer.on("click", function (e) {
|
||||
currX = (e.offsetX || e.pageX - $(e.target).offset().left);
|
||||
currY = (e.offsetY || e.pageY - $(e.target).offset().top);
|
||||
var fontsize = _this.thickness * 0.5;
|
||||
var txId = 'tx' + (+new Date());
|
||||
_this.sendFunction({ "t": "addTextBox", "d": [_this.drawcolor, fontsize, currX, currY, txId] });
|
||||
_this.addTextBox(_this.drawcolor, fontsize, currX, currY, txId, true);
|
||||
});
|
||||
},
|
||||
getRoundedAngles: function (currX, currY) { //For drawing lines at 0,45,90° ....
|
||||
var _this = this;
|
||||
var x = currX - _this.startCoords[0];
|
||||
var y = currY - _this.startCoords[1];
|
||||
var angle = Math.atan2(x, y) * (180 / Math.PI);
|
||||
var angle45 = Math.round(angle / 45) * 45;
|
||||
if (angle45 % 90 == 0) {
|
||||
if (Math.abs(currX - _this.startCoords[0]) > Math.abs(currY - _this.startCoords[1])) {
|
||||
currY = _this.startCoords[1]
|
||||
} else {
|
||||
currX = _this.startCoords[0]
|
||||
}
|
||||
} else {
|
||||
if ((currY - _this.startCoords[1]) * (currX - _this.startCoords[0]) > 0) {
|
||||
currX = _this.startCoords[0] + (currY - _this.startCoords[1]);
|
||||
} else {
|
||||
currX = _this.startCoords[0] - (currY - _this.startCoords[1]);
|
||||
}
|
||||
}
|
||||
return { "x": currX, "y": currY };
|
||||
},
|
||||
triggerMouseMove: function (e) {
|
||||
var _this = this;
|
||||
if (_this.imgDragActive) {
|
||||
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);
|
||||
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];
|
||||
|
||||
if (_this.drawFlag) {
|
||||
if (_this.tool === "pen") {
|
||||
_this.pushPointSmoothPen(currX, currY);
|
||||
} else if (_this.tool == "eraser") {
|
||||
_this.drawEraserLine(currX, currY, _this.prevX, _this.prevY, _this.thickness);
|
||||
_this.sendFunction({ "t": _this.tool, "d": [currX, currY, _this.prevX, _this.prevY], "th": _this.thickness });
|
||||
}
|
||||
}
|
||||
|
||||
if (_this.tool === "eraser") {
|
||||
var left = currX - _this.thickness;
|
||||
var top = currY - _this.thickness;
|
||||
if (_this.ownCursor) _this.ownCursor.css({ "top": top + "px", "left": left + "px" });
|
||||
} else if (_this.tool === "pen") {
|
||||
var left = currX - _this.thickness / 2;
|
||||
var top = currY - _this.thickness / 2;
|
||||
if (_this.ownCursor) _this.ownCursor.css({ "top": top + "px", "left": left + "px" });
|
||||
} else if (_this.tool === "line") {
|
||||
if (_this.svgLine) {
|
||||
if (_this.pressedKeys.shift) {
|
||||
var angs = _this.getRoundedAngles(currX, currY);
|
||||
currX = angs.x;
|
||||
currY = angs.y;
|
||||
}
|
||||
_this.svgLine.setAttribute('x2', currX);
|
||||
_this.svgLine.setAttribute('y2', currY);
|
||||
}
|
||||
} else if (_this.tool === "rect" || (_this.tool === "recSelect" && _this.drawFlag)) {
|
||||
if (_this.svgRect) {
|
||||
var width = Math.abs(currX - _this.startCoords[0]);
|
||||
var height = Math.abs(currY - _this.startCoords[1]);
|
||||
if (_this.pressedKeys.shift) {
|
||||
height = width;
|
||||
var x = currX < _this.startCoords[0] ? _this.startCoords[0] - width : _this.startCoords[0];
|
||||
var y = currY < _this.startCoords[1] ? _this.startCoords[1] - width : _this.startCoords[1];
|
||||
_this.svgRect.setAttribute('x', x);
|
||||
_this.svgRect.setAttribute('y', y);
|
||||
} else {
|
||||
var x = currX < _this.startCoords[0] ? currX : _this.startCoords[0];
|
||||
var y = currY < _this.startCoords[1] ? currY : _this.startCoords[1];
|
||||
_this.svgRect.setAttribute('x', x);
|
||||
_this.svgRect.setAttribute('y', y);
|
||||
}
|
||||
|
||||
_this.svgRect.setAttribute('width', width);
|
||||
_this.svgRect.setAttribute('height', height);
|
||||
}
|
||||
} else if (_this.tool === "circle") {
|
||||
var a = currX - _this.startCoords[0];
|
||||
var b = currY - _this.startCoords[1];
|
||||
var r = Math.sqrt(a * a + b * b);
|
||||
if (_this.svgCirle) {
|
||||
_this.svgCirle.setAttribute('r', r);
|
||||
}
|
||||
}
|
||||
_this.prevX = currX;
|
||||
_this.prevY = currY;
|
||||
});
|
||||
_this.sendFunction({ "t": "cursor", "event": "move", "d": [currX, currY], "username": _this.settings.username });
|
||||
},
|
||||
triggerMouseOver: function () {
|
||||
var _this = this;
|
||||
if (_this.imgDragActive) {
|
||||
return;
|
||||
}
|
||||
if (!_this.mouseover) {
|
||||
var color = _this.drawcolor;
|
||||
var widthHeight = _this.thickness;
|
||||
if (_this.tool === "eraser") {
|
||||
color = "#00000000";
|
||||
widthHeight = widthHeight * 2;
|
||||
}
|
||||
if (_this.tool === "eraser" || _this.tool === "pen") {
|
||||
_this.ownCursor = $('<div id="ownCursor" style="background:' + color + '; border:1px solid gray; position:absolute; width:' + widthHeight + 'px; height:' + widthHeight + 'px; border-radius:50%;"></div>');
|
||||
_this.cursorContainer.append(_this.ownCursor);
|
||||
}
|
||||
}
|
||||
_this.mouseover = true;
|
||||
},
|
||||
triggerMouseOut: function () {
|
||||
var _this = this;
|
||||
if (_this.imgDragActive) {
|
||||
return;
|
||||
}
|
||||
_this.drawFlag = false;
|
||||
_this.mouseover = false;
|
||||
_this.ctx.globalCompositeOperation = _this.oldGCO;
|
||||
if (_this.ownCursor) _this.ownCursor.remove();
|
||||
_this.svgContainer.find("line").remove();
|
||||
_this.svgContainer.find("rect").remove();
|
||||
_this.svgContainer.find("circle").remove();
|
||||
_this.sendFunction({ "t": "cursor", "event": "out" });
|
||||
},
|
||||
redrawMouseCursor: function () {
|
||||
var _this = this;
|
||||
_this.triggerMouseOut();
|
||||
_this.triggerMouseOver();
|
||||
_this.triggerMouseMove({ currX: whiteboard.prevX, currY: whiteboard.prevY });
|
||||
},
|
||||
delKeyAction: function () {
|
||||
var _this = this;
|
||||
$.each(_this.mouseOverlay.find(".dragOutOverlay"), function () {
|
||||
var width = $(this).width();
|
||||
var height = $(this).height();
|
||||
var p = $(this).position();
|
||||
var left = Math.round(p.left * 100) / 100;
|
||||
var top = Math.round(p.top * 100) / 100;
|
||||
_this.drawId++;
|
||||
_this.sendFunction({ "t": "eraseRec", "d": [left, top, width, height] });
|
||||
_this.eraseRec(left, top, width, height);
|
||||
});
|
||||
_this.mouseOverlay.find(".xCanvasBtn").click(); //Remove all current drops
|
||||
_this.textContainer.find("#" + _this.latestActiveTextBoxId).find(".removeIcon").click();
|
||||
},
|
||||
escKeyAction: function () {
|
||||
var _this = this;
|
||||
if (!_this.drawFlag) {
|
||||
_this.svgContainer.empty();
|
||||
}
|
||||
_this.mouseOverlay.find(".xCanvasBtn").click(); //Remove all current drops
|
||||
},
|
||||
pushPointSmoothPen: function (X, Y) {
|
||||
var _this = this;
|
||||
if (_this.penSmoothLastCoords.length >= 8) {
|
||||
_this.penSmoothLastCoords = [_this.penSmoothLastCoords[2], _this.penSmoothLastCoords[3], _this.penSmoothLastCoords[4], _this.penSmoothLastCoords[5], _this.penSmoothLastCoords[6], _this.penSmoothLastCoords[7]]
|
||||
}
|
||||
_this.penSmoothLastCoords.push(X, Y)
|
||||
if (_this.penSmoothLastCoords.length >= 8) {
|
||||
_this.drawPenSmoothLine(_this.penSmoothLastCoords, _this.drawcolor, _this.thickness);
|
||||
_this.sendFunction({ "t": _this.tool, "d": _this.penSmoothLastCoords, "c": _this.drawcolor, "th": _this.thickness });
|
||||
}
|
||||
},
|
||||
dragCanvasRectContent: function (xf, yf, xt, yt, width, height) {
|
||||
var tempCanvas = document.createElement('canvas');
|
||||
tempCanvas.width = width;
|
||||
tempCanvas.height = height;
|
||||
var tempCanvasContext = tempCanvas.getContext('2d');
|
||||
tempCanvasContext.drawImage(this.canvas, xf, yf, width, height, 0, 0, width, height);
|
||||
this.eraseRec(xf, yf, width, height);
|
||||
this.ctx.drawImage(tempCanvas, xt, yt);
|
||||
},
|
||||
eraseRec: function (fromX, fromY, width, height) {
|
||||
var _this = this;
|
||||
_this.ctx.beginPath();
|
||||
_this.ctx.rect(fromX, fromY, width, height);
|
||||
_this.ctx.fillStyle = "rgba(0,0,0,1)";
|
||||
_this.ctx.globalCompositeOperation = "destination-out";
|
||||
_this.ctx.fill();
|
||||
_this.ctx.closePath();
|
||||
_this.ctx.globalCompositeOperation = _this.oldGCO;
|
||||
},
|
||||
drawPenLine: function (fromX, fromY, toX, toY, color, thickness) {
|
||||
var _this = this;
|
||||
_this.ctx.beginPath();
|
||||
_this.ctx.moveTo(fromX, fromY);
|
||||
_this.ctx.lineTo(toX, toY);
|
||||
_this.ctx.strokeStyle = color;
|
||||
_this.ctx.lineWidth = thickness;
|
||||
_this.ctx.lineCap = _this.lineCap;
|
||||
_this.ctx.stroke();
|
||||
_this.ctx.closePath();
|
||||
},
|
||||
drawPenSmoothLine: function (coords, color, thickness) {
|
||||
var _this = this;
|
||||
var xm1 = coords[0];
|
||||
var ym1 = coords[1];
|
||||
var x0 = coords[2];
|
||||
var y0 = coords[3];
|
||||
var x1 = coords[4];
|
||||
var y1 = coords[5];
|
||||
var x2 = coords[6];
|
||||
var y2 = coords[7];
|
||||
var length = Math.sqrt(Math.pow(x0 - x1, 2) + Math.pow(y0 - y1, 2));
|
||||
var steps = Math.ceil(length / 5);
|
||||
_this.ctx.beginPath();
|
||||
_this.ctx.moveTo(x0, y0);
|
||||
for (var i = 0; i < steps; i++) {
|
||||
var point = lanczosInterpolate(xm1, ym1, x0, y0, x1, y1, x2, y2, (i + 1) / steps);
|
||||
_this.ctx.lineTo(point[0], point[1]);
|
||||
}
|
||||
_this.ctx.strokeStyle = color;
|
||||
_this.ctx.lineWidth = thickness;
|
||||
_this.ctx.lineCap = _this.lineCap;
|
||||
_this.ctx.stroke();
|
||||
_this.ctx.closePath();
|
||||
},
|
||||
drawEraserLine: function (fromX, fromY, toX, toY, thickness) {
|
||||
var _this = this;
|
||||
_this.ctx.beginPath();
|
||||
_this.ctx.moveTo(fromX, fromY);
|
||||
_this.ctx.lineTo(toX, toY);
|
||||
_this.ctx.strokeStyle = "rgba(0,0,0,1)";
|
||||
_this.ctx.lineWidth = thickness * 2;
|
||||
_this.ctx.lineCap = _this.lineCap;
|
||||
_this.ctx.globalCompositeOperation = "destination-out";
|
||||
_this.ctx.stroke();
|
||||
_this.ctx.closePath();
|
||||
_this.ctx.globalCompositeOperation = _this.oldGCO;
|
||||
},
|
||||
drawRec: function (fromX, fromY, toX, toY, color, thickness) {
|
||||
var _this = this;
|
||||
toX = toX - fromX;
|
||||
toY = toY - fromY;
|
||||
_this.ctx.beginPath();
|
||||
_this.ctx.rect(fromX, fromY, toX, toY);
|
||||
_this.ctx.strokeStyle = color;
|
||||
_this.ctx.lineWidth = thickness;
|
||||
_this.ctx.lineCap = _this.lineCap;
|
||||
_this.ctx.stroke();
|
||||
_this.ctx.closePath();
|
||||
},
|
||||
drawCircle: function (fromX, fromY, radius, color, thickness) {
|
||||
var _this = this;
|
||||
_this.ctx.beginPath();
|
||||
_this.ctx.arc(fromX, fromY, radius, 0, 2 * Math.PI, false);
|
||||
_this.ctx.lineWidth = thickness;
|
||||
_this.ctx.strokeStyle = color;
|
||||
_this.ctx.stroke();
|
||||
},
|
||||
clearWhiteboard: function () {
|
||||
var _this = this;
|
||||
_this.canvas.height = _this.canvas.height;
|
||||
_this.imgContainer.empty();
|
||||
_this.textContainer.empty();
|
||||
_this.sendFunction({ "t": "clear" });
|
||||
_this.drawBuffer = [];
|
||||
_this.undoBuffer = [];
|
||||
_this.drawId = 0;
|
||||
},
|
||||
setStrokeThickness(thickness) {
|
||||
var _this = this;
|
||||
_this.thickness = thickness;
|
||||
|
||||
if (_this.tool == "text" && _this.latestActiveTextBoxId) {
|
||||
_this.sendFunction({ "t": "setTextboxFontSize", "d": [_this.latestActiveTextBoxId, thickness] });
|
||||
_this.setTextboxFontSize(_this.latestActiveTextBoxId, thickness);
|
||||
}
|
||||
},
|
||||
addImgToCanvasByUrl: function (url) {
|
||||
var _this = this;
|
||||
var wasTextTool = false;
|
||||
if (_this.tool === "text") {
|
||||
wasTextTool = true;
|
||||
_this.setTool("mouse"); //Set to mouse tool while dropping to prevent errors
|
||||
}
|
||||
_this.imgDragActive = true;
|
||||
_this.mouseOverlay.css({ "cursor": "default" });
|
||||
var imgDiv = $('<div class="dragMe" style="border: 2px dashed gray; position:absolute; left:200px; top:200px; min-width:160px; min-height:100px; cursor:move;">' +
|
||||
'<img style="width:100%; height:100%;" src="' + url + '">' +
|
||||
'<div style="position:absolute; right:5px; top:3px;">' +
|
||||
'<button draw="1" style="margin: 0px 0px; background: #03a9f4; padding: 5px; margin-top: 3px; color: white;" class="addToCanvasBtn btn btn-default">Draw to canvas</button> ' +
|
||||
'<button draw="0" style="margin: 0px 0px; background: #03a9f4; padding: 5px; margin-top: 3px; color: white;" class="addToBackgroundBtn btn btn-default">Add to background</button> ' +
|
||||
'<button style="margin: 0px 0px; background: #03a9f4; padding: 5px; margin-top: 3px; color: white;" class="xCanvasBtn btn btn-default">x</button>' +
|
||||
'</div>' +
|
||||
'<i style="position:absolute; bottom: -4px; right: 2px; font-size: 2em; color: gray; transform: rotate(-45deg);" class="fas fa-sort-down" aria-hidden="true"></i>' +
|
||||
'</div>');
|
||||
imgDiv.find(".xCanvasBtn").click(function () {
|
||||
_this.imgDragActive = false;
|
||||
_this.refreshCursorAppearance();
|
||||
imgDiv.remove();
|
||||
if (wasTextTool) {
|
||||
_this.setTool("text");
|
||||
}
|
||||
});
|
||||
imgDiv.find(".addToCanvasBtn,.addToBackgroundBtn").click(function () {
|
||||
var draw = $(this).attr("draw");
|
||||
_this.imgDragActive = false;
|
||||
_this.refreshCursorAppearance();
|
||||
var width = imgDiv.width();
|
||||
var height = imgDiv.height();
|
||||
var p = imgDiv.position();
|
||||
var left = Math.round(p.left * 100) / 100;
|
||||
var top = Math.round(p.top * 100) / 100;
|
||||
if (draw == "1") { //draw image to canvas
|
||||
_this.drawImgToCanvas(url, width, height, left, top);
|
||||
} else { //Add image to background
|
||||
_this.drawImgToBackground(url, width, height, left, top);
|
||||
}
|
||||
_this.sendFunction({ "t": "addImgBG", "draw": draw, "url": url, "d": [width, height, left, top] });
|
||||
_this.drawId++;
|
||||
imgDiv.remove();
|
||||
if (wasTextTool) {
|
||||
_this.setTool("text");
|
||||
}
|
||||
});
|
||||
_this.mouseOverlay.append(imgDiv);
|
||||
imgDiv.draggable();
|
||||
imgDiv.resizable();
|
||||
},
|
||||
drawImgToBackground(url, width, height, left, top) {
|
||||
this.imgContainer.append('<img crossorigin="anonymous" style="width:' + width + 'px; height:' + height + 'px; position:absolute; top:' + top + 'px; left:' + left + 'px;" src="' + url + '">')
|
||||
},
|
||||
addTextBox(textcolor, fontsize, left, top, txId, newLocalBox) {
|
||||
var _this = this;
|
||||
var textBox = $('<div id="' + txId + '" class="textBox" style="font-family: Monospace; position:absolute; top:' + top + 'px; left:' + left + 'px;">' +
|
||||
'<div contentEditable="true" spellcheck="false" class="textContent" style="outline: none; font-size:' + fontsize + 'em; color:' + textcolor + '; min-width:50px; min-height:50px;"></div>' +
|
||||
'<div title="remove textbox" class="removeIcon" style="position:absolute; cursor:pointer; top:-4px; right:2px;">x</div>' +
|
||||
'<div title="move textbox" class="moveIcon" style="position:absolute; cursor:move; top:1px; left:2px; font-size: 0.5em;"><i class="fas fa-expand-arrows-alt"></i></div>' +
|
||||
'</div>');
|
||||
_this.latestActiveTextBoxId = txId;
|
||||
textBox.click(function (e) {
|
||||
e.preventDefault();
|
||||
_this.latestActiveTextBoxId = txId;
|
||||
return false;
|
||||
})
|
||||
textBox.on("mousemove touchmove", function (e) {
|
||||
e.preventDefault();
|
||||
if (_this.imgDragActive) {
|
||||
return;
|
||||
}
|
||||
var textBoxPosition = textBox.position();
|
||||
var currX = (e.offsetX + textBoxPosition.left);
|
||||
var currY = (e.offsetY + textBoxPosition.top);
|
||||
if ($(e.target).hasClass("removeIcon")) {
|
||||
currX += textBox.width() - 4;
|
||||
}
|
||||
_this.sendFunction({ "t": "cursor", "event": "move", "d": [currX, currY], "username": _this.settings.username });
|
||||
})
|
||||
this.textContainer.append(textBox);
|
||||
textBox.draggable({
|
||||
handle: ".moveIcon",
|
||||
stop: function () {
|
||||
var textBoxPosition = textBox.position();
|
||||
_this.sendFunction({ "t": "setTextboxPosition", "d": [txId, textBoxPosition.top, textBoxPosition.left] });
|
||||
},
|
||||
drag: function () {
|
||||
var textBoxPosition = textBox.position();
|
||||
_this.sendFunction({ "t": "setTextboxPosition", "d": [txId, textBoxPosition.top, textBoxPosition.left] });
|
||||
}
|
||||
});
|
||||
textBox.find(".textContent").on("input", function () {
|
||||
var text = btoa(unescape(encodeURIComponent($(this).html()))); //Get html and make encode base64 also take care of the charset
|
||||
_this.sendFunction({ "t": "setTextboxText", "d": [txId, text] });
|
||||
});
|
||||
textBox.find(".removeIcon").click(function (e) {
|
||||
$("#" + txId).remove();
|
||||
_this.sendFunction({ "t": "removeTextbox", "d": [txId] });
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
if (newLocalBox) {
|
||||
textBox.find(".textContent").focus();
|
||||
}
|
||||
if (this.tool === "text") {
|
||||
textBox.addClass("active");
|
||||
}
|
||||
},
|
||||
setTextboxText(txId, text) {
|
||||
$("#" + txId).find(".textContent").html(decodeURIComponent(escape(atob(text)))); //Set decoded base64 as html
|
||||
},
|
||||
removeTextbox(txId) {
|
||||
$("#" + txId).remove();
|
||||
},
|
||||
setTextboxPosition(txId, top, left) {
|
||||
$("#" + txId).css({ "top": top + "px", "left": left + "px" });
|
||||
},
|
||||
setTextboxFontSize(txId, fontSize) {
|
||||
$("#" + txId).find(".textContent").css({ "font-size": fontSize + "em" });
|
||||
},
|
||||
setTextboxFontColor(txId, color) {
|
||||
$("#" + txId).find(".textContent").css({ "color": color });
|
||||
},
|
||||
drawImgToCanvas(url, width, height, left, top, doneCallback) {
|
||||
var _this = this;
|
||||
var img = document.createElement('img');
|
||||
img.onload = function () {
|
||||
_this.ctx.drawImage(img, left, top, width, height);
|
||||
if (doneCallback) {
|
||||
doneCallback();
|
||||
}
|
||||
}
|
||||
img.src = url;
|
||||
},
|
||||
undoWhiteboard: function (username) { //Not call this directly because you will get out of sync whit others...
|
||||
var _this = this;
|
||||
if (!username) {
|
||||
username = _this.settings.username;
|
||||
}
|
||||
for (var i = _this.drawBuffer.length - 1; i >= 0; i--) {
|
||||
if (_this.drawBuffer[i]["username"] == username) {
|
||||
var drawId = _this.drawBuffer[i]["drawId"];
|
||||
for (var i = _this.drawBuffer.length - 1; i >= 0; i--) {
|
||||
if (_this.drawBuffer[i]["drawId"] == drawId && _this.drawBuffer[i]["username"] == username) {
|
||||
_this.undoBuffer.push(_this.drawBuffer[i])
|
||||
_this.drawBuffer.splice(i, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_this.undoBuffer.length > 1000) {
|
||||
_this.undoBuffer.splice(0, _this.undoBuffer.length-1000);
|
||||
}
|
||||
_this.canvas.height = _this.canvas.height;
|
||||
_this.imgContainer.empty();
|
||||
_this.loadDataInSteps(_this.drawBuffer, false, function (stepData) {
|
||||
//Nothing to do
|
||||
});
|
||||
},
|
||||
redoWhiteboard: function (username) { //Not call this directly because you will get out of sync whit others...
|
||||
var _this = this;
|
||||
if (!username) {
|
||||
username = _this.settings.username;
|
||||
}
|
||||
for (var i = _this.undoBuffer.length - 1; i >= 0; i--) {
|
||||
if (_this.undoBuffer[i]["username"] == username) {
|
||||
var drawId = _this.undoBuffer[i]["drawId"];
|
||||
for (var i = _this.undoBuffer.length - 1; i >= 0; i--) {
|
||||
if (_this.undoBuffer[i]["drawId"] == drawId && _this.undoBuffer[i]["username"] == username) {
|
||||
_this.drawBuffer.push(_this.undoBuffer[i])
|
||||
_this.undoBuffer.splice(i, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
_this.canvas.height = _this.canvas.height;
|
||||
_this.imgContainer.empty();
|
||||
_this.loadDataInSteps(_this.drawBuffer, false, function (stepData) {
|
||||
//Nothing to do
|
||||
});
|
||||
},
|
||||
undoWhiteboardClick: function () {
|
||||
this.sendFunction({ "t": "undo" });
|
||||
this.undoWhiteboard();
|
||||
},
|
||||
redoWhiteboardClick: function () {
|
||||
this.sendFunction({ "t": "redo" });
|
||||
this.redoWhiteboard();
|
||||
},
|
||||
setTool: function (tool) {
|
||||
this.tool = tool;
|
||||
if (this.tool === "text") {
|
||||
$(".textBox").addClass("active");
|
||||
this.textContainer.appendTo($(whiteboardContainer)); //Bring textContainer to the front
|
||||
} else {
|
||||
$(".textBox").removeClass("active");
|
||||
this.mouseOverlay.appendTo($(whiteboardContainer));
|
||||
}
|
||||
this.refreshCursorAppearance();
|
||||
this.mouseOverlay.find(".xCanvasBtn").click();
|
||||
this.latestActiveTextBoxId = null;
|
||||
},
|
||||
setDrawColor(color) {
|
||||
var _this = this;
|
||||
_this.drawcolor = color;
|
||||
if (_this.tool == "text" && _this.latestActiveTextBoxId) {
|
||||
_this.sendFunction({ "t": "setTextboxFontColor", "d": [_this.latestActiveTextBoxId, color] });
|
||||
_this.setTextboxFontColor(_this.latestActiveTextBoxId, color);
|
||||
}
|
||||
},
|
||||
updateSmallestScreenResolution(width, height) {
|
||||
this.backgroundGrid.empty();
|
||||
if (width < $(window).width() || height < $(window).height()) {
|
||||
this.backgroundGrid.append('<div style="position:absolute; left:0px; top:0px; border-right:3px dotted black; border-bottom:3px dotted black; width:' + width + 'px; height:' + height + 'px;"></div>');
|
||||
this.backgroundGrid.append('<div style="position:absolute; left:' + (width + 5) + 'px; top:0px;">smallest screen participating</div>');
|
||||
}
|
||||
},
|
||||
handleEventsAndData: function (content, isNewData, doneCallback) {
|
||||
var _this = this;
|
||||
var tool = content["t"];
|
||||
var data = content["d"];
|
||||
var color = content["c"];
|
||||
var username = content["username"];
|
||||
var thickness = content["th"];
|
||||
window.requestAnimationFrame(function () {
|
||||
if (tool === "line" || tool === "pen") {
|
||||
if (data.length == 4) { //Only used for old json imports
|
||||
_this.drawPenLine(data[0], data[1], data[2], data[3], color, thickness);
|
||||
} else {
|
||||
_this.drawPenSmoothLine(data, color, thickness);
|
||||
}
|
||||
} else if (tool === "rect") {
|
||||
_this.drawRec(data[0], data[1], data[2], data[3], color, thickness);
|
||||
} else if (tool === "circle") {
|
||||
_this.drawCircle(data[0], data[1], data[2], color, thickness);
|
||||
} else if (tool === "eraser") {
|
||||
_this.drawEraserLine(data[0], data[1], data[2], data[3], thickness);
|
||||
} else if (tool === "eraseRec") {
|
||||
_this.eraseRec(data[0], data[1], data[2], data[3]);
|
||||
} else if (tool === "recSelect") {
|
||||
_this.dragCanvasRectContent(data[0], data[1], data[2], data[3], data[4], data[5]);
|
||||
} else if (tool === "addImgBG") {
|
||||
if (content["draw"] == "1") {
|
||||
_this.drawImgToCanvas(content["url"], data[0], data[1], data[2], data[3], doneCallback)
|
||||
} else {
|
||||
_this.drawImgToBackground(content["url"], data[0], data[1], data[2], data[3]);
|
||||
}
|
||||
} else if (tool === "addTextBox") {
|
||||
_this.addTextBox(data[0], data[1], data[2], data[3], data[4]);
|
||||
} else if (tool === "setTextboxText") {
|
||||
_this.setTextboxText(data[0], data[1]);
|
||||
} else if (tool === "removeTextbox") {
|
||||
_this.removeTextbox(data[0]);
|
||||
} else if (tool === "setTextboxPosition") {
|
||||
_this.setTextboxPosition(data[0], data[1], data[2]);
|
||||
} else if (tool === "setTextboxFontSize") {
|
||||
_this.setTextboxFontSize(data[0], data[1]);
|
||||
} else if (tool === "setTextboxFontColor") {
|
||||
_this.setTextboxFontColor(data[0], data[1]);
|
||||
} else if (tool === "clear") {
|
||||
_this.canvas.height = _this.canvas.height;
|
||||
_this.imgContainer.empty();
|
||||
_this.textContainer.empty();
|
||||
_this.drawBuffer = [];
|
||||
_this.undoBuffer = [];
|
||||
_this.drawId = 0;
|
||||
} else if (tool === "cursor" && _this.settings) {
|
||||
if (content["event"] === "move") {
|
||||
if (_this.cursorContainer.find("." + content["username"]).length >= 1) {
|
||||
_this.cursorContainer.find("." + content["username"]).css({ "left": data[0] + "px", "top": (data[1] - 15) + "px" });
|
||||
} else {
|
||||
_this.cursorContainer.append('<div style="font-size:0.8em; padding-left:2px; padding-right:2px; background:gray; color:white; border-radius:3px; position:absolute; left:' + data[0] + 'px; top:' + (data[1] - 151) + 'px;" class="userbadge ' + content["username"] + '">' +
|
||||
'<div style="width:4px; height:4px; background:gray; position:absolute; top:13px; left:-2px; border-radius:50%;"></div>' +
|
||||
decodeURIComponent(atob(content["username"])) + '</div>');
|
||||
}
|
||||
} else {
|
||||
_this.cursorContainer.find("." + content["username"]).remove();
|
||||
}
|
||||
} else if (tool === "undo") {
|
||||
_this.undoWhiteboard(username);
|
||||
} else if (tool === "redo") {
|
||||
_this.redoWhiteboard(username);
|
||||
}
|
||||
});
|
||||
|
||||
if (isNewData && ["line", "pen", "rect", "circle", "eraser", "addImgBG", "recSelect", "eraseRec", "addTextBox", "setTextboxText", "removeTextbox", "setTextboxPosition", "setTextboxFontSize", "setTextboxFontColor"].includes(tool)) {
|
||||
content["drawId"] = content["drawId"] ? content["drawId"] : _this.drawId;
|
||||
content["username"] = content["username"] ? content["username"] : _this.settings.username;
|
||||
_this.drawBuffer.push(content);
|
||||
}
|
||||
},
|
||||
userLeftWhiteboard(username) {
|
||||
this.cursorContainer.find("." + username).remove();
|
||||
},
|
||||
refreshUserBadges() {
|
||||
this.cursorContainer.find(".userbadge").remove();
|
||||
},
|
||||
getImageDataBase64() {
|
||||
_this = this;
|
||||
var width = this.mouseOverlay.width();
|
||||
var height = this.mouseOverlay.height();
|
||||
var copyCanvas = document.createElement('canvas');
|
||||
copyCanvas.width = width;
|
||||
copyCanvas.height = height;
|
||||
var ctx = copyCanvas.getContext("2d");
|
||||
|
||||
$.each(_this.imgContainer.find("img"), function () { //Draw Backgroundimages to the export canvas
|
||||
var width = $(this).width();
|
||||
var height = $(this).height();
|
||||
var p = $(this).position();
|
||||
var left = Math.round(p.left * 100) / 100;
|
||||
var top = Math.round(p.top * 100) / 100;
|
||||
ctx.drawImage(this, left, top, width, height);
|
||||
});
|
||||
|
||||
var destCtx = copyCanvas.getContext('2d'); //Draw the maincanvas to the exportcanvas
|
||||
destCtx.drawImage(this.canvas, 0, 0);
|
||||
|
||||
$.each($(".textBox"), function () { //Draw the text on top
|
||||
var textContainer = $(this)
|
||||
var textEl = $(this).find(".textContent");
|
||||
var text = textEl.text();
|
||||
var fontSize = textEl.css('font-size');
|
||||
var fontColor = textEl.css('color');
|
||||
var p = textContainer.position();
|
||||
var left = Math.round(p.left * 100) / 100;
|
||||
var top = Math.round(p.top * 100) / 100;
|
||||
top += 25; //Fix top position
|
||||
ctx.font = fontSize + " Monospace";
|
||||
ctx.fillStyle = fontColor;
|
||||
ctx.fillText(text, left, top);
|
||||
});
|
||||
|
||||
var url = copyCanvas.toDataURL();
|
||||
return url;
|
||||
},
|
||||
getImageDataJson() {
|
||||
var sendObj = [];
|
||||
for (var i = 0; i < this.drawBuffer.length; i++) {
|
||||
sendObj.push(JSON.parse(JSON.stringify(this.drawBuffer[i])));
|
||||
delete sendObj[i]["username"];
|
||||
delete sendObj[i]["wid"];
|
||||
delete sendObj[i]["drawId"];
|
||||
}
|
||||
return JSON.stringify(sendObj);
|
||||
},
|
||||
loadData: function (content) {
|
||||
var _this = this;
|
||||
_this.loadDataInSteps(content, true, function (stepData) {
|
||||
if (stepData["username"] == _this.settings.username && _this.drawId < stepData["drawId"]) {
|
||||
_this.drawId = stepData["drawId"] + 1;
|
||||
}
|
||||
});
|
||||
},
|
||||
loadDataInSteps(content, isNewData, callAfterEveryStep) {
|
||||
var _this = this;
|
||||
|
||||
function lData(index) {
|
||||
for (var i = index; i < content.length; i++) {
|
||||
if (content[i]["t"] === "addImgBG" && content[i]["draw"] == "1") {
|
||||
_this.handleEventsAndData(content[i], isNewData, function () {
|
||||
callAfterEveryStep(content[i], i);
|
||||
lData(i + 1);
|
||||
});
|
||||
break;
|
||||
} else {
|
||||
_this.handleEventsAndData(content[i], isNewData);
|
||||
callAfterEveryStep(content[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
lData(0);
|
||||
},
|
||||
loadJsonData(content, doneCallback) {
|
||||
var _this = this;
|
||||
_this.loadDataInSteps(content, false, function (stepData, index) {
|
||||
_this.sendFunction(stepData);
|
||||
if (index >= content.length - 1) { //Done with all data
|
||||
_this.drawId++;
|
||||
if (doneCallback) {
|
||||
doneCallback();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
sendFunction: function (content) { //Sends every draw to server
|
||||
var _this = this;
|
||||
content["wid"] = _this.settings.whiteboardId;
|
||||
content["username"] = _this.settings.username;
|
||||
content["drawId"] = _this.drawId;
|
||||
|
||||
var tool = content["t"];
|
||||
if (_this.settings.sendFunction) {
|
||||
_this.settings.sendFunction(content);
|
||||
}
|
||||
if (["line", "pen", "rect", "circle", "eraser", "addImgBG", "recSelect", "eraseRec", "addTextBox", "setTextboxText", "removeTextbox", "setTextboxPosition", "setTextboxFontSize", "setTextboxFontColor"].includes(tool)) {
|
||||
_this.drawBuffer.push(content);
|
||||
}
|
||||
},
|
||||
refreshCursorAppearance() { //Set cursor depending on current active tool
|
||||
var _this = this;
|
||||
if (_this.tool === "pen" || _this.tool === "eraser") {
|
||||
_this.mouseOverlay.css({ "cursor": "none" });
|
||||
} else if (_this.tool === "mouse") {
|
||||
this.mouseOverlay.css({ "cursor": "default" });
|
||||
} else { //Line, Rec, Circle, Cutting
|
||||
_this.mouseOverlay.css({ "cursor": "crosshair" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function lanczosKernel(x) {
|
||||
if (x == 0) {
|
||||
return 1.0;
|
||||
}
|
||||
return 2 * Math.sin(Math.PI * x) * Math.sin(Math.PI * x / 2) / Math.pow(Math.PI * x, 2);
|
||||
}
|
||||
|
||||
function lanczosInterpolate(xm1, ym1, x0, y0, x1, y1, x2, y2, a) {
|
||||
var cm1 = lanczosKernel(1 + a);
|
||||
var c0 = lanczosKernel(a);
|
||||
var c1 = lanczosKernel(1 - a);
|
||||
var c2 = lanczosKernel(2 - a);
|
||||
var delta = (cm1 + c0 + c1 + c2 - 1) / 4;
|
||||
cm1 -= delta;
|
||||
c0 -= delta;
|
||||
c1 -= delta;
|
||||
c2 -= delta;
|
||||
return [cm1 * xm1 + c0 * x0 + c1 * x1 + c2 * x2, cm1 * ym1 + c0 * y0 + c1 * y1 + c2 * y2];
|
||||
}
|
||||
Reference in New Issue
Block a user