前言
如今css3d全景已经运用到各方各面,比较好玩的一个例子就是淘宝造物节的3d例子,这个看起来还是蛮酷炫的,其实原理并不是很复杂就是利用了css3d。
css3d知识
transform属性应用于元素的2D或3D转换。这个属性允许你将元素旋转,缩放,移动,倾斜等transform-origin属性允许您更改转换元素的位置。2D转换元素可以改变元素的X和Y轴。 3D转换元素,还可以更改元素的Z轴(transform-origin: x-axis y-axis z-axis;)translate(x,y)沿着 X 和 Y 轴移动元素translateY(n)沿着 X 轴移动元素translateY(n)沿着 Y 轴移动元素translateZ(n)沿着 Z 轴移动元素scale(x,y)定义 2D 缩放, 改变元素的宽度和高度scale3d(x,y,z)定义 3D 缩放scaleX(x)scaleY(y)scaleZ(z)对应所在轴的缩放rotate3d(x,y,z,angle)3D 旋转rotateX(angle)沿 X 轴的 3D 旋转。rotateY(angle)沿 Y 轴的 3D 旋转。rotateZ(angle)沿 Z 轴的 3D 旋转。perspective(n)属性定义 3D 元素距视图的距离,以像素计。该属性允许您改变 3D 元素查看 3D 元素的视图。当为元素定义perspective属性时,其子元素会获得透视效果,而不是元素本身。perspective属性只影响 3D 转换元素。可以简单的理解为视距,用来设置用户和元素3D空间Z平面之间的距离。而其效应由他的值来决定,值越小,用户与3D空间Z平面距离越近,视觉效果更令人印象深刻;反之,值越大,用户与3D空间Z平面距离越远,视觉效果就很小。perspective-origin属性是3D变形中另一个重要属性,主要用来决定perspective属性的源点角度。它实际上设置了X轴和Y轴位置(或者说基点),在该位置观看者好像在观看该元素的子元素。
实战淘宝造物节demo
实现简介
首先我们需要找一张全景图,然后等分分成多分,越多分组成的圆越越平滑。把各个图片分配到div,首先通过旋转div的Y轴,旋转后再在Z轴进行位移就可以组成一个类似圆筒,然后通过调节视距和源点来调节最佳角度,最后使用js监听触摸事件来移动盒子最终实现3d的效果。
拼接的计算公式如下
图1 html代码
<div id="container" class="container">
<div id='box'>
<div>0</div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
<div>14</div>
<div>15</div>
<div>16</div>
<div>17</div>
<div>18</div>
<div>19</div>
</div>
</div>
css代码
.container{
margin: 0 auto 0 auto;
width: 8.0625rem;
perspective: 25rem;/*视距*/
}
#box{
-webkit-transform-style: preserve-3d;/*表示所有子元素在3D空间中呈现*/
height: 100%;
-webkit-perspective-origin: 50% 50%;/*源点角度*/
}
#box > div{
position: absolute;
width: 8.0625rem;
height: 73.125rem;
}
js代码
var container = document.getElementById('container');
var box = document.getElementById('box');//获取盒子
var arr = box.getElementsByTagName('div');//获取需要拼接的div
var radius = calculateRadius(129, 20);//计算Z轴需要的位移
for (var i = 0; i < arr.length; i++) {//给div赋值 背景图片
arr[i].style.background = 'url("./img/p' + (i + 1) + '.png") no-repeat';
arr[i].style.WebkitTransform = "rotateY(" + 360 / arr.length * i + 'deg) translatez(' + radius + 'px)';
}
/**
* 通过三角函数计算出距离
* @param {素材宽度} length
* @param {素材总数} totalNum
*/
function calculateRadius(length, totalNum) {
return Math.round(length / (2 * Math.tan(Math.PI / totalNum))) - 3;
}
var startX = 0,//开始时的坐标
x = 0,//旋转的差值
endX = 0;//手离开时候的坐标
var flag = true;//区分 手触摸 还是 陀螺仪
//手开始触碰时的监听
$('#box').on('touchstart', function(event) {
event.preventDefault();
var touch = event.targetTouches[0];//触碰的范围会返回很多坐标点 取第一个即可
startX = touch.pageX - x;//记录手开始触碰时的 X坐标,由于我们是左右移动只要记录X就行了
})
//手移动时的监听
$('#box').on('touchmove', function(event) {
if (flag) {
event.preventDefault();
var touch = event.targetTouches[0];
endX = touch.pageX;
x = endX - startX;//在移动中 用 endX与startX相减就得到 差值,box旋转差值即可
box.style.transform = 'rotateY(' + x + 'deg)';
} else {
return false;
}
})
//手离开屏幕时的监听
$('#box').on('touchend', function(event) {
console.log("over");
});
window.addEventListener('deviceorientation', function(event) {
var gamma = event.gamma;
if (Math.abs(gamma) > 1) {
flag = false;
box.style.transform = 'rotateY(' + gamma * 3 + 'deg)';
} else {
flag = true;
}
})