如何在点击时正确旋转立方体?

时间:2018-04-18 16:02:36

标签: javascript html css rotation cube

所以我正在尝试的是基本上通过点击位于立方体上或浮在它旁边的按钮来旋转立方体。现在我让它们保持浮动状态,因为我经常试用它,这样就更容易了,但将它们放在立方体上根本不会有任何问题。

实际问题是并非所有旋转轴似乎都被平等对待。我的意思是,如果我沿X旋转,Y轴和Z轴也会旋转。但是,如果我沿Y(或Z)旋转,Z轴(或Y轴)旋转但X轴始终保持相同。 在我的代码中,这意味着无论多维数据集如何旋转,通过单击红色方块“3”或“4”触发的沿X轴的旋转将始终向上或向下旋转立方体,而其他按钮旋转立方体根据其位置。 不要介意数字1,2,5和6被切换。这是我能找到的最接近解决方案但是随机旋转立方体一段时间迟早会导致奇怪的移动。

我的代码:

var rotationX = 0;
var rotationY = 0;
var rotationZ = 0;
var rotation = 0;
var translate = 0;

function showDebug() {
    var deBugInfo = '<p>X: '+rotationX + '</p>';
    deBugInfo += '<p>Y: '+rotationY + '</p>';
    deBugInfo += '<p>Z: '+rotationZ + '</p>';
    
    $('#deBug').html(deBugInfo);
}

function cubeRotate() {
    $('#cube').css('transform', 'rotateX('+rotationX+'deg) rotateY('+rotationY+'deg) rotateZ('+rotationZ+'deg)');
    
    showDebug();
}

/*

function buttonsRotate() {
    $('#buttons').css('transform', 'rotate('+rotation+'deg) translate('+0+')');
    
    showDebug();
}

*/

$(function () {

    $('#dir1').on('click', function () {
        //var myStyle = $('#cube').css('transform');
        //console.log(myStyle);
        //rotationY = rotationY - 90;
        rotationY -= 90;
        cubeRotate();
    });
    
    $('#dir2').on('click', function () {
        rotationY += 90;
        cubeRotate();
    });
    
    $('#dir3').on('click', function () {
        rotationX -= 90;
        cubeRotate();
        rotation -= 90;
//        buttonsRotate();
    });
    
    $('#dir4').on('click', function () {
        rotationX += 90;
        cubeRotate();
        rotation += 90;
//        buttonsRotate();
    });
   
    $('#dir5').on('click', function () {
        rotationZ += 90;
        cubeRotate();
    });
    
    $('#dir6').on('click', function () {
        rotationZ -= 90;
        cubeRotate();
    });

});
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-size: 16px;
    font-family: sans-serif;
    width: 100%;
    height: 100%;
    position: absolute;
    -webkit-perspective: 100vmax;
    /* Safari 4-8 */
    -webkit-perspective-origin: 50% 50%;
    /* Safari 4-8 */
    perspective: 100vmax;
    perspective-origin: 50% 50%;
    overflow: hidden;
}

#cube {
    margin: auto;
    position: absolute;
    top: 50%;
    left: 50%;
    transform-style: preserve-3d;
    transition-duration: 0.5s;
}

.cubeface {
    position: absolute;
    height: 60vmin;
    width: 60vmin;
    margin-left: -30vmin;
    margin-top: -30vmin;
    opacity: 0.5;
}

.cubeface:nth-child(1) {
    transform: rotateY(0deg) translateY(0px) translateZ(30vmin);
    background-color: black;
}

.cubeface:nth-child(2) {
    transform: rotateY(90deg) translateY(0px) translateZ(30vmin);
    background-color: #343434;
}

.cubeface:nth-child(3) {
    transform: rotateY(180deg) translateY(0px) translateZ(30vmin);
    background-color: #525252;
}

.cubeface:nth-child(4) {
    transform: rotateY(270deg) translateY(0px) translateZ(30vmin);
    background-color: #818181;
}

.cubeface:nth-child(5) {
    transform: rotateX(90deg) translateZ(30vmin) translateY(0px);
    background-color: #a0a0a0;
}

.cubeface:nth-child(6) {
    transform: rotateX(-90deg) translateZ(30vmin) translateY(0px);
    background-color: #d8d8d8;
}


.content {
    width: 100%;
    height: 100%;
    position: absolute;
    border-radius: 50%;
    background-color: #a7ff8d;

    color: #f00;
    font-size: 3em;
}

.arrow {
    margin: auto;
    position: absolute;
    left: 50%;
    top: 90vmin;
    width: 5vmin;
    height: 5vmin;

    margin-left: -2.5vmin;
    margin-top: -2.5vmin;

}

.achse {
    height: 2px;
    width: 65vmin;
    background: #f00;
    position: absolute;
    top: 0;
    left: 0;
    transform-origin: 0;
    backface-visibility: visible;
    transform-style: preserve-3d;
}

.achseY {
    background: #0f0;
    transform: rotateZ(-90deg) rotateX(45deg);
}

.achseZ {
    background: #00f;
    transform: rotateY(-90deg) rotateX(45deg);
}

.achseX {
    transform: rotateX(45deg);
}

#deBug {
    background: #000;
    color: #FFF;
    font-size: 2em;
    padding: 1em;
    position: absolute;
    top: 0;
    right: 0;

}

#buttons {
    width: 100%;
    height: 100%;
    z-index: 5;
}

#dir1 {
    margin-left: -27.5vmin;
    background-color: red;
    z-index: 5;

}

#dir2 {
    margin-left: -17.5vmin;
    background-color: red;
    z-index: 5;

}

#dir3 {
    margin-left: -7.5vmin;
    background-color: red;
    z-index: 10;

}

#dir4 {
    margin-left: 2.5vmin;
    background-color: red;
    z-index: 10;

}

#dir5 {
    margin-left: 12.5vmin;
    background-color: red;
    z-index: 5;

}

#dir6 {
    margin-left: 22.5vmin;
    background-color: red;
    z-index: 5;

}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!doctype html>
<html>

<head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">

    <title>Test</title>

    <link rel="stylesheet" href="styles/screen.css">

    <script src="scripts/jquery-3.3.1.min.js"></script>
    <script src="scripts/app.js"></script>

</head>

<body>

    <div id="deBug">

    </div>

    <div class='arrow' id='dir3'>X-</div>
    <div class='arrow' id='dir4'>X+</div>

    <div id="buttons">

        <div class='arrow' id='dir1'>Y-</div>
        <div class='arrow' id='dir2'>Y+</div>
        <div class='arrow' id='dir5'>Z+</div>
        <div class='arrow' id='dir6'>Z-</div>

    </div>

    <div id="cube">

        <div class="cubeface" id="A">

            <div class="content" id="main">

                <p>A</p>

            </div>


            <div class="dir1 right">

            </div>

            <div class="dir2 left">

            </div>

            <div class="dir3 up">

            </div>

            <div class="dir4 down">

            </div>


        </div>

        <div class="cubeface" id="B">

            <div class="content" id="">

                <p>B</p>

            </div>


            <div class="dir1 right">

            </div>

            <div class="dir2 left">

            </div>

            <div class="dir5 up">

            </div>

            <div class="dir6 down">

            </div>


        </div>

        <div class="cubeface" id="C">

            <div class="content" id="">

                <p>C</p>

            </div>


            <div class="dir1 right">

            </div>

            <div class="dir2 left">

            </div>

            <div class="dir4 up">

            </div>

            <div class="dir3 down">

            </div>


        </div>

        <div class="cubeface" id="D">

            <div class="content" id="">

                <p>D</p>

            </div>


            <div class="dir1 right">

            </div>

            <div class="dir2 left">

            </div>

            <div class="dir6 up">

            </div>

            <div class="dir5 down">

            </div>


        </div>

        <div class="cubeface" id="E">

            <div class="content" id="">

                <p>E</p>

            </div>



            <div class="dir6 right">

            </div>

            <div class="dir5 left">

            </div>

            <div class="dir3 up">

            </div>

            <div class="dir4 down">

            </div>


        </div>

        <div class="cubeface" id="F">

            <div class="content" id="">

                <p>F</p>

            </div>


            <div class="dir5 right">

            </div>

            <div class="dir6 left">

            </div>

            <div class="dir3 up">

            </div>

            <div class="dir4 down">

            </div>


        </div>

        <div class="achse achseX"></div>
        <div class="achse achseY"></div>
        <div class="achse achseZ"></div>

    </div>

</body>

</html>

我尝试过给每一个元素“transform-style:preserve-3d”。没工作。 我认为它实际上可以更好地使用立方体上的按钮,但这是一个需要在以后回答的问题,而不是这里的主题。

如果有人知道如何让所有人受到平等对待,请告诉我,我对这个立方体感到很生气:D

谢谢!

编辑:

2018_04_18: 还与设置转换起源无关。

2018_04_19: 更新了代码段,以便按钮不再旋转但已修复,因此您始终可以单击它们。

2018_04_20:

我发现了两个可能有用的笔码示例(它们都是用鼠标拖动多维数据集,我不确定这是否与问题有关)......

  1. https://codepen.io/jordizle/pen/haIdo/ 这个立方体有一个很好的方面,侧面自动旋转,以便它们可以正确读取。但是,如果将它旋转到第1或第6侧,它会显示与我的立方体相同的问题,因为它不会向左或向右旋转。

  2. https://codepen.io/ge1doot/pen/PqZKbv 在这个例子中,问题似乎得到了解决。无论立方体的位置如何,您都可以随时向各个方向旋转。 (但我不需要分割它的功能) 我的问题是我无法真正看出他们使用的抄写器之间有什么区别,因此我不知道为什么第二个抄写完美但我觉得这是正确的轨道。如果有人可以比较它们并解决这个谜,那将是非常好的;)

2 个答案:

答案 0 :(得分:1)

您的问题是由称为Euler Order的问题引起的。基本上,轴是按照什么顺序来计算最终旋转的。

最常见的CSS变换是Euler顺序:X,Y,Z。

首先计算X轴,因此它始终停留在其静止位置。您不能在CSS中更改欧拉顺序。即使可以,欧拉阶的第一个轴也将始终被“不平等地对待”。

欧拉旋转的另一个问题是万向节锁。单击X,单击Y,然后单击演示中的Z。现在尝试旋转X和Z。它们是相同的!您刚刚遇到了Gimbal Lock,它很难解决,而且无法仅通过CSS进行修复。

答案 1 :(得分:1)

相对旋转-立方体旋转轴

function rotate(axis, degrees) {
    cube.outerHTML = `<div class='gimbal' id='container' style="transition: all 0.5s; transform-style: preserve-3d; transform: rotate${axis}(0deg); position: relative; transition-timing-function: ease-in-out; width: 0; height: 0; transform-origin: 50vw 50vh;">${cube.outerHTML}</div>`;
    window.setTimeout(function () {
        container.style.transform = `rotate${axis}(${degrees}deg)`;
        container.removeAttribute('id');
    }, 10);
}
$('#dir1').on('click', function () {
    rotate('Y', '90');
});

$('#dir2').on('click', function () {
    rotate('Y', '-90');
});

$('#dir3').on('click', function () {
    rotate('X', '90');
});

$('#dir4').on('click', function () {
    rotate('X', '-90');
});

$('#dir5').on('click', function () {
    rotate('Z', '90');
});

$('#dir6').on('click', function () {
    rotate('Z', '-90');
});
rotate('X', '0');
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html, body {
    font-size: 16px;
    font-family: sans-serif;
    width: 100%;
    height: 100%;
    -webkit-perspective: 100vmax;
    /* Safari 4-8 */
    -webkit-perspective-origin: 50% 50%;
    /* Safari 4-8 */
    perspective: 100vmax;
    perspective-origin: 50% 50%;
    overflow: hidden;
}

#cube {
    margin: auto;
    position: absolute;
    top: 50vh; left: 50vw;
    transform-style: preserve-3d;
}

.cubeface {
    position: absolute;
    height: 60vmin;
    width: 60vmin;
    margin-left: -30vmin;
    margin-top: -30vmin;
    opacity: 0.5;
}

.cubeface:nth-child(1) {
    transform: rotateY(0deg) translateY(0px) translateZ(30vmin);
    background-color: black;
}

.cubeface:nth-child(2) {
    transform: rotateY(90deg) translateY(0px) translateZ(30vmin);
    background-color: #343434;
}

.cubeface:nth-child(3) {
    transform: rotateY(180deg) translateY(0px) translateZ(30vmin);
    background-color: #525252;
}

.cubeface:nth-child(4) {
    transform: rotateY(270deg) translateY(0px) translateZ(30vmin);
    background-color: #818181;
}

.cubeface:nth-child(5) {
    transform: rotateX(90deg) translateZ(30vmin) translateY(0px);
    background-color: #a0a0a0;
}

.cubeface:nth-child(6) {
    transform: rotateX(-90deg) translateZ(30vmin) translateY(0px);
    background-color: #d8d8d8;
}


.content {
    width: 100%;
    height: 100%;
    position: absolute;
    border-radius: 50%;
    background-color: #a7ff8d;

    color: #f00;
    font-size: 3em;
}

.arrow {
    margin: auto;
    position: absolute;
    left: 50%;
    top: 90vmin;
    width: 5vmin;
    height: 5vmin;

    margin-left: -2.5vmin;
    margin-top: -2.5vmin;

}

.achse {
    height: 2px;
    width: 65vmin;
    background: #f00;
    position: absolute;
    top: 0;
    left: 0;
    transform-origin: 0;
    backface-visibility: visible;
    transform-style: preserve-3d;
}

.achseY {
    background: #0f0;
    transform: rotateZ(-90deg) rotateX(45deg);
}

.achseZ {
    background: #00f;
    transform: rotateY(-90deg) rotateX(45deg);
}

.achseX {
    transform: rotateX(45deg);
}

#deBug {
    background: #000;
    color: #FFF;
    font-size: 2em;
    padding: 1em;
    position: absolute;
    top: 0;
    right: 0;

}

#buttons {
    width: 100%;
    height: 100%;
    z-index: 5;
}

#dir1 {
    margin-left: -27.5vmin;
    background-color: red;
    z-index: 5;

}

#dir2 {
    margin-left: -17.5vmin;
    background-color: red;
    z-index: 5;

}

#dir3 {
    margin-left: -7.5vmin;
    background-color: red;
    z-index: 10;

}

#dir4 {
    margin-left: 2.5vmin;
    background-color: red;
    z-index: 10;

}

#dir5 {
    margin-left: 12.5vmin;
    background-color: red;
    z-index: 5;

}

#dir6 {
    margin-left: 22.5vmin;
    background-color: red;
    z-index: 5;

}
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">

        <title>Test</title>

        <link rel="stylesheet" href="styles/screen.css">

        <script src="scripts/jquery-3.3.1.min.js"></script>
        <script src="scripts/app.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    </head>

    <body>

        <div id="cube" class="gimbal">

            <div class="cubeface" id="A">

                <div class="content" id="main">

                    <p>A</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>

            <div class="cubeface" id="B">

                <div class="content" id="">

                    <p>B</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir5 up">

                </div>

                <div class="dir6 down">

                </div>


            </div>

            <div class="cubeface" id="C">

                <div class="content" id="">

                    <p>C</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir4 up">

                </div>

                <div class="dir3 down">

                </div>


            </div>

            <div class="cubeface" id="D">

                <div class="content" id="">

                    <p>D</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir6 up">

                </div>

                <div class="dir5 down">

                </div>


            </div>

            <div class="cubeface" id="E">

                <div class="content" id="">

                    <p>E</p>

                </div>



                <div class="dir6 right">

                </div>

                <div class="dir5 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>

            <div class="cubeface" id="F">

                <div class="content" id="">

                    <p>F</p>

                </div>


                <div class="dir5 right">

                </div>

                <div class="dir6 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>
        </div>
        
        <div id="buttons">
            <div class='arrow' id='dir1'>Y+</div>
            <div class='arrow' id='dir2'>Y-</div>
            <div class='arrow' id='dir3'>X+</div>
            <div class='arrow' id='dir4'>X-</div>
            <div class='arrow' id='dir5'>Z+</div>
            <div class='arrow' id='dir6'>Z-</div>
        </div>
    </body>
</html>


全球旋转-轴不随立方体旋转

function rotate(axis, degrees) {
    let outermostRotator = $('body > .gimbal').get(0);
    outermostRotator.outerHTML = `<div class='gimbal' id='container' style="transition: all 0.5s; transform-style: preserve-3d; transform: rotate${axis}(0deg); position: relative; transition-timing-function: ease-in-out; width: 0; height: 0; transform-origin: 50vw 50vh;">${outermostRotator.outerHTML}</div>`;
    window.setTimeout(function () {
        container.style.transform = `rotate${axis}(${degrees}deg)`;
        container.removeAttribute('id');
    }, 10);
}
$('#dir1').on('click', function () {
    rotate('Y', '90');
});

$('#dir2').on('click', function () {
    rotate('Y', '-90');
});

$('#dir3').on('click', function () {
    rotate('X', '90');
});

$('#dir4').on('click', function () {
    rotate('X', '-90');
});

$('#dir5').on('click', function () {
    rotate('Z', '90');
});

$('#dir6').on('click', function () {
    rotate('Z', '-90');
});
rotate('X', '0');
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html, body {
    font-size: 16px;
    font-family: sans-serif;
    width: 100%;
    height: 100%;
    -webkit-perspective: 100vmax;
    /* Safari 4-8 */
    -webkit-perspective-origin: 50% 50%;
    /* Safari 4-8 */
    perspective: 100vmax;
    perspective-origin: 50% 50%;
    overflow: hidden;
}

#cube {
    margin: auto;
    position: absolute;
    top: 50vh; left: 50vw;
    transform-style: preserve-3d;
}

.cubeface {
    position: absolute;
    height: 60vmin;
    width: 60vmin;
    margin-left: -30vmin;
    margin-top: -30vmin;
    opacity: 0.5;
}

.cubeface:nth-child(1) {
    transform: rotateY(0deg) translateY(0px) translateZ(30vmin);
    background-color: black;
}

.cubeface:nth-child(2) {
    transform: rotateY(90deg) translateY(0px) translateZ(30vmin);
    background-color: #343434;
}

.cubeface:nth-child(3) {
    transform: rotateY(180deg) translateY(0px) translateZ(30vmin);
    background-color: #525252;
}

.cubeface:nth-child(4) {
    transform: rotateY(270deg) translateY(0px) translateZ(30vmin);
    background-color: #818181;
}

.cubeface:nth-child(5) {
    transform: rotateX(90deg) translateZ(30vmin) translateY(0px);
    background-color: #a0a0a0;
}

.cubeface:nth-child(6) {
    transform: rotateX(-90deg) translateZ(30vmin) translateY(0px);
    background-color: #d8d8d8;
}


.content {
    width: 100%;
    height: 100%;
    position: absolute;
    border-radius: 50%;
    background-color: #a7ff8d;

    color: #f00;
    font-size: 3em;
}

.arrow {
    margin: auto;
    position: absolute;
    left: 50%;
    top: 90vmin;
    width: 5vmin;
    height: 5vmin;

    margin-left: -2.5vmin;
    margin-top: -2.5vmin;

}

.achse {
    height: 2px;
    width: 65vmin;
    background: #f00;
    position: absolute;
    top: 0;
    left: 0;
    transform-origin: 0;
    backface-visibility: visible;
    transform-style: preserve-3d;
}

.achseY {
    background: #0f0;
    transform: rotateZ(-90deg) rotateX(45deg);
}

.achseZ {
    background: #00f;
    transform: rotateY(-90deg) rotateX(45deg);
}

.achseX {
    transform: rotateX(45deg);
}

#deBug {
    background: #000;
    color: #FFF;
    font-size: 2em;
    padding: 1em;
    position: absolute;
    top: 0;
    right: 0;

}

#buttons {
    width: 100%;
    height: 100%;
    z-index: 5;
}

#dir1 {
    margin-left: -27.5vmin;
    background-color: red;
    z-index: 5;

}

#dir2 {
    margin-left: -17.5vmin;
    background-color: red;
    z-index: 5;

}

#dir3 {
    margin-left: -7.5vmin;
    background-color: red;
    z-index: 10;

}

#dir4 {
    margin-left: 2.5vmin;
    background-color: red;
    z-index: 10;

}

#dir5 {
    margin-left: 12.5vmin;
    background-color: red;
    z-index: 5;

}

#dir6 {
    margin-left: 22.5vmin;
    background-color: red;
    z-index: 5;

}
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">

        <title>Test</title>

        <link rel="stylesheet" href="styles/screen.css">

        <script src="scripts/jquery-3.3.1.min.js"></script>
        <script src="scripts/app.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    </head>

    <body>

        <div id="cube" class="gimbal">

            <div class="cubeface" id="A">

                <div class="content" id="main">

                    <p>A</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>

            <div class="cubeface" id="B">

                <div class="content" id="">

                    <p>B</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir5 up">

                </div>

                <div class="dir6 down">

                </div>


            </div>

            <div class="cubeface" id="C">

                <div class="content" id="">

                    <p>C</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir4 up">

                </div>

                <div class="dir3 down">

                </div>


            </div>

            <div class="cubeface" id="D">

                <div class="content" id="">

                    <p>D</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir6 up">

                </div>

                <div class="dir5 down">

                </div>


            </div>

            <div class="cubeface" id="E">

                <div class="content" id="">

                    <p>E</p>

                </div>



                <div class="dir6 right">

                </div>

                <div class="dir5 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>

            <div class="cubeface" id="F">

                <div class="content" id="">

                    <p>F</p>

                </div>


                <div class="dir5 right">

                </div>

                <div class="dir6 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>
        </div>
        
        <div id="buttons">
            <div class='arrow' id='dir1'>Y+</div>
            <div class='arrow' id='dir2'>Y-</div>
            <div class='arrow' id='dir3'>X+</div>
            <div class='arrow' id='dir4'>X-</div>
            <div class='arrow' id='dir5'>Z+</div>
            <div class='arrow' id='dir6'>Z-</div>
        </div>
    </body>
</html>