зеркало из 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 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.
|
||||
const MIN_KEYFRAMES_EASING_OPACITY = 0.5;
|
||||
|
||||
|
@ -163,7 +166,8 @@ class SummaryGraphPath extends PureComponent {
|
|||
{
|
||||
className: "animation-summary-graph-path",
|
||||
preserveAspectRatio: "none",
|
||||
viewBox: `${ startTime } -1 ${ totalDuration } 1`
|
||||
viewBox: `${ startTime } -${ DEFAULT_GRAPH_HEIGHT } `
|
||||
+ `${ totalDuration } ${ DEFAULT_GRAPH_HEIGHT }`,
|
||||
},
|
||||
keyframesList.map(keyframes =>
|
||||
ComputedTimingPath(
|
||||
|
@ -176,7 +180,18 @@ class SummaryGraphPath extends PureComponent {
|
|||
totalDuration,
|
||||
}
|
||||
)
|
||||
),
|
||||
animation.state.easing !== "linear" ?
|
||||
EffectTimingPath(
|
||||
{
|
||||
animation,
|
||||
durationPerPixel,
|
||||
simulateAnimation,
|
||||
totalDuration,
|
||||
}
|
||||
)
|
||||
:
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
DevToolsModules(
|
||||
'ComputedTimingPath.js',
|
||||
'EffectTimingPath.js',
|
||||
'SummaryGraph.js',
|
||||
'SummaryGraphPath.js',
|
||||
'TimingPath.js'
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
// BOUND_EXCLUDING_TIME should be less than 1ms and is used to exclude start
|
||||
// and end bounds when dividing duration in createPathSegments.
|
||||
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.
|
||||
const DEFAULT_MIN_PROGRESS_THRESHOLD = 0.1;
|
||||
// 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
|
||||
// smoothly progress if this resolution is not high enough.
|
||||
// So, if the difference of animation progress between 2 divisions is more than
|
||||
// DEFAULT_MIN_PROGRESS_THRESHOLD, then createPathSegments re-divides
|
||||
// by DURATION_RESOLUTION.
|
||||
// DEFAULT_MIN_PROGRESS_THRESHOLD * DEFAULT_GRAPH_HEIGHT, then createPathSegments
|
||||
// re-divides by DURATION_RESOLUTION.
|
||||
// DURATION_RESOLUTION shoud be integer and more than 2.
|
||||
const DURATION_RESOLUTION = 4;
|
||||
|
||||
|
@ -45,7 +48,8 @@ class SummaryGraphHelper {
|
|||
getValueFunc, toPathStringFunc) {
|
||||
this.totalDuration = totalDuration;
|
||||
this.minSegmentDuration = minSegmentDuration;
|
||||
this.minProgressThreshold = getPreferredProgressThreshold(state, keyframes);
|
||||
this.minProgressThreshold =
|
||||
getPreferredProgressThreshold(state, keyframes) * DEFAULT_GRAPH_HEIGHT;
|
||||
this.durationResolution = getPreferredDurationResolution(keyframes);
|
||||
this.getValue = getValueFunc;
|
||||
this.toPathString = toPathStringFunc;
|
||||
|
@ -79,7 +83,7 @@ class SummaryGraphHelper {
|
|||
*/
|
||||
getSegment(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;
|
||||
}
|
||||
|
||||
module.exports.DEFAULT_GRAPH_HEIGHT = DEFAULT_GRAPH_HEIGHT;
|
||||
exports.SummaryGraphHelper = SummaryGraphHelper;
|
||||
exports.toPathString = toPathString;
|
||||
|
|
|
@ -58,14 +58,17 @@
|
|||
|
||||
.animation-item.cssanimation {
|
||||
--computed-timing-graph-color: var(--theme-contrast-background);
|
||||
--effect-timing-graph-color: var(--theme-highlight-lightorange);
|
||||
}
|
||||
|
||||
.animation-item.csstransition {
|
||||
--computed-timing-graph-color: var(--theme-highlight-blue);
|
||||
--effect-timing-graph-color: var(--theme-highlight-bluegrey);
|
||||
}
|
||||
|
||||
.animation-item.scriptanimation {
|
||||
--computed-timing-graph-color: var(--theme-graphs-green);
|
||||
--effect-timing-graph-color: var(--theme-highlight-green);
|
||||
}
|
||||
|
||||
/* Animation Target */
|
||||
|
@ -103,6 +106,18 @@
|
|||
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 */
|
||||
.animation-error-message {
|
||||
overflow: auto;
|
||||
|
|
Загрузка…
Ссылка в новой задаче