<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>Drawing</title>
<style>
body,
html {
user-select: none;
height: 100%;
margin: 0;
font-family: sans-serif;
background: white;
}
body {
position: fixed;
top: 0;
}
.ui {
position: fixed;
display: flex;
bottom: 0;
width: 100%;
margin-bottom: .2em;
}
.ui .tool {
font-size: 2em;
flex: 1;
text-align: center;
}
.tool span {
cursor: pointer;
display: inline-block;
transform: scale(0.7);
transition: transform 250ms ease-out;
}
.tool span.selected {
transform: scale(1);
}
svg {
overflow: visible;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
input[type=color] {
position: absolute;
left: 0;
top: 0;
height: 100%;
opacity: 0;
cursor: pointer;
}
.message {
position: fixed;
left: 0;
top: 0;
padding: 1em;
width: 100%;
text-align: center;
font-size: 1.2em;
transition: opacity 250ms ease-out;
pointer-events: none;
}
.message.hide {
opacity: 0;
}
</style>
</head>
<body>
<svg class="paper" width="100%" height="100%">
<style>
path {
stroke-linecap: round;
stroke-linejoin: round;
fill: none;
}
</style>
</svg>
<div class="ui">
<div class="tool"><span class="pencil" class="pencil icon selected">✏️</span></div>
<div class="tool"><span class="brush icon">🖌️</span></div>
<div class="tool"><span class="colors icon">🎨
<input class="color" type="color"></span></div>
</div>
<div class="message">
click/tap and drag to draw
</div>
<script>
(() => {
// no scrolling on mobile
document.addEventListener('touchmove', e => e.preventDefault(), {
passive: false
});
function touchify(e) {
const touch = [];
touch.x = touch.y = 0;
if (e.touches != null && e.touches.length > 0) {
touch.x = e.touches[0].clientX;
touch.y = e.touches[0].clientY;
for (let i = 0; i < e.touches.length; i++) {
touch[i] = e.touches[i];
}
} else {
touch.x = e.clientX;
touch.y = e.clientY;
touch[0] = { clientX: e.clientX, clientY: e.clientY };
}
return touch;
}
const els = {};
[...document.querySelectorAll('[class]')].forEach(el => {
els[el.classList[0]] = el;
});
const { paper, pencil, color, brush, message } = els;
let lastSelected = pencil;
let strokeWidth = 1;
let downCount;
let down;
let currPath;
let pathPoints;
const onDown = e => {
down = true;
downCount = 0;
pathPoints = [];
};
const onMove = e => {
const touch = touchify(e);
if (down) {
downCount++;
if (downCount === 1) {
currPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
currPath.setAttribute('stroke', color.value);
currPath.setAttribute('stroke-width', strokeWidth);
currPath.setAttribute('d', `M ${touch.x} ${touch.y}`);
pathPoints.push([touch.x, touch.y]);
paper.appendChild(currPath);
} else {
let path = `M ${pathPoints[0][0]} ${pathPoints[0][1]} L `;
pathPoints.push([touch.x, touch.y]);
for (let i = 1; i < pathPoints.length; i++) {
path += `${pathPoints[i][0]} ${pathPoints[i][1]} `;
}
currPath.setAttribute('d', path);
}
if (downCount === 10) {
message.classList.add('hide');
}
}
};
const onUp = e => {
down = false;
};
const onClick = e => {
if (e.target.classList.contains('pencil')) {
strokeWidth = 1;
} else if (e.target.classList.contains('brush')) {
strokeWidth = 10;
}
if (e.target.classList.contains('icon')) {
if (lastSelected) lastSelected.classList.remove('selected');
e.target.classList.add('selected');
lastSelected = e.target;
}
};
document.addEventListener('mousedown', onDown);
document.addEventListener('touchstart', onDown);
document.addEventListener('mousemove', onMove);
document.addEventListener('touchmove', onMove);
document.addEventListener('mouseup', onUp);
document.addEventListener('touchend', onUp);
document.addEventListener('click', onClick);
document.addEventListener('touchend', onClick);
})();
</script>
</body>
</html>