Я работаю над анимацией и пытаюсь понять, как в нее вписываются ключевые кадры.
Я хочу показать элемент в течение 3 секунд, исчезнуть в течение 1 секунды, подождать 3 секунды, исчезнуть в течение 1 секунды, быть видимым в течение 3 секунд. Итого 8 секунд (3 + 1 + 3 + 1).
Я не знаю, как записать это как ключевые кадры. У меня есть альтернативный набор в моей анимации, поскольку он использует проценты. Вот что у меня есть на данный момент:
time = 0;
window.addEventListener("load", function() {
setInterval(function() {
var label = document.getElementById("label");
if (time==0) {
label.innerHTML = ++time;
}
else {
label.innerHTML = ++time;
}
if (time>=8) time = 0;
}, 1000);
})* {
margin: 0;
padding: 0;
font-family:sans-serif;
}
#Icons_A0 {
position: absolute;
box-sizing: border-box;
transform: translateX(-50%) translateY(-50%);
left: 50%;
top: 50%;
border: 1px solid #A1A1A1;
background: #E5E5E5;
width: 234px;
height: 238px;
background-color: rgba(255,255,255,1);
overflow: hidden;
opacity: 1;
}
#Rectangle_175 {
opacity: 1;
fill: rgba(75,134,193,1);
stroke: rgb(84, 75, 193);
stroke-width: 4px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Rectangle_175 {
position: absolute;
overflow: visible;
width: 134.35028076171875px;
height: 134.3502655029297px;
left: 49.825px;
top: 76.825px;
transform: rotate(45deg);
transform-origin: left;
}
#Ellipse_49 {
opacity: 1;
fill: rgba(180,180,180,1);
stroke: rgb(112, 112, 112);
stroke-width: 1px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Ellipse_49 {
position: absolute;
overflow: visible;
width: 56px;
height: 56px;
left: 72px;
top: 51px;
animation: fadein 8s linear 0s infinite alternate;
}
@keyframes fadein {
0% {
opacity: 1;
}
20% {
opacity: 1;
}
30% {
opacity: 0;
}
60% {
opacity: 0;
}
70% {
opacity: 1;
}
100% {
opacity: 1;
}
}<div id = "Icons_A0">
<svg data-name = "Rectangle 175" data-type = "Rectangle" class = "Rectangle_175">
<rect id = "Rectangle_175" rx = "0" ry = "0" x = "0" y = "0" width = "120" height = "70">
</rect>
</svg>
<svg class = "Ellipse_49">
<ellipse id = "Ellipse_49" rx = "28" ry = "28" cx = "28" cy = "28">
</ellipse>
</svg>
<span id = "label"></span>
</div>


![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Если ваша общая длина составляет 8 секунд, и вам просто нужно перевести это в проценты, математика будет довольно простой: 100/8 = 12,5
Итак, ваши ключевые кадры войдут в:
1 sec : 12.5 * 1 = 12.5%
4 sec : 12.5 * 4 = 50%
7 sec : 12.5 * 7 = 87.5%
8 sec : 12.5 * 8 = 100%
Если я правильно понял ваш вопрос, то этого можно достичь с помощью следующего набора ключевых кадров:
@keyframes fadein {
0% {
opacity: 1;
}
37.5% {
/* 3 / 8 */
opacity: 1;
}
50% {
/* (3 + 1) / 8 */
opacity: 0.0;
}
87.5% {
/* (3 + 1 + 3) / 8 */
opacity: 0.0;
}
100% {
opacity: 1;
}
}
В комментариях показано, как рассчитываются проценты для различных ключевых кадров в соответствии с вашими требованиями. Другое ключевое изменение, которое необходимо сделать, - удалить поведение alternate из правила анимации, чтобы цикл анимации повторялся согласованно, как требуется:
/* remove alternate */
animation: fadein 8s linear 0s infinite;
Вот урезанная копия вашего кода, чтобы изолировать анимированный круг:
function animationListener(event) {
var type = event.type;
var label = type;
if (type= = "animationiteration") {
if (app.interval!=null) {
clearInterval(app.interval);
}
app.time = 0;
app.startTime = new Date().getTime();
app.interval = setInterval(intervalFunction, 1000);
intervalFunction();
label = "iteration";
}
else if (type= = "animationstart") {
label = "start";
}
else if (type= = "animationend") {
label = "end";
}
app.stateLabel.innerHTML = label;
}
function intervalFunction() {
var time = new Date().getTime();
app.timeLabel.innerHTML = Math.round((time - app.startTime)/1000);
app.keyframeLabel.innerHTML = window.getComputedStyle(app.ellipse).content;
}
function loadHandler() {
app.ellipse = document.getElementById("Ellipse_49").parentNode;
app.stateLabel = document.getElementById("stateLabel");
app.timeLabel = document.getElementById("timeLabel");
app.keyframeLabel = document.getElementById("keyframeLabel");
app.ellipse.addEventListener("animationiteration", animationListener);
app.ellipse.addEventListener("animationend", animationListener);
app.ellipse.addEventListener("animationstart", animationListener);
}
document.addEventListener("DOMContentLoaded", loadHandler);
var app = {};* {
font-family: sans-serif;
font-size: 11px;
letter-spacing: .6px;
}
#Ellipse_49 {
opacity: 1;
fill: rgba(180, 180, 180, 1);
stroke: rgb(112, 112, 112);
stroke-width: 1px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Ellipse_49 {
position: absolute;
overflow: visible;
width: 56px;
height: 56px;
left: 72px;
top: 51px;
/* remove alternate */
animation: fadein 8s linear 0s infinite;
}
#container {
top: 130px;
left: 10px;
position: relative;
display: block;
align-items: center;
}
label {
width: 80px;
display: inline-block;
}
@keyframes fadein {
0% {
opacity: 1;
content: "show";
}
37.5% {
/* 3 / 8 */
opacity: 1;
content: "fade out";
}
50% {
/* (3 + 1) / 8 */
opacity: 0.0;
content: "wait";
}
87.5% {
/* (3 + 1 + 3) / 8 */
opacity: 0.0;
content: "fade in";
}
100% {
opacity: 1;
content: "show";
}
}<svg class = "Ellipse_49">
<ellipse id = "Ellipse_49" rx = "28" ry = "28" cx = "28" cy = "28">
</ellipse>
</svg>
<div id = "container">
<label>time: </label>
<span id = "timeLabel"></span>
<br>
<label>state: </label>
<span id = "stateLabel"></span>
<br>
<label>key frame: </label>
<span id = "keyframeLabel"></span>
</div>Добавление здесь ответа @DacreDenny, чтобы я мог изменить его и добавить примечания.
function animationListener(event) {
var type = event.type;
var label = type;
if (type= = "animationiteration") {
if (app.interval!=null) {
clearInterval(app.interval);
}
app.time = 0;
app.startTime = new Date().getTime();
app.interval = setInterval(intervalFunction, 15);
intervalFunction();
label = "iteration";
}
else if (type= = "animationstart") {
label = "start";
}
else if (type= = "animationend") {
label = "end";
}
app.stateLabel.innerHTML = label;
}
function intervalFunction() {
var currentTime = new Date().getTime();
var time = (currentTime - app.startTime)/1000;
var duration = parseFloat(window.getComputedStyle(app.ellipse).animationDuration);
var maxValue = 100;
var position = ((time * maxValue)/duration);
app.timeLabel.innerHTML = Math.round(time);
app.keyframeLabel.innerHTML = window.getComputedStyle(app.ellipse).content;
app.timelineRange.value = position;
app.positionLabel.innerHTML = Math.round(position) + "%";
}
function loadHandler() {
app.ellipse = document.getElementById("Ellipse_49").parentNode;
app.stateLabel = document.getElementById("stateLabel");
app.timeLabel = document.getElementById("timeLabel");
app.keyframeLabel = document.getElementById("keyframeLabel");
app.timelineRange = document.getElementById("timelineRange");
app.positionLabel = document.getElementById("positionLabel");
app.ellipse.addEventListener("animationiteration", animationListener);
app.ellipse.addEventListener("animationend", animationListener);
app.ellipse.addEventListener("animationstart", animationListener);
}
document.addEventListener("DOMContentLoaded", loadHandler);
var app = {};* {
font-family: sans-serif;
font-size: 11px;
letter-spacing: .6px;
}
@keyframes fadein {
0% {
opacity: 1;
content: "show";
}
37.5% {
/* 3 / 8 */
opacity: 1;
content: "fade out";
}
50% {
/* (3 + 1) / 8 */
opacity: 0.0;
content: "wait";
}
87.5% {
/* (3 + 1 + 3) / 8 */
opacity: 0.0;
content: "fade in";
}
100% {
opacity: 1;
content: "show";
}
}
#Ellipse_49 {
opacity: 1;
fill: rgba(180, 180, 180, 1);
stroke: rgb(112, 112, 112);
stroke-width: 1px;
stroke-linejoin: miter;
stroke-linecap: butt;
stroke-miterlimit: 4;
shape-rendering: auto;
}
.Ellipse_49 {
position: absolute;
overflow: visible;
width: 50px;
height: 50px;
left: 20px;
top: 50px;
/* remove alternate */
animation: fadein 4s linear 0s infinite;
}
#container {
top: 130px;
left: 10px;
position: relative;
display: block;
}
label {
width: 80px;
display: inline-block;
}
input[type=range] {
outline: 0px solid red;
display: block;
width: 90%;
margin-left: 0;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 8.4px;
cursor: pointer;
box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d;
background: rgb(255,255,255);
}<svg class = "Ellipse_49">
<ellipse id = "Ellipse_49" rx = "28" ry = "28" cx = "28" cy = "28">
</ellipse>
</svg>
<div id = "container">
<input id = "timelineRange" type = "range" value = "0" min = "0" max = "100">
<br>
<label>time: </label>
<span id = "timeLabel"></span>
<br>
<label>position: </label>
<span id = "positionLabel"></span>
<br>
<label>state: </label>
<span id = "stateLabel"></span>
<br>
<label>key frame: </label>
<span id = "keyframeLabel"></span>
<br>
<br>
</div>
Я добавил в ваш пример состояние анимации, время воспроизведения анимации и информацию о ключевых кадрах анимации. Кажется, что время совпадает с событиями, но вычисленный ключевой кадр анимации, кажется, указывает на предстоящее событие, которое должно произойти через 1 секунду. Кроме того, он запускается после первой итерации. Примечание. Я нашел здесь пример использования содержимого для хранения заметок по ключевым кадрам jsfiddle.net/z4ytsesh. Не стесняйтесь обновлять его.