代码之家  ›  专栏  ›  技术社区  ›  1.21 gigawatts

将时间转换为关键帧动画百分比

  •  3
  • 1.21 gigawatts  · 技术社区  · 6 年前

    我正在制作一个动画,我想知道关键帧是如何融入其中的。

    我想显示一个元素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>
    3 回复  |  直到 6 年前
        1
  •  2
  •   1.21 gigawatts    6 年前

    如果我正确理解您的问题,则可以通过以下关键帧集实现:

    @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>
        2
  •  1
  •   Frederick Brummer    6 年前

    如果你的总长度是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%
    
        3
  •  0
  •   1.21 gigawatts    6 年前

    在此处添加@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>