Home > database >  Drag both circles and corresponding reactive text labels
Drag both circles and corresponding reactive text labels

Time:10-05

I need to make a scatter chart with draggable points and draggable text labels that react to their new positions, so far I have been able to plot the points and their respective labels but not make both their positions and the text labels reactive.

I tried attaching the drag class to the class that stores the text but to no avail. What am i missing out? Any help is appreciated.

https://jsfiddle.net/pdf8wn2h/

<script>

  var svg = d3.select("svg"),
      margin = {top: 20, right: 20, bottom: 30, left: 50},
      width =  svg.attr("width") - margin.left - margin.right,
      height =  svg.attr("height") - margin.top - margin.bottom;


  let points = [[0, 0], [1, 7],[2, 21],[3, 36],[4, 50],[5, 55],[6, 60],[7, 65],[8, 70],[9, 75],[10, 80],[11, 85],[12, 90],[13, 95],[14, 100],[15, 100]];

  var x = d3.scaleLinear()
  .rangeRound([0, width]);

  var y = d3.scaleLinear()
  .rangeRound([height, 0]);

  var xAxis = d3.axisBottom(x),
      yAxis = d3.axisLeft(y);

  var line = d3.line()
  .x(function(d) { return x(d[0]); })
  .y(function(d) { return y(d[1]); });

  let drag = d3.drag()
  .on('start', dragstarted)
  .on('drag', dragged)
  .on('end', dragended);

  svg.append('rect')
    .attr('class', 'zoom')
    .attr('cursor', 'move')
    .attr('fill', 'none')
    .attr('pointer-events', 'all')
    .attr('width', width)
    .attr('height', height)
    .attr('transform', 'translate('   margin.left   ','   margin.top   ')')

  var focus = svg.append("g")
  .attr("transform", "translate("   margin.left   ","   margin.top   ")");

  x.domain(d3.extent(points, function(d) { return d[0]; }));
  y.domain(d3.extent(points, function(d) { return d[1]; }));

  focus.append("path")
    .datum(points)
    .attr("fill", "none")
    .attr("stroke", "green")
    .attr("stroke-linejoin", "round")
    .attr("stroke-linecap", "round")
    .attr("stroke-width", 1.5)
    .attr("d", line);

  focus.selectAll('g')
    .data(points)
    .enter()
    .append('circle')
    .attr('r', 5.0)
    .attr('cx', function(d) { return x(d[0]);  })
    .attr('cy', function(d) { return y(d[1]); })
    .style('cursor', 'pointer')
    .style('fill', 'green');


  focus.selectAll('.dodo')
    .data(points)
    .enter()
    .append("text")
    .attr("class", "dodo")
    .attr("x", function(d) { return x(d[0]); })
    .attr("y", function(d) { return y(d[1]); })
    .attr("dx", ".71em")
    .attr("dy", ".35em")
    .text(function(d) { return d[1];});

  focus.selectAll('circle')
    .call(drag);

  focus.append('g')
    .attr('class', 'axis axis--x')
    .attr('transform', 'translate(0,'   height   ')')
    .call(xAxis);

  focus.append('g')
    .attr('class', 'axis axis--y')
    .call(yAxis);




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

  function dragged(d) {
    // d[0] = x.invert(d3.event.x); Restringe o movimento do eixo x
    d[1] = y.invert(d3.event.y);
    d3.select(this)
      .attr('cx', x(d[0]))
      .attr('cy', y(d[1]))

    focus.select('path').attr('d', line);

  }

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


</script>

CodePudding user response:

See a solution in the snippet below:

    var svg = d3.select("svg"),
        margin = {top: 20, right: 20, bottom: 30, left: 50},
        width =  svg.attr("width") - margin.left - margin.right,
        height =  svg.attr("height") - margin.top - margin.bottom;
        
    
    let points = [[0, 0], [1, 7],[2, 21],[3, 36],[4, 50],[5, 55],[6, 60],[7, 65],[8, 70],[9, 75],[10, 80],[11, 85],[12, 90],[13, 95],[14, 100],[15, 100]];
    
    var x = d3.scaleLinear()
        .rangeRound([0, width]);
    
    var y = d3.scaleLinear()
        .rangeRound([height, 0]);
    
    var xAxis = d3.axisBottom(x),
        yAxis = d3.axisLeft(y);
    
    var line = d3.line()
        .x(function(d) { return x(d[0]); })
        .y(function(d) { return y(d[1]); });
        
    let drag = d3.drag()
            .on('start', dragstarted)
            .on('drag', dragged)
            .on('end', dragended);
            
    svg.append('rect')
        .attr('class', 'zoom')
        .attr('cursor', 'move')
        .attr('fill', 'none')
        .attr('pointer-events', 'all')
        .attr('width', width)
        .attr('height', height)
        .attr('transform', 'translate('   margin.left   ','   margin.top   ')')
    
     var focus = svg.append("g")
                    .attr("transform", "translate("   margin.left   ","   margin.top   ")");
    
    x.domain(d3.extent(points, function(d) { return d[0]; }));
    y.domain(d3.extent(points, function(d) { return d[1]; }));
    
    focus.append("path")
        .datum(points)
        .attr("fill", "none")
        .attr("stroke", "green")
        .attr("stroke-linejoin", "round")
        .attr("stroke-linecap", "round")
        .attr("stroke-width", 1.5)
        .attr("d", line);
    
    const pointG = focus.selectAll('g.point')
        .data(points)
        .enter()
        .append('g')
        .classed('point', true)
        .attr('transform', d => `translate(${x(d[0])},${y(d[1])})`);
        
   pointG.append('circle')
        .attr('r', 5.0)
        .style('cursor', 'pointer')
        .style('fill', 'green');
    
    pointG.append('text')
            .attr("dx", ".71em")
            .attr("dy", ".35em")
            .text(function(d) { return d[1];});

    focus.selectAll('g.point')
            .call(drag);
    
    focus.append('g')
        .attr('class', 'axis axis--x')
        .attr('transform', 'translate(0,'   height   ')')
        .call(xAxis);
        
    focus.append('g')
        .attr('class', 'axis axis--y')
        .call(yAxis);

        

    
    function dragstarted(d) {
        d3.select(this).raise().classed('active', true);
    }
    
    function dragged(d) {
        // d[0] = x.invert(d3.event.x); Restringe o movimento do eixo x
        d[1] = y.invert(d3.event.y);
        d3.select(this)
            .attr('transform', `translate(${x(d[0])},${y(d[1])})`)

        focus.select('path').attr('d', line);
        
    }
    
    function dragended(d) {
        d3.select(this).classed('active', false);
    }
<svg width="500" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script>

  • Related