【问题标题】:How to drag drop elements into svg group如何将拖放元素拖放到 svg 组中
【发布时间】:2015-07-13 13:26:28
【问题描述】:

我左边有几个圆圈,右边有一个 svg 组。我想在拖放时将圆圈拖到 svg 组中。一旦我将元素放入 svg 组,它应该被附加到组中。

到目前为止,我已经创建了一个可拖动的元素和可拖动的组,但找不到任何关于相同的文章。

我左边有几个圆圈,右边有一个 svg 组。我想在拖放时将圆圈拖到 svg 组中。一旦我将元素放入 svg 组,它应该被附加到组中。

到目前为止,我已经创建了一个可拖动的元素和可拖动的组,但找不到任何关于相同的文章。

演示:http://jsbin.com/wowunoluza/1/edit?html,js,output

<!doctype html>
<html>
    <head>
        <title>Editor</title>
        <meta http-equiv="x-ua-compatible" content="ie=9"/>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.js"></script>
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
        <link rel="stylesheet" href="<%=request.getContextPath()%>/style.css" />
        <script type="text/javascript">
            window.onload = function ()
            {
                var svgContainer = d3.select("body").append("svg")
                        .attr("width", 800)
                        .attr("height", 803);

                var sidebar = svgContainer.append("rect")
                        .attr("x", 0)
                        .attr("y", 43.5)
                        .attr("width", 69)
                        .attr("height", 620)
                        .attr("stroke-width", 2)
                        .attr("stroke", "#7E7E7E")
                        .style("fill", "none");

                var rect = svgContainer.append("rect")
                        .attr("x", 10)
                        .attr("y", 50)
                        .attr("width", 51)
                        .attr("height", 41)
                        .attr("rx", 10)
                        .attr("stroke-width", 2)
                        .attr("stroke", "#7E7E7E")
                        .style('cursor', 'move')
                        .style("fill", "none");

                //Draw the Circle
                var circle = svgContainer.append("circle")
                        .attr("cx", 35)
                        .attr("cy", 145)
                        .attr("r", 25)
                        .style("stroke-opacity", .9)
                        .style("stroke", "green")
                        .style("stroke-width", 2)
                        .style('cursor', 'move')
                        .style("fill", "white");

                var circle2 = svgContainer.append("circle")
                        .attr("cx", 35)
                        .attr("cy", 225)
                        .style("stroke-opacity", .9)
                        .style("stroke-width", 2)
                        .style("stroke", "red")
                        .style("fill", "white")
                        .style('cursor', 'move')
                        .attr("r", 25);

                var circle3 = svgContainer.append("circle")
                        .attr("id", "circleToClone")
                        .attr("cx", 35)
                        .attr("cy", 310)
                        .attr("r", 25)
                        .style("fill", "white")
                        .style("stroke-width", 2)
                        .style('cursor', 'move')
                        .style("stroke", "#CDB483");

                var dragGroup = d3.behavior.drag()
                        .origin(function () {
                            var g = this;
                            return {x: d3.transform(g.getAttribute("transform")).translate[0],
                                y: d3.transform(g.getAttribute("transform")).translate[1]};
                        })
                        .on("drag", function (d, i) {

                            g = this;
                            console.log(g);
                            translate = d3.transform(g.getAttribute("transform")).translate;
                            x = d3.event.dx + translate[0],
                                    y = d3.event.dy + translate[1];
                            d3.select(g).attr("transform", "translate(" + x + "," + y + ")");
                            d3.event.sourceEvent.stopPropagation();
                        });

                var group = svgContainer.append("g")
                        .attr("id", "mygroup")
                        .call(dragGroup)
                        .style('cursor', 'move')
                        .attr("transform", "translate(20, 20)");

                group.append("rect")
                        .attr("x", 250)
                        .attr("y", 250)
                        .attr("width", 151)
                        .attr("height", 141)
                        .attr("rx", 10)
                        .attr("stroke-width", 2)
                        .attr("stroke", "#7E7E7E")
                        .style("fill", "white");

                group.append("circle")
                        .attr("cx", 330)
                        .attr("cy", 330)
                        .attr("r", 25)
                        .style("fill", "white")
                        .style("stroke-width", 1)
                        .style("stroke", "red");


                var drag = d3.behavior.drag()
                        .origin(function ()
                        {
                            var t = d3.select(this);
                            return {x: t.attr("cx"), y: t.attr("cy")};
                        })

                        .on('dragend', function (d) {
                            var mouseCoordinates = d3.mouse(this);
                            if (mouseCoordinates[0] > 170) {
                                //Append new element
                                var circle2 = d3.select("svg").append("circle")
                                        .classed("drg", true)
                                        .attr("cx", 100)
                                        .attr("cy", 100)
                                        .attr("r", 20)
                                        .attr("cx", mouseCoordinates[0])
                                        .attr("cy", mouseCoordinates[1])
                                        .style("fill", "white")
                                        .style("stroke-width", 2)
                                        .style("stroke", "#CDB483");
                            }
                        });
                circle.call(drag);
                circle2.call(drag);
                circle3.call(drag);
            };
        </script>
    </head>
    <body>
        <div id="container">
            <div id="header" style="margin-bottom: 0;">
                <h1 id="title">Editor</h1>
                <div id="footer"></div>
            </div>
        </div>
    </body>
</html>

【问题讨论】:

  • 可能有更有效的方法来做到这一点(也许是内置的 d3 命令/与碰撞有关的东西?),但首先想到的是遍历所有组元素在您的页面上,使用r 表示圆形,使用width, height 表示矩形,确定鼠标是否在该组内(设计一个简短的算法来确定最小x,y 和最大x,y)。这会有点复杂,因为cx, cy 定义了圆的中间,x, y 定义了rect 的角,但这是一般的想法。
  • 函数getBBox() 看起来很有用。它给出了相对于形状所属的g 元素的坐标,因此您必须使用g.attr("transform") 并通过translate(x,y) 偏移坐标。 Here 是一个显示getBBox() 的小提琴。
  • @JSBob 使用碰撞检测来实现这一点更好吗?我没有找到任何关于碰撞检测的教程。它唯一的代码示例无处不在

标签: d3.js


【解决方案1】:

当“放下”一个圆时,您可以使用d3.transform 获取g 元素的当前平移,然后检查鼠标的坐标是否在组中的矩形内。

然后您可以在group 上附加一个新圆,其坐标由鼠标坐标和组的平移确定,其笔划由已拖动到组的圆的笔划确定。

所以您的.on("dragend" 函数现在应该如下所示:

var mouseCoordinates = d3.mouse(this);
var groupTransform = d3.transform(group.attr("transform"));
var groupX = groupTransform.translate[0];
var groupY = groupTransform.translate[1];
var rect = group.select("rect");
var rectX = +rect.attr("x");
var rectY = +rect.attr("y");
var rectWidth = +rect.attr("width");
var rectHeight = +rect.attr("height");

if (mouseCoordinates[0] > groupX + rectX 
    && mouseCoordinates[0] < groupX + rectX + rectWidth
    && mouseCoordinates[1] > groupY + rectY
    && mouseCoordinates[1] < groupY + rectY + rectHeight) {
    //Append new element
    var newCircle =   group.append("circle")
        .classed("drg", true)
        .attr("cx", mouseCoordinates[0] - groupX)
        .attr("cy", mouseCoordinates[1] - groupY)
        .attr("r", 20)
        .style("fill", "white")
        .style("stroke-width", 2)
        .style("stroke", d3.select(this).style("stroke"));
}

您仍然可以更改许多内容并将其添加到代码中以使其更好,但这应该可以帮助您入门。

【讨论】:

  • 我不明白鼠标坐标部分。为什么我们在那里使用静态值?是否可以使用上面JSBob提到的getBBox()函数?
  • 我猜碰撞检测是解决这个问题的方法??
  • 我使用静态值是因为我认为rect 的坐标和大小不会改变。我已更新我的答案以动态获取rect 的坐标和大小。
  • 谢谢。我是 d3 js 的新手。我不知道我也可以选择组。现在这应该工作;)
  • 将圆圈放到右侧 y 轴上的矩形上无法正常工作。它正在将圆形推到矩形之外
猜你喜欢
  • 1970-01-01
  • 2015-08-28
  • 1970-01-01
  • 2022-09-24
  • 2018-09-29
  • 1970-01-01
  • 2012-11-16
相关资源
最近更新 更多