Tips for reusing multiple sequences of chained transitions in D3

Looking for a more efficient way to code two lengthy sequences of chained transitions with varying order, properties, and attributes. For example, one sequence might be a, b, c, d, e, f, g, h, and the other e, f, g, h, a, b, c, d. Tried the code below without success. Each transition may have different delay, duration, ease, and apply to different attributes and styles. Any suggestions on a more compact code solution?

P.S.: Similar to a previous question, but that one had a simpler coding case that led to incorrect responses.

var t1 = d3
.transition() // transition "a" specifications 
...
.transition() // transition "b" specifications
...
.transition() // transition "c" specifications
...
.transition() // transition "d" specifications
...
;
var t2 = d3
.transition() // transition "e" specifications 
...
.transition() // transition "f" specifications 
...
.transition() // transition "g" specifications 
...
.transition() // transition "h" specifications 
...
;
someelement1
.transition(t1).transition(t2);
someelement2
.transition(t2).transition(t1);

Answer №1

Commenters have pointed out that the principles for answering this question are consistent with your previous query. Here, you have a collection of disparate transitions that could be applied in any sequence and are denoted by various keys. Let's save them in an object:

var transitions = {
  a: function(sel){ return sel.transition().duration(1000).delay(1000).attr('cy', 200) },
  b: function(sel){ return sel.transition().duration(2000).delay(0).attr('r', 40) },
  c: function(sel){ return sel.transition().duration(500).delay(1500).attr('fill', 'red') },
  d: function(sel){ return sel.transition().duration(1500).delay(500).attr('opacity', 0.5) },
  e: function(sel){ return sel.transition().duration(1000).delay(3000).attr('cy', 300) },
  f: function(sel){ return sel.transition().duration(2000).delay(0).attr('r', 60) },
  g: function(sel){ return sel.transition().duration(500).delay(1500).attr('fill', 'magenta') },
  h: function(sel){ return sel.transition().duration(1500).delay(500).attr('opacity', 0.25) }
};

Each function is designed to take a d3.selection object and apply specific transition parameters along with sets of transformations to it. These functions can be as intricate as needed. In this version, the functions are kept simple with just one transformation due to my lack of creativity.

There's some redundancy in the code above, so we can streamline it by eliminating the selection conversion to a transition and using this instead of passing an argument:

var transitions = {
  a: function(){ return this.duration(1000).delay(1000).attr('cy', 200) },
  b: function(){ return this.duration(2000).delay(0).attr('r', 40) },
  c: function(){ return this.duration(500).delay(1500).attr('fill', 'red') },
  d: function(){ return this.duration(1500).delay(500).attr('opacity', 0.5) },
  e: function(){ return this.duration(1000).delay(3000).attr('cy', 300) },
  f: function(){ return this.duration(2000).delay(0).attr('r', 60) },
  g: function(){ return this.duration(500).delay(1500).attr('fill', 'magenta') },
  h: function(){ return this.duration(1500).delay(500).attr('opacity', 0.25) }
};

Now, these transitions can be executed by invoking code like

transitions['a'].call( selection.transition() )
transitions.f.call( d3.select('circle').transition() )

If you wish to specify an array of transitions to apply to a selection, you can do so with the following setup:

apply_transitions( group.select(":nth-child(1)"), ['a','b','c','d'] );
apply_transitions( group.select(":nth-child(2)"), ['e','f','g','h'] );

The implementation of this function would look like:

/**
* apply a series of transitions to a selection
*
* @param selection - d3 selection
* @param tr_arr - array of transition identifiers, referring to functions in the `transitions` object
*/
function apply_transitions( selection, tr_arr ) {

  transitions[ tr_arr[0] ].call( selection.transition() )
    .on('end', function(){
      if ( tr_arr.length > 1 ) {
        apply_transitions( d3.select(this), tr_arr.slice(1) );
      }
    })
}

Here's an example in action:

    var svg = d3.select('svg').attr('width', 500).attr('height', 500);

    var dataSet = [20, 20];

    var group=svg.append("g");
    var circles = group.selectAll('circle')
    .data(dataSet)
    .enter()
    .append('circle')
    .attr("r",function(d){ return d })
    .attr("cx",function(d, i){ return i * 100 + 50 })
    .attr("cy",50)
    .attr("fill",'black');

    apply_transitions( group.select(":nth-child(1)"), ['a','b','c','d'] );

    apply_transitions( group.select(":nth-child(2)"), ['e','f','g','h'] );

<script src="http://d3js.org/d3.v5.js"></script>
<svg></svg>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the process for integrating php script within javascript?

Is it possible to incorporate php scripts into javascript[1] in the same manner as it can be done in html[2]? server.php: <?php echo 'hello World'; ?> client.js (or client.php if needed): function foo() { var i = <?php include ...

Join the Observable in Angular2 Newsletter for the latest updates and tips

One of my functions stores the previous URL address. prevId () { let name, id, lat, lng; this.router.events .filter(event => event instanceof NavigationEnd) .subscribe(e => { console.log('prev:', this.previo ...

Utilizing AJAX to add information to jQuery data tables without taking advantage of their pagination and advanced features

The jQuery datatables plugin is a useful tool for adding filters, pagination, and search functionality to web applications. I have personally integrated it with my Laravel project to organize and display data effectively. Recently, I decided to enhance th ...

Struggling to configure an onClick handler in Next.js

Unexpectedly, I was met with a surprise while trying to access react.dev, as it stated that create-react-app is no longer recommended for bootstrapping React applications. No worries, the world is always evolving. Let's explore Next.js for my first p ...

Ramda Transitioning to a Liberated Style of Programming

Unable to find a suitable resource for this particular issue. I apologize if this question has already been asked, but my attempts to locate the answer have proven fruitless (perhaps due to a lack of effective search methods). I've developed a functi ...

Why does serializing a JavaScript Object to JSON result in "{}"?

Hello fellow developers, I'm currently working on setting up a LocalStorage feature for my web application. One issue I've come across is that all objects in the Model abstraction layer need to be serialized. I understand that functions aren&a ...

testing exceptions with Jest: a step-by-step guide

As a beginner with Jest, I am currently working on a program to delve deeper into JavaScript. While my tests are functioning properly, I'm wondering if it would be better to replace the try/catch blocks with exceptions. I feel like there might be a mo ...

I am looking for a highly specialized jQuery selector that fits my exact requirements

Hello everyone, I'm encountering an issue with a jQuery selector. Here is the HTML code snippet: <div id="Id_Province_chzn"> <a href="javascript:void(0)" class="chzn-single chzn-default" tabindex="-1"> <span> + this.default_tex ...

Tips on invoking a mixin within a Jade template showcased in a Node/Express endpoint

I'm currently developing a component that I plan to use multiple times on a website through a Jade template. This is how my route is set up: router.get('/', function(req, res, next) { res.render('indicators',{category:"", num ...

Authenticating the identity of the client application - the client is currently within the browser

I have a PHP backend (although it's not really important) and a Javascript client that runs in the browser. Here is how the application operates: The user accesses a URL and receives raw templates for rendering data An Ajax GET query is sent to the ...

Is it wise to question the validity of req.body in express.js?

https://expressjs.com/en/4x/api.html mentions It is crucial to validate all properties and values in the req.body object as they are derived from user input. Any operation performed on this object should be validated to prevent security risks. For instan ...

Is Angular capable of displaying a date within a specific timeframe using ng-show?

So I have a button that, when clicked, displays a list of data. I am adding a unique font awesome icon in there if the JSON key value exists. However, here lies the issue. The particular key happens to be a date. I need my ng-show function to check whether ...

"Unlock the power of Passport.js: A guide to leveraging async rendering for email templates

Currently, my setup involves running Express with Sequelize/MariaDB and Passport.js to handle user authentication. Everything seems to be working smoothly except for the activation email that needs to be sent out after a user signs up. Despite having the ...

Utilize Apollo to retrieve a variety of queries at once

Currently, I'm utilizing nextJS for my frontend development along with Apollo and GraphQL. For fetching queries, I am using the getStaticProps() function. To enhance modularity and maintainability, I have segmented my queries into multiple parts. The ...

Utilize the parsing functionality in three.js to extract JSON geometry data

After exporting a model from Blender using the three.js exporter and successfully loading it with the JSONLoader, my next challenge is to store the JSON information in a variable and parse it to display the model without having to load an external file. T ...

What is the best way to omit a field from my query if the associated variable is empty?

I need help creating a dynamic MongoDB query function that can handle multiple field values, including cases where some fields may be empty strings. In these instances, I want MongoDB to disregard those parts of the query. Here is my current query functio ...

Having all elements at the same height

I am looking to enhance my JavaScript code to only impact 4 items at a time. The goal is to target the first 4 instances of .prodbox, adjust their height accordingly, then move on to the next set of 4 and repeat the process. This sequential adjustment will ...

The issue with Mongoose populate failing to populate

I'm facing an issue with populating my users' car inventory. Each car has a userId attached to it upon creation, but for some reason, the population process isn't working as expected, and no errors are being displayed. Let's take a loo ...

What is the best way to sort through an array using JavaScript?

Here's an array for you: values = ["10%", 1000, "5%", 2000] I'm looking to split this into two separate arrays like so: percentages = ["10%","5%"] numbers = [1000,2000] How can I achieve this using JavaSc ...

Creating registration and login forms using an express server

Currently, I'm in the process of creating a basic website on my localhost that incorporates a signup form along with other essential HTML elements. The setup for the signup procedure went smoothly as planned. When a user completes the form and submits ...