Newer
Older
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
* {
touch-action: none;
}
body {
background-color: red;
}
button {
background-color: #D8D8D8;
border: 1px solid #999999;
border-radius: 5px;
}
button.selected {
box-shadow: 0 0 2px 2px #0597f8;
}
#board {
touch-action: none;
box-shadow: 1px 1px 1px 0.5px rgba(0, 0, 0, 0.1);
cursor: crosshair;
position: absolute;
left: 0px;
border-radius: 8px;
box-shadow: 0.5px 0.5px 2px #555555, inset 0px 0px 1px #555555;
position: absolute;
z-index: 20;
touch-action: none;
#ruler::before {
position:absolute;
background-color: #ffffff;
background:
repeating-linear-gradient(180deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 43px, #777777 46px),
repeating-linear-gradient(90deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 751px, #ffffff 751px, #ffffff 769px),
repeating-linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 30px, #ffffff 30px, #ffffff 50px),
repeating-linear-gradient(90deg, #222222, #222222 1px, rgba(0, 0, 0, 0) 1px, rgba(0, 0, 0, 0) 50px),
repeating-linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 10px, #ffffff 10px, #ffffff 50px),
repeating-linear-gradient(90deg, #222222, #222222 1px, rgba(0, 0, 0, 0) 1px, rgba(0, 0, 0, 0) 5px);
background-position-x: 10px;
opacity: 50%;
width: 100%;
height: 45px;
content: "";
}
#ruler::after {
position:absolute;
background-color: #ffffff;
opacity: 20%;
width: 100%;
height: 10px;
bottom: 0px;
border-top: 1px solid #555555;
filter: blur(1px);
content: "";
}
#ruler #rulerTopLeft {
position: relative;
top: 0px;
left: 0px;
width: 0px;
height: 0px;
background-color: blue;
}
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#menuTop {
position: absolute;
top: 0px;
left: 0px;
margin-left: 30px;
}
#sidePanelLeft {
position: absolute;
width: 30%;
height: 100%;
top: 0px;
left: -30%;
background-color: #fafafa;
box-shadow: #999 0px 0px 12px;
padding: 20px;
box-sizing: border-box;
}
#sidePanelLeft::after {
content: "Notes";
position: absolute;
right: -25px;
width: 25px;
padding: 20px 0px;
font-family: sans-serif;
font-size: 20px;
top: 0px;
background-color: #fafafa;
writing-mode: vertical-rl;
text-orientation: mixed;
box-shadow: #999 0px 0px 12px;
border-top-left-radius: 10px;
transform: rotate(180deg);
}
#sidePanelShadowHider {
position: absolute;
width: 12px;
height: 100%;
right: 0px;
top: 0px;
background-color: #fafafa;
pointer-events: none;
z-index: 2;
}
#sidePanelLeft button {
padding: 20px;
margin-bottom: 20px;
min-width: 150px;
}
#helper, #helper1, #helper2, #helper3, #helper4 {
background-color: fuchsia;
width: 10px;
height: 10px;
position: absolute;
z-index: 21;
touch-action: none;
left: 200px;
top: 200px;
}
#helper1, #helper2 {
width: 150px;
height: 150px;
border-radius: 75px;
opacity: 0.8;
}
#helper1 {
background-color: yellow;
}
#helper2{
background-color: orange;
}
#helper3{
background-color: lime;
border-radius: 5px;
}
#helper4{
background-color: red;
border-radius: 5px;
}
<script type="application/javascript" src="js/lib.js"></script>

Andreas Horn
committed
<script type="application/javascript" src="js/Vector.js"></script>
<script type="application/javascript" src="js/main.js"></script>
<script type="application/javascript" src="js/Board.js"></script>
<script type="application/javascript" src="js/Pen.js"></script>
<script type="application/javascript" src="js/PointerManager.js"></script>
<script type="application/javascript" src="js/Ruler.js"></script>
Ruler.init(document.getElementById("ruler"));
setColor("#000000");
setLineWidth("8");
var pointerDown = function (e) {
//console.log("down");
clearTimeout(redrawAllTimeout);
PointerManager.registerPointer(e);
if (e.pointerType == "pen") {
if (!Pen.erase) {
// start new free hand stroke
Board.strokeData.push([]);
// check if we must follow the ruler
Board.collectStrokeInfo(e, Pen);
} else {
}

Andreas Horn
committed
} else if (e.pointerType == "touch") {
gestureStartPoint[e.pointerId] = e;
var pointerMove = function (e) {
if (!Pen.erase) {
Board.collectStrokeInfo(e, Pen);
} else {
Board.eraseLine(e, Pen);
}
} else if (e.pointerType == "touch") {
detectGesture(e);
var pointerCancel = function (e) {
//console.log("cancel");
if (!Pen.erase) {
Board.drawLastCurve();

Andreas Horn
committed
clearTimeout(redrawAllTimeout);
redrawAllTimeout = setTimeout(_ => Board.redrawAll(), 1000);
}
} else if (e.pointerType == "touch") {
if (gestureStartPoint[e.pointerId]) {
delete gestureStartPoint[e.pointerId];
}

Andreas Horn
committed
}
var pointerSwipeInFromLeft = function (e) {
var swipeDistance = Math.abs(e.detail.x - e.detail.startX);
var width = sidePanelLeft.offsetWidth;
var offsetX = e.detail.x;
var offsetXSidePanel = -width + offsetX;
if (offsetXSidePanel >= 0 || swipeDistance > 100) {

Andreas Horn
committed
showSidePanelLeft();
return;
}
sidePanelLeft.style.transition = "";
sidePanelLeft.style.left = offsetXSidePanel + "px";
document.getElementById("menuTop").style.transition = "";
document.getElementById("menuTop").style.left = offsetX + "px";
}
var pointerSwipeOutToLeft = function (e) {

Andreas Horn
committed
hideSidePanelLeft();
}
var pointerSwipeLeft = function (e) {
if (e.detail.target == sidePanelLeft) {
var swipeDistance = Math.abs(e.detail.x - e.detail.startX);
if (swipeDistance > 100) {

Andreas Horn
committed
hideSidePanelLeft();

Andreas Horn
committed
var hideSidePanelLeft = function () {
sidePanelLeft.style.transition = "left 0.5s";
sidePanelLeft.style.left = -sidePanelLeft.offsetWidth + "px";
document.getElementById("menuTop").style.transition = "left 0.5s";
document.getElementById("menuTop").style.left = "0px";
sidePanelLeft.dataset.visible = false;
}
var showSidePanelLeft = function () {
sidePanelLeft.style.transition = "";
sidePanelLeft.style.left = "0px";
document.getElementById("menuTop").style.transition = "";
document.getElementById("menuTop").style.left = sidePanelLeft.offsetWidth + "px";
sidePanelLeft.dataset.visible = true;
}
var sidePanelLeftOnClick = function () {
if (sidePanelLeft.dataset.visible == "false") {
showSidePanelLeft();
}
}
Board.canvas.addEventListener("pointerdown", pointerDown);
Board.canvas.addEventListener("pointermove", pointerMove);
Board.canvas.addEventListener("pointerup", pointerCancel);
Board.canvas.addEventListener("pointerleave", pointerCancel);
sidePanelLeft = document.getElementById("sidePanelLeft");
noteList = document.getElementById("noteList");
updateNoteList();
sidePanelLeft.addEventListener("pointerdown", pointerDown);
sidePanelLeft.addEventListener("pointermove", pointerMove);
sidePanelLeft.addEventListener("pointerup", pointerCancel);
sidePanelLeft.addEventListener("pointerleave", pointerCancel);

Andreas Horn
committed
sidePanelLeft.addEventListener("pointerdown", sidePanelLeftOnClick);
document.addEventListener("swipeInFromLeft", pointerSwipeInFromLeft);
document.addEventListener("swipeOutToLeft", pointerSwipeOutToLeft);
document.addEventListener("swipeLeft", pointerSwipeLeft);

Andreas Horn
committed
// set drawing call
setInterval(_ => Board.drawLastCurve(), 30);
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
function updateNoteList() {
noteList.innerHTML = "";
for (var key of Object.keys(localStorage)) {
if (key.startsWith("strokeData/")) {
var noteName = key.replace(/^strokeData\//, "");
var btn = newElement("button", {}, noteName);
((noteName) => btn.addEventListener("click", _ => Board.load(noteName)))(noteName);
noteList.appendChild(btn);
noteList.appendChild(newElement("br"));
}
}
}
var sidePanelLeft;
var noteList;
var gestureStartPoint = [];
function detectGesture(ev) {
if (gestureStartPoint[ev.pointerId]) {
var gsp = gestureStartPoint[ev.pointerId];
if (gsp.started == "swipeInFromLeft" || (gsp.clientX < ev.clientX && gsp.clientX < 10)) {
gsp.started = "swipeInFromLeft";
var swipeInFromLeft = new CustomEvent("swipeInFromLeft", {
detail: {
target: ev.target,
pointerId: ev.pointerId,
startX: gsp.clientX,
startY: gsp.clientY,
x: ev.clientX,
y: ev.clientY
}
});
document.dispatchEvent(swipeInFromLeft);
}
if (gsp.clientX > ev.clientX && ev.clientX < 10) {
var swipeOutToLeft = new CustomEvent("swipeOutToLeft", {
detail: {
target: ev.target,
pointerId: ev.pointerId,
startX: gsp.clientX,
startY: gsp.clientY,
x: ev.clientX,
y: ev.clientY
}
});
document.dispatchEvent(swipeOutToLeft);
}
if (gsp.clientX > ev.clientX) {
var swipeLeft = new CustomEvent("swipeLeft", {
detail: {
target: ev.target,
pointerId: ev.pointerId,
startX: gsp.clientX,
startY: gsp.clientY,
x: ev.clientX,
y: ev.clientY
}
});
document.dispatchEvent(swipeLeft);
}
}
}
// sets the color when a color button was pressed
function setColor(btn) {
Pen.colors.fg = (btn.dataset) ? btn.dataset.color : btn;
Pen.erase = Pen.colors.fg.startsWith("erase");
document.querySelectorAll("button[data-color]").forEach(b => b.classList.remove("selected"));
document.querySelector("button[data-color='" + Pen.colors.fg + "']").classList.add("selected");
}
// sets the line with when a line with button was pressed
function setLineWidth(btn) {
Pen.lineWidth = (btn.dataset) ? btn.dataset.lineWidth : btn;
document.querySelectorAll("button[data-line-width]").forEach(b => b.classList.remove("selected"));
document.querySelector("button[data-line-width='" + Pen.lineWidth + "']").classList.add("selected");
}
function toggleRuler(btn) {
if (Ruler.visible) {
Ruler.hide();
btn.classList.remove("selected");
} else {
Ruler.show();
btn.classList.add("selected");
}
}
function btnLoad() {
var noteName = prompt("Please enter the name of the note to load:");
if (noteName != "") {
Board.load(noteName);
} else {
alert("Could not find note, loading the lastest saved note!");
Board.load(Board.latestNote);
}
}
</script>
</head>
<body onload="init();">
<canvas touch-action="none" id="board" width="640" height="640" style="width:320px; height:320px;">
Opps, you cannot play draw N guess with this browser!
</canvas>
<div id="menuTop">
<button style="position:absolute; top:20px; left: 20px; width: 80px; height: 35px;" onclick="Board.save();">save</button>
<button style="position:absolute; top:65px; left: 20px; width: 80px; height: 35px;" onclick="btnLoad();">load</button>
<button style="position:absolute; top:20px; left: 120px; width: 80px; height: 80px;" onclick="Board.clear();">clear</button>
<button data-color="#000000" style="position:absolute; top:20px; left: 220px; width: 35px; height: 35px; background-color: black; color: white" onclick="setColor(this);"> </button>
<button data-color="#FF0000" style="position:absolute; top:20px; left: 265px; width: 35px; height: 35px; background-color: red;" onclick="setColor(this);"> </button>
<button data-color="#4169E1" style="position:absolute; top:65px; left: 220px; width: 35px; height: 35px; background-color: royalblue;" onclick="setColor(this);"> </button>
<button data-color="#32CD32" style="position:absolute; top:65px; left: 265px; width: 35px; height: 35px; background-color: limegreen;" onclick="setColor(this);"> </button>
<button data-color="eraseLine" style="position:absolute; top:20px; left: 320px; width: 80px; height: 35px;" onclick="setColor(this);">erase line</button>
<button data-color="erase" style="position:absolute; top:65px; left: 320px; width: 80px; height: 35px;" onclick="setColor(this);">erase</button>
<button data-line-width="4" style="position:absolute; top:20px; left: 420px; width: 35px; height: 35px;" onclick="setLineWidth(this);">4</button>
<button data-line-width="8" style="position:absolute; top:20px; left: 465px; width: 35px; height: 35px;" onclick="setLineWidth(this);">8</button>
<button data-line-width="16" style="position:absolute; top:65px; left: 420px; width: 35px; height: 35px;" onclick="setLineWidth(this);">16</button>
<button data-line-width="24" style="position:absolute; top:65px; left: 465px; width: 35px; height: 35px;" onclick="setLineWidth(this);">24</button>
<button style="position:absolute; top:20px; left: 520px; width: 80px; height: 35px;" onclick="toggleRuler(this);">Ruler</button>
</div>
<div id="ruler">
<div id="rulerTopLeft">top left</div>
<div id="rulerValues"></div>
</div>

Andreas Horn
committed
<div id="sidePanelLeft" data-visible="false">
<div id="sidePanelShadowHider"></div>
Notes: <br>
<br>
<div id="noteList">
</div>
</div>
<div id="helper"></div>
<div id="helper1"></div>
<div id="helper2"></div>
<div id="helper3"></div>