зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1431573 - Part 4: Implement time label. r=gl
MozReview-Commit-ID: Cg6A4hNLXnO
This commit is contained in:
Родитель
49b1360194
Коммит
162722dd52
|
@ -19,16 +19,23 @@ const {
|
||||||
updateSelectedAnimation,
|
updateSelectedAnimation,
|
||||||
updateSidebarSize
|
updateSidebarSize
|
||||||
} = require("./actions/animations");
|
} = require("./actions/animations");
|
||||||
const { isAllAnimationEqual } = require("./utils/utils");
|
const {
|
||||||
|
isAllAnimationEqual,
|
||||||
|
hasPlayingAnimation,
|
||||||
|
} = require("./utils/utils");
|
||||||
|
|
||||||
class AnimationInspector {
|
class AnimationInspector {
|
||||||
constructor(inspector, win) {
|
constructor(inspector, win) {
|
||||||
this.inspector = inspector;
|
this.inspector = inspector;
|
||||||
this.win = win;
|
this.win = win;
|
||||||
|
|
||||||
|
this.addAnimationsCurrentTimeListener =
|
||||||
|
this.addAnimationsCurrentTimeListener.bind(this);
|
||||||
this.getAnimatedPropertyMap = this.getAnimatedPropertyMap.bind(this);
|
this.getAnimatedPropertyMap = this.getAnimatedPropertyMap.bind(this);
|
||||||
this.getComputedStyle = this.getComputedStyle.bind(this);
|
this.getComputedStyle = this.getComputedStyle.bind(this);
|
||||||
this.getNodeFromActor = this.getNodeFromActor.bind(this);
|
this.getNodeFromActor = this.getNodeFromActor.bind(this);
|
||||||
|
this.removeAnimationsCurrentTimeListener =
|
||||||
|
this.removeAnimationsCurrentTimeListener.bind(this);
|
||||||
this.rewindAnimationsCurrentTime = this.rewindAnimationsCurrentTime.bind(this);
|
this.rewindAnimationsCurrentTime = this.rewindAnimationsCurrentTime.bind(this);
|
||||||
this.selectAnimation = this.selectAnimation.bind(this);
|
this.selectAnimation = this.selectAnimation.bind(this);
|
||||||
this.setAnimationsPlayState = this.setAnimationsPlayState.bind(this);
|
this.setAnimationsPlayState = this.setAnimationsPlayState.bind(this);
|
||||||
|
@ -36,6 +43,7 @@ class AnimationInspector {
|
||||||
this.simulateAnimation = this.simulateAnimation.bind(this);
|
this.simulateAnimation = this.simulateAnimation.bind(this);
|
||||||
this.toggleElementPicker = this.toggleElementPicker.bind(this);
|
this.toggleElementPicker = this.toggleElementPicker.bind(this);
|
||||||
this.update = this.update.bind(this);
|
this.update = this.update.bind(this);
|
||||||
|
this.onAnimationsCurrentTimeUpdated = this.onAnimationsCurrentTimeUpdated.bind(this);
|
||||||
this.onElementPickerStarted = this.onElementPickerStarted.bind(this);
|
this.onElementPickerStarted = this.onElementPickerStarted.bind(this);
|
||||||
this.onElementPickerStopped = this.onElementPickerStopped.bind(this);
|
this.onElementPickerStopped = this.onElementPickerStopped.bind(this);
|
||||||
this.onSidebarResized = this.onSidebarResized.bind(this);
|
this.onSidebarResized = this.onSidebarResized.bind(this);
|
||||||
|
@ -58,10 +66,13 @@ class AnimationInspector {
|
||||||
} = this.inspector.getPanel("boxmodel").getComponentProps();
|
} = this.inspector.getPanel("boxmodel").getComponentProps();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
addAnimationsCurrentTimeListener,
|
||||||
emit: emitEventForTest,
|
emit: emitEventForTest,
|
||||||
getAnimatedPropertyMap,
|
getAnimatedPropertyMap,
|
||||||
getComputedStyle,
|
getComputedStyle,
|
||||||
getNodeFromActor,
|
getNodeFromActor,
|
||||||
|
isAnimationsRunning,
|
||||||
|
removeAnimationsCurrentTimeListener,
|
||||||
rewindAnimationsCurrentTime,
|
rewindAnimationsCurrentTime,
|
||||||
selectAnimation,
|
selectAnimation,
|
||||||
setAnimationsPlayState,
|
setAnimationsPlayState,
|
||||||
|
@ -73,6 +84,8 @@ class AnimationInspector {
|
||||||
const target = this.inspector.target;
|
const target = this.inspector.target;
|
||||||
this.animationsFront = new AnimationsFront(target.client, target.form);
|
this.animationsFront = new AnimationsFront(target.client, target.form);
|
||||||
|
|
||||||
|
this.animationsCurrentTimeListeners = [];
|
||||||
|
|
||||||
const provider = createElement(Provider,
|
const provider = createElement(Provider,
|
||||||
{
|
{
|
||||||
id: "newanimationinspector",
|
id: "newanimationinspector",
|
||||||
|
@ -81,12 +94,15 @@ class AnimationInspector {
|
||||||
},
|
},
|
||||||
App(
|
App(
|
||||||
{
|
{
|
||||||
|
addAnimationsCurrentTimeListener,
|
||||||
emitEventForTest,
|
emitEventForTest,
|
||||||
getAnimatedPropertyMap,
|
getAnimatedPropertyMap,
|
||||||
getComputedStyle,
|
getComputedStyle,
|
||||||
getNodeFromActor,
|
getNodeFromActor,
|
||||||
|
isAnimationsRunning,
|
||||||
onHideBoxModelHighlighter,
|
onHideBoxModelHighlighter,
|
||||||
onShowBoxModelHighlighterForNode,
|
onShowBoxModelHighlighterForNode,
|
||||||
|
removeAnimationsCurrentTimeListener,
|
||||||
rewindAnimationsCurrentTime,
|
rewindAnimationsCurrentTime,
|
||||||
selectAnimation,
|
selectAnimation,
|
||||||
setAnimationsPlayState,
|
setAnimationsPlayState,
|
||||||
|
@ -123,6 +139,8 @@ class AnimationInspector {
|
||||||
this.simulatedElement = null;
|
this.simulatedElement = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.stopAnimationsCurrentTimeTimer();
|
||||||
|
|
||||||
this.inspector = null;
|
this.inspector = null;
|
||||||
this.win = null;
|
this.win = null;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +149,10 @@ class AnimationInspector {
|
||||||
return this.inspector.store.getState().animations;
|
return this.inspector.store.getState().animations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addAnimationsCurrentTimeListener(listener) {
|
||||||
|
this.animationsCurrentTimeListeners.push(listener);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a map of animated property from given animation actor.
|
* Return a map of animated property from given animation actor.
|
||||||
*
|
*
|
||||||
|
@ -201,6 +223,12 @@ class AnimationInspector {
|
||||||
this.inspector.sidebar.getCurrentTabID() === "newanimationinspector";
|
this.inspector.sidebar.getCurrentTabID() === "newanimationinspector";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onAnimationsCurrentTimeUpdated(currentTime) {
|
||||||
|
for (const listener of this.animationsCurrentTimeListeners) {
|
||||||
|
listener(currentTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onElementPickerStarted() {
|
onElementPickerStarted() {
|
||||||
this.inspector.store.dispatch(updateElementPickerEnabled(true));
|
this.inspector.store.dispatch(updateElementPickerEnabled(true));
|
||||||
}
|
}
|
||||||
|
@ -222,10 +250,16 @@ class AnimationInspector {
|
||||||
this.inspector.store.dispatch(updateSidebarSize(size));
|
this.inspector.store.dispatch(updateSidebarSize(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeAnimationsCurrentTimeListener(listener) {
|
||||||
|
this.animationsCurrentTimeListeners =
|
||||||
|
this.animationsCurrentTimeListeners.filter(l => l !== listener);
|
||||||
|
}
|
||||||
|
|
||||||
async rewindAnimationsCurrentTime() {
|
async rewindAnimationsCurrentTime() {
|
||||||
const animations = this.state.animations;
|
const animations = this.state.animations;
|
||||||
await this.animationsFront.setCurrentTimes(animations, 0, true);
|
await this.animationsFront.setCurrentTimes(animations, 0, true);
|
||||||
this.updateAnimations(animations);
|
await this.updateAnimations(animations);
|
||||||
|
this.onAnimationsCurrentTimeUpdated(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
selectAnimation(animation) {
|
selectAnimation(animation) {
|
||||||
|
@ -288,6 +322,19 @@ class AnimationInspector {
|
||||||
return this.simulatedAnimation;
|
return this.simulatedAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stopAnimationsCurrentTimeTimer() {
|
||||||
|
if (this.currentTimeTimer) {
|
||||||
|
this.currentTimeTimer.destroy();
|
||||||
|
this.currentTimeTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startAnimationsCurrentTimeTimer() {
|
||||||
|
const currentTimeTimer = new CurrentTimeTimer(this);
|
||||||
|
currentTimeTimer.start();
|
||||||
|
this.currentTimeTimer = currentTimeTimer;
|
||||||
|
}
|
||||||
|
|
||||||
toggleElementPicker() {
|
toggleElementPicker() {
|
||||||
this.inspector.toolbox.highlighterUtils.togglePicker();
|
this.inspector.toolbox.highlighterUtils.togglePicker();
|
||||||
}
|
}
|
||||||
|
@ -325,6 +372,8 @@ class AnimationInspector {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateState(animations) {
|
updateState(animations) {
|
||||||
|
this.stopAnimationsCurrentTimeTimer();
|
||||||
|
|
||||||
this.inspector.store.dispatch(updateAnimations(animations));
|
this.inspector.store.dispatch(updateAnimations(animations));
|
||||||
// If number of displayed animations is one, we select the animation automatically.
|
// If number of displayed animations is one, we select the animation automatically.
|
||||||
// But if selected animation is in given animations, ignores.
|
// But if selected animation is in given animations, ignores.
|
||||||
|
@ -334,6 +383,45 @@ class AnimationInspector {
|
||||||
!animations.find(animation => animation.actorID === selectedAnimation.actorID)) {
|
!animations.find(animation => animation.actorID === selectedAnimation.actorID)) {
|
||||||
this.selectAnimation(animations.length === 1 ? animations[0] : null);
|
this.selectAnimation(animations.length === 1 ? animations[0] : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasPlayingAnimation(animations)) {
|
||||||
|
this.startAnimationsCurrentTimeTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CurrentTimeTimer {
|
||||||
|
constructor(animationInspector) {
|
||||||
|
const timeScale = animationInspector.state.timeScale;
|
||||||
|
this.baseCurrentTime = timeScale.documentCurrentTime - timeScale.minStartTime;
|
||||||
|
this.startTime = animationInspector.win.performance.now();
|
||||||
|
this.animationInspector = animationInspector;
|
||||||
|
|
||||||
|
this.next = this.next.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.stop();
|
||||||
|
this.animationInspector = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
next() {
|
||||||
|
if (this.doStop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { onAnimationsCurrentTimeUpdated, win } = this.animationInspector;
|
||||||
|
const currentTime = this.baseCurrentTime + win.performance.now() - this.startTime;
|
||||||
|
onAnimationsCurrentTimeUpdated(currentTime);
|
||||||
|
win.requestAnimationFrame(this.next);
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.doStop = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,6 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||||
const AnimationList = createFactory(require("./AnimationList"));
|
const AnimationList = createFactory(require("./AnimationList"));
|
||||||
const AnimationListHeader = createFactory(require("./AnimationListHeader"));
|
const AnimationListHeader = createFactory(require("./AnimationListHeader"));
|
||||||
|
|
||||||
const TimeScale = require("../utils/timescale");
|
|
||||||
|
|
||||||
class AnimationListContainer extends PureComponent {
|
class AnimationListContainer extends PureComponent {
|
||||||
static get propTypes() {
|
static get propTypes() {
|
||||||
return {
|
return {
|
||||||
|
@ -26,6 +24,7 @@ class AnimationListContainer extends PureComponent {
|
||||||
selectAnimation: PropTypes.func.isRequired,
|
selectAnimation: PropTypes.func.isRequired,
|
||||||
setSelectedNode: PropTypes.func.isRequired,
|
setSelectedNode: PropTypes.func.isRequired,
|
||||||
simulateAnimation: PropTypes.func.isRequired,
|
simulateAnimation: PropTypes.func.isRequired,
|
||||||
|
timeScale: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,8 +39,8 @@ class AnimationListContainer extends PureComponent {
|
||||||
selectAnimation,
|
selectAnimation,
|
||||||
setSelectedNode,
|
setSelectedNode,
|
||||||
simulateAnimation,
|
simulateAnimation,
|
||||||
|
timeScale,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const timeScale = new TimeScale(animations);
|
|
||||||
|
|
||||||
return dom.div(
|
return dom.div(
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,13 +8,16 @@ const { createFactory, PureComponent } = require("devtools/client/shared/vendor/
|
||||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||||
|
|
||||||
|
const CurrentTimeLabel = createFactory(require("./CurrentTimeLabel"));
|
||||||
const PauseResumeButton = createFactory(require("./PauseResumeButton"));
|
const PauseResumeButton = createFactory(require("./PauseResumeButton"));
|
||||||
const RewindButton = createFactory(require("./RewindButton"));
|
const RewindButton = createFactory(require("./RewindButton"));
|
||||||
|
|
||||||
class AnimationToolbar extends PureComponent {
|
class AnimationToolbar extends PureComponent {
|
||||||
static get propTypes() {
|
static get propTypes() {
|
||||||
return {
|
return {
|
||||||
|
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
|
||||||
animations: PropTypes.arrayOf(PropTypes.object).isRequired,
|
animations: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
|
||||||
rewindAnimationsCurrentTime: PropTypes.func.isRequired,
|
rewindAnimationsCurrentTime: PropTypes.func.isRequired,
|
||||||
setAnimationsPlayState: PropTypes.func.isRequired,
|
setAnimationsPlayState: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
@ -22,7 +25,9 @@ class AnimationToolbar extends PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
addAnimationsCurrentTimeListener,
|
||||||
animations,
|
animations,
|
||||||
|
removeAnimationsCurrentTimeListener,
|
||||||
rewindAnimationsCurrentTime,
|
rewindAnimationsCurrentTime,
|
||||||
setAnimationsPlayState,
|
setAnimationsPlayState,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
@ -41,6 +46,12 @@ class AnimationToolbar extends PureComponent {
|
||||||
animations,
|
animations,
|
||||||
setAnimationsPlayState,
|
setAnimationsPlayState,
|
||||||
}
|
}
|
||||||
|
),
|
||||||
|
CurrentTimeLabel(
|
||||||
|
{
|
||||||
|
addAnimationsCurrentTimeListener,
|
||||||
|
removeAnimationsCurrentTimeListener,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ const SplitBox = createFactory(require("devtools/client/shared/components/splitt
|
||||||
class App extends PureComponent {
|
class App extends PureComponent {
|
||||||
static get propTypes() {
|
static get propTypes() {
|
||||||
return {
|
return {
|
||||||
|
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
|
||||||
animations: PropTypes.arrayOf(PropTypes.object).isRequired,
|
animations: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
detailVisibility: PropTypes.bool.isRequired,
|
detailVisibility: PropTypes.bool.isRequired,
|
||||||
emitEventForTest: PropTypes.func.isRequired,
|
emitEventForTest: PropTypes.func.isRequired,
|
||||||
|
@ -26,12 +27,14 @@ class App extends PureComponent {
|
||||||
getNodeFromActor: PropTypes.func.isRequired,
|
getNodeFromActor: PropTypes.func.isRequired,
|
||||||
onHideBoxModelHighlighter: PropTypes.func.isRequired,
|
onHideBoxModelHighlighter: PropTypes.func.isRequired,
|
||||||
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
|
onShowBoxModelHighlighterForNode: PropTypes.func.isRequired,
|
||||||
|
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
|
||||||
rewindAnimationsCurrentTime: PropTypes.func.isRequired,
|
rewindAnimationsCurrentTime: PropTypes.func.isRequired,
|
||||||
selectAnimation: PropTypes.func.isRequired,
|
selectAnimation: PropTypes.func.isRequired,
|
||||||
setAnimationsPlayState: PropTypes.func.isRequired,
|
setAnimationsPlayState: PropTypes.func.isRequired,
|
||||||
setDetailVisibility: PropTypes.func.isRequired,
|
setDetailVisibility: PropTypes.func.isRequired,
|
||||||
setSelectedNode: PropTypes.func.isRequired,
|
setSelectedNode: PropTypes.func.isRequired,
|
||||||
simulateAnimation: PropTypes.func.isRequired,
|
simulateAnimation: PropTypes.func.isRequired,
|
||||||
|
timeScale: PropTypes.object.isRequired,
|
||||||
toggleElementPicker: PropTypes.func.isRequired,
|
toggleElementPicker: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -42,6 +45,7 @@ class App extends PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
addAnimationsCurrentTimeListener,
|
||||||
animations,
|
animations,
|
||||||
detailVisibility,
|
detailVisibility,
|
||||||
emitEventForTest,
|
emitEventForTest,
|
||||||
|
@ -50,12 +54,14 @@ class App extends PureComponent {
|
||||||
getNodeFromActor,
|
getNodeFromActor,
|
||||||
onHideBoxModelHighlighter,
|
onHideBoxModelHighlighter,
|
||||||
onShowBoxModelHighlighterForNode,
|
onShowBoxModelHighlighterForNode,
|
||||||
|
removeAnimationsCurrentTimeListener,
|
||||||
rewindAnimationsCurrentTime,
|
rewindAnimationsCurrentTime,
|
||||||
selectAnimation,
|
selectAnimation,
|
||||||
setAnimationsPlayState,
|
setAnimationsPlayState,
|
||||||
setDetailVisibility,
|
setDetailVisibility,
|
||||||
setSelectedNode,
|
setSelectedNode,
|
||||||
simulateAnimation,
|
simulateAnimation,
|
||||||
|
timeScale,
|
||||||
toggleElementPicker,
|
toggleElementPicker,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -68,7 +74,9 @@ class App extends PureComponent {
|
||||||
[
|
[
|
||||||
AnimationToolbar(
|
AnimationToolbar(
|
||||||
{
|
{
|
||||||
|
addAnimationsCurrentTimeListener,
|
||||||
animations,
|
animations,
|
||||||
|
removeAnimationsCurrentTimeListener,
|
||||||
rewindAnimationsCurrentTime,
|
rewindAnimationsCurrentTime,
|
||||||
setAnimationsPlayState,
|
setAnimationsPlayState,
|
||||||
}
|
}
|
||||||
|
@ -98,6 +106,7 @@ class App extends PureComponent {
|
||||||
selectAnimation,
|
selectAnimation,
|
||||||
setSelectedNode,
|
setSelectedNode,
|
||||||
simulateAnimation,
|
simulateAnimation,
|
||||||
|
timeScale,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
vert: false,
|
vert: false,
|
||||||
|
@ -117,6 +126,7 @@ const mapStateToProps = state => {
|
||||||
return {
|
return {
|
||||||
animations: state.animations.animations,
|
animations: state.animations.animations,
|
||||||
detailVisibility: state.animations.detailVisibility,
|
detailVisibility: state.animations.detailVisibility,
|
||||||
|
timeScale: state.animations.timeScale,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||||
|
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||||
|
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||||
|
|
||||||
|
class CurrentTimeLabel extends PureComponent {
|
||||||
|
static get propTypes() {
|
||||||
|
return {
|
||||||
|
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
|
||||||
|
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
const { addAnimationsCurrentTimeListener } = props;
|
||||||
|
this.onCurrentTimeUpdated = this.onCurrentTimeUpdated.bind(this);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
currentTime: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
addAnimationsCurrentTimeListener(this.onCurrentTimeUpdated);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
const { removeAnimationsCurrentTimeListener } = this.props;
|
||||||
|
removeAnimationsCurrentTimeListener(this.onCurrentTimeUpdated);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentTimeUpdated(currentTime) {
|
||||||
|
this.setState({ currentTime });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { currentTime } = this.state;
|
||||||
|
|
||||||
|
return dom.label(
|
||||||
|
{
|
||||||
|
className: "current-time-label",
|
||||||
|
},
|
||||||
|
formatStopwatchTime(currentTime)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a timestamp (in ms) as a mm:ss.mmm string.
|
||||||
|
*
|
||||||
|
* @param {Number} time
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
function formatStopwatchTime(time) {
|
||||||
|
// Format falsy values as 0
|
||||||
|
if (!time) {
|
||||||
|
return "00:00.000";
|
||||||
|
}
|
||||||
|
|
||||||
|
let milliseconds = parseInt(time % 1000, 10);
|
||||||
|
let seconds = parseInt((time / 1000) % 60, 10);
|
||||||
|
let minutes = parseInt((time / (1000 * 60)), 10);
|
||||||
|
|
||||||
|
let pad = (nb, max) => {
|
||||||
|
if (nb < max) {
|
||||||
|
return new Array((max + "").length - (nb + "").length + 1).join("0") + nb;
|
||||||
|
}
|
||||||
|
return nb;
|
||||||
|
};
|
||||||
|
|
||||||
|
minutes = pad(minutes, 10);
|
||||||
|
seconds = pad(seconds, 10);
|
||||||
|
milliseconds = pad(milliseconds, 100);
|
||||||
|
|
||||||
|
return `${minutes}:${seconds}.${milliseconds}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = CurrentTimeLabel;
|
|
@ -9,6 +9,7 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||||
|
|
||||||
const { getStr } = require("../utils/l10n");
|
const { getStr } = require("../utils/l10n");
|
||||||
|
const { hasPlayingAnimation } = require("../utils/utils");
|
||||||
|
|
||||||
class PauseResumeButton extends PureComponent {
|
class PauseResumeButton extends PureComponent {
|
||||||
static get propTypes() {
|
static get propTypes() {
|
||||||
|
@ -43,7 +44,7 @@ class PauseResumeButton extends PureComponent {
|
||||||
|
|
||||||
updateState() {
|
updateState() {
|
||||||
const { animations } = this.props;
|
const { animations } = this.props;
|
||||||
const isPlaying = animations.some(({state}) => state.playState === "running");
|
const isPlaying = hasPlayingAnimation(animations);
|
||||||
this.setState({ isPlaying });
|
this.setState({ isPlaying });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ DevToolsModules(
|
||||||
'AnimationTimelineTickList.js',
|
'AnimationTimelineTickList.js',
|
||||||
'AnimationToolbar.js',
|
'AnimationToolbar.js',
|
||||||
'App.js',
|
'App.js',
|
||||||
|
'CurrentTimeLabel.js',
|
||||||
'KeyframesProgressTickItem.js',
|
'KeyframesProgressTickItem.js',
|
||||||
'KeyframesProgressTickList.js',
|
'KeyframesProgressTickList.js',
|
||||||
'NoAnimationPanel.js',
|
'NoAnimationPanel.js',
|
||||||
|
|
|
@ -12,6 +12,8 @@ const {
|
||||||
UPDATE_SIDEBAR_SIZE,
|
UPDATE_SIDEBAR_SIZE,
|
||||||
} = require("../actions/index");
|
} = require("../actions/index");
|
||||||
|
|
||||||
|
const TimeScale = require("../utils/timescale");
|
||||||
|
|
||||||
const INITIAL_STATE = {
|
const INITIAL_STATE = {
|
||||||
animations: [],
|
animations: [],
|
||||||
detailVisibility: false,
|
detailVisibility: false,
|
||||||
|
@ -21,12 +23,14 @@ const INITIAL_STATE = {
|
||||||
height: 0,
|
height: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
},
|
},
|
||||||
|
timeScale: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const reducers = {
|
const reducers = {
|
||||||
[UPDATE_ANIMATIONS](state, { animations }) {
|
[UPDATE_ANIMATIONS](state, { animations }) {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
animations,
|
animations,
|
||||||
|
timeScale: new TimeScale(animations),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ class TimeScale {
|
||||||
constructor(animations) {
|
constructor(animations) {
|
||||||
this.minStartTime = Infinity;
|
this.minStartTime = Infinity;
|
||||||
this.maxEndTime = 0;
|
this.maxEndTime = 0;
|
||||||
|
this.documentCurrentTime = 0;
|
||||||
|
|
||||||
for (const animation of animations) {
|
for (const animation of animations) {
|
||||||
this.addAnimation(animation.state);
|
this.addAnimation(animation.state);
|
||||||
}
|
}
|
||||||
|
@ -38,6 +40,7 @@ class TimeScale {
|
||||||
addAnimation(state) {
|
addAnimation(state) {
|
||||||
let {
|
let {
|
||||||
delay,
|
delay,
|
||||||
|
documentCurrentTime,
|
||||||
duration,
|
duration,
|
||||||
endDelay = 0,
|
endDelay = 0,
|
||||||
iterationCount,
|
iterationCount,
|
||||||
|
@ -67,6 +70,8 @@ class TimeScale {
|
||||||
const length = toRate(delay) + rateRelativeDuration + toRate(minZero(endDelay));
|
const length = toRate(delay) + rateRelativeDuration + toRate(minZero(endDelay));
|
||||||
const endTime = previousStartTime + length;
|
const endTime = previousStartTime + length;
|
||||||
this.maxEndTime = Math.max(this.maxEndTime, endTime);
|
this.maxEndTime = Math.max(this.maxEndTime, endTime);
|
||||||
|
|
||||||
|
this.documentCurrentTime = Math.max(this.documentCurrentTime, documentCurrentTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -69,6 +69,16 @@ function isAllAnimationEqual(animationsA, animationsB) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check wether the animations are running at least one.
|
||||||
|
*
|
||||||
|
* @param {Array} animations.
|
||||||
|
* @return {Boolean} true: playing
|
||||||
|
*/
|
||||||
|
function hasPlayingAnimation(animations) {
|
||||||
|
return animations.some(({state}) => state.playState === "running");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the equality given states as effect timing.
|
* Check the equality given states as effect timing.
|
||||||
*
|
*
|
||||||
|
@ -88,5 +98,6 @@ function isTimingEffectEqual(stateA, stateB) {
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.findOptimalTimeInterval = findOptimalTimeInterval;
|
exports.findOptimalTimeInterval = findOptimalTimeInterval;
|
||||||
|
exports.hasPlayingAnimation = hasPlayingAnimation;
|
||||||
exports.isAllAnimationEqual = isAllAnimationEqual;
|
exports.isAllAnimationEqual = isAllAnimationEqual;
|
||||||
exports.isTimingEffectEqual = isTimingEffectEqual;
|
exports.isTimingEffectEqual = isTimingEffectEqual;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче