zoukankan      html  css  js  c++  java
  • 动态旋转与平滑恢复

    动态旋转与平滑恢复

    需求:使用CSS+JavaScript实现以下Web效果:

    1. 三个DOM元素:一张图片,两个按钮
    2. 点击开始按钮,使图片开始不停旋转(rotate0 -> rotate360)
    3. 点击停止按钮,图片停止旋转,并平滑恢复到初始状态

    小结:

    1. 抽象了函数 getMatrixFromDegree() 和 getDegreeFromMatrix() 用于矩阵和角度间的转换
    2. 需要加深理解 transform 和 matrix 的关系原理

    实现:

    <html>
    <body>
      <div id="target">G</div>
      <button id="play">PLAY</button>
      <button id="pause">PAUSE</button>
      <style>
        body {
          background: #333;
        }
        button {
           200px;
          height: 50px;
          font-size: 30px;
        }
        #target {
           200px;
          height: 200px;
          font-size: 170px;
          line-height: 170px;
          text-align: center;
          border-radius: 50%;
          color: #fff;
          background: lightgreen;
        }
        #target.play {
          animation-name: rotateTarget;
          animation-iteration-count: infinite;
          animation-timing-function: linear;
          animation-duration: 5s;
        }
        @keyframes rotateTarget {
          0%   { transform: rotate(0deg); }
          100% { transform: rotate(360deg); }
        }
        /* 
        由于 transform matrix 控制的角度从 180 迈向 180+ 会发生一个未知的回转现象
        故不采用 matrix 进行角度旋转的控制
        0%    { transform: matrix( 1, 0, 0, 1, 0, 0); }
        25%   { transform: matrix( 0, 1,-1, 0, 0, 0); }
        50%   { transform: matrix(-1, 0, 0,-1, 0, 0); }
        75%   { transform: matrix( 0,-1, 1, 0, 0, 0); }
        100%  { transform: matrix( 1, 0, 0, 1, 0, 0); }
          */
      </style>
      <script>
        const getMatrixFromDegree = (degreeValue) => {
          // transform中Matrix的学习可参考:
          // https://www.zhangxinxu.com/wordpress/2012/06/css3-transform-matrix-矩阵/
          const cosVal = Math.cos( this.value * Math.PI / 180 ).toFixed(6);
          const sinVal = Math.sin( this.value * Math.PI / 180 ).toFixed(6);
          const transform = `matrix(${cosVal},${sinVal},${-1 * sinVal},${cosVal},0,0)`;
          return transform;
        }
        
        const getDegreeFromMatrix = (matrixString) => {
          // degree的精确度参考:https://developer.mozilla.org/en-US/docs/Web/CSS/angle
          const reg     = matrixString.match(/matrix((.*?), (.*?),/);
          const scaleX  = +reg[1];
          const skewY   = +reg[2];
          const degree  = +(Math.acos(scaleX) * 180 / Math.PI).toFixed(2);
          if (skewY > 0) {
            return degree;
          } else {
            return 360 - degree;
          }
        }
    
        const target = document.getElementById('target');
        const play = document.getElementById('play');
        const pause = document.getElementById('pause');
    
        play.onclick = () => {
          target.className = 'play';
        }
        pause.onclick = () => {
          const smoothTime = 0.5; // 平滑恢复一周所用时间
          const currentTransform = window.getComputedStyle(target).getPropertyValue('transform');
    
          const currentDegree = getDegreeFromMatrix(currentTransform);
          const percent = +(currentDegree / 360).toFixed(2);
          const runTime = smoothTime * (1 - percent);
          const getHalfKeyFrame = () => {
            if (currentDegree < 180) {
              const halfPercent = (((0.5 - percent) / (1 - percent)) * 100).toFixed(2);
              return `${halfPercent}% { transform: rotate(180deg); }`;
            } else {
              return '';
            }
          };
    
          const runkeyframes = `
            #target.pause {
              animation-name: resetTargetSmooth;
              animation-timing-function: linear;
              animation-duration: ${runTime}s;
              will-change: auto;
            }
            @keyframes resetTargetSmooth {
              0%          { transform: rotate(${currentDegree}deg); }
              ${getHalfKeyFrame()}
              100%        { transform: rotate(360deg); }
            }`;
    
          const style = document.createElement('style');
          style.type = 'text/css';
          style.innerHTML = runkeyframes;
          document.body.appendChild(style);
    
          target.onanimationend = (e) => { // 动画结束时刻清理
            if (e.animationName === 'resetTargetSmooth') {
              document.body.removeChild(style)
            }
          };
    
          const animationFunc = function () {
            target.className = 'pause';
          }
    
          requestAnimationFrame(animationFunc);
        }
      </script>
    </body>
    </html>
    
  • 相关阅读:
    python面试题目【转1】
    让python和C/C++联姻【转】
    python面试模拟真题讲解
    JavaScript真的要一统江湖了
    WebApp
    Linux服务器之SSH
    web服务之http
    SNMP简单网络管理协议
    Storm,Spark和Samza
    Stream computing
  • 原文地址:https://www.cnblogs.com/hencins/p/14356201.html
Copyright © 2011-2022 走看看