如何使所有绘制的(矩形、圆形、线条、多边形)可拖动?纯JS

Posted

技术标签:

【中文标题】如何使所有绘制的(矩形、圆形、线条、多边形)可拖动?纯JS【英文标题】:How to make all drawn (rectangle, circles, lines, polygon) draggable? Pure JS 【发布时间】:2015-06-09 00:16:45 【问题描述】:

我有一个简单的画布 html5。它可以通过选择选项绘制一些形状,如线条、圆形、矩形、多边形,但现在我想让所有绘制都可拖动,如果可能的话可调整大小,没有 3 部分库,只有纯 JS。

    var canvas,
    context,
    dragStartLocation,
    snapshot;
    dragdrop = false;
    isDrag = false;




function resizeCanvas() 
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;




function getCanvasCoordinates(event) 
    var x = event.clientX - canvas.getBoundingClientRect().left;
        y = event.clientY - canvas.getBoundingClientRect().top;

    return x: x, y: y;




function takeSnapshot() 
    snapshot = context.getImageData(0, 0, canvas.width, canvas.height);



function restoreSnapshot() 
    context.putImageData(snapshot, 0, 0);


function drawLine(position) 

    context.beginPath();
    context.moveTo(dragStartLocation.x, dragStartLocation.y);
    context.lineTo(position.x, position.y );
    context.stroke();

    

function drawRect(position) 

    context.beginPath();
    //context.moveTo(dragStartLocation.x, dragStartLocation.y);
    context.fillRect(position.x, position.y, dragStartLocation.x - position.x, dragStartLocation.y - position.y);
    //context.stroke();



function drawCircle(position) 
    var radius = Math.sqrt(Math.pow((dragStartLocation.x - position.x), 2) + Math.pow((dragStartLocation.y - position.y), 2));
    context.beginPath();
    context.arc(dragStartLocation.x, dragStartLocation.y, radius, 0, 2 * Math.PI, false);



/*
function drawPolygon(position, sides, angle) 
    var coordinates = [],
        radius = Math.sqrt(Math.pow((dragStartLocation.x - position.x), 2) + Math.pow((dragStartLocation.y - position.y), 2)),
        index = 0;

    for (index = 0; index < sides; index++) 
        coordinates.push(x: dragStartLocation.x + radius * Math.cos(angle), y: dragStartLocation.y - radius * Math.sin(angle));
        angle += (2 * Math.PI) / sides;
    

    context.beginPath();
    context.moveTo(coordinates[0].x, coordinates[0].y);
    for (index = 1; index < sides; index++) 
        context.lineTo(coordinates[index].x, coordinates[index].y);
    

    context.closePath();
*/


function draw(position) 

    var fillBox = document.getElementById("fillBox"),
        shape = document.querySelector('#tools option:checked').value,
        /*polygonSides = document.getElementById("polygonSides").value,
        polygonAngle = document.getElementById("polygonAngle").value,*/
        lineCap = document.querySelector('input[type="radio"][name="lineCap"]:checked').value;
        /*composition = document.querySelector('input[type="radio"][name="composition"]:checked').value;*/

    context.lineCap = lineCap;
    /*context.globalCompositeOperation = composition;*/

    if (shape === "circle") 
        drawCircle(position);

    
    if (shape === "line") 
        drawLine(position);
    

    if (shape === "rect") 
        drawRect(position);
    

    if (shape === "polygon") 
        drawPolygon(position, polygonSides, polygonAngle * (Math.PI / 180));
    

    if (shape !== "line") 
        if (fillBox.checked) 
            context.fill();
         else 
            context.stroke();
        
    


function dragStart(event) 
    dragging = true;
    dragStartLocation = getCanvasCoordinates(event);
    takeSnapshot();


function drag(event) 
    var position;
    if (dragging === true) 
        restoreSnapshot();
        position = getCanvasCoordinates(event);
        draw(position);
    


function dragStop(event) 
    dragging = false;
    restoreSnapshot();
    var position = getCanvasCoordinates(event);
    draw(position);


function changeLineWidth() 
    context.lineWidth = this.value;
    event.stopPropagation();


function changeFillStyle() 
    context.fillStyle = this.value;
    event.stopPropagation();


function changeStrokeStyle() 
    context.strokeStyle = this.value;
    event.stopPropagation();


function changeBackgroundColor() 
    context.save();
    context.fillStyle = document.getElementById("backgroundColor").value;
    context.fillRect(0, 0, canvas.width, canvas.height);
    context.restore();


function eraseCanvas() 
    context.clearRect(0, 0, canvas.width, canvas.height);



function init() 
    canvas = document.getElementById("canvas");
    context = canvas.getContext('2d');
    var lineWidth = document.getElementById("lineWidth"),
        fillColor = document.getElementById("fillColor"),
        strokeColor = document.getElementById("strokeColor"),
        //canvasColor = document.getElementById("backgroundColor"),
        clearCanvas = document.getElementById("clearCanvas");
        //saveCanvas = document.getElementById("saveCanvas");

    context.strokeStyle = strokeColor.value;
    context.fillStyle = fillColor.value;
    context.lineWidth = lineWidth.value;

    /*window.addEventListener('resize', resizeCanvas, false);
    window.addEventListener('orientationchange', resizeCanvas, false);
    resizeCanvas();*/


    canvas.addEventListener('mousedown', dragStart, false);
    canvas.addEventListener('mousemove', drag, false);
    canvas.addEventListener('mouseup', dragStop, false);
    lineWidth.addEventListener("input", changeLineWidth, false);
    fillColor.addEventListener("input", changeFillStyle, false);
    strokeColor.addEventListener("input", changeStrokeStyle, false);
    //canvasColor.addEventListener("input", changeBackgroundColor, false);
    clearCanvas.addEventListener("click", eraseCanvas, false);
    //saveCanvas.addEventListener("click", salvaCanvas, false);



window.addEventListener('load', init, false);

【问题讨论】:

*** 上有很多(几十个?)与“拖动”画布绘图相关的问题/答案。我怀疑搜索会很快显示您需要的代码;-) 【参考方案1】:

canvas 的一个基本特性是它只存储由所有绘制操作形成的光栅图像。这就是为什么 canvas 速度快且内存效率高的原因。

缺点是您必须擦除画布上受影响的矩形(或最坏情况下的整个画布)并重新绘制所有需要调整大小、移动等的形状。画布不会将它们存储为对象,因此您的 JS 代码必须负责在画布上存储、修改和重新绘制它们。除非您使用某些第三方库,否则工作量很大。

另一种方法是使用 HTML5 的类似 SVG 的功能而不是画布:&lt;line&gt;&lt;path&gt;&lt;rect&gt; 等。它们由浏览器作为对象保存并通过 DOM 访问。然而,这是一种完全不同的方法,需要完全重写您的代码。

【讨论】:

可拖动 SVG 的示例可以在 here 找到。没有使用任何库,甚至 jQuery。 但是在我的代码中是否可以适应呢?如果我使用第三方库行 jcanvas,我如何才能将它与我的代码一起使用,仅用于拖放? SVG 方法是您的替代方法,我认为没有办法将两者结合起来。可以继续使用画布,但是您的脚本必须保留所有绘制形状的列表,检测正在拖动/调整大小的形状,并在鼠标移动时重新绘制所有形状。不幸的是,我在纯 JS 中没有现成的解决方案。 @MikeBessonov。支持您引用的 Peter Collingridge 的文章,它提供了一种简洁的方式来拖动没有 jQuery 的 SVG 元素 :-) 顺便说一句,提问者似乎想要将 SVG 导出为图像,讽刺的是,这会让您重新使用画布元素作为出口车辆。 ;-) @markE。好点子。如果最终目的是将草图导出为光栅,那么我仍然会在矢量 (SVG) 中对其进行编辑,最后只需将 SVG 图像拍到画布上并让浏览器渲染它,如 getcontext.net/read/svg-images-on-a-html5-canvas 中所述.

以上是关于如何使所有绘制的(矩形、圆形、线条、多边形)可拖动?纯JS的主要内容,如果未能解决你的问题,请参考以下文章

CODESOFT中线条形状该如何绘制

Java 在PDF文档中绘制图形

如何使用鼠标拖动绘制矩形和椭圆?

如何在android中动态地使形状可拖动和调整大小

OpenCV 轮廓周围绘制矩形框和圆形框

绘制基本 图形之矩形与多边形