зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1253493 - Part2: Show iterationStart to the GUI. r=pbro
This commit is contained in:
Родитель
459706a9ee
Коммит
a096e3264f
|
@ -57,15 +57,22 @@ AnimationTimeBlock.prototype = {
|
|||
let {x, iterationW, delayX, delayW, negativeDelayW} =
|
||||
TimeScale.getAnimationDimensions(animation);
|
||||
|
||||
// background properties for .iterations element
|
||||
let backgroundIterations = TimeScale.getIterationsBackgroundData(animation);
|
||||
|
||||
createNode({
|
||||
parent: this.containerEl,
|
||||
attributes: {
|
||||
"class": "iterations" + (state.iterationCount ? "" : " infinite"),
|
||||
// Individual iterations are represented by setting the size of the
|
||||
// repeating linear-gradient.
|
||||
// The background-size, background-position, background-repeat represent
|
||||
// iterationCount and iterationStart.
|
||||
"style": `left:${x}%;
|
||||
width:${iterationW}%;
|
||||
background-size:${100 / (state.iterationCount || 1)}% 100%;`
|
||||
background-size:${backgroundIterations.size}% 100%;
|
||||
background-position:${backgroundIterations.position}% 0;
|
||||
background-repeat:${backgroundIterations.repeat};`
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -43,13 +43,19 @@ Keyframes.prototype = {
|
|||
this.propertyName = propertyName;
|
||||
this.animation = animation;
|
||||
|
||||
let iterationStartOffset =
|
||||
animation.state.iterationStart % 1 == 0
|
||||
? 0
|
||||
: 1 - animation.state.iterationStart % 1;
|
||||
|
||||
this.keyframesEl.classList.add(animation.state.type);
|
||||
for (let frame of this.keyframes) {
|
||||
let offset = frame.offset + iterationStartOffset;
|
||||
createNode({
|
||||
parent: this.keyframesEl,
|
||||
attributes: {
|
||||
"class": "frame",
|
||||
"style": `left:${frame.offset * 100}%;`,
|
||||
"style": `left:${offset * 100}%;`,
|
||||
"data-offset": frame.offset,
|
||||
"data-property": propertyName,
|
||||
"title": frame.value
|
||||
|
|
|
@ -4,33 +4,81 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
// Check iteration start.
|
||||
// Check that the iteration start is displayed correctly in time blocks.
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab(URL_ROOT + "doc_script_animation.html");
|
||||
let {panel, controller} = yield openAnimationInspector();
|
||||
let {panel} = yield openAnimationInspector();
|
||||
let timelineComponent = panel.animationsTimelineComponent;
|
||||
let timeBlockComponents = timelineComponent.timeBlocks;
|
||||
let detailsComponents = timelineComponent.details;
|
||||
|
||||
info("Getting the animation element by script");
|
||||
let timelineEl = panel.animationsTimelineComponent.rootWrapperEl;
|
||||
let timeBlockNameEl = timelineEl.querySelector(".time-block .name");
|
||||
for (let i = 0; i < timeBlockComponents.length; i++) {
|
||||
info(`Expand time block ${i} so its keyframes are visible`);
|
||||
yield clickOnAnimation(panel, i);
|
||||
|
||||
let state = controller.animationPlayers[0].state;
|
||||
let title = timeBlockNameEl.getAttribute("title");
|
||||
if (state.iterationStart !== 0) {
|
||||
let iterationStartTime = state.iterationStart * state.duration / 1000;
|
||||
let iterationStartTimeString =
|
||||
iterationStartTime.toLocaleString(undefined,
|
||||
{ maximumFractionDigits: 2,
|
||||
minimumFractionDigits: 2 })
|
||||
.replace(".", "\\.");
|
||||
let iterationStartString =
|
||||
state.iterationStart.toString().replace(".", "\\.");
|
||||
let regex = new RegExp("Iteration start: " + iterationStartString +
|
||||
" \\(" + iterationStartTimeString + "s\\)");
|
||||
ok(title.match(regex), "The tooltip shows the iteration start");
|
||||
} else {
|
||||
ok(!title.match(/Iteration start:/),
|
||||
"The tooltip doesn't show the iteration start");
|
||||
info(`Check the state of time block ${i}`);
|
||||
let {containerEl, animation: {state}} = timeBlockComponents[i];
|
||||
|
||||
checkAnimationTooltip(containerEl, state);
|
||||
checkIterationBackground(containerEl, state);
|
||||
|
||||
// Get the first set of keyframes (there's only one animated property
|
||||
// anyway), and the first frame element from there, we're only interested in
|
||||
// its offset.
|
||||
let keyframeComponent = detailsComponents[i].keyframeComponents[0];
|
||||
let frameEl = keyframeComponent.keyframesEl.querySelector(".frame");
|
||||
checkKeyframeOffset(containerEl, frameEl, state);
|
||||
}
|
||||
});
|
||||
|
||||
function checkAnimationTooltip(el, {iterationStart, duration}) {
|
||||
info("Check an animation's iterationStart data in its tooltip");
|
||||
let title = el.querySelector(".name").getAttribute("title");
|
||||
|
||||
let iterationStartTime = iterationStart * duration / 1000;
|
||||
let iterationStartTimeString = iterationStartTime.toLocaleString(undefined, {
|
||||
maximumFractionDigits: 2,
|
||||
minimumFractionDigits: 2
|
||||
}).replace(".", "\\.");
|
||||
let iterationStartString = iterationStart.toString().replace(".", "\\.");
|
||||
|
||||
let regex = new RegExp("Iteration start: " + iterationStartString +
|
||||
" \\(" + iterationStartTimeString + "s\\)");
|
||||
ok(title.match(regex), "The tooltip shows the expected iteration start");
|
||||
}
|
||||
|
||||
function checkIterationBackground(el, {iterationCount, iterationStart}) {
|
||||
info("Check the background-image used to display iterations is offset " +
|
||||
"correctly to represent the iterationStart");
|
||||
|
||||
let iterationsEl = el.querySelector(".iterations");
|
||||
let start = getIterationStartFromBackground(iterationsEl, iterationCount);
|
||||
is(start, iterationStart % 1,
|
||||
"The right background-position for iteration start");
|
||||
}
|
||||
|
||||
function getIterationStartFromBackground(el, iterationCount) {
|
||||
if (iterationCount == 1) {
|
||||
let size = parseFloat(/([.\d]+)%/.exec(el.style.backgroundSize)[1]);
|
||||
return 1 - size / 100;
|
||||
}
|
||||
|
||||
let size = parseFloat(/([.\d]+)%/.exec(el.style.backgroundSize)[1]);
|
||||
let position = parseFloat(/([-\d]+)%/.exec(el.style.backgroundPosition)[1]);
|
||||
let iterationStartW = -position / size * (100 - size);
|
||||
let rounded = Math.round(iterationStartW * 100);
|
||||
return rounded / 10000;
|
||||
}
|
||||
|
||||
function checkKeyframeOffset(timeBlockEl, frameEl, {iterationStart}) {
|
||||
info("Check that the first keyframe is offset correctly");
|
||||
|
||||
let start = getIterationStartFromLeft(frameEl);
|
||||
is(start, iterationStart % 1, "The frame offset for iteration start");
|
||||
}
|
||||
|
||||
function getIterationStartFromLeft(el) {
|
||||
let left = 100 - parseFloat(/(\d+)%/.exec(el.style.left)[1]);
|
||||
return left / 100;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,19 @@
|
|||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
#target {
|
||||
#target1 {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background: red;
|
||||
}
|
||||
|
||||
#target2 {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background: green;
|
||||
}
|
||||
|
||||
#target3 {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background: blue;
|
||||
|
@ -11,17 +23,33 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target"></div>
|
||||
<div id="target1"></div>
|
||||
<div id="target2"></div>
|
||||
<div id="target3"></div>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
var el = document.getElementById("target");
|
||||
el.animate(
|
||||
[{ opacity: 0 }, { opacity: 1 }],
|
||||
{ duration: 1000,
|
||||
iterationStart: 0.5,
|
||||
fill: "both" }
|
||||
);
|
||||
document.getElementById("target1").animate([{ opacity: 0 }, { opacity: 1 }],
|
||||
{ duration: 100,
|
||||
iterations: 2,
|
||||
iterationStart: 0.25,
|
||||
fill: "both" }
|
||||
);
|
||||
|
||||
document.getElementById("target2").animate([{ opacity: 0 }, { opacity: 1 }],
|
||||
{ duration: 100,
|
||||
iterations: 1,
|
||||
iterationStart: 0.25,
|
||||
fill: "both" }
|
||||
);
|
||||
|
||||
document.getElementById("target3").animate([{ opacity: 0 }, { opacity: 1 }],
|
||||
{ duration: 100,
|
||||
iterations: 1.5,
|
||||
iterationStart: 2.5,
|
||||
fill: "both" }
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -309,6 +309,31 @@ var TimeScale = {
|
|||
let negativeDelayW = delay < 0 ? delayW : 0;
|
||||
|
||||
return {x, w, iterationW, delayX, delayW, negativeDelayW};
|
||||
},
|
||||
|
||||
/**
|
||||
* Given an animation, get the background data for .iterations element.
|
||||
* This background represents iterationCount and iterationStart.
|
||||
* Returns three properties.
|
||||
* 1. size: x of background-size (%)
|
||||
* 2. position: x of background-position (%)
|
||||
* 3. repeat: background-repeat (string)
|
||||
*/
|
||||
getIterationsBackgroundData: function({state}) {
|
||||
let iterationCount = state.iterationCount || 1;
|
||||
let iterationStartW = state.iterationStart % 1 * 100;
|
||||
let background = {};
|
||||
if (iterationCount == 1) {
|
||||
background.size = 100 - iterationStartW;
|
||||
background.position = 0;
|
||||
background.repeat = "no-repeat";
|
||||
} else {
|
||||
background.size = 1 / iterationCount * 100;
|
||||
background.position = -iterationStartW * background.size /
|
||||
(100 - background.size);
|
||||
background.repeat = "repeat-x";
|
||||
}
|
||||
return background;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -330,13 +330,11 @@ body {
|
|||
borders between each iteration. These borders must have the same color as
|
||||
the border of this element */
|
||||
background-image:
|
||||
linear-gradient(to right,
|
||||
linear-gradient(to left,
|
||||
var(--timeline-border-color) 0,
|
||||
var(--timeline-border-color) 1px,
|
||||
transparent 1px,
|
||||
transparent 2px);
|
||||
background-repeat: repeat-x;
|
||||
background-position: -1px 0;
|
||||
border: 1px solid var(--timeline-border-color);
|
||||
/* Border-right is already handled by the gradient */
|
||||
border-width: 1px 0 1px 1px;
|
||||
|
|
Загрузка…
Ссылка в новой задаче