зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1406285 - Part 7: Implement effect timing graph. r=gl
MozReview-Commit-ID: DIrt9PdY2Nd --HG-- extra : rebase_source : d3c2829abefda76a8099be746cfd1bb38b236995
This commit is contained in:
Родитель
32e5aaaef8
Коммит
9f2d2b30d6
|
@ -0,0 +1,72 @@
|
||||||
|
/* 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 PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||||
|
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||||
|
|
||||||
|
const { SummaryGraphHelper, toPathString } = require("../../utils/graph-helper");
|
||||||
|
const TimingPath = require("./TimingPath");
|
||||||
|
|
||||||
|
class EffectTimingPath extends TimingPath {
|
||||||
|
static get propTypes() {
|
||||||
|
return {
|
||||||
|
animation: PropTypes.object.isRequired,
|
||||||
|
durationPerPixel: PropTypes.number.isRequired,
|
||||||
|
simulateAnimation: PropTypes.func.isRequired,
|
||||||
|
totalDuration: PropTypes.number.isRequired,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
animation,
|
||||||
|
durationPerPixel,
|
||||||
|
simulateAnimation,
|
||||||
|
totalDuration,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const { state } = animation;
|
||||||
|
const effectTiming = Object.assign({}, state, {
|
||||||
|
iterations: state.iterationCount ? state.iterationCount : Infinity
|
||||||
|
});
|
||||||
|
|
||||||
|
const simulatedAnimation = simulateAnimation(null, effectTiming, false);
|
||||||
|
const endTime = simulatedAnimation.effect.getComputedTiming().endTime;
|
||||||
|
|
||||||
|
const getValueFunc = time => {
|
||||||
|
if (time < 0) {
|
||||||
|
return { x: time, y: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
simulatedAnimation.currentTime = time < endTime ? time : endTime;
|
||||||
|
return Math.max(simulatedAnimation.effect.getComputedTiming().progress, 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
const toPathStringFunc = segments => {
|
||||||
|
const firstSegment = segments[0];
|
||||||
|
let pathString = `M${ firstSegment.x },0 `;
|
||||||
|
pathString += toPathString(segments);
|
||||||
|
const lastSegment = segments[segments.length - 1];
|
||||||
|
pathString += `L${ lastSegment.x },0`;
|
||||||
|
return pathString;
|
||||||
|
};
|
||||||
|
|
||||||
|
const helper = new SummaryGraphHelper(state, null,
|
||||||
|
totalDuration, durationPerPixel,
|
||||||
|
getValueFunc, toPathStringFunc);
|
||||||
|
const offset = state.previousStartTime ? state.previousStartTime : 0;
|
||||||
|
|
||||||
|
return dom.g(
|
||||||
|
{
|
||||||
|
className: "animation-effect-timing-path",
|
||||||
|
transform: `translate(${ offset })`
|
||||||
|
},
|
||||||
|
super.renderGraph(state, helper)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = EffectTimingPath;
|
|
@ -10,6 +10,9 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||||
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
|
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
|
||||||
|
|
||||||
const ComputedTimingPath = createFactory(require("./ComputedTimingPath"));
|
const ComputedTimingPath = createFactory(require("./ComputedTimingPath"));
|
||||||
|
const EffectTimingPath = createFactory(require("./EffectTimingPath"));
|
||||||
|
const { DEFAULT_GRAPH_HEIGHT } = require("../../utils/graph-helper");
|
||||||
|
|
||||||
// Minimum opacity for semitransparent fill color for keyframes's easing graph.
|
// Minimum opacity for semitransparent fill color for keyframes's easing graph.
|
||||||
const MIN_KEYFRAMES_EASING_OPACITY = 0.5;
|
const MIN_KEYFRAMES_EASING_OPACITY = 0.5;
|
||||||
|
|
||||||
|
@ -163,7 +166,8 @@ class SummaryGraphPath extends PureComponent {
|
||||||
{
|
{
|
||||||
className: "animation-summary-graph-path",
|
className: "animation-summary-graph-path",
|
||||||
preserveAspectRatio: "none",
|
preserveAspectRatio: "none",
|
||||||
viewBox: `${ startTime } -1 ${ totalDuration } 1`
|
viewBox: `${ startTime } -${ DEFAULT_GRAPH_HEIGHT } `
|
||||||
|
+ `${ totalDuration } ${ DEFAULT_GRAPH_HEIGHT }`,
|
||||||
},
|
},
|
||||||
keyframesList.map(keyframes =>
|
keyframesList.map(keyframes =>
|
||||||
ComputedTimingPath(
|
ComputedTimingPath(
|
||||||
|
@ -176,7 +180,18 @@ class SummaryGraphPath extends PureComponent {
|
||||||
totalDuration,
|
totalDuration,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
),
|
||||||
|
animation.state.easing !== "linear" ?
|
||||||
|
EffectTimingPath(
|
||||||
|
{
|
||||||
|
animation,
|
||||||
|
durationPerPixel,
|
||||||
|
simulateAnimation,
|
||||||
|
totalDuration,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
:
|
||||||
|
null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
DevToolsModules(
|
DevToolsModules(
|
||||||
'ComputedTimingPath.js',
|
'ComputedTimingPath.js',
|
||||||
|
'EffectTimingPath.js',
|
||||||
'SummaryGraph.js',
|
'SummaryGraph.js',
|
||||||
'SummaryGraphPath.js',
|
'SummaryGraphPath.js',
|
||||||
'TimingPath.js'
|
'TimingPath.js'
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
// BOUND_EXCLUDING_TIME should be less than 1ms and is used to exclude start
|
// BOUND_EXCLUDING_TIME should be less than 1ms and is used to exclude start
|
||||||
// and end bounds when dividing duration in createPathSegments.
|
// and end bounds when dividing duration in createPathSegments.
|
||||||
const BOUND_EXCLUDING_TIME = 0.001;
|
const BOUND_EXCLUDING_TIME = 0.001;
|
||||||
|
// We define default graph height since if the height of viewport in SVG is
|
||||||
|
// too small (e.g. 1), vector-effect may not be able to calculate correctly.
|
||||||
|
const DEFAULT_GRAPH_HEIGHT = 100;
|
||||||
// DEFAULT_MIN_PROGRESS_THRESHOLD shoud be between more than 0 to 1.
|
// DEFAULT_MIN_PROGRESS_THRESHOLD shoud be between more than 0 to 1.
|
||||||
const DEFAULT_MIN_PROGRESS_THRESHOLD = 0.1;
|
const DEFAULT_MIN_PROGRESS_THRESHOLD = 0.1;
|
||||||
// In the createPathSegments function, an animation duration is divided by
|
// In the createPathSegments function, an animation duration is divided by
|
||||||
|
@ -14,8 +17,8 @@ const DEFAULT_MIN_PROGRESS_THRESHOLD = 0.1;
|
||||||
// But depending on the timing-function, we may be not able to make the graph
|
// But depending on the timing-function, we may be not able to make the graph
|
||||||
// smoothly progress if this resolution is not high enough.
|
// smoothly progress if this resolution is not high enough.
|
||||||
// So, if the difference of animation progress between 2 divisions is more than
|
// So, if the difference of animation progress between 2 divisions is more than
|
||||||
// DEFAULT_MIN_PROGRESS_THRESHOLD, then createPathSegments re-divides
|
// DEFAULT_MIN_PROGRESS_THRESHOLD * DEFAULT_GRAPH_HEIGHT, then createPathSegments
|
||||||
// by DURATION_RESOLUTION.
|
// re-divides by DURATION_RESOLUTION.
|
||||||
// DURATION_RESOLUTION shoud be integer and more than 2.
|
// DURATION_RESOLUTION shoud be integer and more than 2.
|
||||||
const DURATION_RESOLUTION = 4;
|
const DURATION_RESOLUTION = 4;
|
||||||
|
|
||||||
|
@ -45,7 +48,8 @@ class SummaryGraphHelper {
|
||||||
getValueFunc, toPathStringFunc) {
|
getValueFunc, toPathStringFunc) {
|
||||||
this.totalDuration = totalDuration;
|
this.totalDuration = totalDuration;
|
||||||
this.minSegmentDuration = minSegmentDuration;
|
this.minSegmentDuration = minSegmentDuration;
|
||||||
this.minProgressThreshold = getPreferredProgressThreshold(state, keyframes);
|
this.minProgressThreshold =
|
||||||
|
getPreferredProgressThreshold(state, keyframes) * DEFAULT_GRAPH_HEIGHT;
|
||||||
this.durationResolution = getPreferredDurationResolution(keyframes);
|
this.durationResolution = getPreferredDurationResolution(keyframes);
|
||||||
this.getValue = getValueFunc;
|
this.getValue = getValueFunc;
|
||||||
this.toPathString = toPathStringFunc;
|
this.toPathString = toPathStringFunc;
|
||||||
|
@ -79,7 +83,7 @@ class SummaryGraphHelper {
|
||||||
*/
|
*/
|
||||||
getSegment(time) {
|
getSegment(time) {
|
||||||
const value = this.getValue(time);
|
const value = this.getValue(time);
|
||||||
return { x: time, y: value };
|
return { x: time, y: value * DEFAULT_GRAPH_HEIGHT };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,5 +239,6 @@ function toPathString(segments) {
|
||||||
return pathString;
|
return pathString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports.DEFAULT_GRAPH_HEIGHT = DEFAULT_GRAPH_HEIGHT;
|
||||||
exports.SummaryGraphHelper = SummaryGraphHelper;
|
exports.SummaryGraphHelper = SummaryGraphHelper;
|
||||||
exports.toPathString = toPathString;
|
exports.toPathString = toPathString;
|
||||||
|
|
|
@ -58,14 +58,17 @@
|
||||||
|
|
||||||
.animation-item.cssanimation {
|
.animation-item.cssanimation {
|
||||||
--computed-timing-graph-color: var(--theme-contrast-background);
|
--computed-timing-graph-color: var(--theme-contrast-background);
|
||||||
|
--effect-timing-graph-color: var(--theme-highlight-lightorange);
|
||||||
}
|
}
|
||||||
|
|
||||||
.animation-item.csstransition {
|
.animation-item.csstransition {
|
||||||
--computed-timing-graph-color: var(--theme-highlight-blue);
|
--computed-timing-graph-color: var(--theme-highlight-blue);
|
||||||
|
--effect-timing-graph-color: var(--theme-highlight-bluegrey);
|
||||||
}
|
}
|
||||||
|
|
||||||
.animation-item.scriptanimation {
|
.animation-item.scriptanimation {
|
||||||
--computed-timing-graph-color: var(--theme-graphs-green);
|
--computed-timing-graph-color: var(--theme-graphs-green);
|
||||||
|
--effect-timing-graph-color: var(--theme-highlight-green);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Animation Target */
|
/* Animation Target */
|
||||||
|
@ -103,6 +106,18 @@
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.animation-effect-timing-path path {
|
||||||
|
fill: none;
|
||||||
|
stroke: var(--effect-timing-graph-color);
|
||||||
|
stroke-dasharray: 2px 2px;
|
||||||
|
transform: scale(1, -1);
|
||||||
|
vector-effect: non-scaling-stroke;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animation-effect-timing-path path.infinity:nth-child(n+2) {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
/* No Animation Panel */
|
/* No Animation Panel */
|
||||||
.animation-error-message {
|
.animation-error-message {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче