Reputation: 43
I'm trying to make a simple drawing script in HTML and JavaScript. I'm doing so by creating a div over the entire window, and then tracking the mouse position by having that div's onmousemove event call updateFunc() so that when you hold down left click, a red, circular div element is created and appended per update to resemble a brush.
The problem is that the updating of the onmousemove event is so slow that if you move the cursor too suddenly, there are wide gaps between each created div element. Ideally, creating a line, no matter the speed you move your cursor, should be as smooth as possible. Is there a way to do this using this method, or should I try something else?
<div onmousemove="updateFunc();" id="background" style="position:fixed;width:100%;height:100%;z-index:100%;" onmousedown="isDown = true;" onmouseup="isDown = false;"></div>
<div id="test1" style="width:10px;height:10px;background-color:red;"></div>
<script>
var test1 = document.getElementById("test1");
var isDown = false;
function updateFunc() {
x = event.clientX;
y = event.clientY;
document.getElementById("test1").style.left = (x - (Number(test1.style.width.slice(0,-2)) / 2)) + "px";
document.getElementById("test1").style.top = (y - (Number(test1.style.height.slice(0,-2)) / 2)) + "px";
if (isDown) {
var div = document.createElement("div");
div.style.position = "absolute";
div.style.top = (y - (Number(test1.style.height.slice(0,-2)) / 2)) + "px";
div.style.left = (x - (Number(test1.style.width.slice(0,-2)) / 2)) + "px";
div.style.backgroundColor = "red";
div.style.width = "10px";
div.style.height = "10px";
div.style.borderRadius = "200px 200px 200px 200px";
var body = document.querySelector("body");
body.appendChild(div);
}
}
</script>
Upvotes: 1
Views: 1036
Reputation: 206467
There's no way to accelerate the browser firing mousemove
events.
You could use some basic trigonometry, after two points are created, simply connect the two points with the missing DIV... wait, did I just said DIVs?
DOM should not be used to make paint applications (well, unless you're creating a 32x32 favicon generator, but even than...) use canvas
. It's really easy to get you started.
Canvas will have the same "problem" though. It will connect your mousemove points with a line, but if you're fast with your mouse - the line will look like a polygon's edge. In such case, some bezier or quadratic curve might help. The end result will be a faster and more UX-plesant app. The user can also download his own drawing (save as image) once creatively exhausted.
Here's a demo that uses canvas
, and quadraticCurveTo
:
var pen = {
color: "rgba(255, 0, 0, 1.0)", // Set desired color
size: 3 // Set desired size
};
var pts = [];
var isDown = false;
var isTouch = false;
var cvs = document.getElementById('canvas');
var cvs2 = document.createElement('canvas');
var ctx = cvs.getContext('2d');
var ctx2 = cvs2.getContext('2d');
function setCvsSize() {
cvs.width = cvs2.width = document.documentElement.clientWidth;
cvs.height = cvs2.height = document.documentElement.clientHeight;
}
function penDown(ev) {
ev.preventDefault();
isTouch = ev.type === "touchstart";
ev = isTouch ? ev.touches[0] : ev;
isDown = true;
pts.push({
x: ev.clientX,
y: ev.clientY
});
drawPoints();
}
function penMove(ev) {
ev.preventDefault();
ev = isTouch ? ev.touches[0] : ev;
if (isDown) {
ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx.drawImage(cvs2, 0, 0); // Draw to inmemory cvs2
pts.push({
x: ev.clientX,
y: ev.clientY
});
drawPoints();
}
}
function penUp(ev) {
ev.preventDefault();
isDown = isTouch = false;
pts = [];
// Save state to in-memory cvs2
ctx2.clearRect(0, 0, cvs.width, cvs.height);
ctx2.drawImage(cvs, 0, 0);
}
function clear() {
ctx.clearRect(0, 0, cvs.width, cvs.height);
ctx2.clearRect(0, 0, cvs.width, cvs.height);
}
function drawPoints() {
var i = 0;
var i2 = pts.length > 1 ? 1 : 0;
ctx.beginPath();
ctx.lineWidth = pen.size;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.moveTo(pts[0].x, pts[0].y);
for (; i < pts.length - i2; i++) {
ctx.quadraticCurveTo(
pts[i].x,
pts[i].y,
(pts[i].x + pts[i + i2].x) / 2,
(pts[i].y + pts[i + i2].y) / 2
);
}
ctx.strokeStyle = pen.color;
ctx.stroke();
ctx.closePath();
}
// EVENTS
cvs.addEventListener('touchstart', penDown);
cvs.addEventListener('mousedown', penDown);
cvs.addEventListener('touchmove', penMove);
cvs.addEventListener('mousemove', penMove);
cvs.addEventListener('touchend', penUp);
cvs.addEventListener('mouseup', penUp);
window.addEventListener('resize', setCvsSize);
// INIT
setCvsSize();
*{margin: 0;}
#canvas {
display: block;
}
<canvas id='canvas'></canvas>
Upvotes: 2