Reputation: 844
I have a canvas where I draw a curve. onmouseup lines are drawn based on that curve and connecting specific x-points for it.
The problem is that if the mouse is moved fast, not all of its points are captured.
var canvas;
var ctx;
function drawCanvas(popup) {
var flag = false;
canvas = document.querySelector(popup + " #canvasG");
ctx = canvas.getContext('2d');
var sketch = document.querySelector(popup + " #canvasD");
var sketch_style = getComputedStyle(sketch);
canvas.width = parseInt(sketch_style.getPropertyValue('width'));
canvas.height = parseInt(sketch_style.getPropertyValue('height'));
// Creating a tmp canvas
var tmp_canvas = document.createElement('canvas');
var tmp_ctx = tmp_canvas.getContext('2d');
tmp_canvas.id = 'tmp_canvas';
tmp_canvas.width = canvas.width;
tmp_canvas.height = canvas.height;
sketch.appendChild(tmp_canvas);
var mouse = {x: 0, y: 0};
// Pencil Points
var ppts = [];
var mousXprev = 0;
/* Mouse capturing work -- here is the problem!!! */
tmp_canvas.addEventListener('mousemove', function(e) {
if (!flag) { drawScales(ctx, canvas); flag = true; }
if (mousXprev <= e.offsetX // only allow to draw inside the allowed area
&& e.offsetX > 12 && mouse.x > 12 && e.offsetX <= 12*24+12 && mouse.x < 12*24+12
&& e.offsetY < tmp_canvas.height-28 && mouse.y < tmp_canvas.height-28 && e.offsetY > tmp_canvas.height-224 && mouse.y > tmp_canvas.height-224) {
mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
mousXprev = mouse.x;
mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;
} else {
drawLines(tmp_ctx, canvas, ppts);
ppts = []; // clear points
}
}, false);
tmp_ctx.lineWidth = 2;
tmp_ctx.lineJoin = 'round';
tmp_ctx.lineCap = 'round';
tmp_ctx.strokeStyle = 'blue';
tmp_ctx.fillStyle = 'blue';
tmp_canvas.addEventListener('mousedown', function(e) {
tmp_canvas.addEventListener('mousemove', onPaint, false);
mousXprev = 0;
ppts = []; // clear points
ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height); // clear path
drawScales(ctx, canvas);
if (e.offsetX > 12 && e.offsetX <= 12*24+12 && e.offsetY < tmp_canvas.height-28 && e.offsetY > tmp_canvas.height-224) {
mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;
ppts.push({x: mouse.x, y: mouse.y});
onPaint();
}
}, false);
tmp_canvas.addEventListener('mouseup', function() {
tmp_canvas.removeEventListener('mousemove', onPaint, false);
if (ppts.length > 1) {
ctx.drawImage(tmp_canvas, 0, 0);
tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);
// draw lines...
ppts = [];
}
}, false);
var onPaint = function() {
ppts.push({x: mouse.x, y: mouse.y});
if (ppts.length < 3) {
var b = ppts[0];
tmp_ctx.beginPath();
tmp_ctx.arc(b.x, b.y, tmp_ctx.lineWidth / 2, 0, Math.PI * 2, !0);
tmp_ctx.fill();
tmp_ctx.closePath();
return;
}
tmp_ctx.clearRect(0, 0, tmp_canvas.width, tmp_canvas.height);
tmp_ctx.beginPath();
tmp_ctx.moveTo(ppts[0].x, ppts[0].y);
for (var i = 1; i < ppts.length - 2; i++) {
var c = (ppts[i].x + ppts[i + 1].x) / 2;
var d = (ppts[i].y + ppts[i + 1].y) / 2;
tmp_ctx.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d);
}
// For the last 2 points
tmp_ctx.quadraticCurveTo(
ppts[i].x,
ppts[i].y,
ppts[i + 1].x,
ppts[i + 1].y
);
tmp_ctx.stroke();
};
};
The second problem is that in IE and fireFox, drawing is not possible. What can be the compatibility fix for IE/fireFox?
Upvotes: 0
Views: 1531
Reputation: 105015
You are not likely "missing" any mousemove events.
Each operating system regulates (limits) how many mousemove events per second are emitted. So moving the mouse fast will cause more distance (less resolution) between mousemove events. There is no workaround to get more mousemove points per second.
It looks like you are capturing points to create a spline. If so, Stackoverflow's Ken Fyrstenberg has created a nice script that will create a spline when fed a set of points. You can loosen the tension on Ken's spline which will cause your spline to become more smoothed relative to the waypoints. Loosening the tension will reduce the effects of having fewer than desired mousemove waypoints.
how to draw smooth curve through N points using javascript HTML5 canvas?
As far as capturing mouse events in a cross-browser compliant way...
Here's a template for capturing mouse drag events in across browsers:
window.onload=function(){
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var BB,BBoffsetX,BBoffsetY;
setBB();
// a flag indicating the mouse is being dragged
var isDown=false;
// an array of points accumulated during mouse dragging
var ppts=[];
// listen for mouse events
canvas.onmousedown=handleMousedown;
canvas.onmousemove=handleMousemove;
canvas.onmouseup=handleMouseup;
canvas.onmouseout=handleMouseup;
// recalculate the canvas offset if the window is scrolled
window.onscroll=function(e){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
function handleMousedown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get the mouse position relative to the canvas
var mouseX=e.clientX-BBoffsetX;
var mouseY=e.clientY-BBoffsetY;
// start a new ppts array
ppts=[];
// set the mouse-is-down flag
isDown=true;
}
function handleMouseup(e){
// if the mouse isn't being dragged, just return
if(!isDown){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// clear the mouse-is-down flag
isDown=false;
// get the mouse position relative to the canvas
var mouseX=e.clientX-BBoffsetX;
var mouseY=e.clientY-BBoffsetY;
// add this point to ppts
ppts.push({x:mouseX,y:mouseY});
alert('You have accumulated '+ppts.length+' points.');
}
function handleMousemove(e){
// if the mouse isn't being dragged, just return
if(!isDown){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get the mouse position relative to the canvas
var mouseX=e.clientX-BBoffsetX;
var mouseY=e.clientY-BBoffsetY;
// add this point to ppts
ppts.push({x:mouseX,y:mouseY});
}
// calculate the canvas offset
function setBB(){
BB=canvas.getBoundingClientRect();
BBoffsetX=BB.left;
BBoffsetY=BB.top;
}
}; // end window.onload;
body{ background-color: ivory; }
canvas{border:1px solid red;}
<h4>Drag mouse to accumulate ppts</h4>
<canvas id="canvas" width=300 height=300></canvas>
Upvotes: 1