2017-01-11 18 views
9

CSSアニメーションを使用して、scaleZ()のプロパティとtranslateZ()のdivのアニメーションを実行する必要があります。matrix3dの値で初期のキーフレームを使用すると、CSSアニメーションが正しく動作しない

transformプロパティのアニメーションの最初と最後のキーフレーム値は、同様の "形式" である場合、次のコードが正常に動作:

  • 0%transform: rotateY(-179deg) scaleZ(2) translateZ(200px);
  • 100%transform: rotateY(179deg) scaleZ(2) translateZ(200px);
あります

 console.clear(); 
 
     document.addEventListener('DOMContentLoaded',() => { 
 
      let content1 = document.querySelector('#content1'); 
 
      var computedTransform = window.getComputedStyle(content1).transform; 
 
      console.log(computedTransform); 
 

 
     });
 @-webkit-keyframes animation { 
 
      0% { 
 
       /*works*/ 
 
       -webkit-transform: rotateY(-179deg) scaleZ(2) translateZ(200px); 
 
         transform: rotateY(-179deg) scaleZ(2) translateZ(200px); 
 
       /*issue*/ 
 
       /*transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);*/ 
 
      } 
 

 

 
      100% { 
 
       -webkit-transform: rotateY(179deg) scaleZ(2) translateZ(200px); 
 
         transform: rotateY(179deg) scaleZ(2) translateZ(200px); 
 
      } 
 
     } 
 

 
     @keyframes animation { 
 
      0% { 
 
       /*works*/ 
 
       -webkit-transform: rotateY(-179deg) scaleZ(2) translateZ(200px); 
 
         transform: rotateY(-179deg) scaleZ(2) translateZ(200px); 
 
       /*issue*/ 
 
       /*transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);*/ 
 
      } 
 

 

 
      100% { 
 
       -webkit-transform: rotateY(179deg) scaleZ(2) translateZ(200px); 
 
         transform: rotateY(179deg) scaleZ(2) translateZ(200px); 
 
      } 
 
     } 
 

 
     #content1 { 
 
      -webkit-animation: animation 2s; 
 
        animation: animation 2s; 
 
      -webkit-animation-fill-mode: forwards; 
 
        animation-fill-mode: forwards; 
 
      /*works*/ 
 
      -webkit-transform: rotateY(-179deg) scaleZ(2) translateZ(200px); 
 
        transform: rotateY(-179deg) scaleZ(2) translateZ(200px); 
 
      /*issue*/ 
 
      /*transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);*/ 
 
     }
<div id="wrapper1" style="position:fixed; top: 100px; left:300px; perspective: 1000px; width: 250px; height:250px; border: dotted 1px blue"> 
 
     <div id="content1" style="width: 250px; height:250px; background-color:lightsalmon; opacity:0.2;"> 
 
     </div> 
 
    </div>


matrix3Dアニメーション正しく動作しませんWindow.getComputedStyle()から返される0%書かれたキーフレームのためtransformと同じアニメーション:

  • 0%transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1);
  • 100%transform: rotateY(179deg) scaleZ(2) translateZ(200px);
  • あります

 console.clear(); 
 
     document.addEventListener('DOMContentLoaded',() => { 
 
      let content1 = document.querySelector('#content1'); 
 
      var computedTransform = window.getComputedStyle(content1).transform; 
 
      console.log(computedTransform); 
 

 
     });
@-webkit-keyframes animation { 
 
      0% { 
 
       /*works*/ 
 
       /*transform: rotateY(-179deg) scaleZ(2) translateZ(200px);*/ 
 
       /*issue*/ 
 
       -webkit-transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1); 
 
         transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1); 
 
      } 
 

 

 
      100% { 
 
       -webkit-transform: rotateY(179deg) scaleZ(2) translateZ(200px); 
 
         transform: rotateY(179deg) scaleZ(2) translateZ(200px); 
 
      } 
 
     } 
 

 
     @keyframes animation { 
 
      0% { 
 
       /*works*/ 
 
       /*transform: rotateY(-179deg) scaleZ(2) translateZ(200px);*/ 
 
       /*issue*/ 
 
       -webkit-transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1); 
 
         transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1); 
 
      } 
 

 

 
      100% { 
 
       -webkit-transform: rotateY(179deg) scaleZ(2) translateZ(200px); 
 
         transform: rotateY(179deg) scaleZ(2) translateZ(200px); 
 
      } 
 
     } 
 

 
     #content1 { 
 
      -webkit-animation: animation 2s; 
 
        animation: animation 2s; 
 
      -webkit-animation-fill-mode: forwards; 
 
        animation-fill-mode: forwards; 
 
      /*works*/ 
 
      /*transform: rotateY(-179deg) scaleZ(2) translateZ(200px);*/ 
 
      /*issue*/ 
 
      -webkit-transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1); 
 
        transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1); 
 
     }
<div id="wrapper1" style="position:fixed; top: 100px; left:300px; perspective: 1000px; width: 250px; height:250px; border: dotted 1px blue"> 
 
     <div id="content1" style="width: 250px; height:250px; background-color:lightsalmon; opacity:0.2;"> 
 
     </div> 
 
    </div>
私は transformationの値が適切に利用できる場合 Window.getComputedStyle()または別の関数を使用して、DOMに計算されたスタイルから返されたキーフレームを0%として使用する必要がある技術的な理由

私の質問:

  1. は、第二の例バギーのための私のコードですか?
  2. 計算された値をDOMから取得する別の方法を提案できますか?
  3. Window.getComputedStyle()から返された値に関連するバグを知っていますか?
  4. CSSアニメーションのバグとtransformの別の "表記法"について知っていますか?

注:この問題は、最新のChrome(55.0.2883.87 m)とFireFox(50.1.0)で表示されます。

すべてのソリューションやアイデアを歓迎します。


EDIT:

私は、さらなる調査のために(Chromeの)いくつかの新しい例を作成しました。

値が代わりによって取られる所望の効果 https://jsbin.com/bodaxefake/edit?html,output

を予想通り

は基本的に2つの例では、「表記」のいずれかのタイプの変換を使用

from rotateY(20deg) to rotateY(90deg)

作品回転します計算されたCSSスタイルで、matrix3dを使ってアニメーションに再適用すると、アニメーションにはわずかな歪みがあります。

代わりに私はWindow.getComputedStyle()からmatrix3dを理解するのと全く同じ結果が同じ値を返すはずのアニメーションを再現することを期待しています。

不正な効果が https://jsbin.com/luhikahexi/edit?html,output

答えて

5

あなたの問題は、ポイント番号4である。しかし、それはそれはがやりたいあなたに何をすべきかを把握しよう複雑なアルゴリズム、本当にバグではありません。

アニメーションを回転(0deg)から回転(360deg)に移動させる場合、2つの行列がまったく同じであると思ったことはありますか?初期状態のみが指定されている場合、アニメーションは存在しません。

アニメーションをあなたのやり方に設定すると、アルゴリズムは何をすべきか分かりません。したがって、その動作は期待したものではありません。しかし、私はこれがバグだとは言いません。

私はあなたが望むことをするアニメーションを設定しました。トリックは、マトリックスを一定のままにして、最初のローテーションを追加し、元の状態を維持するために、これとは逆の回転を追加します。

このスニペットは少し拡張されているので、私はWebkitプレフィックスを削除しました。 (一方で、でも本当に、今日必要)

console.clear(); 
 
document.addEventListener('DOMContentLoaded',() => { 
 
    let content1 = document.querySelector('#content1'); 
 
    var computedTransform = window.getComputedStyle(content1).transform; 
 
    console.log(computedTransform); 
 

 
});
@keyframes animation { 
 
    0% { 
 
    transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1); 
 
    } 
 
    0.1% { 
 
    transform: rotateY(-179deg) rotateY(179deg) matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1); 
 
    } 
 
    100% { 
 
    transform: rotateY(179deg) rotateY(179deg) matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1); 
 
    } 
 
} 
 
#content1 { 
 
    animation: animation 2s; 
 
    animation-fill-mode: forwards; 
 
    transform: matrix3d(-0.999848, 0, 0.0174524, 0, 0, 1, 0, 0, -0.0349048, 0, -1.9997, 0, -6.98096, 0, -399.939, 1); 
 
}
<div id="wrapper1" style="position:fixed; top: 100px; left:300px; perspective: 1000px; width: 250px; height:250px; border: dotted 1px blue"> 
 
    <div id="content1" style="width: 250px; height:250px; background-color:lightsalmon; opacity:0.2;"> 
 
    </div> 
 
</div>

本当の問題は、それを再構築するために、アニメーションの最初と最後の点で十分な情報がないということです。変換の行列には、一連の個々の変換で与える情報がありません。

スニペット(2D)を参照してください。開始状態と終了状態は同じで、アニメーションはありません。 3Dで、さらによりposibilitiesは変換関数として開始および終了キーフレームの両方が記載されていないように、変換関数間 数値補間はない仕様https://www.w3.org/TR/css-transforms-1/

へ従って

.test { 
 
    width: 50px; 
 
    height: 50px; 
 
    position: absolute; 
 
    top: 400px; 
 
    left: 100px; 
 
} 
 
#one { 
 
    background-color: lightgreen; 
 
    transform: translateX(200px); 
 
    animation: tr1 6s infinite; 
 
} 
 
@keyframes tr1 { 
 
    0% { 
 
    transform: rotate(0deg) translateX(200px) 
 
    } 
 
    33%, 
 
    100% { 
 
    transform: rotate(-90deg) translateX(200px) 
 
    } 
 
} 
 
#two { 
 
    background-color: lightblue; 
 
    transform: translate(200px, 0px); 
 
    animation: tr2 6s infinite; 
 
} 
 
@keyframes tr2 { 
 
    0%, 33% { 
 
    transform: translate(200px, 0px) rotate(0deg) 
 
    } 
 
    66%, 
 
    100% { 
 
    transform: translate(0px, -200px) rotate(-90deg) 
 
    } 
 
} 
 
#three { 
 
    background-color: tomato; 
 
    transform: translate(200px, -200px) rotate(0deg) translateY(200px); 
 
    animation: tr3 6s infinite; 
 
} 
 
@keyframes tr3 { 
 
    0%, 66% { 
 
    transform: translate(200px, -200px) rotate(0deg) translateY(200px) rotate(0deg); 
 
    } 
 
    100% { 
 
    transform: translate(200px, -200px) rotate(-270deg) translateY(200px) rotate(180deg); 
 
    } 
 
}
<div class="test" id="one">1</div> 
 
<div class="test" id="two">2</div> 
 
<div class="test" id="three">3</div>

+0

は、あなたはこれを達成することが可能であると思いますか?この問題にお時間をいただきありがとうございます。 – GibboK

+1

360degの違いは無関係です(e-16)。これは、degからradに変換するときの単なる丸め誤差です。他の問題については、私は試してみますが、DOMから値を取得して、2つのローテーションの前に追加することができます。 – vals

+0

私は計算された値に0%を得るためにちょっとした工夫をしましたが、もしあなたのコメントがありがとうと – vals

0

あります(補間変換の最後の規則https://www.w3.org/TR/css-transforms-1/#interpolation-of-transformsで説明されているように)マトリックス補間を使用する代わりに、可能なブラウザとブラウザが必要です。

マトリクス補間中に、ターン数に関するいくつかの情報が失われ、アニメーションが期待される動作と異なる動作をする可能性があります。

ウェブアニメーションのAPIを使用したデモンストレーション(最新クローム): - キーフレームスタートのために0 に回転Zを設定 - キーフレームスタートのためには、360または350 に回転Zを設定する - ボタンのアニメーションをクリックします。

アニメーションがターン情報を失います。

この動作は、開始キーフレームと終了キーフレームの両方が変換関数として記述されていても、順序または引数の数が異なる場合にも発生することに注意してください。私はキーフレームで0%が計算されたDOMスタイルによってのみ返されたソリューションを必要とするポイント3について

(function() { 
 
      let data = { 
 
       translateX: { 
 
        type: 'range', 
 
        unit: 'px', 
 
        min: -200, 
 
        max: 200, 
 
        steps: 400, 
 
        value: { 
 
         start: 0, 
 
         end: 0 
 
        } 
 
       }, 
 
       translateY: { 
 
        type: 'range', 
 
        unit: 'px', 
 
        min: -200, 
 
        max: 200, 
 
        steps: 400, 
 
        value: { 
 
         start: 0, 
 
         end: 0 
 
        } 
 
       }, 
 
       translateZ: { 
 
        type: 'range', 
 
        unit: 'px', 
 
        min: -200, 
 
        max: 200, 
 
        steps: 400, 
 
        value: { 
 
         start: 0, 
 
         end: 0 
 
        } 
 
       }, 
 
       scaleX: { 
 
        type: 'range', 
 
        unit: '', 
 
        min: -3, 
 
        max: 3, 
 
        steps: 6, 
 
        value: { 
 
         start: 1, 
 
         end: 1 
 
        } 
 
       }, 
 
       scaleY: { 
 
        type: 'range', 
 
        unit: '', 
 
        min: -3, 
 
        max: 3, 
 
        steps: 6, 
 
        value: { 
 
         start: 1, 
 
         end: 1 
 
        } 
 
       }, 
 
       scaleZ: { 
 
        type: 'range', 
 
        unit: '', 
 
        min: -3, 
 
        max: 3, 
 
        steps: 6, 
 
        value: { 
 
         start: 1, 
 
         end: 1 
 
        } 
 
       }, 
 
       rotateX: { 
 
        type: 'range', 
 
        unit: 'deg', 
 
        min: -180, 
 
        max: 180, 
 
        steps: 360, 
 
        value: { 
 
         start: 0, 
 
         end: 0 
 
        } 
 
       }, 
 
       rotateY: { 
 
        type: 'range', 
 
        unit: 'deg', 
 
        min: -180, 
 
        max: 180, 
 
        steps: 360, 
 
        value: { 
 
         start: 0, 
 
         end: 0 
 
        } 
 
       }, 
 
       rotateZ: { 
 
        type: 'range', 
 
        unit: 'deg', 
 
        min: 0, 
 
        max: 360, 
 
        steps: 360, 
 
        value: { 
 
         start: 0, 
 
         end: 0 
 
        } 
 
       }, 
 
       skewX: { 
 
        type: 'range', 
 
        unit: 'deg', 
 
        min: 0, 
 
        max: 180, 
 
        steps: 180, 
 
        value: { 
 
         start: 0, 
 
         end: 0 
 
        } 
 
       }, 
 
       skewY: { 
 
        type: 'range', 
 
        unit: 'deg', 
 
        min: 0, 
 
        max: 180, 
 
        steps: 180, 
 
        value: { 
 
         start: 0, 
 
         end: 0 
 
        } 
 
       }, 
 
       perspective: { 
 
        type: 'range', 
 
        unit: 'px', 
 
        min: 200, 
 
        max: 1000, 
 
        steps: 800, 
 
        value: { 
 
         start: 1000, 
 
         end: 1000 
 
        } 
 
       }, 
 
       perspectiveOrigin: { 
 

 
        type: 'text', 
 
        unit: '', 
 
        value: { 
 
         start: '50% 50%', 
 
         end: '50% 50%' 
 
        } 
 
       } 
 
      }; 
 

 
      let player; 
 

 
      let submitedBy; 
 

 
      let elmForm, 
 
       elmPanelStart, 
 
       elmPanelEnd, 
 
       elmWrapper, 
 
       elmContent, 
 
       elmButtonAnimate, 
 
       elmButtonReset; 
 

 
      let getDoms =() => { 
 
       elmForm = document.querySelector('#form'); 
 
       elmPanelStart = document.querySelector('#panel-start'); 
 
       elmPanelEnd = document.querySelector('#panel-end'); 
 
       elmWrapper = document.querySelector('#wrapper'); 
 
       elmContent = document.querySelector('#content'); 
 
       elmButtonAnimate = document.querySelector('#button-animate'); 
 
       elmButtonReset = document.querySelector('#button-reset'); 
 
      }; 
 

 
      let init =() => { 
 
       getDoms(); 
 
       createUi('start'); 
 
       createUi('end'); 
 
       createUiHandlers('start'); 
 
       createUiHandlers('end'); 
 
       createUiHandlersControls(); 
 
      }; 
 

 
      let createUi = (type) => { 
 
       let html = ''; 
 
       Object.keys(data).forEach((name) => { 
 
        let props = data[name]; 
 
        if (props.type === 'range') { 
 
         html += `<label>${name}<input id="${name}-${type}" type="${props.type}" value="${props.value[type]}" name="${name}" min="${props.min}" max="${props.max}" steps="${props.steps}" ><input id="${name}-${type}-display" type="text" value="${props.value[type]}" name="${name}-${type}-show" readonly><br></label>`; 
 
        } 
 
        if (props.type === 'text') { 
 
         html += `<label>${name}<input id="${name}-${type}" type="${props.type}" value="${props.value[type]}" name="${name}" ></label><br>`; 
 
        } 
 
       }); 
 
       if (type === 'start') { 
 
        elmPanelStart.innerHTML = html; 
 
       } 
 
       if (type === 'end') { 
 
        elmPanelEnd.innerHTML = html; 
 
       } 
 
      }; 
 

 
      let updateDisplay = (type, name, value) => { 
 
       if (name === 'perspectiveOrigin') { 
 
        return; 
 
       } 
 
       let elmDisplay = document.querySelector(`#${name}-${type}-display`); 
 
       elmDisplay.value = value; 
 
      }; 
 

 
      let handler = (type, event) => { 
 
       let name = event.target.name, 
 
        value = event.target.value; 
 
       updateDisplay(type, name, value); 
 
       updateData(type, name, value); // update data 
 
       updateDomTarget(); 
 
      }; 
 
      let updateDomTarget =() => { 
 
       let inline = ''; 
 
       Object.keys(data).forEach((name) => { 
 
        if (name === 'perspective' || name === 'perspectiveOrigin') { 
 
         return; 
 
        } 
 
        let props = data[name]; 
 
        inline += ` ${name}(${props.value.start}${props.unit})`; 
 
       }); 
 
       inline = inline.trim(); 
 
       elmContent.style.transform = inline; 
 

 
       elmWrapper.style.perspective = `${data.perspective.value.start}${data.perspective.unit}`; 
 
       elmWrapper.style.perspectiveOrigin = `${data.perspectiveOrigin.value.start}${data.perspectiveOrigin.unit}`; 
 
      }; 
 

 
      let updateData = (type, name, value) => { 
 
       data[name].value[type] = value; 
 
      }; 
 

 
      let refresh =() => { 
 
       location.reload(); 
 
      }; 
 

 
      let resetPlayer =() => { 
 
       if (player) { 
 
        player.cancel(); 
 
        player = null; 
 
       } 
 
      }; 
 

 
      let logicAnimate =() => { 
 
       resetPlayer(); 
 
       let timing = { 
 
        duration: 1000, 
 
        fill: 'forwards' 
 
       }, 
 
       kfStart = '', 
 
       kfEnd = ''; 
 
       Object.keys(data).forEach((name) => { 
 
        if (name === 'perspective' || name === 'perspectiveOrigin') { 
 
         return; 
 
        } 
 
        let props = data[name]; 
 
        kfStart += ` ${name}(${props.value.start}${props.unit})`; 
 
        kfEnd += ` ${name}(${props.value.end}${props.unit})`; 
 
       }); 
 
       kfStart = kfStart.trim(); 
 
       kfEnd = kfEnd.trim(); 
 
       // change here 
 
       kfStartComputedStyle = window.getComputedStyle(elmContent).transform; 
 
       console.log(kfStartComputedStyle); 
 
       kfStart = { 
 
        transform: kfStartComputedStyle 
 
       }; 
 
       kfEnd = { 
 
        transform: kfEnd 
 
       }; 
 
       elmContent.animate([kfStart, kfEnd], timing); 
 

 
      }; 
 

 
      let createUiHandlers = (type) => { 
 
       Object.keys(data).forEach((name) => { 
 
        let elm = document.querySelector(`#${name}-${type}`); 
 
        elm.addEventListener('change', (event) => { 
 
         handler(type, event); 
 
        }); 
 
       }); 
 
      }; 
 

 
      let createUiHandlersControls = (type) => { 
 
       elmButtonAnimate.addEventListener('click', (event) => { 
 
        logicAnimate(); 
 
       }); 
 

 
       elmButtonReset.addEventListener('click', (event) => { 
 
        refresh(); 
 
       }); 
 
      }; 
 
      document.addEventListener('DOMContentLoaded',() => { 
 
       init(); 
 
      }); 
 
     })();
h1 { 
 
      font-size: 15px; 
 
     } 
 

 
     #content { 
 
      width: 150px; 
 
      height: 200px; 
 
      background-color: red; 
 
     } 
 

 
     #panel-start-wrapper { 
 
      position: fixed; 
 
      top: 0; 
 
      right: 0; 
 
      margin: 10px; 
 
     } 
 

 
     #panel-end-wrapper { 
 
      position: fixed; 
 
      top: 420px; 
 
      right: 0; 
 
      margin: 10px; 
 
     } 
 

 
     #panel-controls { 
 
      position: fixed; 
 
      top: 850px; 
 
      right: 0; 
 
      margin: 10px; 
 
     } 
 

 
     label { 
 
      display: block; 
 
     } 
 

 
     input[type=text] { 
 
      width: 50px; 
 
     }
<div id="wrapper" style="position:absolute; perspective: 500px; top:10%; left:10%;"> 
 
     <div id="content"> 
 
      Hello world! 
 
     </div> 
 
    </div> 
 
    <form id="form"> 
 
     <div id="panel-start-wrapper"> 
 
      <h1>Keyframe Start</h1> 
 
      <div id="panel-start"> 
 
      </div> 
 
     </div> 
 
     <div id="panel-end-wrapper"> 
 
      <h1>Keyframe End</h1> 
 
      <div id="panel-end"> 
 
      </div> 
 
     </div> 
 
     <div id="panel-controls"> 
 
      <button id="button-animate" type="button">Animate</button> 
 
      <button id="button-reset" type="button">Reset</button> 
 
     </div> 
 
    </form>

+0

私は正しい方向(+1)を指してくれてありがとうございます。 – GibboK

関連する問題