D3不正确的拖动行为

时间:2017-09-29 15:05:34

标签: javascript d3.js drag

这是我之前的问题的后续内容 d3 rect in one group interfering with rect in another group

两个问题:

  1. 不正确的拖动行为。当点击第二个矩形进行拖动时,它会跳到第三个矩形所在的位置。

  2. 我添加了一个匿名函数,该函数在svg点击任意位置时运行。这应该添加一个新的rect。然而,那就是工作。

  3. 我知道每个问题我应该只有一个问题,但这些问题是相关的,我怀疑它们会一起解决。

    <!DOCTYPE html>
    <meta charset="utf-8">
    <style>
      /*.active {
        stroke: #000;
        stroke-width: 2px;
      }*/
    </style>
    <svg width="960" height="500"></svg>
    <script src="//d3js.org/d3.v4.min.js"></script>
    <script>
      var margin = {
          top: 20,
          right: 20,
          bottom: 20,
          left: 20
        },
        width = 600 - margin.left - margin.right,
        height = 600 - margin.top - margin.bottom;
    
      var svg = d3.select("svg");
    
      var data = [{
        x: 200
      }, {
        x: 300
      }, {
        x: 400
      }];
    
      var groove = svg.append("g")
        .attr("class", "groove_group");
    
      groove.append("rect")
        .attr("x", 100)
        .attr("y", 150)
        .attr("rx", 2)
        .attr("ry", 2)
        .attr("height", 6)
        .attr("width", 800)
        .style("fill", "grey");
    
      groove.append("rect")
        .attr("x", 102)
        .attr("y", 152)
        .attr("rx", 2)
        .attr("ry", 2)
        .attr("height", 2)
        .attr("width", 796)
        .style("fill", "black");
    
      // create group
      var group = svg.selectAll(null)
        .data(data)
        .enter().append("g")
        .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended))
        .on("click", removeElement);
    
      group.append("rect")
        .attr("x", function(d) {
          return d.x;
        })
        .attr("y", 100)
        .attr("height", 100)
        .attr("width", 15)
        .style("fill", "lightblue")
        .attr('id', function(d, i) {
          return 'handle_' + i;
        })
        .attr("rx", 6)
        .attr("ry", 6)
        .attr("stroke-width", 2)
        .attr("stroke", "black");
    
      group.append("text")
        .attr("x", function(d) {
          return d.x
        })
        .attr("y", 100)
        .attr("text-anchor", "start")
        .style("fill", "black")
        .text(function(d) {
          return "x:" + d.x
        });
    
      // create group
      var group = svg.selectAll("g")
        .data(data)
        .enter().append("g")
        .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended))
        .on("click", removeElement);
    
      group.append("rect")
        .attr("x", function(d) {
          return d.x;
        })
        .attr("y", 200)
        .attr("height", 100)
        .attr("width", 15)
        .style("fill", "lightblue")
        .attr('id', function(d, i) {
          return 'handle_' + i;
        })
        .attr("rx", 6)
        .attr("ry", 6)
        .attr("stroke-width", 2)
        .attr("stroke", "black");
    
      group.append("text")
        .attr("x", function(d) {
          return d.x
        })
        .attr("y", 200)
        .attr("text-anchor", "start")
        .style("fill", "black")
        .text(function(d) {
          return "x:" + d.x
        });
    
      svg.on("click", function() {
        var coords = d3.mouse(this);
    
        var newData = {
          x: d3.event.x,
        }
        data.push(newData);
    
        group.selectAll("rect")
          .data(data)
          .enter()
          .append("rect")
          .attr("x", function(d) {
            return d.x;
          })
          .attr("y", 200)
          .attr("height", 100)
          .attr("width", 15)
          .style("fill", "steelblue")
          .attr('id', function(d, i) {
            return 'rect_' + i;
          })
          .attr("rx", 6)
          .attr("ry", 6)
          .attr("stroke-width", 2)
          .attr("stroke", "black");
      });
    
    
      function dragstarted(d) {
        d3.select(this).raise().classed("active", true);
      }
    
      function dragged(d) {
        d3.select(this).select("text")
          .attr("x", d.x = d3.event.x);
        d3.select(this).select("rect")
          .attr("x", d.x = d3.event.x);
      }
    
      function dragended(d) {
        d3.select(this)
          .classed("active", false);
      }
    
      function removeElement(d) {
        d3.event.stopPropagation();
        data = data.filter(function(e) {
          return e != d;
        });
        d3.select(this)
          .remove();
      }
    </script>

2 个答案:

答案 0 :(得分:1)

对于正确的拖放行为,请重写您的代码:

var margin = {
      top: 20,
      right: 20,
      bottom: 20,
      left: 20
    },
    width = 600 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

  var svg = d3.select("svg");

  var data = [{
    x: 200
  }, {
    x: 300
  }, {
    x: 400
  }];

  var groove = svg.append("g")
    .attr("class", "groove_group");

  groove.append("rect")
    .attr("x", 100)
    .attr("y", 150)
    .attr("rx", 2)
    .attr("ry", 2)
    .attr("height", 6)
    .attr("width", 800)
    .style("fill", "grey");

  groove.append("rect")
    .attr("x", 102)
    .attr("y", 152)
    .attr("rx", 2)
    .attr("ry", 2)
    .attr("height", 2)
    .attr("width", 796)
    .style("fill", "black");

  // create group
  var group = svg.selectAll(null)
    .data(data)
    .enter().append("g")
    .call(d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended))
    .on("click", removeElement);

  group.append("rect")
    .attr("x", function(d) {
      return d.x;
    })
    .attr("y", 100)
    .attr("height", 100)
    .attr("width", 15)
    .style("fill", "lightblue")
    .attr('id', function(d, i) {
      return 'handle_' + i;
    })
    .attr("rx", 6)
    .attr("ry", 6)
    .attr("stroke-width", 2)
    .attr("stroke", "black");

  group.append("text")
    .attr("x", function(d) {
      return d.x
    })
    .attr("y", 100)
    .attr("text-anchor", "start")
    .style("fill", "black")
    .text(function(d) {
      return "x:" + d.x
    });

  svg.on("click", function() {
    var coords = d3.mouse(this);

    var newData = {
      x: d3.event.x,
    }
    data.push(newData);

    group.selectAll("rect")
      .data(data)
			.exit()
			.enter()
      .append("rect")
      .attr("x", function(d) {
        return d.x;
      })
      .attr("y", 200)
      .attr("height", 100)
      .attr("width", 15)
      .style("fill", "steelblue")
      .attr('id', function(d, i) {
        return 'rect_' + i;
      })
      .attr("rx", 6)
      .attr("ry", 6)
      .attr("stroke-width", 2)
      .attr("stroke", "black");
  });


  function dragstarted(d) {
    d3.select(this).raise().classed("active", true);
  }

  function dragged(d) {
    d3.select(this).select("text")
      .attr("x", d.x = d3.event.x);
    d3.select(this).select("rect")
      .attr("x", d.x = d3.event.x);
  }

  function dragended(d) {
    d3.select(this)
      .classed("active", false);
  }

  function removeElement(d) {
    d3.event.stopPropagation();
    data = data.filter(function(e) {
      return e != d;
    });
    d3.select(this)
      .remove();
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.2/d3.min.js"></script>
<svg width="960" height="500"></svg>

但是,添加新元素的问题是什么,我不知道。

答案 1 :(得分:1)

以下是对您的问题的解释:

  1. 您正在重新分配var groups,也就是说,您的代码中有两个var groups,最后一个覆盖了第一个<g>。只需删除最后一个变量。
  2. 在附加新矩形的函数中,您正在使用选择矩形的更新选择。但是,您的输入选择会附加组(var newGroup = svg.selectAll(".group") .data(data, function(d) { return d.x }) .enter() .append("g") //etc... newGroup.append("rect") //etc... )元素,而不是矩形。
  3. 查看重构函数,它将数据绑定到新创建的组,并将矩形附加到该组:

    .data(data, function(d){return d.x})
    

    此外,在数据绑定中使用键选择,因此您确切地知道正在拖动的矩形:

    <!DOCTYPE html>
    <meta charset="utf-8">
    <style>
      /*.active {
        stroke: #000;
        stroke-width: 2px;
      }*/
    </style>
    <svg width="960" height="500"></svg>
    <script src="//d3js.org/d3.v4.min.js"></script>
    <script>
      var margin = {
          top: 20,
          right: 20,
          bottom: 20,
          left: 20
        },
        width = 600 - margin.left - margin.right,
        height = 600 - margin.top - margin.bottom;
    
      var svg = d3.select("svg");
    
      var data = [{
        x: 200
      }, {
        x: 300
      }, {
        x: 400
      }];
    
      var groove = svg.append("g")
        .attr("class", "groove_group");
    
      groove.append("rect")
        .attr("x", 100)
        .attr("y", 150)
        .attr("rx", 2)
        .attr("ry", 2)
        .attr("height", 6)
        .attr("width", 800)
        .style("fill", "grey");
    
      groove.append("rect")
        .attr("x", 102)
        .attr("y", 152)
        .attr("rx", 2)
        .attr("ry", 2)
        .attr("height", 2)
        .attr("width", 796)
        .style("fill", "black");
    
      // create group
      var group = svg.selectAll(null)
        .data(data, function(d){return d.x})
        .enter().append("g")
        .attr("class", "group")
        .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended))
        .on("click", removeElement);
    
      group.append("rect")
        .attr("x", function(d) {
          return d.x;
        })
        .attr("y", 100)
        .attr("height", 100)
        .attr("width", 15)
        .style("fill", "lightblue")
        .attr('id', function(d, i) {
          return 'handle_' + i;
        })
        .attr("rx", 6)
        .attr("ry", 6)
        .attr("stroke-width", 2)
        .attr("stroke", "black");
    
      group.append("text")
        .attr("x", function(d) {
          return d.x
        })
        .attr("y", 100)
        .attr("text-anchor", "start")
        .style("fill", "black")
        .text(function(d) {
          return "x:" + d.x
        });
    
      svg.on("click", function() {
        var coords = d3.mouse(this);
    
        var newData = {
          x: coords[0],
        }
        
        data.push(newData);
    
        var newGroup = svg.selectAll(".group")
          .data(data, function(d){return d.x})
          .enter()
          .append("g")
          .attr("class", "group")
              .call(d3.drag()
          .on("start", dragstarted)
          .on("drag", dragged)
          .on("end", dragended))
        .on("click", removeElement);
          
          newGroup.append("rect")
          .attr("x", function(d) {
            return d.x;
          })
          .attr("y", 200)
          .attr("height", 100)
          .attr("width", 15)
          .style("fill", "steelblue")
          .attr('id', function(d, i) {
            return 'rect_' + i;
          })
          .attr("rx", 6)
          .attr("ry", 6)
          .attr("stroke-width", 2)
          .attr("stroke", "black");
      });
    
    
      function dragstarted(d) {
        d3.select(this).raise().classed("active", true);
      }
    
      function dragged(d) {
        d3.select(this).select("text")
          .attr("x", d.x = d3.event.x);
        d3.select(this).select("rect")
          .attr("x", d.x = d3.event.x);
      }
    
      function dragended(d) {
        d3.select(this)
          .classed("active", false);
      }
    
      function removeElement(d) {
        d3.event.stopPropagation();
        data = data.filter(function(e) {
          return e != d;
        });
        d3.select(this)
          .remove();
      }
    </script>

    以下是包含这些更改的代码:

    let NASAURL = URL(string: "https://images-api.nasa.gov/search?q=moon")
        let session = URLSession(configuration: .default)
        let task = session.dataTask(with: NASAURL!) { (rdata, response, error) in
            NSLog("Data Description: " + (rdata!.debugDescription) + "\nResponse: " + response.debugDescription + "\nError Description: " + error.debugDescription)
    
            guard rdata != nil else{
                NSLog("No data")
                return
            }
            guard error == nil else{
                NSLog(response.debugDescription + "\n")
                NSLog(error.debugDescription)
                NSLog(error.debugDescription)
                return
            }
            let decoder = JSONDecoder()
            do{
                NSLog(rdata.debugDescription)
                let usr = try decoder.decode(Collect.self, from: rdata!) // Throws
                NSLog(usr.href)
    
            } catch {
                NSLog("Error: " + error.localizedDescription)
            }
        }
        task.resume()
    
    // Collect is in its own class/file
    struct Collect: Codable {
        var href: String
        //var items: [Items]
    }