繁体   English   中英

D3js v4笔刷,缩放和最新笔刷

[英]D3js v4 brush & zoom & recenter brush on click

我正在使用D3js v4。 我想要实现的是将根据示例的笔刷和缩放行为与单击以单击中心的笔刷相结合,其中单击后笔刷重新居中,并且笔刷边界以平滑过渡圆滑。 到目前为止,这是我的小提琴

我的问题是,brushended函数永远不会执行。 似乎缩放阻止笔刷接收mouseup事件。 仅当通过注释掉所有缩放功能完全禁用缩放时,我才开始工作。 我在mousedown上尝试了event.stopPropagation和event.stopImmediatePropagation,如下面的代码片段所示,以防止缩放接收到mousedown和mouseup事件,但它不起作用。

context.append("g")
  .attr("class", "brush")
  .call(brush)
  .call(brush.move, [x2(new Date(2013, 0, 1)), x2(new Date(2013, 6, 1))])
  .selectAll(".overlay")
  .each(function(d) {
    d.type = "selection";
  })
  .on("mousedown touchstart", function() { d3.event.stopPropagation(); })
  .on("mousedown touchstart", brushcentered)

我是否将stopPropagation放在错误的位置,或者我完全错过了什么? 任何帮助,将不胜感激。

哇! 您在这里进行了很多事件处理。 让我们分解一下,首先是这个调用:

 svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
   .scale(width / (s[1] - s[0]))
   .translate(-s[0], 0));

在您的brushed事件处理程序中正在吃掉brushend 我的第一个想法是使用简单的setTimeout hack来允许brushend处理。 在执行此操作的同时,它只是引发了一个新问题,然后在brush.move中的brushedend作为缩放事件被引发,而不是在brushed进行处理。 因此,相反,我只是用zoom替换了move,然后让zoom事件处理画笔位置,如下所示:

function brushended() {
  if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom
  if (!d3.event.selection) return; // Ignore empty selections.

  var d0 = d3.event.selection.map(x2.invert), //=Datum, linker+rechter Brush-Rand
    d1 = d0.map(d3.timeMonth.round);

  // If empty when rounded, use floor & ceil instead.
  if (d1[0] >= d1[1]) {
    d1[0] = d3.timeMonth.floor(d0[0]);
    d1[1] = d3.timeMonth.offset(d1[0]);
  };

  var s = d1.map(x2);
  setTimeout(function(){
    svg.select(".zoom").call(zoom.transform, d3.zoomIdentity
      .scale(width / (s[1] - s[0]))
      .translate(-s[0], 0));
  });
}

我认为这正在产生您想要的行为。

在下面运行代码, 在这里运行:

 <!DOCTYPE html> <html> <head> <script src="https://d3js.org/d3.v4.js"></script> <style> #Type1 { stroke: DarkTurquoise; } #Type2 { stroke: steelblue; } .data-line { fill: none; stroke-width: 2.5; opacity: 0.8; stroke-linecap: round; clip-path: url(#clip); transition: 0.5s; } .context-line { fill: none; stroke-width: 1.5; stroke: grey; stroke-linecap: round; clip-path: url(#clip); } div.svg-container { display: inline-block; position: relative; width: 100%; height: 100%; vertical-align: top; } .zoom { cursor: move; fill: none; pointer-events: all; } </style> </head> <body> <div> </div> <script> var svg = d3.select("div") .append("div").classed("svg-container", true) .append("svg") .attr("width", 700) .attr("height", 400) var margin = { top: 20, right: 20, bottom: 130, left: 60 }, margin2 = { top: 300, right: 20, bottom: 30, left: 60 }, width = +svg.attr("width") - margin.left - margin.right, height = +svg.attr("height") - margin.top - margin.bottom, height2 = +svg.attr("height") - margin2.top - margin2.bottom; // Achsen Datumsbehandlung var parseDate = d3.timeParse("%Y-%m-%d %H:%M:%S"); 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); //Linien var line = d3.line() .x(function(d) { return x(d.Datum); }) // .y0(height) //nur area-chType .y(function(d) { return y(d.Summe); }); // .y1(function(d) { return y(d.Summe); }); //nur area-chType //Linien var lineType1 = d3.line() .curve(d3.curveStepAfter) .x(function(d) { return x(d.Datum); }) .y(function(d) { return y(d.Summe); }); var line2 = d3.line() .x(function(d) { return x2(d.Datum); }) .y(function(d) { return y2(d.Summe); }); 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 + ")"); //Zoom & Brush var brush = d3.brushX() .extent([ [0, 0], [width, height2] ]) .handleSize(10) .on("start brush", brushed) .on("end", brushended); var zoom = d3.zoom() .scaleExtent([1, 100]) .translateExtent([ [0, 0], [width, height] ]) .extent([ [0, 0], [width, height] ]) .on("zoom", zoomed); // ===Daten=== var data = [{ "Datum": "2013-02-04 00:00:00", "Summe": "1000.00", "Type": "Type1", "Notizen": null }, { "Datum": "2013-02-04 00:00:00", "Summe": "200.00", "Type": "Type2", "Notizen": null }, { "Datum": "2013-02-21 00:00:00", "Summe": "4000.00", "Type": "Type1", "Notizen": null }, { "Datum": "2013-02-23 00:00:00", "Summe": "2000.00", "Type": "Type1", "Notizen": null }, { "Datum": "2013-02-23 00:00:00", "Summe": "601.00", "Type": "Type2", "Notizen": null }, { "Datum": "2013-03-04 00:00:00", "Summe": "775.00", "Type": "Type1", "Notizen": null }, { "Datum": "2013-03-04 00:00:00", "Summe": "1395.10", "Type": "Type2", "Notizen": null }, { "Datum": "2013-04-03 00:00:00", "Summe": "400.00", "Type": "Type1", "Notizen": null }, { "Datum": "2013-04-03 00:00:00", "Summe": "1040.00", "Type": "Type2", "Notizen": null }, { "Datum": "2013-05-24 00:00:00", "Summe": "400.00", "Type": "Type1", "Notizen": null }, { "Datum": "2013-05-24 00:00:00", "Summe": "3288.88", "Type": "Type2", "Notizen": null }, { "Datum": "2013-05-28 00:00:00", "Summe": "400.00", "Type": "Type1", "Notizen": null }, { "Datum": "2013-05-28 00:00:00", "Summe": "4407.10", "Type": "Type2", "Notizen": null }, { "Datum": "2013-06-01 00:00:00", "Summe": "400.00", "Type": "Type1", "Notizen": null }, { "Datum": "2013-06-01 00:00:00", "Summe": "3525.86", "Type": "Type2", "Notizen": null }, { "Datum": "2013-06-04 00:00:00", "Summe": "400.00", "Type": "Type1", "Notizen": null }, { "Datum": "2013-06-04 00:00:00", "Summe": "2990.17", "Type": "Type2", "Notizen": null }, { "Datum": "2013-06-10 00:00:00", "Summe": "390.00", "Type": "Type1", "Notizen": null }, { "Datum": "2013-06-10 00:00:00", "Summe": "366.00", "Type": "Type2", "Notizen": null }, { "Datum": "2013-06-14 00:00:00", "Summe": "390.00", "Type": "Type1", "Notizen": null }, { "Datum": "2013-06-14 00:00:00", "Summe": "925.18", "Type": "Type2", "Notizen": null }, { "Datum": "2013-06-16 00:00:00", "Summe": "708.44", "Type": "Type1", "Notizen": null }, { "Datum": "2013-06-16 00:00:00", "Summe": "609.10", "Type": "Type2", "Notizen": null }, { "Datum": "2013-06-20 00:00:00", "Summe": "708.44", "Type": "Type1", "Notizen": null }, { "Datum": "2013-06-20 00:00:00", "Summe": "1760.80", "Type": "Type2", "Notizen": null }] data.forEach(function(d) { d.Datum = parseDate(d.Datum); d.Summe = +d.Summe; }); x.domain([d3.min(data, function(d) { return d.Datum; }), d3.max(data, function(d) { return d.Datum; })]).nice(d3.timeYear); y.domain([d3.min(data, function(d) { return d.Summe; }), 1.1 * d3.max(data, function(d) { return d.Summe; })]).nice(); x2.domain(x.domain()); y2.domain(y.domain()); var dataGroup = d3.nest() .key(function(d) { return d.Type; }) .entries(data); focus.append("rect") .attr("class", "zoom") .attr("width", width) .attr("height", height) .call(zoom); 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("path#Type2") .data(dataGroup) .enter() .append("path") .filter(function(d) { return d.key == "Type2" }) .attr("class", "data-line") .attr("d", function(d) { return line(d.values); }) .attr("id", function(d) { return d.key }); focus.selectAll("path#Type1") .data(dataGroup) .enter() .append("path") .filter(function(d) { return d.key == "Type1" }) .attr("class", "data-line") .attr("d", function(d) { return lineType1(d.values); }) .attr("id", function(d) { return d.key }); context.selectAll(".context-line") .data(dataGroup) .enter() .append("path") .attr("class", "context-line") .attr("d", function(d) { return line2(d.values); }); context.append("g") .attr("class", "axis axis--x") .attr("transform", "translate(0," + height2 + ")") .call(xAxis2); context.append("g") .attr("class", "brush") .call(brush) .call(brush.move, [x2(new Date(2013, 0, 1)), x2(new Date(2013, 6, 1))]) .selectAll(".overlay") .each(function(d) { d.type = "selection"; }) .on("mousedown touchstart", brushcentered); // ===Funktionen=== 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.selectAll("path#Type1").attr("d", function(d) { return lineType1(d.values); }); focus.selectAll("path#Type2").attr("d", function(d) { return line(d.values); }); focus.select(".axis--x").call(xAxis); setTimeout(function(){ svg.select(".zoom").call(zoom.transform, d3.zoomIdentity .scale(width / (s[1] - s[0])) .translate(-s[0], 0)); }); } function brushcentered() { var dx = 30, // Use a fixed width when recentering, = ca 2 Monate cx = d3.mouse(this)[0], x0 = cx - dx / 2, x1 = cx + dx / 2; d3.select(this.parentNode).call(brush.move, x1 > width ? [width - dx, width] : x0 < 0 ? [0, dx] : [x0, x1]); } function brushended() { if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom if (!d3.event.selection) return; // Ignore empty selections. var d0 = d3.event.selection.map(x2.invert), //=Datum, linker+rechter Brush-Rand d1 = d0.map(d3.timeMonth.round); // If empty when rounded, use floor & ceil instead. if (d1[0] >= d1[1]) { d1[0] = d3.timeMonth.floor(d0[0]); d1[1] = d3.timeMonth.offset(d1[0]); }; var s = d1.map(x2); setTimeout(function(){ 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; var t = d3.event.transform; x.domain(t.rescaleX(x2).domain()); focus.selectAll("path#Type1").attr("d", function(d) { return lineType1(d.values) }); focus.selectAll("path#Type2").attr("d", function(d) { return line(d.values) }); focus.select(".axis--x").call(xAxis); context.select(".brush").call(brush.move, x.range().map(t.invertX, t)); } </script> </body> </html> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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