注:
事实证明,这个问题在CSS中有点难解决。如果您真的需要这样一个复杂的转换,其中新的转换应该应用到以前的状态,那么可以尝试其他方法。
解释
transform
财产,像这样
transform: "rotateX(90deg) rotateY(90deg)"
正如@ihazkode所建议的那样,
rotate3d
就是要走的路。它允许绕任意轴旋转,而不限于X、Y和Z轴。
接受3个参数
rotate3d(x, y, z, angle).
x、y和z指定旋转轴。看待它的方式是这样的:想象一下从
(x,y,z)
transform-origin
您指定了。这条线将是旋转轴。现在想象一下你在看
朝着
从…起
。从该视图中,对象将旋转
顺时针方向的
通过
angle
度。
然而,我仍然面临一个问题。虽然
旋转3d
matrix3d
所有物基本上,每次mousedown和mousemove事件发生时,我都会遵循这些步骤
-
我将根据mousedown发生的位置和mousemove中的当前鼠标位置计算一个向量。例如,如果mousedown发生在(123145)处,然后mousemove发生在(120143)处,则可以从这两点生成向量[x,y,z,m],其中
x是x分量,它是新的x位置减去鼠标按下的x位置=120-123=-3
z=0,因为鼠标无法在z方向上移动
2.
+y
2.
因此,鼠标移动可以表示为向量[-3,-2,0,3.606]
-
现在请注意,立方体的旋转矢量应垂直于鼠标移动。例如,如果我将鼠标笔直向上移动3个像素,则鼠标移动向量为[0,-1,0,3](y为负,因为在浏览器中,左上角是原点)。但是如果我用这个向量作为旋转向量,把它传递到
旋转3d
,即围绕y轴顺时针旋转立方体(从上面看)。但那是不对的!如果我向上滑动鼠标,它应该绕x轴旋转!要解决这个问题,只需交换x和y并对新的x求反。也就是说,向量应该是[1,0,0,3]。因此,步骤1中的向量应为[2,-3,0,3.606]。
使改变
transform: "rotate3d(2,-3,0,3.606)"
所以现在,我想出了如何根据鼠标移动正确旋转立方体,而不必面对之前的问题
rotateX
rotateY
-
现在立方体可以正确旋转了。但是如果我放开鼠标,然后再次执行鼠标下移并尝试旋转立方体,会怎么样。如果我遵循上面相同的步骤,会发生的是我传递到的新向量
旋转3d
从…起
要做到这一点,我需要
新旋转到上一个旋转上。所以我可以这样做
transform: "rotate3d(previous_rotation_vector) rotate3d(new_rotation_vector)"
毕竟,这将执行第一个旋转,然后在此基础上执行第二个旋转。但是,想象一下执行100个旋转。这个
使改变
房产需要100英镑
s、 这不是最好的解决方法。
使改变
类节点的css属性
$('.cube').css('transform');
matrix2d(...)
)如果只执行了2D变换,或者3D变换矩阵(看起来像
matrix3d(...)
否则
transform: "matrix3d(saved_matrix_from_last_rotation) rotate3d(new_rotation_vector)"
这将首先将立方体转换为其最后一个旋转状态,然后在其上应用新的旋转。不需要通过100分
旋转3d
s
-
我发现了最后一个问题。还有一个相同的问题,物体的轴随着物体旋转。
假设我将立方体沿x轴旋转90度
transform: rotate3d(1,0,0,90deg);
然后从那里绕y轴旋转45度
transform: matrix3d(saved values) rotate3d(0,1,0,45deg)
旋转3d
允许您围绕任意旋转轴旋转对象,该任意轴仍然参照对象的轴,并且
通过相对于用户的固定x、y和z轴。这和轴旋转的问题是一样的
对象。
因此,如果立方体当前处于某种旋转状态,我希望它在步骤1和2中通过鼠标获得的向量(x,y,z)上进一步旋转,我首先需要将该向量转换为
x
y
z
angle
矩阵3d
矩阵作为4x4矩阵,然后如果我将3D变换矩阵乘以旋转向量,我得到旧的旋转向量,但转换为
位置现在我可以在3d矩阵之后应用这个向量,如步骤3所示,最后立方体的行为完全符合它应该的方式。
JavaScript代码
var lastX; //stores x position from mousedown
var lastY; //y position from mousedown
var matrix3d = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]] //this identity matrix performs no transformation
$(document).ready(function() {
$('body').on('mousedown', function(event) {
$('body').on('mouseup', function() {
$('body').off('mousemove');
m = $('.cube').css('transform');
//if this condition is true, transform property is either "none" in initial state or "matrix2d" which happens when the cube is at 0 rotation.
if(m.match(/matrix3d/) == null)
matrix3d = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; //identity matrix for no transformaion
else
matrix3d = stringToMatrix(m.substring(8,m.length));
});
lastX=event.pageX;
lastY=event.pageY;
$('body').on('mousemove', function (event) {
var x = -(event.pageY - lastY);
var y = event.pageX - lastX;
var angle = Math.sqrt(x*x + y*y);
var r = [[x],[y],[0],[angle]]; //rotation vector
rotate3d = multiply(matrix3d, r); //multiply to get correctly transformed rotation vector
var str = 'matrix3d' + matrixToString(matrix3d)
+ ' rotate3d(' + rotate3d[0][0] + ', ' + rotate3d[1][0] + ', ' + rotate3d[2][0] + ', ' + rotate3d[3][0] + 'deg)';
$('.cube').css('transform',str);
});
});
});
//converts transform matrix to a string of all elements separated by commas and enclosed in parentheses.
function matrixToString(matrix) {
var s = "(";
for(i=0; i<matrix.length; i++) {
for(j=0; j<matrix[i].length; j++) {
s+=matrix[i][j];
if(i<matrix.length-1 || j<matrix[i].length-1) s+=", ";
}
}
return s+")";
}
//converts a string of transform matrix into a matrix
function stringToMatrix(s) {
array=s.substring(1,s.length-1).split(", ");
return [array.slice(0,4), array.slice(4,8), array.slice(8,12), array.slice(12,16)];
}
//matrix multiplication
function multiply(a, b) {
var aNumRows = a.length, aNumCols = a[0].length,
bNumRows = b.length, bNumCols = b[0].length,
m = new Array(aNumRows); // initialize array of rows
for (var r = 0; r < aNumRows; ++r) {
m[r] = new Array(bNumCols); // initialize the current row
for (var c = 0; c < bNumCols; ++c) {
m[r][c] = 0; // initialize the current cell
for (var i = 0; i < aNumCols; ++i) {
m[r][c] += a[r][i] * b[i][c];
}
}
}
return m;
}