質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • JavaScript

    16429questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    6708questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • CSS

    5788questions

    CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

カーソルの動きに合わせて要素を動かす場合の速度の指定方法について

解決済

回答 1

投稿

  • 評価
  • クリップ 2
  • VIEW 735

IGE

score 23

すみません。
無知ながら恐縮なのですが、CSS、JSで以下参考サイトのような、
カーソルと連動して3Dで動くwebを作りたいと思っております。

参考サイト:
https://www.clicktorelease.com/code/css3d-clouds-tutorial/final.html
https://www.clicktorelease.com/blog/how-to-make-clouds-with-css-3d/

ただ、こちらの参考サイトはカーソルの動きに過敏?に反応し、
カーソルを動かせば要素もすぐ動く、といった動作で、
カーソルを動かした時の動きに滑らかさがありません。

これにヌルヌルとして滑らかの動きを付けれれば、、と思っております。

カーソルを動かした時の、要素の動く速度などを調整し、easingなどを付ければいいのかと思うのですが、
どのように書けばよいのでしょうか。。

参考サイトのJSは以下のようになっております。

<script>

    (function() {
        var lastTime = 0;
        var vendors = ['ms', 'moz', 'webkit', 'o'];
        for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
            window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
            window.cancelRequestAnimationFrame = window[vendors[x]+
              'CancelRequestAnimationFrame'];
        }

        if (!window.requestAnimationFrame)
            window.requestAnimationFrame = function(callback, element) {
                var currTime = new Date().getTime();
                var timeToCall = Math.max(0, 16 - (currTime - lastTime));
                var id = window.setTimeout(function() { callback(currTime + timeToCall); },
                  timeToCall);
                lastTime = currTime + timeToCall;
                return id;
            };

        if (!window.cancelAnimationFrame)
            window.cancelAnimationFrame = function(id) {
                clearTimeout(id);
            };
    }())

    var layers = [],
        objects = [],

        world = document.getElementById( 'world' ),
        viewport = document.getElementById( 'viewport' ),

        d = 0,
        p = 400,
        worldXAngle = 0,
        worldYAngle = 0;

    viewport.style.webkitPerspective = p;
    viewport.style.MozPerspective = p;
    viewport.style.oPerspective = p;

    generate();

    function createCloud() {

        var div = document.createElement( 'div'  );
        div.className = 'cloudBase';
        var x = 256 - ( Math.random() * 512 );
        var y = 256 - ( Math.random() * 512 );
        var z = 256 - ( Math.random() * 512 );
        var t = 'translateX( ' + x + 'px ) translateY( ' + y + 'px ) translateZ( ' + z + 'px )';
        div.style.webkitTransform = t;
        div.style.MozTransform = t;
        div.style.oTransform = t;
        world.appendChild( div );

        for( var j = 0; j < 5 + Math.round( Math.random() * 10 ); j++ ) {
            var cloud = document.createElement( 'img' );
            cloud.style.opacity = 0;
            var r = Math.random();
            var src = 'cloud.png';
            ( function( img ) { img.addEventListener( 'load', function() {
                img.style.opacity = .8;
            } ) } )( cloud );
            cloud.setAttribute( 'src', src );
            cloud.className = 'cloudLayer';

            var x = 256 - ( Math.random() * 512 );
            var y = 256 - ( Math.random() * 512 );
            var z = 100 - ( Math.random() * 200 );
            var a = Math.random() * 360;
            var s = .25 + Math.random();
            x *= .2; y *= .2;
            cloud.data = {
                x: x,
                y: y,
                z: z,
                a: a,
                s: s,
                speed: .1 * Math.random()
            };
            var t = 'translateX( ' + x + 'px ) translateY( ' + y + 'px ) translateZ( ' + z + 'px ) rotateZ( ' + a + 'deg ) scale( ' + s + ' )';
            cloud.style.webkitTransform = t;
            cloud.style.MozTransform = t;
            cloud.style.oTransform = t;

            div.appendChild( cloud );
            layers.push( cloud );
        }

        return div;
    }

    window.addEventListener( 'mousewheel', onContainerMouseWheel );
    window.addEventListener( 'DOMMouseScroll', onContainerMouseWheel );
    window.addEventListener( 'mousemove', onMouseMove );
    window.addEventListener( 'touchmove', onMouseMove );

    function onMouseMove ( e ) {

        var x = e.clientX || e.touches[ 0 ].clientX;
        var y = e.clientY || e.touches[ 0 ].clientY;

        worldYAngle = -( .5 - ( x / window.innerWidth ) ) * 180;
        worldXAngle = ( .5 - ( y / window.innerHeight ) ) * 180;
        updateView();
        event.preventDefault();

    }

    function onContainerMouseWheel( event ) {

        event = event ? event : window.event;
        d = d - ( event.detail ? event.detail * -5 : event.wheelDelta / 8 );
        updateView();
        event.preventDefault();

    }

    function generate() {

        objects = [];

        if ( world.hasChildNodes() ) {
            while ( world.childNodes.length >= 1 ) {
                world.removeChild( world.firstChild );
            }
        }

        for( var j = 0; j < 5; j++ ) {
            objects.push( createCloud() );
        }

    }

    function updateView() {
        var t = 'translateZ( ' + d + 'px ) rotateX( ' + worldXAngle + 'deg) rotateY( ' + worldYAngle + 'deg)';
        world.style.webkitTransform = t;
        world.style.MozTransform = t;
        world.style.oTransform = t;
    }

    function update (){

        for( var j = 0; j < layers.length; j++ ) {
            var layer = layers[ j ];
            layer.data.a += layer.data.speed;
            var t = 'translateX( ' + layer.data.x + 'px ) translateY( ' + layer.data.y + 'px ) translateZ( ' + layer.data.z + 'px ) rotateY( ' + ( - worldYAngle ) + 'deg ) rotateX( ' + ( - worldXAngle ) + 'deg ) rotateZ( ' + layer.data.a + 'deg ) scale( ' + layer.data.s + ')';
            layer.style.webkitTransform = t;
            layer.style.MozTransform = t;
            layer.style.oTransform = t;
        }

        requestAnimationFrame( update );

    }

    update();

    </script>

上記コードにどのうように書き足せば思った動きに近づくか、
お教えいただければ幸いです。。

どうぞよろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

上記のサイトの雲の方を拝見させていただきました。

 簡単に仕組み

マウスを移動した場合、現在のポインタの位置と画面の幅・高さを計算して画面を何度回転させるかを計算してcssのtransform: rotate(xdeg, ydeg)に入れます。
マウスをスクロールした場合は、cssのtransform: translateZ(z)に値を入れて画面全体を拡大したり縮小したりします

 コードの中身を見てみる

マウスを動かしたりスクロールしたりすると色々画面が変更されるのでその部分を探してみましょう。
コードの中にマウスを移動したり、スクロールしたりなどのイベントがあります。

window.addEventListener( 'mousewheel', onContainerMouseWheel );
window.addEventListener( 'DOMMouseScroll', onContainerMouseWheel );
window.addEventListener( 'mousemove', onMouseMove );
window.addEventListener( 'touchmove', onMouseMove );

次に、マウスが移動して画面がくるくる回る部分だけにまず注目しましょう。
上記のイベントだとmousemoveが該当するのでonMouseMoveに注目します。

function onMouseMove ( e ) {
  var x = e.clientX || e.touches[ 0 ].clientX;
  var y = e.clientY || e.touches[ 0 ].clientY;

  worldYAngle = -( .5 - ( x / window.innerWidth ) ) * 180;
  worldXAngle = ( .5 - ( y / window.innerHeight ) ) * 180;
  updateView();
  event.preventDefault();
}

e.clientXe.clientYは画面上でのマウスポインターの場所です。
それを色々計算してworldXAngleworldYAngleと言うものを出していますよね?

これで計算された値をupdateView()で反映しているわけです。

function updateView() {
  var t = 'translateZ( ' + d + 'px ) rotateX( ' + worldXAngle + 'deg) rotateY( ' + worldYAngle + 'deg)';
  world.style.webkitTransform = t;
  world.style.MozTransform = t;
  world.style.oTransform = t;
    }


translateZとrotateXとrotateYに、dとworldXAngleとworldYAngleを入れてますよね?

 マウス移動だけに注目して仕組みを見てみる

先ほどのonMouseMoveに戻って、worldXanguleを見るとx/window.innerWidthというものを計算しています。
windowの横幅が1000pxと仮定し、画面の横幅の真ん中にマウスを持ってきたとしましょう。
その場合のworldXAngleは0度になります。

worldXAngle = -( .5 - ( x / window.innerWidth ) ) * 180;
↓
worldXAngle = -( .5 - ( 500 / 1000 ) ) * 180;
↓
worldXAngle = -( .5 - 0.5 ) * 180;
↓
worldXAngle = 0;

同様に、画面の左端(0px)と右端(1000px)は

// 0pxの場合
worldXAngle = -(.5 * 180); //-90deg

// 1000pxの場合
worldXAngle = -(-0.5 * 180); //90deg

これはy軸も同様です。
これからわかることは、実はこの雲は180度しか回っていません。
360度が1回転なので、0.5回転で反転(日本語あってるかな?)しかしてません。

つまり、画面をどう動かしても*半分しか回転しない*ということです。
なのでクルクルの速度は画面が小さい早くなり、画面が大きいとマウスを動かす量が大きくなるのでゆっくり回るということです。

 結論

ただ、こちらの参考サイトはカーソルの動きに過敏?に反応し、カーソルを動かせば要素もすぐ動く、といった動作で、カーソルを動かした時の動きに滑らかさがありません。
>これにヌルヌルとして滑らかの動きを付けれれば、、と思っております。

長くなってしまいましたが、質問者様がおっしゃっていることを満たすのあれば、方法は2つです。

 画面を大きくする

これは冗談というかユーザーの環境に大きく影響するので実現不可能だと思います。
ただ、仕組み的には画面が大きい&マウスの移動距離が大きくなるのでゆっくり回ると思います。
1つの可能性として捉えてください(笑)

 回転率計算の部分の式をいじる

これは結構現実的です。
マウスの場所のx座標を実際の値より小さくする or 回転するmax値(下の例で言うと180)を小さくする方法です。

function onMouseMove ( e ) {
  var x = e.clientX || e.touches[ 0 ].clientX; //ここをいじる or 
  var y = e.clientY || e.touches[ 0 ].clientY;

  worldYAngle = -( .5 - ( x / window.innerWidth ) ) * 180; // ここをいじる
  worldXAngle = ( .5 - ( y / window.innerHeight ) ) * 180;
  updateView();
  event.preventDefault();
}

 x座標の値をいじる

function onMouseMove ( e ) {
  var x = (e.clientX || e.touches[ 0 ].clientX) / 2; //実際の場所の半分
  var y = (e.clientY || e.touches[ 0 ].clientY) / 2; //実際の場所の半分

  worldYAngle = -( .5 - ( x / window.innerWidth ) ) * 180; //当然算出される角度も半分に
  worldXAngle = ( .5 - ( y / window.innerHeight ) ) * 180; //当然算出される角度も半分に
  updateView();
  event.preventDefault();
}

 回転の幅をいじる

function onMouseMove ( e ) {
  var x = e.clientX || e.touches[ 0 ].clientX;
  var y = e.clientY || e.touches[ 0 ].clientY;

  worldYAngle = -( .5 - ( x / window.innerWidth ) ) * 90; //回転のmax幅を半分にする
  worldXAngle = ( .5 - ( y / window.innerHeight ) ) * 90; //回転のmax幅を半分にする
  updateView();
  event.preventDefault();
}

 デメリット

ただ、上記の方法にはもちろんデメリットも有り、それは見える範囲が狭くなってしまうという点です。
まぁ画面というインターフェースしかない以上しょうがない気もしますが。。。

 まとめ

すごく長くなってしまいましたが、説明したとおりです。
仕組み等を理解していただけるとうれしいです!

失礼しました!

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/16 23:23

    とても詳しいご回答ありがとうございます!!何度も見返し勉強させていただきたいと思います。ありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.51%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • JavaScript

    16429questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    6708questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • CSS

    5788questions

    CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。