javascript - how to perform d3 drag and drop - Stack Overflow

Having Issue with d3.drag for angular 4. whenever I drag the rectangle object , it is moving fine for f

Having Issue with d3.drag for angular 4. whenever I drag the rectangle object , it is moving fine for first time. After release of mousepress and again trying to drag the rectangle, it is going back to previous event and not able to make mouse control on draggable object. Please give solution to my problem.

import { Component,Input, ElementRef, OnInit } from '@angular/core'; 
import * as d3 from 'd3';  
interface LineData{
  xVal: number,
  yVal:number
}

@Component({
  selector: 'app-line-chart',
  template:'<svg height="500" width="500" ></svg>',
  styleUrl: [] 
})

export class LineChartComponent implements OnInit {
  @Input() data : LineData[];
  private parentNativeElement : any;
  constructor(private element:ElementRef) { 
      this.parentNativeElement = element.nativeElement;
  }

  ngOnInit() {
    var width = 300;
    var height = 300;
    var margin = {top: 10, right: 10, bottom: 30, left: 10}

    var x = d3.scaleLinear().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);

    var xAxis = d3.axisBottom(x)
        .scale(x)
        .ticks(5);

    var yAxis = d3.axisLeft(y)
        .scale(y)
        .ticks(5);

    var valueline:any = d3.line()
        .x(function (d) {
            return x(d['xVal']);
        })
        .y(function (d) {
            return y(d['yVal']);
        });
        console.log(valueline);

    var svg = d3.select("svg");
    d3.select(this.parentNativeElement)
        .append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g");

    // Get the data
    var data = [
                  {
                    "xVal": 1,
                    "yVal": 2
                  },
                  {
                    "xVal": 2,
                    "yVal": 4
                  },
                  {
                    "xVal": 3,
                    "yVal": 1
                  },
                  {
                    "xVal": 4,
                    "yVal": 5
                  },
                  {
                    "xVal": 5,
                    "yVal": 3
                  }
              ];

    // Scale the range of the data
    x.domain(d3.extent(data,
        function (d) {
            return d.xVal;
        }));
    y.domain([
        0, d3.max(data,
            function (d) {
                return d.yVal;
            })
    ]);
     let color = d3.scaleOrdinal(d3.schemeCategory10);

     svg.append("path").datum(data).attr("class","path")// Add the valueline path.
    .attr("fill", "none")
    .attr("stroke", "red")
    .attr("stroke-width", 1.5)
    .attr("d", valueline(data)).attr("class", "line");


    let rectangle:any = d3.range(1).map(function(){
        return{
            x: Math.floor(Math.random()*width),
            y: Math.floor(Math.random()*height)
        };
    });

    console.log(rectangle);

   let dragRect = svg.selectAll('g').data(rectangle).enter().append("g")

    dragRect.append("rect")
    .attr("x",function(d){return d['x'];})
    .attr("y",function(d){return d['y'];})
    .attr("height",50)
    .attr("width",50).style("fill", "steelblue");

   svg.selectAll('g').attr("transform", 
    "translate(" + margin.left + "," + margin.top + ")").data(rectangle)
    .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended));


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



    function dragged(d){
        d.xVal = x.invert(d3.event.x);
        d.yVal = y.invert(d3.event.y);
        d3.select(this).select("rect")
        .attr("x", x(d.xVal))
        .attr("y", y(d.yVal))
        .attr("transform","translate("+d.xVal+","+d.yVal+")")
        console.log(d); 
    }


    function dragended(d){
        d3.select(this).raise().classed("active",false);
        //d3.select('rect#no-drag').on('mousedown.drag',null);
    }



    svg.append("g") // Add the X Axis
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    svg.append("g") // Add the Y Axis
        .attr("class", "y axis"`enter code here`)
        .call(yAxis);
  }

}

Having Issue with d3.drag for angular 4. whenever I drag the rectangle object , it is moving fine for first time. After release of mousepress and again trying to drag the rectangle, it is going back to previous event and not able to make mouse control on draggable object. Please give solution to my problem.

import { Component,Input, ElementRef, OnInit } from '@angular/core'; 
import * as d3 from 'd3';  
interface LineData{
  xVal: number,
  yVal:number
}

@Component({
  selector: 'app-line-chart',
  template:'<svg height="500" width="500" ></svg>',
  styleUrl: [] 
})

export class LineChartComponent implements OnInit {
  @Input() data : LineData[];
  private parentNativeElement : any;
  constructor(private element:ElementRef) { 
      this.parentNativeElement = element.nativeElement;
  }

  ngOnInit() {
    var width = 300;
    var height = 300;
    var margin = {top: 10, right: 10, bottom: 30, left: 10}

    var x = d3.scaleLinear().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);

    var xAxis = d3.axisBottom(x)
        .scale(x)
        .ticks(5);

    var yAxis = d3.axisLeft(y)
        .scale(y)
        .ticks(5);

    var valueline:any = d3.line()
        .x(function (d) {
            return x(d['xVal']);
        })
        .y(function (d) {
            return y(d['yVal']);
        });
        console.log(valueline);

    var svg = d3.select("svg");
    d3.select(this.parentNativeElement)
        .append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g");

    // Get the data
    var data = [
                  {
                    "xVal": 1,
                    "yVal": 2
                  },
                  {
                    "xVal": 2,
                    "yVal": 4
                  },
                  {
                    "xVal": 3,
                    "yVal": 1
                  },
                  {
                    "xVal": 4,
                    "yVal": 5
                  },
                  {
                    "xVal": 5,
                    "yVal": 3
                  }
              ];

    // Scale the range of the data
    x.domain(d3.extent(data,
        function (d) {
            return d.xVal;
        }));
    y.domain([
        0, d3.max(data,
            function (d) {
                return d.yVal;
            })
    ]);
     let color = d3.scaleOrdinal(d3.schemeCategory10);

     svg.append("path").datum(data).attr("class","path")// Add the valueline path.
    .attr("fill", "none")
    .attr("stroke", "red")
    .attr("stroke-width", 1.5)
    .attr("d", valueline(data)).attr("class", "line");


    let rectangle:any = d3.range(1).map(function(){
        return{
            x: Math.floor(Math.random()*width),
            y: Math.floor(Math.random()*height)
        };
    });

    console.log(rectangle);

   let dragRect = svg.selectAll('g').data(rectangle).enter().append("g")

    dragRect.append("rect")
    .attr("x",function(d){return d['x'];})
    .attr("y",function(d){return d['y'];})
    .attr("height",50)
    .attr("width",50).style("fill", "steelblue");

   svg.selectAll('g').attr("transform", 
    "translate(" + margin.left + "," + margin.top + ")").data(rectangle)
    .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended));


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



    function dragged(d){
        d.xVal = x.invert(d3.event.x);
        d.yVal = y.invert(d3.event.y);
        d3.select(this).select("rect")
        .attr("x", x(d.xVal))
        .attr("y", y(d.yVal))
        .attr("transform","translate("+d.xVal+","+d.yVal+")")
        console.log(d); 
    }


    function dragended(d){
        d3.select(this).raise().classed("active",false);
        //d3.select('rect#no-drag').on('mousedown.drag',null);
    }



    svg.append("g") // Add the X Axis
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    svg.append("g") // Add the Y Axis
        .attr("class", "y axis"`enter code here`)
        .call(yAxis);
  }

}
Share Improve this question edited Oct 26, 2018 at 6:08 fiza khan 1,29614 silver badges24 bronze badges asked Oct 26, 2018 at 5:50 Kanduri MadhurikaKanduri Madhurika 811 silver badge8 bronze badges 1
  • This is for Line chart having draggable object (rectangle). on moving the rectangle , dragged axis values will be rendered – Kanduri Madhurika Commented Oct 26, 2018 at 5:59
Add a ment  | 

1 Answer 1

Reset to default 5

The basic problem seems to be that dragged function is not remembering the x & y between successive drag events.

To do this, you need

d3.select(this)
  .attr("x", d.x = x(d.xVal))
  .attr("y", d.y = y(d.yVal))

instead of

d3.select(this)
  .attr("x", x(d.xVal))
  .attr("y", y(d.yVal))

Run this code snippet to check it out

console.clear()
var width = 300;
var height = 300;
var margin = {top: 10, right: 10, bottom: 30, left: 10}

var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);

var xAxis = d3.axisBottom(x).scale(x).ticks(5);

var yAxis = d3.axisLeft(y).scale(y).ticks(5);

var valueline = d3.line()
  .x(function (d) { return x(d['xVal']); })
  .y(function (d) { return y(d['yVal']); });

var svg = d3.select("svg");
d3.select(this.parentNativeElement)
  .append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g");

// Get the data
var data = [
  {
    "xVal": 1,
    "yVal": 2
  },
  {
    "xVal": 2,
    "yVal": 4
  },
  {
    "xVal": 3,
    "yVal": 1
  },
  {
    "xVal": 4,
    "yVal": 5
  },
  {
    "xVal": 5,
    "yVal": 3
  }
];

// Scale the range of the data
x.domain(d3.extent(data,
  function (d) {
    return d.xVal;
  }));
y.domain([
    0, d3.max(data,
        function (d) {
            return d.yVal;
        })
]);

let color = d3.scaleOrdinal(d3.schemeCategory10);

svg.append("path").datum(data).attr("class","path")
  .attr("fill", "none")
  .attr("stroke", "red")
  .attr("stroke-width", 1.5)
  .attr("d", valueline(data)).attr("class", "line");

let rectangle = d3.range(3).map(function() {
  return {
    x: Math.floor(Math.random()*width),
    y: Math.floor(Math.random()*height)
  };
});

let dragRect = svg.selectAll('g').data(rectangle).enter()
  .append("g")

dragRect.append("rect")
  .attr("x",function(d){return d['x'];})
  .attr("y",function(d){return d['y'];})
  .attr("height", 50)
  .attr("width", 50)
  .style("fill", "steelblue")

svg.selectAll('rect')
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
  .data(rectangle)
  .call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended)
  );

const dragBounds = {}
const tickHeight = 10;

function setDragBounds(subject) {
  dragBounds.top = 0 - margin.top;
  dragBounds.left = 0 - margin.left;
  dragBounds.bottom = height - tickHeight - subject.attr('height');
  dragBounds.right = width - margin.right - subject.attr('width');
}

function dragstarted(d){
  /* 
    Calculate drag bounds at dragStart because it's one event vs many 
    events if done in 'dragged()'
  */    
  setDragBounds(d3.select(this)) 
  d3.select(this).raise().classed("active", true);
}

function dragged(d){
  d3.select(this)
    .attr("x", getX(d.x = d3.event.x) )
    .attr("y", getY(d.y = d3.event.y) );
}

function getX(x) {
  return x < dragBounds.left ? dragBounds.left
    : x > dragBounds.right ? dragBounds.right 
    : x
}

function getY(y) {
  return y < dragBounds.top ? dragBounds.top
    : y > dragBounds.bottom ? dragBounds.bottom 
    : y
}

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

svg.append("g") // Add the X Axis
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis)

svg.append("g") // Add the Y Axis
  .attr("class", "y axis")
  .call(yAxis);
  
<script src="https://cdnjs.cloudflare./ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg height="500" width="500" ></svg>

Note I attached the drag events to rect instead of g, which I assume was a typo.


Keeping within bounds

To constrain the drag to bounds the way I found works best is a max/min function on the x & y values.

function dragged(d){
  d3.select(this)
    .attr("x", getX(d.x = d3.event.x) )
    .attr("y", getY(d.y = d3.event.y) );
}

function getX(x) {
  return x < dragBounds.left ? dragBounds.left
    : x > dragBounds.right ? dragBounds.right 
    : x
}

function getY(y) {
  return y < dragBounds.top ? dragBounds.top
    : y > dragBounds.bottom ? dragBounds.bottom 
    : y
}

Bounds are set at drag start to avoid repetition of any calculation.

const dragBounds = {}
const tickHeight = 10;

function setDragBounds(subject) {
  dragBounds.top = 0 - margin.top;
  dragBounds.left = 0 - margin.left;
  dragBounds.bottom = height - tickHeight - subject.attr('height');
  dragBounds.right = width - margin.right - subject.attr('width');
}

function dragstarted(d){
  /* 
    Calculate drag bounds at dragStart because it's one event vs many 
    events if done in 'dragged()'
  */    
  setDragBounds(d3.select(this)) 
  d3.select(this).raise().classed("active", true);
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745487839a4629847.html

相关推荐

  • javascript - how to perform d3 drag and drop - Stack Overflow

    Having Issue with d3.drag for angular 4. whenever I drag the rectangle object , it is moving fine for f

    3小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信