D3.js的刷子行为触发了两个人的结局'事件

时间:2018-03-16 08:26:00

标签: javascript d3.js charts

所以,实现一个受M Bostock example启发的画笔行为我遇到了一些我不太了解的东西。 如果为'结束'设置回调刷子的事件,只要你直接与画笔交互,就会按预期调用它。 但每当我重新定位画笔时,似乎结束事件被触发两次。 为什么会这样?或者,这是我在这里做错了吗?



constructor(
    private wsMyService: WSMyService,

ngOnInit():
  ...
  this.mySocketSubscription = this.wsMyService.connect().subscribe(message => {
 ... }
  this.wsMyService.onclose.subscribe(evt => {
  // the server has closed the connection
  })

ngOnDestroy() {

    this.wsMyService.close();
    this.mySocketSubscription.unsubscribe();
    ...
}




2 个答案:

答案 0 :(得分:2)

每当您想要阻止事件触发多层操作时,您都可以使用:

d3.event.stopPropagation();

您可以在brushcentered函数的末尾包含它:

function brushcentered() {
  var dx = x(1) - x(0), // Use a fixed width when recentering.
  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]);
  d3.event.stopPropagation();
}

演示:

<style>

.selected {
  fill: red;
  stroke: brown;
}

</style>
<svg width="960" height="150"></svg>
<div>Event fired <span id="test"></span></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

var fired=0;
var randomX = d3.randomUniform(0, 10),
    randomY = d3.randomNormal(0.5, 0.12),
    data = d3.range(800).map(function() { return [randomX(), randomY()]; });

var svg = d3.select("svg"),
    margin = {top: 10, right: 50, bottom: 30, left: 50},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom,
    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var x = d3.scaleLinear()
    .domain([0, 10])
    .range([0, width]);

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

var brush = d3.brushX()
    .extent([[0, 0], [width, height]])
    .on("start brush", brushed)
	  .on("end", brushend);

var dot = g.append("g")
    .attr("fill-opacity", 0.2)
  .selectAll("circle")
  .data(data)
  .enter().append("circle")
    .attr("transform", function(d) { return "translate(" + x(d[0]) + "," + y(d[1]) + ")"; })
    .attr("r", 3.5);

g.append("g")
    .call(brush)
    .call(brush.move, [3, 5].map(x))
  .selectAll(".overlay")
    .each(function(d) { d.type = "selection"; }) // Treat overlay interaction as move.
    .on("mousedown touchstart", brushcentered); // Recenter before brushing.

g.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

function brushcentered() {
  var dx = x(1) - x(0), // Use a fixed width when recentering.
      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]);
  d3.event.stopPropagation();
}

function brushed() {
  var extent = d3.event.selection.map(x.invert, x);
  dot.classed("selected", function(d) { return extent[0] <= d[0] && d[0] <= extent[1]; });
}


function brushend() {
  document.getElementById('test').innerHTML = ++fired;
}
</script>

答案 1 :(得分:1)

<强> -UPDATE -

为了这个片段的目的,我可以使用布尔标志来停止第一个事件,然后让第二个事件通过。这意味着我仍然可以在重新定位后拖动画笔,一次又一次。

<!DOCTYPE html>
<style>

.selected {
  fill: red;
  stroke: brown;
}

</style>
<svg width="960" height="150"></svg>
<div>Event fired <span id="test"></span></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

var fired=0;
var justcentered = false;
var randomX = d3.randomUniform(0, 10),
    randomY = d3.randomNormal(0.5, 0.12),
    data = d3.range(800).map(function() { 
      return [randomX(), randomY()];
    });

var svg = d3.select("svg"),
    margin = { top: 10, right: 50, bottom: 30, left: 50 },
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom,
    g = svg.append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var x = d3.scaleLinear()
    .domain([0, 10])
    .range([0, width]);

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

var brush = d3.brushX()
    .extent([[0, 0], [width, height]])
    .on("start brush", brushed)
	  .on("end", brushend);

var dot = g.append("g")
      .attr("fill-opacity", 0.2)
    .selectAll("circle")
      .data(data)
      .enter()
      .append("circle")
      .attr("transform", function(d) { 
          return "translate(" + x(d[0]) + "," + y(d[1]) + ")";
        })
      .attr("r", 3.5);

g.append("g")
    .call(brush)
    .call(brush.move, [3, 5].map(x))
  .selectAll(".overlay")
    .each(function(d) { d.type = "selection"; }) // Treat overlay interaction as move.
    .on("mousedown touchstart", brushcentered); // Recenter before brushing.

g.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

function brushcentered() {
  var dx = x(1) - x(0), // Use a fixed width when recentering.
      cx = d3.mouse(this)[0],
      x0 = cx - dx / 2,
      x1 = cx + dx / 2;
	justcentered = true;
  d3.select(this.parentNode)
    .call(brush.move, x1 > width ? [width - dx, width] : x0 < 0 ? [0, dx] : [x0, x1]);
}

function brushed() {
  var extent = d3.event.selection.map(x.invert, x);
  dot.classed("selected", function(d) { return extent[0] <= d[0] && d[0] <= extent[1]; });
}


function brushend() {
	if(justcentered) {
    justcentered = false;
    return;
  }
  document.getElementById('test').innerHTML = ++fired;
}
</script>