码迷,mamicode.com
首页 > 其他好文 > 详细

径向动画

时间:2018-04-20 23:47:25      阅读:228      评论:0      收藏:0      [点我收藏+]

标签:this   alt   math   oct   nim   位置   开始   sandbox   ini   

IMOOC 数学在css中的应用

一、径向动画菜单

代码:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>径向动画菜单</title>
	<style type="text/css">
		* {
			margin: 0;
			padding: 0;
		}
		body {
			background-color: #292a38;
			font-family: "Microsoft Yahei";
		}
		h1 {
			margin-top: 20px;
			text-align: center;
		  	color: #fff;
		}

		.nav-wrap {
		  	position: relative;
		  	width: 200px;
			height: 200px;
			margin: 50px auto;
			border: 2px dotted #4e5061;
			border-radius: 50%;
		}
		.nav-wrap .main-nav {
			position: absolute;
			left: 50%;
			top: 50%;
			transform: translate(-50%,-50%);
			width: 40px;
			height: 40px;
			line-height: 40px;
			font-size: 12px;
			text-align: center;
			text-decoration: none;
			color: #fff;
			border-radius: 3px;
			text-shadow: 1px 1px 0px #000;
			background: #15a5f3;
			cursor: pointer;
		}
		.nav-wrap nav {
			position: absolute;
			width: 100%;
			height: 100%;
			transform: scale(0) rotate(0);
			transition: all 0.5s ease-out;
			opacity: 0;
		}
		.nav-wrap.active nav {
			transform: scale(1) rotate(360deg);
			opacity: 1;
		}
		.nav-wrap nav > a{
			position: absolute;
			width: 30px;
			height: 30px;
			background: #f44283;
			text-align: center;
			line-height: 30px;
			text-decoration: none;
			color: #fff;
			border-radius: 3px;
			text-shadow: 1px 1px 0px #000;
			transform: translate(-50%,-50%) rotateY(0deg);/*rotateY不能省,省了就不行了*/
		}
		-webkit-@keyframes rotate{
			100% {transform:translate(-50%,-50%) rotateY(360deg);}
		} 
		@keyframes rotate{
			100% {transform:translate(-50%,-50%) rotateY(360deg);}
		} 
	</style>
</head>
<body>
	<h1>径向动画菜单效果分步演示</h1>
	<div class="nav-wrap">
		<nav>
			<a class="nav-item">1</a>
			<a class="nav-item">2</a>
			<a class="nav-item">3</a>
			<a class="nav-item">4</a>
			<a class="nav-item">5</a>
			<a class="nav-item">6</a>
			<a class="nav-item">7</a>
			<a class="nav-item">8</a>
		</nav>
		<a class="main-nav">点我</a>
	</div>

</body>
<script src="http://s0.qhimg.com/lib/jquery/183.js" ></script>
<script type="text/javascript">
	(function(){

		// 当菜单没被激活时
		var isLocated = false;

		$(‘.nav-wrap‘).on(‘click‘,‘.main-nav‘,function(e){
			e.preventDefault();

			var me = $(this),
				  navWrap = me.closest(‘.nav-wrap‘), // 动画效果的父容器
				  navs = navWrap.find(‘nav a‘); // 父容器中的所有子菜单
			
			if(!navWrap.hasClass(‘active‘) && !isLocated){

				// 圆的半径 raduis
				var width = navWrap.width(),
					  radius = width / 2;

				// 圆形菜单的起始、终止角度
				var startAngle = 0,
					  endAngle = 360;

				// 两个子菜单间的夹角 gap
				var total = navs.length,
					  gap = (endAngle - startAngle)/total;

				// 角度->弧度
				var radian = Math.PI / 180;


				/*
				 * 计算并确定各个子菜单的最终位置
				 */
				$.each(navs, function(index, item){

					// 当前子菜单与x轴正向的夹角 θ (角度->弧度)
					var myAngle = (startAngle + gap*index) * radian;  // θ

					// 计算当前子菜单相对于左上角(0,0)的坐标 (x,y)
					var myX = radius + radius * Math.cos( myAngle ), // x=r+rcos(θ)
						  myY = radius + radius * Math.sin( myAngle ); // y=r+rsin(θ)
				
					// 设置当前子菜单的位置 (left,top) = (x,y)
					$(this).css({
		                    left: myX + ‘px‘,
		                    top:  myY + ‘px‘,
							webkitAnimation: "rotate 10s linear 1s infinite",
							animation: "rotate 5s linear 1s infinite",
		           });
						 
		    });

				isLocated = true;
			}

			navWrap.toggleClass(‘active‘);
		});

	})();
</script>
</html>  

  效果:

原理:

        动画是卡片从圆心开始平均散开到圆的相应位置,如下图,假设卡片就是圆上某一点,其运动轨迹与x轴的夹角为θ,则该点的相对于容器的坐标为(r+rcosθ,r+rsinθ)。则其相对于容器的left和top分别为其x和y坐标的值这样,通过脚本设置卡片的left和top和容器position改为relative就可以实现平均分布了。然后通过给容器添加transition和transform:scale(0)给容器加上过渡动画和缩小到0在其父元素中心(即圆心),这样一开始就看不到卡片(不过已经在容器的边上了),点击按钮时容器加上scale(1),容器从圆心扩展到原来大小,由于卡片在容器边上,卡片随着容器的扩展,好像跟着慢慢运动到圆的边上。给容器加上rotate(0deg)到rotate(360deg)可以实现卡片边“运动”边“旋转”的效果。 

      技术分享图片

         在这里回顾一下涉及到的数学知识:

             1.在直角三角形中,夹角θ所对的边,边长为斜边 * sinθ;相邻的边为斜边 * cosθ。上图θ是圆上某一点与圆心的连线(半径)与x轴的夹角。

             2.弧度制与度数的换算: 1deg = π / 180弧度(randian)

             3.将x个点平均放在一个长为y的线上,将线划分为x-1段,从端点(也算)开始每隔y / (x-1)长度放一个点,即可平均放置。

             4.将x个点平均反正一个循环路线上(如圆),将线划分为x段,从端点(也算)开始每隔y / x长度放一个点,即可平均放置。

      所以,如果只想实现半圆效果,就用到第三个数学知识,应该把度数划分为total-1份而不是现在的total份,即把(endAngle-startAngle)/total改为(endAngle-startAngle)/total-1

二、时钟

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<title></title>
	<style type="text/css">
		body {
			/*background-color: #ccc;*/
		}
		ol,ul {
			margin: 0;
			padding: 0;
			list-style: none;
		}
		h1{
			text-align: center;
			color: #333;
			margin-top: 40px;
			font-family: ‘Microsoft Yahei‘;
		}

		/*表盘*/
		.clock {
			position: relative;
			width: 200px;
			height: 200px;
			border-radius: 100%;
			background-color: #292a38;
			margin: 50px auto;
		}
		.pointer li.circle {
			position: absolute;
			top: 50%;
			left: 50%;
			transform-origin: left center;
			background: #fff;
			width: 10px;
			height: 10px;
			border-radius: 100%;
			margin-top: -5px;
			margin-left: -5px;
		}

		/*演示*/
		/*.line-demo {
			position: absolute;
			left: 50%;
			top: 50%;
			transform:rotate(-60deg) translate(75px, -50%);
			transform-origin: left center;
			width: 20px;
			height: 10px;
			background-color: red;
			z-index: 1;	
		}*/

		/*刻度*/
		.line-hour li,
		.line-min li {
			position: absolute;
			left: 50%;
			top: 50%;
			transform-origin: left center;
			background-color: #fff;
		}
		.line-hour li {
			width: 10px;
			height: 2px;
		}
		.line-min li {
			width: 5px;
			height: 2px;
		}

		/*数字*/
		.number {
			position: absolute;
			height: 150px;
			width: 150px;
			left: 50%;
			top: 50%;
			transform: translate(-50%, -50%);
			font-family: ‘Microsoft Yahei‘;
			font-size: 15px;
			color: #fff;
		}
		.number li {
			position: absolute;
			transform: translate(-50%, -50%);
		}

		/*指针*/
		.pointer li {
			position: absolute;
			top: 50%;
			left: 50%;
			transform-origin: left center;/*先确定origin即时钟中心,再translate*/
			background: #fff;
		}
		.pointer li.hour {
			width: 45px;
			height: 3px;
			margin-top: -1px;
		}
		.pointer li.min {
			width: 60px;
			height: 2px;
			margin-top: -1px;
		}
		.pointer li.sec {
			width: 80px;
			height: 1px;
			margin-top: -1px;
		}
	</style>
</head>
<body>

	<h1>CSS 时钟效果分步实现</h1>

	<div class="clock">
		<ul class="line-min"></ul>
		<ul class="line-hour">
			<!-- <li class="line-demo"></li> -->
		</ul>
		<ol class="number"></ol>
		<ul class="pointer">
			<li class="hour"></li>
			<li class="min"></li>
			<li class="sec"></li>
			<li class="circle"></li>
		</ul>
	</div>
</body>
<script type="text/javascript" src="jquery-3.2.1.min.js"></script>
<script>
	$(function(){

		function init(){
			drawLines($(‘.line-min‘), 60, 85);
			drawLines($(‘.line-hour‘), 12, 80);
			drawNumbers($(‘.number‘));
			move();
		}
		init();


		/*
		 * 绘制钟表刻度线
		 * @param wrap 刻度线的父容器
		 * @param total 刻度线的总个数
		 * @param translateX 刻度线在x轴方向的偏移量
		 */
		function drawLines(wrap, total, translateX){
			var gap = 360/total;
			var strHtml = ‘‘;
			for(var i=0; i<total; i++){
				strHtml += ‘<li style="transform:rotate(‘+ (i*gap) + ‘deg) translate(‘ + translateX + ‘px,-50%)"></li>‘;
			}
			wrap.html(strHtml);
		}


		/* 
		 * 绘制时钟数字
		 * @param wrap 数字的父容器
		 */
		function drawNumbers(wrap){
			var radius = wrap.width() / 2;

			var strHtml = ‘‘;
			for(var i=1; i<=12; i++){
				var myAngle = (i-3)/6 * Math.PI;

				var myX = radius + radius*Math.cos(myAngle), // x=r+rcos(θ)
					myY = radius + radius*Math.sin(myAngle); // y=r+rsin(θ)

				strHtml += ‘<li style="left:‘ + myX + ‘px; top:‘+ myY +‘px">‘ + i + ‘</li>‘;
			}
			wrap.html(strHtml);
		}


		/*
		 * 钟表走动,转动秒针、分针、时针
		 */
		function move(){
			var domHour = $(".hour"),
			    domMin = $(".min"),
			    domSec = $(".sec");

			setInterval(function(){
				var now = new Date(),
					hour = now.getHours(),
				    min = now.getMinutes(),
				    sec = now.getSeconds();

				var secAngle = sec*6 - 90,  // s*6-90 //60个sec才使min移动1个单位6度,故1个sec移动0.1度
				    minAngle = min*6 + sec*0.1 - 90,  // m*6+s*0.1-90
				    hourAngle = hour*30 + min*0.5 - 90;  // h*30+m*0.5 - 90

				domSec.css(‘transform‘, ‘rotate(‘ + secAngle + ‘deg)‘);
				domMin.css(‘transform‘, ‘rotate(‘ + minAngle + ‘deg)‘);
				domHour.css(‘transform‘, ‘rotate(‘ + hourAngle + ‘deg)‘);

				document.title = hour + ‘:‘ + min + ‘:‘ + sec;
			},1000);
		}

	});
</script>
</html>

  效果:

原理:

数字的摆放和径向菜单的原理一样,就是相对于容器改left和top的值。这里解释一下number容器为什么是height和width是150px。容器的右半边就是75px,而时针刻度线是向右translate(移动)80px,长10px又退回50%,就是它的左端离圆心为75px刚好和数字相切。 接着说一个较难懂的地方,想了很久。刻度的transform-orign都为left center,也就是刻度自己本身的左边的中点作为旋转点。这就容易产生疑惑,因为它移动了啊。其实它是先执行transform-origin和translate,执行完后,它相对于圆心是向右平移了,而且translateY -50%使其left center和圆心在一条线上,这是旋转,与对着圆心旋转的效果一样。如下图所示:绿色长方形为绕圆心的旋转效果,紫色长方形是移动后旋转的效果。

 技术分享图片

最后说一下代码的数学换算:

1. myAngle = (i-3)/6 * Math.PI; 这是数字与x轴的夹角。可知,数字总共有12个,分为12份,则每份为 360deg/12=30deg。而从12点刻度开始分配,其夹角为-90deg,所以第i个数字的夹角为-90+30*ideg,换算成弧度制 则乘π/180,化简即可得到该算式。

2. secAngle = sec*6 - 90;minAngle = min*6 + sec*0.1 - 90;hourAngle = hour*30 + min*0.5 - 90 秒针是“瞬间”旋转的,而秒针是指向分钟刻度,即每秒6deg,从12点钟方向开始,故-90。下面的-90一样,不再说。 分针是每60个秒增加1,而分针移动1次是6deg,则每一秒使分针移动0.1deg。而本身每分移动6deg。所以是该算式。

3.时针是每60个分增加1,而时针移动1次是30deg,则每一分使时针移动0.5deg,对时针而言秒可以忽略不计。

径向动画

标签:this   alt   math   oct   nim   位置   开始   sandbox   ini   

原文地址:https://www.cnblogs.com/githubMYL/p/8893006.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!