зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1456828 - Part 2: Apply ProgressInspectionPanel to animations. r=gl
MozReview-Commit-ID: 7It2CibH3oa --HG-- extra : rebase_source : a1e0cce1f9c0af731cb0e6d29c70e9ce20e4d5ea
This commit is contained in:
Родитель
976f361b5c
Коммит
bb01d0ac70
|
@ -6,11 +6,20 @@
|
|||
|
||||
const { createFactory, PureComponent } =
|
||||
require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
|
||||
|
||||
const AnimationList = createFactory(require("./AnimationList"));
|
||||
const AnimationListHeader = createFactory(require("./AnimationListHeader"));
|
||||
const CurrentTimeScrubberController =
|
||||
createFactory(require("./CurrentTimeScrubberController"));
|
||||
const ProgressInspectionPanel = createFactory(require("./ProgressInspectionPanel"));
|
||||
|
||||
const { findOptimalTimeInterval } = require("../utils/utils");
|
||||
|
||||
// The minimum spacing between 2 time graduation headers in the timeline (px).
|
||||
const TIME_GRADUATION_MIN_SPACING = 40;
|
||||
|
||||
class AnimationListContainer extends PureComponent {
|
||||
static get propTypes() {
|
||||
|
@ -32,6 +41,44 @@ class AnimationListContainer extends PureComponent {
|
|||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
// tick labels and lines on the progress inspection panel
|
||||
ticks: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updateState(this.props);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.updateState(nextProps);
|
||||
}
|
||||
|
||||
updateState(props) {
|
||||
const { timeScale } = props;
|
||||
const tickLinesEl = ReactDOM.findDOMNode(this).querySelector(".tick-lines");
|
||||
const width = tickLinesEl.offsetWidth;
|
||||
const animationDuration = timeScale.getDuration();
|
||||
const minTimeInterval = TIME_GRADUATION_MIN_SPACING * animationDuration / width;
|
||||
const intervalLength = findOptimalTimeInterval(minTimeInterval);
|
||||
const intervalWidth = intervalLength * width / animationDuration;
|
||||
const tickCount = width / intervalWidth;
|
||||
|
||||
const ticks = [];
|
||||
|
||||
for (let i = 0; i <= tickCount; i++) {
|
||||
const position = i * intervalWidth * 100 / width;
|
||||
const label = timeScale.formatTime(timeScale.distanceToRelativeTime(position));
|
||||
ticks.push({ position, label });
|
||||
}
|
||||
|
||||
this.setState({ ticks });
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
addAnimationsCurrentTimeListener,
|
||||
|
@ -49,36 +96,48 @@ class AnimationListContainer extends PureComponent {
|
|||
simulateAnimation,
|
||||
timeScale,
|
||||
} = this.props;
|
||||
const { ticks } = this.state;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "animation-list-container"
|
||||
},
|
||||
AnimationListHeader(
|
||||
ProgressInspectionPanel(
|
||||
{
|
||||
addAnimationsCurrentTimeListener,
|
||||
removeAnimationsCurrentTimeListener,
|
||||
setAnimationsCurrentTime,
|
||||
timeScale,
|
||||
}
|
||||
),
|
||||
AnimationList(
|
||||
{
|
||||
animations,
|
||||
emitEventForTest,
|
||||
getAnimatedPropertyMap,
|
||||
getNodeFromActor,
|
||||
onHideBoxModelHighlighter,
|
||||
onShowBoxModelHighlighterForNode,
|
||||
selectAnimation,
|
||||
setHighlightedNode,
|
||||
setSelectedNode,
|
||||
simulateAnimation,
|
||||
timeScale,
|
||||
indicator: CurrentTimeScrubberController(
|
||||
{
|
||||
addAnimationsCurrentTimeListener,
|
||||
removeAnimationsCurrentTimeListener,
|
||||
setAnimationsCurrentTime,
|
||||
timeScale,
|
||||
}
|
||||
),
|
||||
list: AnimationList(
|
||||
{
|
||||
animations,
|
||||
emitEventForTest,
|
||||
getAnimatedPropertyMap,
|
||||
getNodeFromActor,
|
||||
onHideBoxModelHighlighter,
|
||||
onShowBoxModelHighlighterForNode,
|
||||
selectAnimation,
|
||||
setHighlightedNode,
|
||||
setSelectedNode,
|
||||
simulateAnimation,
|
||||
timeScale,
|
||||
}
|
||||
),
|
||||
ticks,
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimationListContainer;
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
sidebarWidth: state.animations.sidebarSize ? state.animations.sidebarSize.width : 0
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = connect(mapStateToProps)(AnimationListContainer);
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
/* 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 { createFactory, PureComponent } =
|
||||
require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const AnimationTimelineTickList = createFactory(require("./AnimationTimelineTickList"));
|
||||
const CurrentTimeScrubberController =
|
||||
createFactory(require("./CurrentTimeScrubberController"));
|
||||
|
||||
class AnimationListHeader extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
addAnimationsCurrentTimeListener: PropTypes.func.isRequired,
|
||||
removeAnimationsCurrentTimeListener: PropTypes.func.isRequired,
|
||||
setAnimationsCurrentTime: PropTypes.func.isRequired,
|
||||
timeScale: PropTypes.object.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
addAnimationsCurrentTimeListener,
|
||||
removeAnimationsCurrentTimeListener,
|
||||
setAnimationsCurrentTime,
|
||||
timeScale,
|
||||
} = this.props;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "animation-list-header"
|
||||
},
|
||||
dom.div(
|
||||
{
|
||||
className: "devtools-toolbar"
|
||||
}
|
||||
),
|
||||
AnimationTimelineTickList(
|
||||
{
|
||||
timeScale
|
||||
}
|
||||
),
|
||||
CurrentTimeScrubberController(
|
||||
{
|
||||
addAnimationsCurrentTimeListener,
|
||||
removeAnimationsCurrentTimeListener,
|
||||
setAnimationsCurrentTime,
|
||||
timeScale,
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimationListHeader;
|
|
@ -1,32 +0,0 @@
|
|||
/* 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 PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
class AnimationTimeTickItem extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
position: PropTypes.number.isRequired,
|
||||
timeTickLabel: PropTypes.string.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { position, timeTickLabel } = this.props;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "animation-timeline-tick-item",
|
||||
style: { left: `${ position }%` }
|
||||
},
|
||||
timeTickLabel
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AnimationTimeTickItem;
|
|
@ -1,101 +0,0 @@
|
|||
/* 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 { Component, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
|
||||
|
||||
const AnimationTimelineTickItem = createFactory(require("./AnimationTimelineTickItem"));
|
||||
|
||||
const { findOptimalTimeInterval } = require("../utils/utils");
|
||||
|
||||
// The minimum spacing between 2 time graduation headers in the timeline (px).
|
||||
const TIME_GRADUATION_MIN_SPACING = 40;
|
||||
|
||||
class AnimationTimelineTickList extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
sidebarWidth: PropTypes.number.isRequired,
|
||||
timeScale: PropTypes.object.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
tickList: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updateTickList(this.props);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.updateTickList(nextProps);
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState) {
|
||||
if (this.state.tickList.length !== nextState.tickList.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.state.tickList.length; i++) {
|
||||
const currentTickItem = this.state.tickList[i];
|
||||
const nextTickItem = nextState.tickList[i];
|
||||
|
||||
if (currentTickItem.timeTickLabel !== nextTickItem.timeTickLabel) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
updateTickList(props) {
|
||||
const { timeScale } = props;
|
||||
const tickListEl = ReactDOM.findDOMNode(this);
|
||||
const width = tickListEl.offsetWidth;
|
||||
const animationDuration = timeScale.getDuration();
|
||||
const minTimeInterval = TIME_GRADUATION_MIN_SPACING * animationDuration / width;
|
||||
const intervalLength = findOptimalTimeInterval(minTimeInterval);
|
||||
const intervalWidth = intervalLength * width / animationDuration;
|
||||
const tickCount = width / intervalWidth;
|
||||
const intervalPositionPercentage = 100 * intervalWidth / width;
|
||||
|
||||
const tickList = [];
|
||||
for (let i = 0; i <= tickCount; i++) {
|
||||
const position = i * intervalPositionPercentage;
|
||||
const timeTickLabel =
|
||||
timeScale.formatTime(timeScale.distanceToRelativeTime(position));
|
||||
tickList.push({ position, timeTickLabel });
|
||||
}
|
||||
|
||||
this.setState({ tickList });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { tickList } = this.state;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "animation-timeline-tick-list"
|
||||
},
|
||||
tickList.map(tickItem => AnimationTimelineTickItem(tickItem))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
sidebarWidth: state.animations.sidebarSize ? state.animations.sidebarSize.width : 0
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = connect(mapStateToProps)(AnimationTimelineTickList);
|
|
@ -18,10 +18,7 @@ DevToolsModules(
|
|||
'AnimationItem.js',
|
||||
'AnimationList.js',
|
||||
'AnimationListContainer.js',
|
||||
'AnimationListHeader.js',
|
||||
'AnimationTarget.js',
|
||||
'AnimationTimelineTickItem.js',
|
||||
'AnimationTimelineTickList.js',
|
||||
'AnimationToolbar.js',
|
||||
'App.js',
|
||||
'CurrentTimeLabel.js',
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
// Test for following timeline tick items.
|
||||
// * animation list header elements existence
|
||||
// * timeline tick item elements existence
|
||||
// * count and label of timeline tick elements changing by the sidebar width
|
||||
// * tick labels elements existence
|
||||
// * count and text of tick label elements changing by the sidebar width
|
||||
|
||||
const TimeScale = require("devtools/client/inspector/animation/utils/timescale");
|
||||
const { findOptimalTimeInterval } =
|
||||
|
@ -29,27 +29,24 @@ add_task(async function() {
|
|||
ok(listHeaderEl, "The header element should be in animation list container element");
|
||||
|
||||
info("Checking time tick item elements existence");
|
||||
assertTimelineTickItems(timeScale, listContainerEl);
|
||||
const timelineTickItemLength =
|
||||
listContainerEl.querySelectorAll(".animation-timeline-tick-item").length;
|
||||
assertTickLabels(timeScale, listContainerEl);
|
||||
const timelineTickItemLength = listContainerEl.querySelectorAll(".tick-label").length;
|
||||
|
||||
info("Checking timeline tick item elements after enlarge sidebar width");
|
||||
await setSidebarWidth("100%", inspector);
|
||||
assertTimelineTickItems(timeScale, listContainerEl);
|
||||
ok(timelineTickItemLength <
|
||||
listContainerEl.querySelectorAll(".animation-timeline-tick-item").length,
|
||||
assertTickLabels(timeScale, listContainerEl);
|
||||
ok(timelineTickItemLength < listContainerEl.querySelectorAll(".tick-label").length,
|
||||
"The timeline tick item elements should increase");
|
||||
});
|
||||
|
||||
/**
|
||||
* Assert timeline tick item's position and label.
|
||||
* Assert tick label's position and label.
|
||||
*
|
||||
* @param {TimeScale} - timeScale
|
||||
* @param {Element} - listContainerEl
|
||||
*/
|
||||
function assertTimelineTickItems(timeScale, listContainerEl) {
|
||||
const timelineTickListEl =
|
||||
listContainerEl.querySelector(".animation-timeline-tick-list");
|
||||
function assertTickLabels(timeScale, listContainerEl) {
|
||||
const timelineTickListEl = listContainerEl.querySelector(".tick-labels");
|
||||
ok(timelineTickListEl,
|
||||
"The animation timeline tick list element should be in header");
|
||||
|
||||
|
@ -59,8 +56,7 @@ function assertTimelineTickItems(timeScale, listContainerEl) {
|
|||
const interval = findOptimalTimeInterval(minTimeInterval);
|
||||
const expectedTickItem = Math.ceil(animationDuration / interval);
|
||||
|
||||
const timelineTickItemEls =
|
||||
timelineTickListEl.querySelectorAll(".animation-timeline-tick-item");
|
||||
const timelineTickItemEls = timelineTickListEl.querySelectorAll(".tick-label");
|
||||
is(timelineTickItemEls.length, expectedTickItem,
|
||||
"The expected number of timeline ticks were found");
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
--fill-color-cssanimation: var(--theme-contrast-background);
|
||||
--fill-color-csstransition: var(--theme-highlight-blue);
|
||||
--fill-color-scriptanimation: var(--theme-graphs-green);
|
||||
--graph-height: 30px;
|
||||
--graph-right-offset: 10px;
|
||||
--keyframe-marker-shadow-color: #c4c4c4;
|
||||
--pause-image: url(chrome://devtools/skin/images/pause.svg);
|
||||
|
@ -88,10 +89,7 @@ select.playback-rate-selector.devtools-button:not(:empty):not(:disabled):not(.ch
|
|||
|
||||
/* Animation List Container */
|
||||
.animation-list-container {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
@ -100,50 +98,10 @@ select.playback-rate-selector.devtools-button:not(:empty):not(:disabled):not(.ch
|
|||
cursor: col-resize;
|
||||
}
|
||||
|
||||
/* Animation List Header */
|
||||
.animation-list-header {
|
||||
display: grid;
|
||||
grid-template-columns: var(--sidebar-width) calc(100% - var(--sidebar-width) - var(--graph-right-offset)) var(--graph-right-offset);
|
||||
line-height: var(--devtools-toolbar-height);
|
||||
min-height: 100%;
|
||||
padding: 0;
|
||||
pointer-events: none;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.animation-list-header .devtools-toolbar {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Animation Timeline Tick List */
|
||||
.animation-timeline-tick-list {
|
||||
grid-column: 2/3;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.animation-timeline-tick-item {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.animation-timeline-tick-item::before {
|
||||
border-left: var(--tick-line-style);
|
||||
content: "";
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* Current Time Scrubber */
|
||||
.current-time-scrubber-controller {
|
||||
grid-column: 2 / 3;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.current-time-scrubber-controller::before {
|
||||
|
@ -163,7 +121,6 @@ select.playback-rate-selector.devtools-button:not(:empty):not(:disabled):not(.ch
|
|||
pointer-events: auto;
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.current-time-scrubber::before {
|
||||
|
@ -186,22 +143,7 @@ select.playback-rate-selector.devtools-button:not(:empty):not(:disabled):not(.ch
|
|||
width: 0;
|
||||
}
|
||||
|
||||
/* Animation List */
|
||||
.animation-list {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: var(--devtools-toolbar-height);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Animation Item */
|
||||
.animation-item {
|
||||
display: flex;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.animation-item:nth-child(2n+1) {
|
||||
background-color: var(--animation-even-background-color);
|
||||
}
|
||||
|
@ -229,9 +171,9 @@ select.playback-rate-selector.devtools-button:not(:empty):not(:disabled):not(.ch
|
|||
.animation-target {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
grid-column: 1 / 2;
|
||||
height: var(--graph-height);
|
||||
padding-left: 4px;
|
||||
width: var(--sidebar-width);
|
||||
}
|
||||
|
||||
/* Reps component */
|
||||
|
@ -259,10 +201,10 @@ select.playback-rate-selector.devtools-button:not(:empty):not(:disabled):not(.ch
|
|||
/* Summary Graph */
|
||||
.animation-summary-graph {
|
||||
cursor: pointer;
|
||||
height: 100%;
|
||||
grid-column: 2 / 3;
|
||||
height: var(--graph-height);
|
||||
padding-top: 5px;
|
||||
position: relative;
|
||||
width: calc(100% - var(--sidebar-width) - var(--graph-right-offset));
|
||||
}
|
||||
|
||||
.animation-summary-graph.compositor::after {
|
||||
|
@ -277,7 +219,6 @@ select.playback-rate-selector.devtools-button:not(:empty):not(:disabled):not(.ch
|
|||
top: 5px;
|
||||
width: 15px;
|
||||
-moz-context-properties: fill;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.animation-summary-graph-path {
|
||||
|
@ -382,7 +323,7 @@ select.playback-rate-selector.devtools-button:not(:empty):not(:disabled):not(.ch
|
|||
height: 100%;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.animation-detail-header {
|
||||
|
@ -527,7 +468,7 @@ select.playback-rate-selector.devtools-button:not(:empty):not(:disabled):not(.ch
|
|||
/* Animated Property Item */
|
||||
.animated-property-item {
|
||||
display: flex;
|
||||
height: 30px;
|
||||
height: var(--graph-height);
|
||||
}
|
||||
|
||||
.animated-property-item:nth-child(2n+1) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче