d3 Transition Promise

Creates a then() function on a D3 prototype to allow the use of Promises on completion of transitions.

HTML

<svg></svg>

CSS

circle {
  fill: red;
}

JavaScript

// CLASSIFICATION: EXTERNAL. Copyright (c) 2016 MooD Enterprises Ltd.  All Rights Reserved.

/**
 * The then() method returns a Promise that will be fullfilled upon the completion of all transitions.
 * @param {Function} - A Function called when the Transition has completed. This function has one argument, the fulfillment value.
 * @param {Function} - A Function called when the Transition fails for any reason. This function has one argument, the rejection reason.
 * @return {Function} - A Promise
 */
d3.transition.prototype.then = function(onFulfilled, onRejected) {
   
   // Create a sub transition. Within `then` we use the .each("end) function
   // which will over-write any that have already been called on the
   // transition object. Therefore the best way is to create a sub-transition
   // to preserve the original that doesn't do anything
   //let promiseTransition = this.transition();
   let promiseTransition = this;
   
   // Work out the transition object which is either __transition__ or __transition_fill_ 
   // depending on whether or not it is named
   const transitionName = this.namespace || "__transition__";
   
   // Construct a promise that is going to be returned, this
   // promise will be stored (with any other promises) against
   // the transition object
   return new Promise((resolve, reject) => {
     
     // We're going to count the number of elements
     // that we're transitioning over, such that the promise 
     // only fires when all elements have finished transitioning
     let n = 0;
     
     // Store the resolve of the promise against each element, 
     // along with incrementing our counter. Note that we don't
     // currently fire a rejected
     promiseTransition.each(function() { 
       const transition = this[transitionName];
       transition._promises = transition._promises || [];
       transition._promises.push(resolve);
       n++; 
     })
     .each("end.test", function() { 
     	 const transition =...