如何在HTML5的画布上使绘图可拖动

3
我是一个HTML5和JavaScript的新手,我知道有很多库可以做到这一点,但我想知道是否有一种方法只使用纯JavaScript来完成。
我有一个画布,当用户在画布上点击某个地方时,将出现一个小红点。我希望使每个小点可拖动,对此有什么想法吗?谢谢。
这是我拥有的代码:
在HTML中:
<div id="primal_plane" style="position:absolute; top:100px; left:10px;">
    <canvas id="canvas_prime" onclick="drawDot('canvas_prime')" width="700" height="500"></canvas>
</div>

在JS文件中:

function drawDot(plane) {
    var canvas = document.getElementById(plane);
    var context = canvas.getContext("2d");

    context.beginPath();
    context.arc(mouseX * 50, mouseY * 50, 4, 0, 2 * Math.PI, false);

    context.fillStyle = 'green';
    context.fill();

    context.lineWidth = 1;
    context.strokeStyle = 'yellow';
    context.stroke();
}
2个回答

8
为了概述你的解决方案:
  • 监听mousedown事件,如果鼠标不在圆内,就创建一个新的圆;如果鼠标在圆内,就开始对圆进行拖动操作。
  • 监听mousemove事件,按照鼠标自上次mousemove事件以来的移动距离移动被拖动的圆。
  • 监听mouseup事件,并停止拖动操作。
这里有注释过的代码和演示:http://jsfiddle.net/m1erickson/ytUhL/
<!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; }
    #canvas{border:1px solid red;}
</style>
<script>
    $(function() {

        // canvas related variables
        // references to canvas and its context and its position on the page
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");
        var $canvas = $("#canvas");
        var canvasOffset = $canvas.offset();
        var offsetX = canvasOffset.left;
        var offsetY = canvasOffset.top;
        var scrollX = $canvas.scrollLeft();
        var scrollY = $canvas.scrollTop();
        var cw = canvas.width;
        var ch = canvas.height;

        // flag to indicate a drag is in process
        // and the last XY position that has already been processed
        var isDown = false;
        var lastX;
        var lastY;

        // the radian value of a full circle is used often, cache it
        var PI2 = Math.PI * 2;

        // variables relating to existing circles
        var circles = [];
        var stdRadius = 10;
        var draggingCircle = -1;

        // clear the canvas and redraw all existing circles
        function drawAll() {
            ctx.clearRect(0, 0, cw, ch);
            for(var i=0; i<circles.length; i++){
                var circle = circles[i];
                ctx.beginPath();
                ctx.arc(circle.x, circle.y, circle.radius, 0, PI2);
                ctx.closePath();
                ctx.fillStyle = circle.color;
                ctx.fill();
            }
        }

        function handleMouseDown(e) {
            // tell the browser we'll handle this event
            e.preventDefault();
            e.stopPropagation();

            // save the mouse position
            // in case this becomes a drag operation
            lastX = parseInt(e.clientX - offsetX);
            lastY = parseInt(e.clientY - offsetY);

            // hit test all existing circles
            var hit = -1;
            for (var i=0; i < circles.length; i++) {
                var circle = circles[i];
                var dx = lastX - circle.x;
                var dy = lastY - circle.y;
                if (dx*dx + dy*dy < circle.radius * circle.radius) {
                    hit = i;
                }
            }

            // if no hits then add a circle
            // if hit then set the isDown flag to start a drag
            if (hit < 0) {
                circles.push({x:lastX, y:lastY, radius:stdRadius, color:randomColor()});
                drawAll();
            } else {
                draggingCircle = circles[hit];
                isDown = true;
            }

        }

        function handleMouseUp(e) {
            // tell the browser we'll handle this event
            e.preventDefault();
            e.stopPropagation();

            // stop the drag
            isDown = false;
        }

        function handleMouseMove(e) {

            // if we're not dragging, just exit
            if (!isDown) { return; }

            // tell the browser we'll handle this event
            e.preventDefault();
            e.stopPropagation();

            // get the current mouse position
            mouseX = parseInt(e.clientX - offsetX);
            mouseY = parseInt(e.clientY - offsetY);

            // calculate how far the mouse has moved
            // since the last mousemove event was processed
            var dx = mouseX - lastX;
            var dy = mouseY - lastY;

            // reset the lastX/Y to the current mouse position
            lastX = mouseX;
            lastY = mouseY;

            // change the target circles position by the 
            // distance the mouse has moved since the last
            // mousemove event
            draggingCircle.x += dx;
            draggingCircle.y += dy;

            // redraw all the circles
            drawAll();
        }

        // listen for mouse events
        $("#canvas").mousedown(function(e) { handleMouseDown(e); });
        $("#canvas").mousemove(function(e) { handleMouseMove(e); });
        $("#canvas").mouseup(function(e) { handleMouseUp(e); });
        $("#canvas").mouseout(function(e) { handleMouseUp(e); });

        //////////////////////
        // Utility functions

        function randomColor(){ 
            return('#' + Math.floor(Math.random()*16777215).toString(16));
        }


    }); // end $(function(){});
</script>
</head>
<body>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

1
这是一段非常好的代码,清晰易懂,非常有帮助! - moffeltje
你好,代码写得不错。我需要如何更改脚本才能在画布上用鼠标绘制东西,并使拖动功能可用。你有任何想法如何调整当前点击的画布大小吗? - utdev

0

你需要存储创建的点的列表,但是你需要检查该点是否已经存在。如果存在,则设置一个布尔标志来标识mousedown事件发生时的拖动行为,并且另一个标识被拖动的点。在mouseup事件上清除标志。mousemove方法应更新存储当前鼠标位置并更新被拖动的当前点的位置的变量。使用jQuery。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接