Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
374 views
in Technique[技术] by (71.8m points)

javascript - D3: .transition() not working with events

I'm busy plotting a bar chart using D3 in Angular4.

// Enter Phase
this.chart.selectAll('.bar')
  .data(this.barData)
  .enter()
  .append('rect')
  .attr('class', 'bar');

// Update Phase
let bars = this.chart.selectAll('.bar').transition()
  .attr('x', (d) => {return this.x(this.parseTime(d.date.toUpperCase()));})
  .attr('y', (d) => {return this.y(d.point)})
  .attr('width', 15)
  .attr('height', (d) => {return this.charDimensions.height - this.y(d.point);})
    .on("mouseover", function (d) {D3.select(this).style('opacity', 0.5);})
    .on("mouseout", function (d) {D3.select(this).style('opacity', 1);})
    .on("click", (d) => {this.barClicked.emit(d);});

// Exit phase
this.chart.selectAll('.bar')
  .data(this.barData)
  .exit().remove();

In my plotting method, when I call animate() I get an error: Error: unknown type: mouseover. Which makes sense, since I'm probably trying to call the on("<event>") on a the transition returned by D3, the transition effect is there, however, everything after the transition breaks, i.e: The animation works, but the plotting is broken ofc.

However when I attempt to do the following:

// Update Phase
let bars = this.chart.selectAll('.bar');
bars.transition();
bars.attr('x', (d) => {return this.x(this.parseTime(d.date.toUpperCase()));})
  .attr('y', (d) => {return this.y(d.point)})
  .attr('width', 15)
  .attr('height', (d) => {return this.charDimensions.height - this.y(d.point);})
    .on("mouseover", function (d) {D3.select(this).style('opacity', 0.5);})
    .on("mouseout", function (d) {D3.select(this).style('opacity', 1);})
    .on("click", (d) => {this.barClicked.emit(d);});

No errors occur, but nothing happens, there is no transition effect to the new data set.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem here is a confusion between two different methods that use the same name:

Since you have a transition selection, when you write...

.on(...

The method expects to see three things (or typenames):

  • "start"
  • "end"
  • "interrupt"

However, "mouseover", "mouseout" or "click" are none of them. And then you get your error...

> Uncaught Error: unknown type: mouseover

Solution:

Bind the event listeners to a regular selection. Then, after that, create your transition selection.

Therefore, in your case, bind all the on listeners to the "enter" selection (which, by the way, makes more sense), removing them from the update selection.

Have a look at this little demo. First, I create a regular, enter selection, to which I add the event listener:

var bars = svg.selectAll(null)
    .data(data)
    .enter()
    .append("rect")
    //some attr here
    .on("mouseover", function(d) {
        console.log(d)
    });

Then, I add the transition:

bars.transition()
    .duration(1000)
    etc...

Hover over the bars to see the "mouseover" working:

var svg = d3.select("svg");
var data = [30, 280, 40, 140, 210, 110];
var bars = svg.selectAll(null)
  .data(data)
  .enter()
  .append("rect")
  .attr("x", 0)
  .attr("width", 0)
  .attr("y", function(d, i) {
    return i * 20
  })
  .attr("height", 18)
  .attr("fill", "teal")
  .on("mouseover", function(d) {
    console.log(d)
  });

bars.transition()
  .duration(1000)
  .attr("width", function(d) {
    return d
  })
.as-console-wrapper { max-height: 25% !important;}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...