Drawing circle/ellipse on HTML5 canvas using mouse events

前端 未结 3 755
鱼传尺愫
鱼传尺愫 2020-12-06 15:34

I want something like ellipse option in paint for drawing on my canvas. I have achieved this partially. The problem is i am not able to get radius of circle, currently i hav

相关标签:
3条回答
  • 2020-12-06 15:49

    Here's an example of how to drag-draw an oval.

    Demo: http://jsfiddle.net/m1erickson/3SFJy/

    enter image description here

    Example code using 2 Bezier curves to drag-draw an oval:

    <!doctype html>
    <html>
    <head>
    <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    
    <style>
    body{ background-color: ivory; padding:0px;}
    #canvas{ border:1px solid blue; }
    </style>
    
    <script>
    $(function(){
    
        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
        var canvasOffset=$("#canvas").offset();
        var offsetX=canvasOffset.left;
        var offsetY=canvasOffset.top;
        var startX;
        var startY;
        var isDown=false;
    
        function drawOval(x,y){
            ctx.clearRect(0,0,canvas.width,canvas.height);
            ctx.beginPath();
            ctx.moveTo(startX, startY + (y-startY)/2);
            ctx.bezierCurveTo(startX, startY, x, startY, x, startY + (y-startY)/2);
            ctx.bezierCurveTo(x, y, startX, y, startX, startY + (y-startY)/2);
            ctx.closePath();
            ctx.stroke();
        }
    
        function handleMouseDown(e){
          e.preventDefault();
          e.stopPropagation();
          startX=parseInt(e.clientX-offsetX);
          startY=parseInt(e.clientY-offsetY);
          isDown=true;
        }
    
        function handleMouseUp(e){
          if(!isDown){ return; }
          e.preventDefault();
          e.stopPropagation();
          isDown=false;
        }
    
        function handleMouseOut(e){
          if(!isDown){ return; }
          e.preventDefault();
          e.stopPropagation();
          isDown=false;
        }
    
        function handleMouseMove(e){
          if(!isDown){ return; }
          e.preventDefault();
          e.stopPropagation();
          mouseX=parseInt(e.clientX-offsetX);
          mouseY=parseInt(e.clientY-offsetY);
          drawOval(mouseX,mouseY);
        }
    
        $("#canvas").mousedown(function(e){handleMouseDown(e);});
        $("#canvas").mousemove(function(e){handleMouseMove(e);});
        $("#canvas").mouseup(function(e){handleMouseUp(e);});
        $("#canvas").mouseout(function(e){handleMouseOut(e);});
    
    }); // end $(function(){});
    </script>
    </head>
    <body>
        <h4>Drag to create a circle or oval</h4>
        <canvas id="canvas" width=300 height=300></canvas>
    </body>
    </html>
    
    0 讨论(0)
  • I would something similar as with markE's answer however, using Bezier curve will draw ellipses but it won't give you the exact radius that you probably would need.

    For that a function to draw a manual ellipse is needed, and it's rather simple -

    This function will take a corner start point and and end point and draw an ellipse exactly within that boundary:

    Live demo

    Snapshot from demo

    function drawEllipse(x1, y1, x2, y2) {
    
        var radiusX = (x2 - x1) * 0.5,   /// radius for x based on input
            radiusY = (y2 - y1) * 0.5,   /// radius for y based on input
            centerX = x1 + radiusX,      /// calc center
            centerY = y1 + radiusY,
            step = 0.01,                 /// resolution of ellipse
            a = step,                    /// counter
            pi2 = Math.PI * 2 - step;    /// end angle
        
        /// start a new path
        ctx.beginPath();
    
        /// set start point at angle 0
        ctx.moveTo(centerX + radiusX * Math.cos(0),
                   centerY + radiusY * Math.sin(0));
    
        /// create the ellipse    
        for(; a < pi2; a += step) {
            ctx.lineTo(centerX + radiusX * Math.cos(a),
                       centerY + radiusY * Math.sin(a));
        }
        
        /// close it and stroke it for demo
        ctx.closePath();
        ctx.strokeStyle = '#000';
        ctx.stroke();
    }
    

    The demo marks the rectangle area too to show that the ellipse is exactly within it.

    Draw

    To handle mouse operation that will let you draw the ellipse you can do:

    var canvas = document.getElementById('myCanvas'),
        ctx = canvas.getContext('2d'),
        w = canvas.width,
        h = canvas.height,
        x1,                 /// start points
        y1,
        isDown = false;     /// if mouse button is down
    
    /// handle mouse down    
    canvas.onmousedown = function(e) {
    
        /// get corrected mouse position and store as first point
        var rect = canvas.getBoundingClientRect();
        x1 = e.clientX - rect.left;
        y1 = e.clientY - rect.top;
        isDown = true;
    }
    
    /// clear isDown flag to stop drawing
    canvas.onmouseup = function() {
        isDown = false;
    }
    
    /// draw ellipse from start point
    canvas.onmousemove = function(e) {
    
        if (!isDown) return;
        
        var rect = canvas.getBoundingClientRect(),
            x2 = e.clientX - rect.left,
            y2 = e.clientY - rect.top;
        
        /// clear canvas
        ctx.clearRect(0, 0, w, h);
    
        /// draw ellipse
        drawEllipse(x1, y1, x2, y2);
    }
    

    A tip can be to create a top canvas on top of your main canvas and do the drawing itself there. When mouse button is released then transfer the drawing to your main canvas. This way you don't have to redraw everything when drawing a new shape.

    Hope this helps!

    0 讨论(0)
  • 2020-12-06 16:08

    Here's my way of drawing an ellipse onto a canvas with mouse drag.

    It uses radius of 1, but dynamic scaling to get the ellipse effect :)

    https://jsfiddle.net/richardcwc/wdf9cocz/

    //Canvas
    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    //Variables
    var scribble_canvasx = $(canvas).offset().left;
    var scribble_canvasy = $(canvas).offset().top;
    var scribble_last_mousex = scribble_last_mousey = 0;
    var scribble_mousex = scribble_mousey = 0;
    var scribble_mousedown = false;
    
    //Mousedown
    $(canvas).on('mousedown', function(e) {
        scribble_last_mousex = parseInt(e.clientX-scribble_canvasx);
    	scribble_last_mousey = parseInt(e.clientY-scribble_canvasy);
        scribble_mousedown = true;
    });
    
    //Mouseup
    $(canvas).on('mouseup', function(e) {
        scribble_mousedown = false;
    });
    
    //Mousemove
    $(canvas).on('mousemove', function(e) {
        scribble_mousex = parseInt(e.clientX-scribble_canvasx);
    	scribble_mousey = parseInt(e.clientY-scribble_canvasy);
        if(scribble_mousedown) {
            ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
            //Save
            ctx.save();
            ctx.beginPath();
            //Dynamic scaling
            var scalex = 1*((scribble_mousex-scribble_last_mousex)/2);
            var scaley = 1*((scribble_mousey-scribble_last_mousey)/2);
            ctx.scale(scalex,scaley);
            //Create ellipse
            var centerx = (scribble_last_mousex/scalex)+1;
            var centery = (scribble_last_mousey/scaley)+1;
            ctx.arc(centerx, centery, 1, 0, 2*Math.PI);
            //Restore and draw
            ctx.restore();
            ctx.strokeStyle = 'black';
            ctx.lineWidth = 5;
            ctx.stroke();
        }
        //Output
        $('#output').html('current: '+scribble_mousex+', '+scribble_mousey+'<br/>last: '+scribble_last_mousex+', '+scribble_last_mousey+'<br/>mousedown: '+scribble_mousedown);
    });
    canvas {
        cursor: crosshair;
        border: 1px solid #000000;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <canvas id="canvas" width="800" height="500"></canvas>
    <div id="output"></div>

    0 讨论(0)
提交回复
热议问题