如何在放置到HTML5画布后拖动图像?

3

我修改了一个页面,可以将图片拖放到画布上。它完成了我想要的所有功能,除了一个问题。我尝试了多种方法(包括脚本,如Kinetic和Raphael,我仍然认为这可能是正确的路线),但都陷入了困境:

一旦图片被放下,我无法将其在画布上拖动到新位置。

function drag(e)
{
    //store the position of the mouse relativly to the image position
    e.dataTransfer.setData("mouse_position_x",e.clientX - e.target.offsetLeft );
    e.dataTransfer.setData("mouse_position_y",e.clientY - e.target.offsetTop  );

    e.dataTransfer.setData("image_id",e.target.id);
}

function drop(e)
{
    e.preventDefault();
    var image = document.getElementById( e.dataTransfer.getData("image_id") );

    var mouse_position_x = e.dataTransfer.getData("mouse_position_x");
    var mouse_position_y = e.dataTransfer.getData("mouse_position_y");

    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');

    // the image is drawn on the canvas at the position of the mouse when we lifted the mouse button
    ctx.drawImage( image , e.clientX - canvas.offsetLeft - mouse_position_x , e.clientY - canvas.offsetTop - mouse_position_y );
}

function convertCanvasToImage() {
    var canvas = document.getElementById('canvas');

    var image_src = canvas.toDataURL("image/png");
    window.open(image_src);

}

这是我最初使用的JSFiddle作为起点 - http://fiddle.jshell.net/gael/GF96n/4/(将JSFiddle徽标拖到画布上,然后尝试移动它)。我已经向我的页面添加了CSS、选项卡、内容等几乎可以工作的页面。我不想失去的功能是能够将单个图像多次拖动(克隆)到画布上的能力。你有什么创意/示例/指针来创建这个功能吗?

我完成了相同的功能。为此,您需要在拖动的位置再次绘制图像。 - MJQ
2个回答

6
你需要对代码进行一些更改,不要立即将图像绘制到画布上,而是需要跟踪所有拖放的图像。 imagesOnCanvas 将包含所有已拖放的图像。
var imagesOnCanvas = [];

function drop(e)
{
    e.preventDefault();
    var image = document.getElementById( e.dataTransfer.getData("image_id") );

    var mouse_position_x = e.dataTransfer.getData("mouse_position_x");
    var mouse_position_y = e.dataTransfer.getData("mouse_position_y");

    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');

    imagesOnCanvas.push({
      context: ctx,  
      image: image,  
      x:e.clientX - canvas.offsetLeft - mouse_position_x,
      y:e.clientY - canvas.offsetTop - mouse_position_y,
      width: image.offsetWidth,
      height: image.offsetHeight
    });

}

你还需要一个动画循环,它将依次遍历imagesOnCanvas中的所有图像并绘制它们。使用requestAnimationFrame来实现此目的。
function renderScene() {
    requestAnimationFrame(renderScene);

    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    ctx.clearRect(0,0,
        canvas.width,
        canvas.height
    );


    for(var x = 0,len = imagesOnCanvas.length; x < len; x++) {
        var obj = imagesOnCanvas[x];
        obj.context.drawImage(obj.image,obj.x,obj.y);

    }
}

requestAnimationFrame(renderScene);

接下来,您需要监视画布上的mousedown事件,如果该事件发生在图像上,则可以调用startMove操作。

canvas.onmousedown = function(e) {
    var downX = e.offsetX,downY = e.offsetY;

    // scan images on canvas to determine if event hit an object
    for(var x = 0,len = imagesOnCanvas.length; x < len; x++) {
        var obj = imagesOnCanvas[x];
        if(!isPointInRange(downX,downY,obj)) {
            continue;
        }

        startMove(obj,downX,downY);
        break;
    }

}

isPointInRange 函数返回true,如果鼠标事件发生在图像对象上。

function isPointInRange(x,y,obj) {
    return !(x < obj.x ||
        x > obj.x + obj.width ||
        y < obj.y ||
        y > obj.y + obj.height);
}

一旦“移动模式”激活,对象的x/y坐标将更改为反映新鼠标位置。
function startMove(obj,downX,downY) {
    var canvas = document.getElementById('canvas');

    var origX = obj.x, origY = obj.y;
    canvas.onmousemove = function(e) {
        var moveX = e.offsetX, moveY = e.offsetY;
        var diffX = moveX-downX, diffY = moveY-downY;


        obj.x = origX+diffX;
        obj.y = origY+diffY;
    }

    canvas.onmouseup = function() {
        // stop moving
        canvas.onmousemove = function(){};
    }
}

这里有一个实际工作的例子:

http://jsfiddle.net/XU2a3/41/


感谢您的快速回复!我已经尝试了以下代码,并在JSFiddle中看到几乎相同的结果:IE 8.0-没有显示画布。什么都不起作用。FF 17.0-第一张图片可以拖放。移动时消失。随后的图像可以拖放但无法移动。生成图像无法工作。Chrome 23-拖放功能正常。放置在画布上后可以移动图像。生成图像无法工作。Safari 5.1.7-拖放功能无法工作。生成图像会打开一个新窗口,但无法确定它是否完全可用,因为无法放置图像。有什么建议可以修复吗? - Bob Tahmaseb
lostsource - 你的 jsfiddle 在 jsfiddle 上似乎可以在 Chrome 中工作,但是当我将代码复制(包括或不包括关闭 </html>)并从文件或 Web 服务器运行时,它就无法工作了。你做了什么更改(我没有看到任何更改),我做错了什么?谢谢。 - Bob Tahmaseb
没有对这个小工具进行任何更改,请确保您拖动的图像来自与您相同的域,否则可能会出现与跨域相关的安全问题。(该示例中的图像来自 jsfiddle 域) - lostsource
啊!新手错误。现在在Chrome中可以工作了。现在要想办法让它跨浏览器工作。谢谢!!! - Bob Tahmaseb
如果您有与原问题无关的问题,我认为将它们作为单独的问题发布会更好。 - lostsource
不了...这个问题没有更多的疑问了。再次感谢您的帮助。从您的回答中学到了很多东西。 - Bob Tahmaseb

0

我知道已经过去了2年,但我会尝试一下...在@lostsource提供的答案中,dataTransfer对象在Opera浏览器中不被支持,并且jsfiddle无法工作。我非常需要那个答案,那就是我一直在寻找的,但它不起作用!


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