简体   繁体   中英

Html5/Js canvas capturing mouse coords when it moves fast

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?

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> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM