简体   繁体   中英

How to know nearest X-axis tick value from my drag able rectangles in d3

Here is my jsfiddle https://jsfiddle.net/t4ka8atv/ . Now I got 2 drag able rectangles one left and another right. I want to know nearest x-axis tick value from my drag able rectangles while sliding them through. How I can achieve this .

For this I added a dragend capability so it checks whats the closest tick on dragend :

.on('dragend', function(d) {
      console.log('dragendRight')
      var thisCoordinate = d3.mouse(this);
      checkXAxis(thisCoordinate);
    });

This passes current mouse coordinates to a function that checks which is closest. This is the function, fully commented so hopefully you will understand :

function checkXAxis(mousePoints) {

    var thisMouseX = mousePoints[0];
    var thisPointDist = 10000; //this is set to  1000 so the first tick checked will be the current 
    var thisPoint; //used to set the closest point
    var xAxis = document.getElementsByClassName('x axis'); //gets all x axis ticks
    var xAxisChildren = xAxis[0]; //gets the x axis children, i.e each tick

    for (var i = 0; i < xAxisChildren.childNodes.length; i++) { //loops through the ticks
      var thisTickX = xAxisChildren.childNodes[i].getBoundingClientRect().left - margin.left; //gets the tick position
      if(xAxisChildren.childNodes[i].localName != 'path'){ //this is to make sure you're only getting the ticks not paths
      if (Math.abs(thisMouseX - thisTickX) < thisPointDist) { //check if distance is smaller than last checked
        thisPointDist = Math.abs(thisMouseX - thisTickX) //sets distance
        thisPoint = xAxisChildren.childNodes[i].__data__; //gets the point which is closest at this time
      }
      }

    } 
    alert(thisPoint) //alert the closest point

  }

Updated fiddle : https://jsfiddle.net/thatoneguy/t4ka8atv/6/

Basically what this does is on drag end it goes through each child of the x axis, ie each tick and gets the difference between the mouse coordinates and each tick and which ever one has the smallest difference it sets this as thisPoint variable. In the code I alert this, but you can do what ever you wish.

 var isXChecked = true, isYChecked = true; var heightRect = 200, dragbarw = 20; var margin = { top: 10, right: 10, bottom: 100, left: 40 }, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; function drawRangeSelector(data, id) { window["widthRect1" + id] = 100; window["widthRect2" + id] = 100; var dragright = d3.behavior.drag() .origin(Object) .on("drag", rdragresize) .on('dragend', function(d) { console.log('dragendRight') var thisCoordinate = d3.mouse(this); checkXAxis(thisCoordinate); }); var dragleft = d3.behavior.drag() .origin(Object) .on("drag", ldragresize) .on('dragend', function(d) { console.log('dragendLeft') var thisCoordinate = d3.mouse(this); checkXAxis(thisCoordinate); }); function checkXAxis(mousePoints) { var thisMouseX = mousePoints[0]; var thisPointDist = 10000; //this is set to 1000 so the first tick checked will be the current var thisPoint; //used to set the closest point var xAxis = document.getElementsByClassName('x axis'); //gets all x axis ticks var xAxisChildren = xAxis[0]; //gets the x axis children, ie each tick for (var i = 0; i < xAxisChildren.childNodes.length; i++) { //loops through the ticks console.log(xAxisChildren.childNodes[i]) console.dir(xAxisChildren.childNodes[i]) var thisTickX = xAxisChildren.childNodes[i].getBoundingClientRect().left - margin.left; //gets the tick position console.log(thisTickX) if(xAxisChildren.childNodes[i].localName != 'path'){ //this is to make sure you're only getting the ticks not paths if (Math.abs(thisMouseX - thisTickX) < thisPointDist) { //check if distance is smaller than last checked thisPointDist = Math.abs(thisMouseX - thisTickX) //sets distance thisPoint = xAxisChildren.childNodes[i].__data__; //gets the point which is closest at this time } } } console.log(thisPoint) console.dir(thisPoint) alert(thisPoint) //alert the closest point } var x = d3.scale.ordinal() .domain(data.map(function(d) { return d.date; })) .rangePoints([0, width]), y = d3.scale.linear().range([height, 0]); var xAxis = d3.svg.axis().scale(x).orient("bottom"), yAxis = d3.svg.axis().scale(y).orient("left"); var area = d3.svg.area() .interpolate("monotone") .x(function(d) { return x(d.date); }) .y0(height) .y1(function(d) { return y(d.price); }); var svg = d3.select("#" + id).append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom); var div = d3.select("#" + id).append("div") .attr("class", "tooltip") .style("opacity", 0); svg.append("defs").append("clipPath") .attr("id", "clip") .append("rect") .attr("width", width) .attr("height", height); var focus = svg.append("g") .attr("class", "focus") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); y.domain([0, d3.max(data.map(function(d) { return d.price; }))]); focus.append("path") .datum(data) .attr("class", "area") .attr("d", area); focus.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); focus.append("g") .attr("class", "y axis") .call(yAxis); focus.selectAll(".dot").data(data) .enter().append("circle").attr('class', 'dot') .attr("r", 5) .attr("cx", function(d) { return x(d.date); }) .attr("cy", function(d) { return y(d.price); }) .on("mouseover", function(d) { div.transition() .duration(200) .style("opacity", .9); div.html(d.date + "<br/>" + d.price) .style("left", (d3.event.pageX) + "px") .style("top", (d3.event.pageY - 28) + "px"); }) .on("mouseout", function(d) { div.transition() .duration(500) .style("opacity", 0); }); var newg = focus.append("g") .data([{ x: width / 700, y: height / 4 }]); window["dragrect" + id] = newg.append("rect") .attr("id", "active") .attr("x", function(d) { return dx; }) //.attr("y", function(d) { return dy; }) .attr("height", height) .attr("width", window["widthRect1" + id]) .attr("fill-opacity", .5) window["dragbarright" + id] = newg.append("rect") .attr("x", function(d) { return dx + window["widthRect1" + id] - (dragbarw / 2); }) //.attr("y", function(d) { return dy + (dragbarw/2); }) .attr("id", "dragright" + id) .attr("height", height - dragbarw) .attr("width", dragbarw) .attr("fill", "lightblue") .attr("fill-opacity", .5) .attr("cursor", "ew-resize") .call(dragright); var newg1 = focus.append("g") .data([{ x: width - 100, y: height / 4 }]); window["dragrect1" + id] = newg1.append("rect") .attr("id", "active1") .attr("x", function(d) { return dx; }) //.attr("y", function(d) { return dy; }) .attr("height", height) .attr("width", window["widthRect2" + id]) .attr("fill-opacity", .5); window["dragbarleft" + id] = newg1.append("rect") .attr("x", function(d) { return dx - (dragbarw / 2); }) //.attr("y", function(d) { return dy + (dragbarw/2); }) .attr("height", height - dragbarw) .attr("id", "dragleft" + id) .attr("width", dragbarw) .attr("fill", "lightblue") .attr("fill-opacity", .5) .attr("cursor", "ew-resize") .call(dragleft); function rdragresize(d) { if (isXChecked) { //Max x on the left is x - width //Max x on the right is width of screen + (dragbarw/2) var limit2 = d3.select('#dragleft' + id).attr("x"); var dragx = Math.max(dx + (dragbarw / 2), Math.min(width, dx + window["widthRect1" + id] + d3.event.dx)); // console.log(parseFloat(limit2)-parseFloat(dragx)) //console.log(parseInt(limit2)) if ((parseFloat(limit2) - parseFloat(dragx)) >= 30.00) { //recalculate width window["widthRect1" + id] = dragx - dx; //move the right drag handle window["dragbarright" + id] .attr("x", function(d) { return dragx - (dragbarw / 2) }); //resize the drag rectangle //as we are only resizing from the right, the x coordinate does not need to change window["dragrect" + id] .attr("width", window["widthRect1" + id]); } } } function ldragresize(d) { if (isXChecked) { var oldx = dx; //Max x on the right is x + width - dragbarw //Max x on the left is 0 - (dragbarw/2) var limit1 = d3.select('#dragright' + id).attr("x"); dx = Math.max(0, Math.min(dx + window["widthRect2" + id] - (dragbarw / 2), d3.event.x)); //console.log(parseFloat(dx)-parseFloat(limit1)) if ((parseFloat(dx) - parseFloat(limit1)) >= 50.00) { window["widthRect2" + id] = window["widthRect2" + id] + (oldx - dx); window["dragbarleft" + id] .attr("x", function(d) { return dx - (dragbarw / 2); }); window["dragrect1" + id] .attr("x", function(d) { return dx; }) .attr("width", window["widthRect2" + id]); } else { dx = oldx; } } } } function type(d) { d.date = d.date; d.price = +d.price; return d; } var data = [{ "date": "A", "price": 0 }, { "date": "B", "price": 1 }, { "date": "C", "price": 2 }, { "date": "D", "price": 0 }, { "date": "E", "price": 2 }, { "date": "F", "price": 0 }, { "date": "G", "price": 4 }, { "date": "H", "price": 3 }, { "date": "I", "price": 0 }, { "date": "J", "price": 0 }, { "date": "K", "price": 3 }]; drawRangeSelector(data, 'charts'); drawRangeSelector(data, 'charts1'); 
 svg { font: 10px sans-serif; } .area { fill: steelblue; clip-path: url(#clip); } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .brush .extent { stroke: #fff; fill-opacity: .125; shape-rendering: crispEdges; } div.tooltip { position: absolute; text-align: center; width: 60px; height: 28px; padding: 2px; font: 12px sans-serif; background: lightsteelblue; border: 0px; border-radius: 8px; pointer-events: none; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <body> <div id='charts'> <div id='charts1'> </div> <script src="//d3js.org/d3.v3.min.js"></script> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM