如何在d3 js中调整矩形的大小?

时间:2022-11-19 13:25:09

Right now I am able to resize a circle. I have created a rectangle using g.append('svg:rect') but I am not sure how to resize a rectangle in d3

现在我可以调整一个圆的大小。我已经使用g.append('svg:rect')创建了一个矩形,但是我不知道如何在d3中调整矩形的大小。

This is what I have tried:

这就是我所尝试的:

var boxWidth = 1300;
var boxHeight = 600;

var box = d3.select('body')
        .append('svg')
        .attr('class', 'box')
        .attr('width', boxWidth)
        .attr('height', boxHeight);

var drag = d3.behavior.drag()
        .on('drag', function () {
            g.selectAll('*')
                    .attr('cx', d3.event.x)
                    .attr('cy', d3.event.y);
        });

var resize = d3.behavior.drag()
        .on('drag', function () {
            g.selectAll('.resizingContainer')
                    .attr('r', function (c) {
                        return Math.pow(Math.pow(this.attributes.cx.value - d3.event.x, 2) + Math.pow(this.attributes.cy.value - d3.event.y, 2), 0.5) + 6;
                    });
            g.selectAll('.draggableCircle')
                    .attr('r', function (c) {
                        return Math.pow(Math.pow(this.attributes.cx.value - d3.event.x, 2) + Math.pow(this.attributes.cy.value - d3.event.y, 2), 0.5);
                    });
        });

var g = box.selectAll('.draggableGroup')
        .data([{
                x: 65,
                y: 55,
                r: 25
            }])
        .enter()
        .append('g');

g.append('svg:circle')
        .attr('class', 'resizingContainer')
        .attr('cx', function (d) {
            return d.x;
        })
        .attr('cy', function (d) {
            return d.y;
        })
        .attr('r', function (d) {
            return d.r + 6;
        })
        .style('fill', '#999')
        .call(resize);

g.append('svg:circle')
        .attr('class', 'draggableCircle')
        .attr('cx', function (d) {
            return d.x;
        })
        .attr('cy', function (d) {
            return d.y;
        })
        .attr('r', function (d) {
            return d.r;
        })
        .call(drag)
        .style('fill', 'black');

g.append('svg:rect')
        .attr("width", 70)
        .attr("height", 70)
        .attr("x", 30)
        .attr("y", 130)
        .attr("rx", 6)
        .attr("ry", 6)
        .style("fill", d3.scale.category20c());

html:

html:

<!DOCTYPE html>
<html>
    <head>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script>
        <script src='d3.js' charset='utf-8'></script>

        <style>
            .box {
                border: 1px black;
                border-radius: 10px;
            }
            .resizingContainer {
                cursor: nesw-resize;
            }
        </style>
    </head>
    <body>
        <script src='drag.js'></script>
        <div id="checks">
        X-axis:<input type="checkbox" id="xChecked" checked/>
        Y-axis:<input type="checkbox" id="yChecked" checked/>
    </div>
    </body>
</html>

Here's the live demo: https://jsbin.com/dejewumali/edit?html,js,output

这里是现场演示:https://jsbin.com/dejewumali/edit?html,js,输出。

2 个解决方案

#1


4  

Added rectangle resize for your code. Note that you need to use the bottom right corner for resizing (that was the easiest corner to add the resizing to :-))

为您的代码添加矩形大小。注意,您需要使用右下角来调整大小(这是添加调整大小的最简单的方法:-))

var boxWidth = 1300;
var boxHeight = 600;

var box =
    d3.select('body')
        .append('svg')
        .attr('class', 'box')
        .attr('width', boxWidth)
        .attr('height', boxHeight);

var drag = d3.behavior.drag()
        .on('drag', function () {
            g.selectAll('*')
                .attr('cx', d3.event.x)
                .attr('cy', d3.event.y);
        });

var resize = d3.behavior.drag()
        .on('drag', function () {
            g.selectAll('.resizingContainer')
                    .attr('r', function (c) {
                        return Math.pow(Math.pow(this.attributes.cx.value - d3.event.x, 2) + Math.pow(this.attributes.cy.value - d3.event.y, 2), 0.5) + 6;
                    });
            g.selectAll('.circle')
                    .attr('r', function (c) {
                        return Math.pow(Math.pow(this.attributes.cx.value - d3.event.x, 2) + Math.pow(this.attributes.cy.value - d3.event.y, 2), 0.5);
                    });
        });


var g = box.selectAll('.draggableCircle')
        .data([{
            x: 65,
            y: 55,
            r: 25
        }])
        .enter()
        .append('g')
        .attr('class', 'draggableCircle');

g.append('svg:circle')
        .attr('class', 'resizingContainer')
        .attr('cx', function (d) {
            return d.x;
        })
        .attr('cy', function (d) {
            return d.y;
        })
        .attr('r', function (d) {
            return d.r + 6;
        })
        .style('fill', '#999')
        .call(resize);

g.append('svg:circle')
        .attr('class', 'circle')
        .attr('cx', function (d) {
            return d.x;
        })
        .attr('cy', function (d) {
            return d.y;
        })
        .attr('r', function (d) {
            return d.r;
        })
        .call(drag)
        .style('fill', 'black');


var distance = function (p1, p2) {
    return Math.pow(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2), 0.5);
}

var resize2 = d3.behavior.drag()
        .on('drag', function () {
            var c = g2.selectAll('.resizingSquare');
            var s = g2.selectAll('.square');

            var e = d3.event;
            var x = Number(this.attributes.x.value);
            var y = Number(this.attributes.y.value);
            var w = Number(this.attributes.width.value);
            var h = Number(this.attributes.height.value);
            var c1 = { x: x, y: y };
            var c2 = { x: x + w, y: y };
            var c3 = { x: x + w, y: y + h };
            var c4 = { x: x, y: y + h };

            // figure out which corner this is closest to
            var d = []
            var m1 = distance(e, c1)
            var m2 = distance(e, c2)
            var m3 = distance(e, c3)
            var m4 = distance(e, c4)
            switch (Math.min(m1, m2, m3, m4)) {
                case m3:
                    c
                        .attr('width', function () { return w + (e.x - c3.x) + 12 })
                        .attr('height', function () { return h + (e.y - c3.y) + 12 })
                    s
                        .attr('width', function () { return w + (e.x - c3.x) })
                        .attr('height', function () { return h + (e.y - c3.y) })
                    break;
            }
        });

var g2 = box.selectAll('.draggableSquare')
    .data([{
        x: 65,
        y: 155,
        width: 70,
        height: 70
    }])
    .enter()
    .append('g')
    .attr('class', 'draggableSquare');

g2
    .append('svg:rect')
        .attr('class', 'resizingSquare')
        .attr("width", function (d) {
            return d.width + 12;
        })
        .attr("height", function (d) {
            return d.height + 12;
        })
        .attr("x", function (d) {
            return d.x - 6;
        })
        .attr("y", function (d) {
            return d.y - 6;
        })
        .attr("rx", 6)
        .attr("ry", 6)
        .style("fill", '#999')
        .call(resize2);

g2
    .append('svg:rect')
        .attr('class', 'square')
        .attr("width", function (d) {
            return d.width;
        })
        .attr("height", function (d) {
            return d.height;
        })
        .attr("x", function (d) {
            return d.x;
        })
        .attr("y", function (d) {
            return d.y;
        })
        .attr("rx", 6)
        .attr("ry", 6)
        .style("fill", d3.scale.category20c());

JS Bin - https://jsbin.com/zenomoziso/1/edit

JS本——https://jsbin.com/zenomoziso/1/edit


That said, if you are looking to use this beyond a proof of concept it's going to be very difficult. There are several problems with the above that will manifest once you have more elements

也就是说,如果你想用这个概念来证明这个概念,这将是非常困难的。上面有几个问题,一旦你有了更多的元素就会显现出来。

  1. The container (g or g2) being used is a global variable.
  2. 被使用的容器(g或g2)是一个全局变量。
  3. The code is clunky (I just tacked on most of it based on the watches - there could be far more efficient ways of doing the same thing - e.g. you could not the start position onDragStart and use that to calculate the change in dimensions)
  4. 这段代码很笨拙(我只是基于表的大部分内容进行了修改),可能会有更有效的方法来做同样的事情——例如,你不能启动一个启动位置,然后用它来计算尺寸的变化。
  5. The code could be cleaner (think objects, better naming conventions, etc.). You might just want do d3.data... squares({ resize: true, move: true }) in your main block instead of all the individual steps.
  6. 代码可以更简洁(比如对象、更好的命名约定等等)。你可能只需要d3数据…方块({resize: true, move: true})在主块中,而不是所有的单个步骤。
  7. You'll be better off searching for some existing diagramming library (why do all the math, when it's already done and tested :-)) - I found a blog with the canvas variant here - http://simonsarris.com/blog/510-making-html5-canvas-useful
  8. 您将更好地搜索一些现有的图表库(为什么要做所有的计算,当它已经完成并经过测试的时候:-))-我在这里找到了一个带有canvas变体的博客- http://simonsarris.com/blog/510-making-html5-canvas-useful。

#2


1  

Rectangle size is based on the width and height attributes. Thus to resize the rectangle you'll want to use something of this ilk:

矩形大小基于宽度和高度属性。因此,要调整矩形的大小,你需要用到这个ilk:

 d3.selectAll('rect')
        .attr('width', function(c){
          return d3.event.x - this.attributes.x.value;
      }).attr('height', function(c){
          return d3.event.y - this.attributes.y.value;
      });

Inserted into your resize behaviour. If you do this and click to drag the circle and move to the origin of the rectangle, it'll then expand linearly with your cursor. It will likely work with little modification if the drag event was attached to the rectangle. Here is a simple application that showcases dragging and re-sizing of a rectangle.

插入到调整大小的行为中。如果你这样做,然后点击拖动圆圈,移动到矩形的原点,它就会随着你的光标线性扩展。如果拖拽事件被附加到矩形上,它将很可能进行少量修改。下面是一个简单的应用程序,它展示了一个矩形的拖动和重新调整大小。

For more reliability you'd want to select by a class identifier rather than a global rectangle select, but this is the basic idea.

要获得更多的可靠性,您需要选择一个类标识符而不是一个全局矩形选择,但这是基本思想。

#1


4  

Added rectangle resize for your code. Note that you need to use the bottom right corner for resizing (that was the easiest corner to add the resizing to :-))

为您的代码添加矩形大小。注意,您需要使用右下角来调整大小(这是添加调整大小的最简单的方法:-))

var boxWidth = 1300;
var boxHeight = 600;

var box =
    d3.select('body')
        .append('svg')
        .attr('class', 'box')
        .attr('width', boxWidth)
        .attr('height', boxHeight);

var drag = d3.behavior.drag()
        .on('drag', function () {
            g.selectAll('*')
                .attr('cx', d3.event.x)
                .attr('cy', d3.event.y);
        });

var resize = d3.behavior.drag()
        .on('drag', function () {
            g.selectAll('.resizingContainer')
                    .attr('r', function (c) {
                        return Math.pow(Math.pow(this.attributes.cx.value - d3.event.x, 2) + Math.pow(this.attributes.cy.value - d3.event.y, 2), 0.5) + 6;
                    });
            g.selectAll('.circle')
                    .attr('r', function (c) {
                        return Math.pow(Math.pow(this.attributes.cx.value - d3.event.x, 2) + Math.pow(this.attributes.cy.value - d3.event.y, 2), 0.5);
                    });
        });


var g = box.selectAll('.draggableCircle')
        .data([{
            x: 65,
            y: 55,
            r: 25
        }])
        .enter()
        .append('g')
        .attr('class', 'draggableCircle');

g.append('svg:circle')
        .attr('class', 'resizingContainer')
        .attr('cx', function (d) {
            return d.x;
        })
        .attr('cy', function (d) {
            return d.y;
        })
        .attr('r', function (d) {
            return d.r + 6;
        })
        .style('fill', '#999')
        .call(resize);

g.append('svg:circle')
        .attr('class', 'circle')
        .attr('cx', function (d) {
            return d.x;
        })
        .attr('cy', function (d) {
            return d.y;
        })
        .attr('r', function (d) {
            return d.r;
        })
        .call(drag)
        .style('fill', 'black');


var distance = function (p1, p2) {
    return Math.pow(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2), 0.5);
}

var resize2 = d3.behavior.drag()
        .on('drag', function () {
            var c = g2.selectAll('.resizingSquare');
            var s = g2.selectAll('.square');

            var e = d3.event;
            var x = Number(this.attributes.x.value);
            var y = Number(this.attributes.y.value);
            var w = Number(this.attributes.width.value);
            var h = Number(this.attributes.height.value);
            var c1 = { x: x, y: y };
            var c2 = { x: x + w, y: y };
            var c3 = { x: x + w, y: y + h };
            var c4 = { x: x, y: y + h };

            // figure out which corner this is closest to
            var d = []
            var m1 = distance(e, c1)
            var m2 = distance(e, c2)
            var m3 = distance(e, c3)
            var m4 = distance(e, c4)
            switch (Math.min(m1, m2, m3, m4)) {
                case m3:
                    c
                        .attr('width', function () { return w + (e.x - c3.x) + 12 })
                        .attr('height', function () { return h + (e.y - c3.y) + 12 })
                    s
                        .attr('width', function () { return w + (e.x - c3.x) })
                        .attr('height', function () { return h + (e.y - c3.y) })
                    break;
            }
        });

var g2 = box.selectAll('.draggableSquare')
    .data([{
        x: 65,
        y: 155,
        width: 70,
        height: 70
    }])
    .enter()
    .append('g')
    .attr('class', 'draggableSquare');

g2
    .append('svg:rect')
        .attr('class', 'resizingSquare')
        .attr("width", function (d) {
            return d.width + 12;
        })
        .attr("height", function (d) {
            return d.height + 12;
        })
        .attr("x", function (d) {
            return d.x - 6;
        })
        .attr("y", function (d) {
            return d.y - 6;
        })
        .attr("rx", 6)
        .attr("ry", 6)
        .style("fill", '#999')
        .call(resize2);

g2
    .append('svg:rect')
        .attr('class', 'square')
        .attr("width", function (d) {
            return d.width;
        })
        .attr("height", function (d) {
            return d.height;
        })
        .attr("x", function (d) {
            return d.x;
        })
        .attr("y", function (d) {
            return d.y;
        })
        .attr("rx", 6)
        .attr("ry", 6)
        .style("fill", d3.scale.category20c());

JS Bin - https://jsbin.com/zenomoziso/1/edit

JS本——https://jsbin.com/zenomoziso/1/edit


That said, if you are looking to use this beyond a proof of concept it's going to be very difficult. There are several problems with the above that will manifest once you have more elements

也就是说,如果你想用这个概念来证明这个概念,这将是非常困难的。上面有几个问题,一旦你有了更多的元素就会显现出来。

  1. The container (g or g2) being used is a global variable.
  2. 被使用的容器(g或g2)是一个全局变量。
  3. The code is clunky (I just tacked on most of it based on the watches - there could be far more efficient ways of doing the same thing - e.g. you could not the start position onDragStart and use that to calculate the change in dimensions)
  4. 这段代码很笨拙(我只是基于表的大部分内容进行了修改),可能会有更有效的方法来做同样的事情——例如,你不能启动一个启动位置,然后用它来计算尺寸的变化。
  5. The code could be cleaner (think objects, better naming conventions, etc.). You might just want do d3.data... squares({ resize: true, move: true }) in your main block instead of all the individual steps.
  6. 代码可以更简洁(比如对象、更好的命名约定等等)。你可能只需要d3数据…方块({resize: true, move: true})在主块中,而不是所有的单个步骤。
  7. You'll be better off searching for some existing diagramming library (why do all the math, when it's already done and tested :-)) - I found a blog with the canvas variant here - http://simonsarris.com/blog/510-making-html5-canvas-useful
  8. 您将更好地搜索一些现有的图表库(为什么要做所有的计算,当它已经完成并经过测试的时候:-))-我在这里找到了一个带有canvas变体的博客- http://simonsarris.com/blog/510-making-html5-canvas-useful。

#2


1  

Rectangle size is based on the width and height attributes. Thus to resize the rectangle you'll want to use something of this ilk:

矩形大小基于宽度和高度属性。因此,要调整矩形的大小,你需要用到这个ilk:

 d3.selectAll('rect')
        .attr('width', function(c){
          return d3.event.x - this.attributes.x.value;
      }).attr('height', function(c){
          return d3.event.y - this.attributes.y.value;
      });

Inserted into your resize behaviour. If you do this and click to drag the circle and move to the origin of the rectangle, it'll then expand linearly with your cursor. It will likely work with little modification if the drag event was attached to the rectangle. Here is a simple application that showcases dragging and re-sizing of a rectangle.

插入到调整大小的行为中。如果你这样做,然后点击拖动圆圈,移动到矩形的原点,它就会随着你的光标线性扩展。如果拖拽事件被附加到矩形上,它将很可能进行少量修改。下面是一个简单的应用程序,它展示了一个矩形的拖动和重新调整大小。

For more reliability you'd want to select by a class identifier rather than a global rectangle select, but this is the basic idea.

要获得更多的可靠性,您需要选择一个类标识符而不是一个全局矩形选择,但这是基本思想。