Bug 1210796 - Part 9: Add progress indicator. r=pbro

MozReview-Commit-ID: GRcj1tFIKZB

--HG--
extra : rebase_source : be49edec53ba2068b59a9095a2faa0957fbd8c64
This commit is contained in:
Daisuke Akatsuka 2017-04-18 12:15:56 +09:00
Родитель 781c534bf5
Коммит f9582a91b0
4 изменённых файлов: 98 добавлений и 11 удалений

Просмотреть файл

@ -48,6 +48,7 @@ AnimationDetails.prototype = {
this.unrender(); this.unrender();
this.containerEl = null; this.containerEl = null;
this.serverTraits = null; this.serverTraits = null;
this.progressIndicatorEl = null;
}, },
unrender: function () { unrender: function () {
@ -186,11 +187,21 @@ AnimationDetails.prototype = {
// Get animation type for each CSS properties. // Get animation type for each CSS properties.
const animationTypes = yield this.getAnimationTypes(Object.keys(this.tracks)); const animationTypes = yield this.getAnimationTypes(Object.keys(this.tracks));
// Render progress indicator.
this.renderProgressIndicator();
// Render animated properties header. // Render animated properties header.
this.renderAnimatedPropertiesHeader(); this.renderAnimatedPropertiesHeader();
// Render animated properties body. // Render animated properties body.
this.renderAnimatedPropertiesBody(animationTypes); this.renderAnimatedPropertiesBody(animationTypes);
// Create dummy animation to indicate the animation progress.
const timing = Object.assign({}, animation.state, {
iterations: animation.state.iterationCount
? animation.state.iterationCount : Infinity
});
this.dummyAnimation =
new this.win.Animation(new this.win.KeyframeEffect(null, null, timing), null);
// Useful for tests to know when rendering of all animation detail UIs // Useful for tests to know when rendering of all animation detail UIs
// have been completed. // have been completed.
this.emit("animation-detail-rendering-completed"); this.emit("animation-detail-rendering-completed");
@ -286,6 +297,44 @@ AnimationDetails.prototype = {
keyframesComponent.on("frame-selected", this.onFrameSelected); keyframesComponent.on("frame-selected", this.onFrameSelected);
this.keyframeComponents.push(keyframesComponent); this.keyframeComponents.push(keyframesComponent);
} }
},
renderProgressIndicator: function () {
// The wrapper represents the area which the indicator is displayable.
const progressIndicatorWrapperEl = createNode({
parent: this.containerEl,
attributes: {
"class": "track-container progress-indicator-wrapper"
}
});
this.progressIndicatorEl = createNode({
parent: progressIndicatorWrapperEl,
attributes: {
"class": "progress-indicator"
}
});
createNode({
parent: this.progressIndicatorEl,
attributes: {
"class": "progress-indicator-shape"
}
});
},
indicateProgress: function (time) {
if (!this.progressIndicatorEl) {
// Not displayed yet.
return;
}
const startTime = this.animation.state.previousStartTime || 0;
this.dummyAnimation.currentTime =
(time - startTime) * this.animation.state.playbackRate;
this.progressIndicatorEl.style.left =
`${ this.dummyAnimation.effect.getComputedTiming().progress * 100 }%`;
},
get win() {
return this.containerEl.ownerDocument.defaultView;
} }
}; };

Просмотреть файл

@ -6,6 +6,7 @@
"use strict"; "use strict";
const {Task} = require("devtools/shared/task");
const EventEmitter = require("devtools/shared/event-emitter"); const EventEmitter = require("devtools/shared/event-emitter");
const { const {
createNode, createNode,
@ -58,6 +59,7 @@ function AnimationsTimeline(inspector, serverTraits) {
this.onAnimationSelected = this.onAnimationSelected.bind(this); this.onAnimationSelected = this.onAnimationSelected.bind(this);
this.onWindowResize = this.onWindowResize.bind(this); this.onWindowResize = this.onWindowResize.bind(this);
this.onFrameSelected = this.onFrameSelected.bind(this); this.onFrameSelected = this.onFrameSelected.bind(this);
this.onTimelineDataChanged = this.onTimelineDataChanged.bind(this);
EventEmitter.decorate(this); EventEmitter.decorate(this);
} }
@ -273,6 +275,7 @@ AnimationsTimeline.prototype = {
this.details.off("frame-selected", this.onFrameSelected); this.details.off("frame-selected", this.onFrameSelected);
this.details.unrender(); this.details.unrender();
this.animationsEl.innerHTML = ""; this.animationsEl.innerHTML = "";
this.off("timeline-data-changed", this.onTimelineDataChanged);
}, },
onWindowResize: function () { onWindowResize: function () {
@ -290,7 +293,7 @@ AnimationsTimeline.prototype = {
}, TIMELINE_BACKGROUND_RESIZE_DEBOUNCE_TIMER); }, TIMELINE_BACKGROUND_RESIZE_DEBOUNCE_TIMER);
}, },
onAnimationSelected: function (e, animation) { onAnimationSelected: Task.async(function* (e, animation) {
let index = this.animations.indexOf(animation); let index = this.animations.indexOf(animation);
if (index === -1) { if (index === -1) {
return; return;
@ -324,10 +327,11 @@ AnimationsTimeline.prototype = {
selectedAnimationEl.classList.add("selected"); selectedAnimationEl.classList.add("selected");
this.animationDetailEl.style.display = this.animationDetailEl.style.display =
this.animationDetailEl.dataset.defaultDisplayStyle; this.animationDetailEl.dataset.defaultDisplayStyle;
this.details.render(animation); yield this.details.render(animation);
this.onTimelineDataChanged(null, { time: this.currentTime || 0 });
this.animationAnimationNameEl.textContent = getFormattedAnimationTitle(animation); this.animationAnimationNameEl.textContent = getFormattedAnimationTitle(animation);
this.emit("animation-selected", animation); this.emit("animation-selected", animation);
}, }),
/** /**
* When a frame gets selected, move the scrubber to the corresponding position * When a frame gets selected, move the scrubber to the corresponding position
@ -483,6 +487,9 @@ AnimationsTimeline.prototype = {
? TimeScale.minStartTime ? TimeScale.minStartTime
: documentCurrentTime); : documentCurrentTime);
} }
// To indicate the animation progress in AnimationDetails.
this.on("timeline-data-changed", this.onTimelineDataChanged);
}, },
isAtLeastOneAnimationPlaying: function () { isAtLeastOneAnimationPlaying: function () {
@ -592,5 +599,12 @@ AnimationsTimeline.prototype = {
} }
}); });
} }
},
onTimelineDataChanged: function (e, { time }) {
this.currentTime = time;
const indicateTime =
TimeScale.minStartTime === Infinity ? 0 : this.currentTime + TimeScale.minStartTime;
this.details.indicateProgress(indicateTime);
} }
}; };

Просмотреть файл

@ -381,18 +381,11 @@ function* clickOnAnimation(panel, index, shouldAlreadySelected) {
? "animation-already-selected" ? "animation-already-selected"
: "animation-selected"); : "animation-selected");
// If we're opening the animation, also wait for
// the animation-detail-rendering-completed event.
let onReady = shouldAlreadySelected
? Promise.resolve()
: timeline.details.once("animation-detail-rendering-completed");
info("Click on animation " + index + " in the timeline"); info("Click on animation " + index + " in the timeline");
let timeBlock = timeline.rootWrapperEl.querySelectorAll(".time-block")[index]; let timeBlock = timeline.rootWrapperEl.querySelectorAll(".time-block")[index];
EventUtils.sendMouseEvent({type: "click"}, timeBlock, EventUtils.sendMouseEvent({type: "click"}, timeBlock,
timeBlock.ownerDocument.defaultView); timeBlock.ownerDocument.defaultView);
yield onReady;
return yield onSelectionChanged; return yield onSelectionChanged;
} }

Просмотреть файл

@ -19,6 +19,8 @@
/* The color for other animation type */ /* The color for other animation type */
--other-border-color: var(--theme-graphs-bluegrey); --other-border-color: var(--theme-graphs-bluegrey);
--other-background-color: #5e88b080; --other-background-color: #5e88b080;
/* The color for progress indicator */
--progress-indicator-color: var(--theme-highlight-gray);
} }
.theme-light { .theme-light {
@ -47,6 +49,8 @@
/* The color for other animation type */ /* The color for other animation type */
--other-border-color: var(--theme-graphs-bluegrey); --other-border-color: var(--theme-graphs-bluegrey);
--other-background-color: #0072ab80; --other-background-color: #0072ab80;
/* The color for progress indicator */
--progress-indicator-color: gray;
} }
:root { :root {
@ -621,7 +625,6 @@ body {
height: 0; height: 0;
background-color: inherit; background-color: inherit;
cursor: pointer; cursor: pointer;
z-index: 1;
} }
.keyframes .frame::before { .keyframes .frame::before {
@ -755,3 +758,31 @@ body {
/* To display animation progress graph clealy when the scroll is bottom. */ /* To display animation progress graph clealy when the scroll is bottom. */
padding-bottom: calc(var(--timeline-animation-height) / 2); padding-bottom: calc(var(--timeline-animation-height) / 2);
} }
.animated-properties .progress-indicator-wrapper {
pointer-events: none;
z-index: 5;
}
.progress-indicator-wrapper .progress-indicator {
position: absolute;
pointer-events: none;
}
.progress-indicator-wrapper .progress-indicator .progress-indicator-shape {
position: fixed;
width: 0;
height: 100vh;
border-right: 1px solid var(--progress-indicator-color);
}
.progress-indicator-wrapper .progress-indicator .progress-indicator-shape::before {
content: "";
position: absolute;
top: 0;
right: -6px;
width: 1px;
border-top: 5px solid var(--progress-indicator-color);
border-left: 5px solid transparent;
border-right: 5px solid transparent;
}