Skip to content

TransformTracker

TransformTracker (from scenerystack/scenery) watches every Node along a Trail and notifies you when the trail's cumulative transform (the composed local-to-global matrix) changes — without recomputing the whole matrix chain from scratch each time. It caches the composed matrix and only recomputes the portion downstream of whichever Node actually changed, using a dirty index. Scenery uses it internally for exactly this reason: DragListener's trackAncestors option creates one to reposition a dragged Node when an ancestor moves, and the highlight-rendering overlay uses one per active focus highlight to keep it aligned with the Node it surrounds.

ts
import { TransformTracker } from 'scenerystack/scenery';

const trail = someNode.getUniqueTrail();
const tracker = new TransformTracker( trail );

tracker.addListener( () => {
  console.log( 'cumulative transform changed:', tracker.matrix );
} );

// ... later, when this tracker is no longer needed:
tracker.dispose();

Constructor and options

new TransformTracker( trail, providedOptions? ) takes the Trail to watch and:

OptionDefaultEffect
isStaticfalseIf true, listeners are notified synchronously without defensively copying the listener array first — a minor performance win when you're certain listeners won't add/remove other listeners during notification

Methods

MethodEffect
addListener( listener )Registers a no-argument callback fired synchronously whenever any Node in the trail (except the root) changes its transform
removeListener( listener )Removes a previously added listener
getMatrix() / .matrixReturns the current local-to-global Matrix3 for the trail's leaf node — recomputed lazily, only as far up the dirty chain as needed
dispose()Removes all the internal per-Node listeners this tracker installed; call this when you're done, or the tracked Nodes will hold references indefinitely

Exclude the leaf node's own transform with trail.copy().removeDescendant()

A TransformTracker includes every Node in the given trail. If you only care about ancestor transform changes (not the dragged/highlighted Node's own transform, which you're presumably setting yourself), pass a trail with the leaf removed — this is exactly the pattern DragListener uses internally: new TransformTracker( pressedTrail.copy().removeDescendant() ).