Advanced methods for transition coordination, event handling, and lifecycle management.
Returns a promise that resolves when all elements in the transition complete successfully, or rejects if any transition is cancelled or interrupted.
/**
* Returns a promise that resolves when the transition completes
* @returns Promise that resolves when all elements finish transitioning
*/
transition.end(): Promise<void>;Usage Examples:
// Wait for transition to complete
const t = select("circle")
.transition()
.attr("r", 100);
t.end().then(() => {
console.log("Transition completed!");
}).catch(() => {
console.log("Transition was interrupted");
});
// Sequential animations with async/await
async function animateSequence() {
await select(".item1").transition().attr("x", 100).end();
await select(".item2").transition().attr("x", 100).end();
console.log("All animations complete");
}
// Parallel animations
const t1 = select(".group1").transition().attr("opacity", 0).end();
const t2 = select(".group2").transition().attr("opacity", 1).end();
Promise.all([t1, t2]).then(() => {
console.log("Both transitions finished");
});
// Handle interruption
select("button").on("click", function() {
const transition = select("circle").transition().attr("r", 50);
transition.end()
.then(() => console.log("Animation completed normally"))
.catch(() => console.log("Animation was interrupted"));
// Later interruption
setTimeout(() => {
select("circle").interrupt();
}, 100);
});Adds or removes event listeners for transition lifecycle events.
/**
* Adds or removes event listeners for transition events
* @param typenames - Event type names (space-separated)
* @param listener - Event listener function, or null to remove
* @returns The transition instance for chaining, or current listener if no listener provided
*/
transition.on(typenames: string, listener?: EventListener): Transition | EventListener;Event Types:
start - Fired when transition startsend - Fired when transition ends normallyinterrupt - Fired when transition is interruptedcancel - Fired when transition is cancelledUsage Examples:
// Basic event handling
transition
.on("start", function(d, i) {
console.log("Transition started on element", i);
})
.on("end", function(d, i) {
console.log("Transition ended on element", i);
})
.attr("r", 20);
// Multiple event types
transition.on("start end", function() {
console.log("Transition event:", d3.event.type);
});
// Named event listeners (allows multiple listeners per type)
transition
.on("start.log", function() { console.log("Started"); })
.on("start.highlight", function() { this.style.stroke = "red"; })
.on("end.log", function() { console.log("Ended"); })
.on("end.cleanup", function() { this.style.stroke = null; });
// Remove specific listener
transition.on("start.log", null);
// Remove all listeners for a type
transition.on("start", null);
// Get current listener
const startListener = transition.on("start");
// Interruption handling
transition
.on("interrupt", function() {
console.log("Animation was interrupted");
// Cleanup code here
})
.on("cancel", function() {
console.log("Animation was cancelled");
});Creates a new transition that starts when the current transition ends, inheriting timing configuration.
/**
* Creates a chained transition that starts when current transition ends
* @returns New transition scheduled to start after current transition
*/
transition.transition(): Transition;Usage Examples:
// Sequential animations
select("circle")
.transition()
.duration(500)
.attr("cx", 100)
.transition() // Starts after first transition
.duration(750)
.attr("cy", 100)
.transition() // Starts after second transition
.attr("fill", "red");
// Complex sequence with different timings
select(".element")
.transition()
.duration(300)
.ease(d3.easeLinear)
.style("opacity", 0)
.transition()
.duration(0) // Immediate
.style("display", "none")
.style("transform", "scale(0)")
.transition()
.delay(500)
.style("display", "block")
.transition()
.duration(400)
.ease(d3.easeBounceOut)
.style("opacity", 1)
.style("transform", "scale(1)");
// Infinite animation loop
function pulse() {
select("circle")
.transition()
.duration(1000)
.attr("r", 20)
.transition()
.duration(1000)
.attr("r", 10)
.on("end", pulse); // Restart the animation
}
pulse();Returns the d3-selection corresponding to this transition.
/**
* Returns the selection corresponding to this transition
* @returns d3-selection Selection instance
*/
transition.selection(): Selection;Usage Examples:
// Convert transition to selection for immediate operations
const t = selectAll("circle").transition();
// Immediate operations on selection
t.selection()
.classed("animating", true)
.attr("data-transition-id", "pulse");
// Then continue with transition
t.attr("r", 15);
// Mixed immediate and animated changes
const selection = selectAll(".item");
const transition = selection.transition();
// Immediate changes
transition.selection()
.style("border", "1px solid red")
.classed("transitioning", true);
// Animated changes
transition
.style("transform", "translateX(100px)")
.on("end", function() {
// Remove class when done
select(this).classed("transitioning", false);
});Invokes a function for each element in the transition.
/**
* Invokes a function for each element in the transition
* @param function - Function to invoke for each element
* @returns The transition instance for chaining
*/
transition.each(function: EachFunction): Transition;Invokes a function once with the transition as the first argument, enabling reusable transition configurations.
/**
* Invokes a function with the transition and optional arguments
* @param function - Function to invoke with transition
* @param args - Additional arguments to pass to function
* @returns The transition instance for chaining
*/
transition.call(function: CallFunction, ...args: any[]): Transition;Usage Examples:
// each: perform action on each element
transition.each(function(d, i) {
console.log("Element", i, "data:", d);
// 'this' is the DOM element
this.dataset.index = i;
});
// call: reusable transition configurations
function fadeAndSlide(transition, direction, distance) {
return transition
.style("opacity", 0)
.style("transform", `translate${direction}(${distance}px)`);
}
// Use the reusable function
selectAll(".item")
.transition()
.call(fadeAndSlide, "X", 100)
.duration(500);
// Multiple reusable functions
function setTiming(transition, duration, delay) {
return transition.duration(duration).delay(delay);
}
function setEasing(transition, easeFunction) {
return transition.ease(easeFunction);
}
selectAll("circle")
.transition()
.call(setTiming, 1000, 200)
.call(setEasing, d3.easeBounceOut)
.attr("r", 20);/**
* Utility methods inherited from d3-selection
*/
// Returns true if transition contains no elements
transition.empty(): boolean;
// Returns array of all elements in transition
transition.nodes(): Element[];
// Returns first element in transition
transition.node(): Element | null;
// Returns total number of elements in transition
transition.size(): number;selectAll("circle").transition()
.delay((d, i) => i * 50)
.on("start", function repeat() {
active(this)
.style("fill", "red")
.transition()
.style("fill", "green")
.transition()
.style("fill", "blue")
.transition()
.on("start", repeat);
});const states = ["idle", "hover", "active", "disabled"];
let currentState = 0;
function nextState() {
currentState = (currentState + 1) % states.length;
const state = states[currentState];
select(".button")
.transition()
.duration(300)
.attr("class", `button ${state}`)
.on("end", () => {
setTimeout(nextState, 1000);
});
}
nextState();const masterTransition = transition().duration(2000);
// All elements synchronized to same timeline
selectAll(".group1").transition(masterTransition)
.attr("transform", "translate(100, 0)");
selectAll(".group2").transition(masterTransition)
.attr("opacity", 0.5);
selectAll(".group3").transition(masterTransition)
.style("fill", "red");
// All finish at the same time
masterTransition.end().then(() => {
console.log("All synchronized animations complete");
});type EventListener = (this: Element, d: any, i: number, group: Element[]) => void;
type EachFunction = (this: Element, d: any, i: number, group: Element[]) => void;
type CallFunction = (transition: Transition, ...args: any[]) => void;start event fired, tweens initializedend event fired (normal completion) or interrupt/cancel events fired