简体   繁体   中英

D3 V4 How to move dots according to zoom in linechart?

Small problems are difficult to identify. I am using example to create a linechart using d3 v4. I'm using d3.line() rather than d3.area() . Also drawing circles on the line peak points. Things are working fine.

Problem is with the drawn circles. They are not moving to the correct position when i'm zooming the graph. Here is the complete code:

 .area { fill: none; stroke: #a2dced; stroke-width: 2; clip-path: url(#clip); } .zoom { cursor: move; fill: none; pointer-events: all; } rect.selection { fill:green; } 
 <script src="https://d3js.org/d3.v4.min.js"></script> <svg width="960" height="500"></svg> <script> var data = [{date: "10:30:00", price: 36000}, {date: "11:00:20", price: 40000}, {date: "12:00:00", price: 38000}, {date: "14:20:00", price: 50400}]; var svg = d3.select("svg"), margin = {top: 20, right: 20, bottom: 110, left: 40}, margin2 = {top: 430, right: 20, bottom: 30, left: 40}, width = +svg.attr("width") - margin.left - margin.right, height = +svg.attr("height") - margin.top - margin.bottom, height2 = +svg.attr("height") - margin2.top - margin2.bottom; var parseDate = d3.timeParse("%H:%M:%S");//"%b %Y"); var x = d3.scaleTime().range([0, width]), x2 = d3.scaleTime().range([0, width]), y = d3.scaleLinear().range([height, 0]), y2 = d3.scaleLinear().range([height2, 0]); var xAxis = d3.axisBottom(x), xAxis2 = d3.axisBottom(x2), yAxis = d3.axisLeft(y); var brush = d3.brushX() .extent([[0, 0], [width, height2]]) .on("brush end", brushed); var zoom = d3.zoom() .scaleExtent([1, Infinity]) .translateExtent([[0, 0], [width, height]]) .extent([[0, 0], [width, height]]) .on("zoom", zoomed); var area = d3.line() //.curve(d3.curveMonotoneX) .x(function (d) { return x(d.date); }) .y(function (d) { return y(d.price); }); var area2 = d3.line() .curve(d3.curveMonotoneX) .x(function (d) { return x2(d.date); }) .y(function (d) { return y2(d.price); }); 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 + ")"); var context = svg.append("g") .attr("class", "context") .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")"); function update(){ for(var k in data) { type(data[k]); } x.domain(d3.extent(data, function(d) { return d.date; })); y.domain([0, d3.max(data, function(d) { return d.price; })]); x2.domain(x.domain()); y2.domain(y.domain()); focus.append("path") .datum(data) .attr("class", "area") .attr("d", area); 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); focus.selectAll("circle") .data(data) .enter().append("circle") .attr("class","circle") .attr("r", 5) .style("fill", 'orange') .style("stroke", 'red') .style("stroke-width", "2") .attr("cx", function(d) { return x(d.date) }) .attr("cy", function(d) { return y(d.price); }); context.append("path") .datum(data) .attr("class", "area") .attr("d", area2); context.append("g") .attr("class", "axis axis--x") .attr("transform", "translate(0," + height2 + ")") .call(xAxis2); context.selectAll("circle") .data(data) .enter().append("circle") .attr("class","circle") .attr("r", 1) .style("fill", 'blue') .style("stroke", 'red') .style("stroke-width", "2") .attr("cx", function(d) { return x(d.date) }) .attr("cy", function(d) { return y(d.price); }); context.append("g") .attr("class", "brush") .call(brush) .call(brush.move, x.range()); svg.append("rect") .attr("class", "zoom") .attr("width", width) .attr("height", height) .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .call(zoom); } function brushed() { if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom var s = d3.event.selection || x2.range(); x.domain(s.map(x2.invert, x2)); focus.select(".area").attr("d", area); focus.selectAll('.circle').attr("transform", function(d) { return "translate(" + x(d.date) + "," + y(d.price) + ")"; }); focus.select(".axis--x").call(xAxis); svg.select(".zoom").call(zoom.transform, d3.zoomIdentity .scale(width / (s[1] - s[0])) .translate(-s[0], 0)); } function zoomed() { if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush var t = d3.event.transform; x.domain(t.rescaleX(x2).domain()); focus.select(".area").attr("d", area); focus.selectAll('.circle').attr("transform", function(d) { return "translate(" + x(d.date) + "," + y(d.price) + ")"; }); focus.select(".axis--x").call(xAxis); context.select(".brush").call(brush.move, x.range().map(t.invertX, t)); context.selectAll('.circle').attr("transform", function(d) { return "translate(" + x2(d.date) + "," + y2(d.price) + ")"; }); } function type(d) { d.date = parseDate(d.date); d.price = +d.price; return d; } update(); </script> 

JSFiddle link.

I updated you jsfiddle by replacing all transform attributes by changing it to cx and cy , eg:

before

focus.selectAll('.circle').attr("transform", function(d) { 
    return "translate(" + x(d.date) + "," + y(d.price) + ")"; 
  });

after

focus.selectAll('.circle')
      .attr("cx", function(d) { return x(d.date) })
      .attr("cy", function(d) { return y(d.price); });

Otherwise, you will translate with your other coordinates, which might lead to hard to find problems

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