@deck.gl/core
Version:
deck.gl core library
122 lines • 4.88 kB
JavaScript
// deck.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
// deck.gl, MIT license
import GPUInterpolationTransition from "../../transitions/gpu-interpolation-transition.js";
import GPUSpringTransition from "../../transitions/gpu-spring-transition.js";
import log from "../../utils/log.js";
const TRANSITION_TYPES = {
interpolation: GPUInterpolationTransition,
spring: GPUSpringTransition
};
export default class AttributeTransitionManager {
constructor(device, { id, timeline }) {
if (!device)
throw new Error('AttributeTransitionManager is constructed without device');
this.id = id;
this.device = device;
this.timeline = timeline;
this.transitions = {};
this.needsRedraw = false;
this.numInstances = 1;
}
finalize() {
for (const attributeName in this.transitions) {
this._removeTransition(attributeName);
}
}
/* Public methods */
// Called when attribute manager updates
// Check the latest attributes for updates.
update({ attributes, transitions, numInstances }) {
// Transform class will crash if elementCount is 0
this.numInstances = numInstances || 1;
for (const attributeName in attributes) {
const attribute = attributes[attributeName];
const settings = attribute.getTransitionSetting(transitions);
// this attribute might not support transitions?
if (!settings)
continue; // eslint-disable-line no-continue
this._updateAttribute(attributeName, attribute, settings);
}
for (const attributeName in this.transitions) {
const attribute = attributes[attributeName];
if (!attribute || !attribute.getTransitionSetting(transitions)) {
// Animated attribute has been removed
this._removeTransition(attributeName);
}
}
}
// Returns `true` if attribute is transition-enabled
hasAttribute(attributeName) {
const transition = this.transitions[attributeName];
return transition && transition.inProgress;
}
// Get all the animated attributes
getAttributes() {
const animatedAttributes = {};
for (const attributeName in this.transitions) {
const transition = this.transitions[attributeName];
if (transition.inProgress) {
animatedAttributes[attributeName] = transition.attributeInTransition;
}
}
return animatedAttributes;
}
/* eslint-disable max-statements */
// Called every render cycle, run transform feedback
// Returns `true` if anything changes
run() {
if (this.numInstances === 0) {
return false;
}
for (const attributeName in this.transitions) {
const updated = this.transitions[attributeName].update();
if (updated) {
this.needsRedraw = true;
}
}
const needsRedraw = this.needsRedraw;
this.needsRedraw = false;
return needsRedraw;
}
/* eslint-enable max-statements */
/* Private methods */
_removeTransition(attributeName) {
this.transitions[attributeName].delete();
delete this.transitions[attributeName];
}
// Check an attributes for updates
// Returns a transition object if a new transition is triggered.
_updateAttribute(attributeName, attribute, settings) {
const transition = this.transitions[attributeName];
// an attribute can change transition type when it updates
// let's remove the transition when that happens so we can create the new transition type
// TODO: when switching transition types, make sure to carry over the attribute's
// previous buffers, currentLength, startIndices, etc, to be used as the starting point
// for the next transition
let isNew = !transition || transition.type !== settings.type;
if (isNew) {
if (transition) {
this._removeTransition(attributeName);
}
const TransitionType = TRANSITION_TYPES[settings.type];
if (TransitionType) {
this.transitions[attributeName] = new TransitionType({
attribute,
timeline: this.timeline,
device: this.device
});
}
else {
log.error(`unsupported transition type '${settings.type}'`)();
isNew = false;
}
}
if (isNew || attribute.needsRedraw()) {
this.needsRedraw = true;
this.transitions[attributeName].start(settings, this.numInstances);
}
}
}
//# sourceMappingURL=attribute-transition-manager.js.map