【问题标题】:How can I make different shapes of a canvas draggable and particular area of it droppable in the same canvas如何使画布的不同形状可拖动,并将其特定区域拖放到同一画布中
【发布时间】:2015-06-12 13:25:43
【问题描述】:

我想创建一个画布,其中有两个区域(左侧和右侧),左侧面板将包含一些可拖动的形状(也是静态的),在右侧我可以放下它们,但我面临以下问题,

  1. 我无法将我在左侧绘制的形状设置为可拖动的,因为它们没有关联的 ID。
  2. 我不知道如何使某些特定区域可放置。

这是可视化我想要实现的目标的代码 -

<body>
<canvas id="myCanvas" width="800" height="600" style="border:1px solid #000000;">
</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.moveTo(250,0);
ctx.lineTo(250,600);
ctx.stroke();

ctx.fillStyle = "#FF0000";
ctx.fillRect(50,50,160,25);
ctx.fillStyle = "#0000FF";
ctx.font = "15px";
ctx.strokeText("Draggable Elements here",57,67);

ctx.fillStyle = "#FF0000";
ctx.fillRect(500,50,130,25);
ctx.font = "15px";
ctx.strokeText("Droppable area Here",510,67);    
</script>

</body>

这是相同的 JS 小提琴 - http://jsfiddle.net/akki166786/4tfyy4o5/

因此,如果有人能阐明我如何实现这一目标,那将是一个很大的帮助。

提前致谢

【问题讨论】:

  • 在画布中,所有像素都是混合在一起的,没有对象。您需要手动实现较低的逻辑来处理对象。看看那里的众多库之一是否可以提供帮助(kineticjs、fabricjs、..)。
  • 感谢@K3N 的输入,如果我有任何疑问,我一定会查看这些库并回复您。

标签: javascript canvas drag-and-drop


【解决方案1】:

在特定区域拖放

更新:盒子的副本在移动时保持在原始位置。

首先,您需要能够检测矩形。您可以通过将 then 变成代码中的对象来做到这一点:

function box(x,y,w,h,rgb) {
    this.x = x,
    this.y = y;
    this.xS = x; //saving x
    this.yS = y; //saving y
    this.w = w;
    this.h = h;
    this.rgb = rgb;

    //to determine if the box is being draged
    this.draging = false;
}

不,您需要添加一个事件侦听器来确定是否有人在点击,您还需要确定该人是否点击了您的某个框。

c.addEventListener("mousedown",down);
c.addEventListener("mousemove",move);
c.addEventListener("mouseup",up);

因此,已经制作了事件来检测鼠标按钮何时被按下、何时释放以及鼠标是否在画布内移动。对于这些事件,我们有准备执行的函数,down()、move() 和 up()。

所有函数都将在下面的示例中可见。

当我们愉快地拖动盒子并释放鼠标按钮时,我们需要检查盒子是否被放置在可放置区域中。我们在 up() 函数中执行此操作。如果放置正常,盒子可以保留,否则我们将其送回原处。

工作示例

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

c.width = 600;
c.height = 300;

//My mouse coordinates
var x,y;
c.addEventListener("mousedown",down);
c.addEventListener("mousemove",move);
c.addEventListener("mouseup",up);

//I'll save my boxes in this array
var myBoxes = new Array();

//This function describes what a box is.
//Each created box gets its own values
function box(x,y,w,h,rgb) {
    this.x = x,
    this.y = y;
    this.xS = x; //saving x
    this.yS = y; //saving y
    this.w = w;
    this.h = h;
    this.rgb = rgb;
    
    //to determine if the box is being draged
    this.draging = false;
}

//Let's make some boxes!!
myBoxes[0] = new box(10,10,50,100,"green");
myBoxes[1] = new box(80,50,100,75,"blue");
myBoxes[2] = new box(40,150,20,70,"yellow");


//here we draw everything
function draw() {
    ctx.clearRect(0,0,c.width,c.height);
    //Dropable area
    ctx.fillStyle="red";
    ctx.fillRect(c.width/2,0,c.width,c.height);
    
    //Boxes!
    for (var i = 0; i<myBoxes.length; i++) {
        var b = myBoxes[i];

        //NEW CODE FOR UPDATE
        if (b.draging) { //box on the move
            //Also draw it on the original spot
            ctx.fillStyle="grey"; //I chose a different color to make it appear more as a shadow of the box that's being moved.
            ctx.fillRect(b.xS,b.yS,b.w,b.h);
            ctx.strokeRect(b.xS,b.yS,b.w,b.h);
        }
        //End of new code for update

        ctx.fillStyle=b.rgb;
        ctx.fillRect(b.x,b.y,b.w,b.h);
        ctx.strokeRect(b.x,b.y,b.w,b.h);
    }
    
    //Let's keep re-drawing this
    requestAnimationFrame(draw);
}


function down(event) {
    event = event || window.event;
    x = event.pageX - c.offsetLeft,
    y = event.pageY - c.offsetTop;
    
    for (var i = 0; i<myBoxes.length; i++) {
        var b = myBoxes[i];
        if (x>b.x && x<b.x+b.w && y>b.y && y<b.y+b.h) {
            b.draging = true;
        }
    }
}

function move(event) {
    event = event || window.event;
    x = event.pageX - c.offsetLeft,
    y = event.pageY - c.offsetTop;
    
    for (var i = 0; i<myBoxes.length; i++) {
        var b = myBoxes[i];
        if (b.draging) {
            b.x = x;
            b.y = y;
        }
    }
}
function up(event) {
    event = event || window.event;
    x = event.pageX - c.offsetLeft,
    y = event.pageY - c.offsetTop;
    
    for (var i = 0; i<myBoxes.length; i++) {
        var b = myBoxes[i];
        if (b.draging) {
            //Let's see if the rectangle is inside the dropable area
            if (b.x>c.width/2) {
                //Yes is it!
                b.x = x;
                b.y = y;
                b.draging = false;
            }
            else {
                //No it's not, sending it back to its ordiginal spot   
                b.x = b.xS;
                b.y = b.yS;
                b.draging = false;                
            }

        }
    }
}


draw();
canvas {
  border: 1px solid black;
  }
&lt;canvas id="canvas"&gt;&lt;/canvas&gt;

【讨论】:

  • 非常感谢,这是一个很大的帮助,还有一件事,当我拖动框时,它的副本应该用鼠标移动它(当它发生时)但原始框也应该取而代之,任何想法我怎么能做到这一点?
  • 查看更新的答案,添加了检查框是否正在移动。如果是这样,还要在其原始位置绘制框。我选择将其设为灰色,使其看起来有点像阴影,但这是可选的。
  • 我希望即使在将盒子丢到另一边之后,原始盒子也能留在原处,但无论如何,这对你很有帮助。非常感谢你。
  • @Novice 干得好!根据您希望在 cnavas 上发生的情况,您需要调整代码。如果您希望该框同时在两个地方可见,则需要 2 组坐标(上面的示例具有)。如果您想让它在 3 个位置(原始、移动和可放置区域中的最后一个好位置)上可见,则每个对象需要 3 组坐标。继续尝试,如果遇到问题,请打开一个新问题 =)
【解决方案2】:

您只使用了一个画布,如果您使用两个单独的画布可能会更好,一个用于您要在页面上处理的每个元素。所以每个元素都有一个元素 ID。 加。如果您的绘图很简单,请考虑使用 div 代替画布

【讨论】:

  • 我的目标无法通过 div 实现,稍后左侧面板上的形状将是很难显示为/在 div 上的乐高形状。但是关于两幅画布,我可以考虑购买你的论点。
  • 对于每个乐高积木,您添加一个画布,您可以封装一个将积木绘制到画布的函数,您可以传递积木的颜色和行数/列数,这将非常好!如果对您有帮助,请将我的回答标记为已接受
【解决方案3】:

一旦绘制到画布上,形状(或线条、图像、所有东西)就无法再访问了。

您需要做的是将每个形状存储在代码中的一个对象中。例如:

var rectangle = {
    width: 100,
    height: 100,
    x: 50,
    y: 50
}

然后,当您拖动 rectangle 时,您需要在 mouseup 上更新它的 xy 属性(或者如果您想要拖动预览,则在拖动时)。

【讨论】:

    猜你喜欢
    • 2012-12-25
    • 1970-01-01
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 2014-04-13
    • 1970-01-01
    • 2016-03-10
    相关资源
    最近更新 更多