代码之家  ›  专栏  ›  技术社区  ›  Vinod Louis

如何在drag n drop d3 v4中获取目标元素?

  •  1
  • Vinod Louis  · 技术社区  · 6 年前

    我在D3v4中尝试拖放功能。我在努力寻找目标元素。举个例子,当小圆圈被放下时,我想确定这个圆圈是在哪个路径上放下的。

    谢谢你的帮助

    d3.selection.prototype.moveToFront = function() {  
          return this.each(function(){
            this.parentNode.appendChild(this);
          });
        };
        
        // Feel free to change or delete any of the code you see in this editor!
        const svg = d3.select("body").append("svg")
          .attr("width", 960)
          .attr("height", 960)
          
        
        const svgp = svg.append("g")
    			.attr("transform", "translate(400,300)")
          // set constants
          var PI = Math.PI;
          var arcMin = 0;        // inner radius of the first arc
          var arcWidth = 25;      // width
          var arcPad = 0;         // padding between arcs
          var pieces = 4;
    
          var arcPieces = [{start:0,end:90},{start:90,end:180},{start:180,end:270},{start:270,end:360}];
        
          var drawArc = d3.arc()
          .innerRadius(function(d, i) {
            return  d.ir;
          })
          .outerRadius(function(d, i) {
            return d.or;
          })
          .startAngle(function(d, i) {
            //console.log(d);
            return d.start * Math.PI/180;
          })
          .endAngle(function(d, i) {
            return (d.end * Math.PI/180);
          });
          
        var q = ["q1","q2","q3","q4"];
        var p = [1,2,3,4,5,6,7,8,9,10];
        var step = 360/q.length;
        var objData = []
        var drawData = q.forEach((q,i)=>{
          p.forEach((p,j)=>{
            objData.push({
              q:q,
              p:p,
              start:(i*step),
              end:((i+1)*step),
              ir : j*25,
              or : (j+1) *25
            })
          })
        });
        
      
       
      //console.log(objData);
        
        
            // bind the data
          var arcs = svgp.selectAll("path.arc-path").data(objData);
    
          arcs.enter().append("svg:path")
              .attr("class", "arc-path")                  // assigns a class for easier selecting
              .attr("id",(d)=>d.q+"-"+d.p)
                  // sets position--easier than setting x's and y's
              .attr("fill", function(d,i){
                  // fill is an rgb value with the green value determined by the data
                  // smaller numbers result in a higher green value (1 - d/60)
                  // you should also look into using d3 scales to create gradients
                //var grn = Math.floor((1 - d/60)*255);
                //console.log((d.q.replace("q",'')*10));
                return "rgb(0, 0,"+ (d.q.replace("q",'')*20) +")";
              })
              .attr("d", drawArc)     // draw the arc
              .on('click',function(d){
            		//console.log(d);
          		})
              .on('mouseover',function(){
            //d3.select(this).attr("fill","#ffffff");
          })
          .on('dragover',function(){
            alert("on arc")
          })
          
          
          var circleC = svg.append("circle").attr("cx",25).attr("cy",25).attr("r",10)
          .call(d3.drag()
            .on("start", dragstarted)
            .on("drag", dragged)
            .on("end", dragended));
        
        function dragstarted(d,e){
          //console.log("s",d,e);
          d3.select(this).raise().classed("active", true);
        }
        
        function dragged(d,e){
          //console.log(d3.event,event,this);
          circleC.attr("cx",d3.event.x)
          circleC.attr("cy",d3.event.y)
        }
        
        function dragended(d,e){
          //I want to get on which path is is dropped
          //console.log("e",d,e)
        }
    <script src="https://d3js.org/d3.v4.min.js"></script>
    1 回复  |  直到 6 年前
        1
  •  2
  •   Gerardo Furtado    6 年前

    最直接和直接的解决方案可能是使用 elementFromPoint .

    例如,获取 id <path> :

    d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY))
        .attr("id");
    

    要想让这个发挥作用,我们必须 lower 先绕一圈,这样它就不会在路的顶端。

    这是您的更新代码:

    d3.selection.prototype.moveToFront = function() {
      return this.each(function() {
        this.parentNode.appendChild(this);
      });
    };
    
    // Feel free to change or delete any of the code you see in this editor!
    const svg = d3.select("body").append("svg")
      .attr("width", 960)
      .attr("height", 960)
    
    
    const svgp = svg.append("g")
      .attr("transform", "translate(400,300)")
    // set constants
    var PI = Math.PI;
    var arcMin = 0; // inner radius of the first arc
    var arcWidth = 25; // width
    var arcPad = 0; // padding between arcs
    var pieces = 4;
    
    var arcPieces = [{
      start: 0,
      end: 90
    }, {
      start: 90,
      end: 180
    }, {
      start: 180,
      end: 270
    }, {
      start: 270,
      end: 360
    }];
    
    var drawArc = d3.arc()
      .innerRadius(function(d, i) {
        return d.ir;
      })
      .outerRadius(function(d, i) {
        return d.or;
      })
      .startAngle(function(d, i) {
        //console.log(d);
        return d.start * Math.PI / 180;
      })
      .endAngle(function(d, i) {
        return (d.end * Math.PI / 180);
      });
    
    var q = ["q1", "q2", "q3", "q4"];
    var p = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    var step = 360 / q.length;
    var objData = []
    var drawData = q.forEach((q, i) => {
      p.forEach((p, j) => {
        objData.push({
          q: q,
          p: p,
          start: (i * step),
          end: ((i + 1) * step),
          ir: j * 25,
          or: (j + 1) * 25
        })
      })
    });
    
    
    
    //console.log(objData);
    
    
    // bind the data
    var arcs = svgp.selectAll("path.arc-path").data(objData);
    
    arcs.enter().append("svg:path")
      .attr("class", "arc-path") // assigns a class for easier selecting
      .attr("id", (d) => d.q + "-" + d.p)
      // sets position--easier than setting x's and y's
      .attr("fill", function(d, i) {
        // fill is an rgb value with the green value determined by the data
        // smaller numbers result in a higher green value (1 - d/60)
        // you should also look into using d3 scales to create gradients
        //var grn = Math.floor((1 - d/60)*255);
        //console.log((d.q.replace("q",'')*10));
        return "rgb(0, 0," + (d.q.replace("q", '') * 20) + ")";
      })
      .attr("d", drawArc) // draw the arc
      .on('click', function(d) {
        //console.log(d);
      })
      .on('mouseover', function() {
        //d3.select(this).attr("fill","#ffffff");
      })
      .on('dragover', function() {
        alert("on arc")
      })
    
    
    var circleC = svg.append("circle").attr("cx", 25).attr("cy", 25).attr("r", 10)
      .call(d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended));
    
    function dragstarted(d, e) {
      //console.log("s",d,e);
      d3.select(this).raise().classed("active", true);
    }
    
    function dragged(d, e) {
      //console.log(d3.event,event,this);
      circleC.attr("cx", d3.event.x)
      circleC.attr("cy", d3.event.y)
    }
    
    function dragended(d, e) {
      //I want to get on which path is is dropped
      d3.select(this).lower();
      console.log(d3.select(document.elementFromPoint(d3.event.sourceEvent.clientX, d3.event.sourceEvent.clientY)).attr("id"));
      d3.select(this).raise();
    }
    <script src="https://d3js.org/d3.v4.min.js"></script>

    因为没有 身份证件 对于SVG本身,如果将圆放在路径之外,将得到 null .