Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Translation of time to keyframe animation percentages

I'm working on an animation and I'm trying to understand how keyframes fit into it.

I want to show an element for 3 seconds, fade out for 1 second, wait for 3 seconds, fade in for 1 second, be visible for 3 seconds. So a total of 8 seconds (3 + 1 + 3 + 1).

I don't know how to write that as keyframes. I have alternate set in my animation since it's using percentages. Here is what I have so far:

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>
like image 299
1.21 gigawatts Avatar asked Jan 30 '26 18:01

1.21 gigawatts


2 Answers

If I understand your question correctly, then this can be achieved via the following key frame set:

@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; 
  }
}

The comments show how the percentages for different key frames are calculated based on your requirements. The other key change to make is to remove the alternate behaviour from your animation rule, to ensure the animation cycle repeats in a consistent fashion as required:

/* remove alternate */
animation: fadein 8s linear 0s infinite;

Here's a stripped down copy of your code to isolate the animated circle:

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>
like image 81
Dacre Denny Avatar answered Feb 02 '26 07:02

Dacre Denny


If your total length is 8s, and you just need to translate that to percentages the math is pretty simple: 100/8=12.5

So, your keyframes would come in at:

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%
like image 40
Frederick Brummer Avatar answered Feb 02 '26 06:02

Frederick Brummer