WGS
WGS

Reputation: 14179

Chained transitions don't trigger step-by-step

First off, some related items I've research, tried, and haven't had a good result with.

Next, the relevant part of my code:

function moveMarker(i) {

    var curr_i = parseInt(d3.select("#nomad").attr("nomad-index"));
    var target_i = parseInt(i);

    switch (curr_i) {
        case 0:
            switch (target_i) {
                case 0:
                    break;
                case 1:
                    moveToMark(1);
                    break;
                case 2:
                    moveToMark(1);
                    moveToMark(2);
                    break;
                case 3:
                    moveToMark(1);
                    moveToMark(2);
                    moveToMark(3);
                    break;
                case 4:
                    moveToMark(1);
                    moveToMark(2);
                    moveToMark(3);
                    moveToMark(4);
                    break;
            }
        case 1:
            switch (target_i) {
                case 0:
                    moveToMark(0);
                    break;
                case 1:
                    break;
                case 2:
                    moveToMark(2);
                    break;
                case 3:
                    moveToMark(2);
                    moveToMark(3);
                    break;
                case 4:
                    moveToMark(2);
                    moveToMark(3);
                    moveToMark(4);
                    break;
            }
        case 2:
            switch (target_i) {
                case 0:
                    moveToMark(1);
                    moveToMark(0);
                    break;
                case 1:
                    moveToMark(1);
                    break;
                case 2:
                    break;
                case 3:
                    moveToMark(3);
                    break;
                case 4:
                    moveToMark(3);
                    moveToMark(4);
                    break;
            }
        case 3:
            switch (target_i) {
                case 0:
                    moveToMark(2);
                    moveToMark(1);
                    moveToMark(0);
                    break;
                case 1:
                    moveToMark(2);
                    moveToMark(1);
                    break;
                case 2:
                    moveToMark(2);
                    break;
                case 3:
                    break;
                case 4:
                    moveToMark(4);
                    break;
            }
        case 4:
            switch (target_i) {
                case 0:
                    moveToMark(3);
                    moveToMark(2);
                    moveToMark(1);
                    moveToMark(0);
                    break;
                case 1:
                    moveToMark(3);
                    moveToMark(2);
                    moveToMark(1);
                    break;
                case 2:
                    moveToMark(3);
                    moveToMark(2);
                    break;
                case 3:
                    moveToMark(3);
                    break;
                case 4:
                    break;
            }
    }
}

function moveToMark(i) {

    var x = spot[i][7]; // Latitude
    var y = spot[i][8]; // Longitude

    d3.select("#nomad")
        .attr("nomad-index", i)
        .transition()
        .delay(3000)
        .duration(1000)
        .attr("cx", x)
        .attr("cy", y);
}

The gist of what I'm trying to do:

I have a table of events. On clicking any of the events in the table, I have a circle (nomad) that moves to the respective location of that event as determined in the spot dataset. Directly moving point-to-point is no issue. However, I have one particular constraint: I have to move according to the timeline of the events.

Say, I click on event #3. My circle must move first to event #1 and #2, after which they'll stay in event #3. If the circle is in any event, clicking on any other event, whether of a lower or a higher index, it will need to traverse the events between its current position and its target.

I believe my nested switch case can explain this further. I believe what I'm attempting is not as complicated as I'm making it out to be. However, I've hit a major snag: my nomad circle does not go through the events step-by-step but rather jumps to the last event right away after the delay.

I have read in the above links that transitions have an issue about chaining, or that I have to employ end(...) to make this work.

The question/s:

Is it possible to reduce this attempt to a recursive function instead? If so, how? If not, how can I make it so that each moveToMark fires consecutively?

Upvotes: 0

Views: 63

Answers (1)

Lars Kotthoff
Lars Kotthoff

Reputation: 109282

The problem is that creating a transition on a D3 selection cancels any other transitions that may have been created. That is, only your last call to .transition() takes effect as all the previous transitions are cancelled.

The solution is to create another transition on the transition and not the selection (see the documentation). This would look something like the following:

var cur_trans;

function moveMarker(i) {
  cur_trans = d3.select("#nomad");
  // more code
}

function moveToMark(i) {
  var x = spot[i][7]; // Latitude
  var y = spot[i][8]; // Longitude

  d3.select("#nomad")
    .attr("nomad-index", i);

  cur_trans = cur_trans
    .transition()
    .delay(3000)
    .duration(1000)
    .attr("cx", x)
    .attr("cy", y);
}

This will overwrite cur_trans with the new transition at each call, thus making sure that you don't lose any transitions.

Note that depending on the rest of your code and its call structure there may be race conditions etc that you may have to guard against.

Upvotes: 1

Related Questions