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

我的问题是,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中进行处理。因此,我只用缩放替换了移动,然后让缩放事件处理笔刷的位置,如下所示:

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));
  });
}


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

在下面运行代码和punker here



<!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>

关于javascript - D3js v4笔刷,缩放和最新笔刷,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45246500/

10-11 14:11