径向动画

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不能省,省了就不行了*/
		}
		[email protected] 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,对时针而言秒可以忽略不计。

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

时间: 2024-10-10 07:49:27

径向动画的相关文章

解析:用 CSS3 和 JavaScript 制作径向动画菜单

原作者的解析(英文):http://creative-punch.net/2014/02/making-animated-radial-menu-css3-javascript/ 原作者的解析(译文):http://developer.51cto.com/art/201404/437152.htm 本文非转载,为个人原创解析,转载请先联系博主.谢谢~ 首先,看看html的结构: <!DOCTYPE html> <head> <meta charset="UTF-8&

径向菜单的制作

最终效果: 在径向菜单的制作前,首先需要知道几点知识点: Math.sin(x)      x 的正玄值.返回值在 -1.0 到 1.0 之间: Math.cos(x)    x 的余弦值.返回的是 -1.0 到 1.0 之间的数: 这两个函数中的X 都是指的“弧度”而非“角度”,弧度的计算公式为: 2*PI/360*角度,使用js表示是这样的:Math.PI/180*度数(1度=180/Math.PI) 如:30° 角度 的弧度 = 2*PI/360*30 如何计算圆的极坐标(用于计算出子菜单

Flutter Demo: 径向菜单动画

video import 'dart:math'; import 'package:flutter/material.dart'; import 'package:vector_math/vector_math.dart' show radians; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return

HTML5 CSS3 诱人的实例: 3D立方体旋转动画

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/34120047 创意来自:http://www.html5tricks.com/demo/html5-3d-cube/index.html , 同学给我发的样例,感觉非常不错,只是实在想不出来实际的用处.可是效果非常炫~ 效果图: 知识点: 1.perspective ,transform 的复习 2.css3 backgroud实现格格背景.即面上的小格格 3. @-webki

《深入浅出WPF》笔记——绘画与动画

<深入浅出WPF>笔记——绘画与动画 本篇将记录一下如何在WPF中绘画和设计动画,这方面一直都不是VS的强项,然而它有一套利器Blend:这方面也不是我的优势,幸好我有博客园,能记录一下学习的过程.在本记录中,为了更好的理解绘画与动画,多数的例子还是在VS里面敲出来的.好了,不废话了,现在开始. 一.WPF绘画 1.1基本图形 在WPF中可以绘制矢量图,不会随窗口或图型的放大或缩小出现锯齿或变形,除此之外,XAML绘制出来的图有个好处就是便于修改,当图不符合要求的时间,通常改某些属性就可以完成

WPF学习之绘图和动画

如今的软件市场,竞争已经进入白热化阶段,功能强.运算快.界面友好.Bug少.价格低都已经成为了必备条件.这还不算完,随着计算机的多媒体功能越来越强,软件的界面是否色彩亮丽.是否能通过动画.3D等效果是否吸引用户的眼球也已经成为衡量软件的标准. 软件项目成功的三个要素是:资源.成本.时间.无论是为了在竞争中保持不败还是为了激发起用户对软件的兴趣,提高软件界面的美化程度.恰当的将动画和3D等效果引入应用程序都是一个必然趋势.然而使用传统的桌面应用程序开发工具和框架(如Winform.MFC.VB.D

HTML5 CSS3 诱人的实例: 3D立方体旋转动画DEMO

创意来自:http://www.html5tricks.com/demo/html5-3d-cube/index.html , 同学给我发的例子,感觉很不错,不过实在想不出来实际的用处,但是效果很炫~ 效果图: 知识点: 1.perspective ,transform 的复习 2.css3 backgroud实现格格背景,即面上的小格格 3. @-webkit-keyframes 实现动画 HTML: <body> <div class="stage"> &l

《深入浅出WPF》学习笔记之绘图和动画

绘图 通过WPF绘制的图形都是矢量图,可以通过Design或Blend工具绘制原型图然后导出XAML再在Visual Studio中调整.绘图可以在任意布局控件中完成,常用的为Canvas和Grid,WPF会自动根据容器的不同计算图形坐标.WPF基本图像都继承自Shape类. Line,绘制直线,通过设置起始点坐标和终止点坐标确定直线的位置,可以设置直线的样式,颜色,粗细等.通过设置Stroke属性设置图形的颜色,Stroke属性为Brush类型,Brush为抽象类.WPF系统包含丰富的Brus

WPF绘画和动画(原文:http://blog.csdn.net/fwj380891124/article/details/8177125 )

1.1   WPF绘图 与传统的.net开发使用GDI+进行绘图不同,WPF拥有自己的一套绘图API.使用这套API不但可以轻松绘制出精美的图形,还可以为各种图形添加类似与PhotoShop的"滤镜效果"及"变形效果".本节我们就一起研究WPF图形API绘图,效果和变形等功能. 先观察下面一组图片: 显然,这组图片是矢量图(Vector Image),无论怎样放大缩小都不会出现锯齿.你可能会想:"这是组PNG格式的图片吗?"答案是"NO