前面的话

  运动除了直线运动曲线运动两种运动形式外,还有一种运动形式是鼠标跟随运动,而这种跟随运动需要用到三角函数的相关内容或者需要进行比例运算。本文将以几个小实例来介绍鼠标跟随运动的相关内容

眼球转动

  在很多网页中,都存在着跟随运动,比如眼球转动。鼠标在网页中移动时,眼球也会跟着朝相应方向转动

  上面是眼球转动的示意图,(x0,y0)是眼球的位置,而(x,y)是鼠标的位置。设直线与垂直方向的夹角为a,假设圆心点坐标为(0,0),可以得到以下公式

    tan(a) = x/y = x0/y0
x0 = r*sin(a)
y0 = r*cos(a)

  在mousemove事件中,可以很容易的得到鼠标位置(x,y),由此求出夹角a,进而可以求出眼球的位置

  设左眼为ball1,右眼为ball2。左眼的圆心坐标是(39,72),右眼的圆心坐标是(106,68),眼球可以移动的半径是12px

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#test{position: absolute;top: 100px;left: 200px;}
#ball1{position: absolute;top: 62px;left: 28px;}
#ball2{position: absolute;top: 58px;left: 96px;}
</style>
</head>
<body>
<div id="test">
<img src="head.png" alt="body">
<img id="ball1" src="ball.png" alt="ball">
<img id="ball2" src="ball.png" alt="ball">
</div>
<script>
//声明脑袋的默认偏移
var offsetLeft = test.offsetLeft;
var offsetTop = test.offsetTop;
//声明左眼夹角a1、右眼夹角a2
var a1,a2;
//声明左眼圆心(X1,Y1)、右眼圆心(X2,Y2)
var X1 = 38,Y1 = 72,X2 = 106,Y2 = 68;
//声明半径
var R = 12;
document.onmousemove = function(e){
e = e || event;
//获取鼠标坐标
var x = e.clientX;
var y = e.clientY;
//更新夹角a1、a2
a1 = Math.atan2(x-X1-offsetLeft,y-Y1-offsetTop);
a2 = Math.atan2(x-X2-offsetLeft,y-Y2-offsetTop);
//更新左眼、右眼的left、top值
ball1.style.left = R*Math.sin(a1) + X1 -10 + 'px';
ball1.style.top = R*Math.cos(a1) + Y1 -10+ 'px';
ball2.style.left = R*Math.sin(a2) + X2 -10 + 'px';
ball2.style.top = R*Math.cos(a2) + Y2 -10 + 'px';
}
</script>
</body>
</html>

苹果菜单

  苹果菜单中也存在着鼠标跟随运动,与鼠标距离越近的菜单项的宽高越大,越远则宽高越小

  鼠标坐标可以通过mousemove事件中的clientX和clientY获得。菜单项的坐标其实是已知项。而鼠标坐标与菜单项的距离就是要求的距离,而距离与菜单项的宽高成反比

  [注意]不能够将元素的自定义属性命名为x,因为x已经被浏览器使用

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body{margin: 0;}
#test{position: absolute;bottom:10px;width: 100%;text-align: center;}
img{width: 64px;height: 64px;}
</style>
</head>
<body>
<div id="test">
<img id="img1" src="img/1.png">
<img src="img/2.png">
<img src="img/3.png">
<img src="img/4.png">
<img src="img/5.png">
</div>
<script>
//声明菜单项的宽高值
var offsetWidth = img1.offsetWidth;
var offsetHeight = img1.offsetHeight;
//声明外层盒子的left、top值
var offsetLeft = test.offsetLeft;
var offsetTop = test.offsetTop;
//获取菜单项
var imgs = test.getElementsByTagName('img');
document.onmousemove = function(e){
e = e || event;
//更新鼠标位置
var x = e.clientX;
var y = e.clientY;
for(var i = 0; i < imgs.length; i++){
//获取菜单项的坐标
imgs[i].x0= imgs[i].offsetLeft+offsetLeft+imgs[i].offsetWidth/2;
imgs[i].y0 = imgs[i].offsetTop + offsetTop + imgs[i].offsetHeight/2;
//更新鼠标与菜单项的距离
imgs[i].len =Math.sqrt((x-imgs[i].x0)*(x-imgs[i].x0) + (y-imgs[i].y0)*(y-imgs[i].y0));
//限制范围
if(imgs[i].len > 150){
imgs[i].len = 150;
}
//更新菜单项的宽高
imgs[i].style.width = (1-imgs[i].len/300)*2*offsetWidth + 'px';
imgs[i].style.height = (1-imgs[i].len/300)*2*offsetHeight + 'px'; }
}
</script>
</body>
</html>

方向跟随

  有许多网页都有方向跟随的效果。鼠标从哪个方向移入,元素就跟着从哪个方向移入。鼠标从哪个方向移出,类似地,元素也跟着从哪个方向移出

  移入移出的运动效果使用匀速直线运动即可,这里主要需要判断方向

  由示意图中所示,可以把一个正方形的元素分成(上-右、上-左、左-上、左-下、下-右、下-左、右-上、右-下)这8个部分,每个部分是一个等腰直角三角形,当元素进入某个区域时,横线前面的方向就表示元素的方向

  假设正方形的中心坐标为(x0,y0),动态元素(move)进入时的坐标为(x,y),以这两个坐标组成的直线与水平正方向的直线的夹角作为基准角,假设为a,则通过确定夹角a的范围,可以确定动态元素(move)进入的方向

  -45<a<45时,进入方向为右

  45<a<135时,进入方向为上

  a>135或a<-135时,进入方向为左

  -135<a<-45时,进入方向为下

  确定好动态元素(move)进入的方向后,需要根据方向,将动态元素(move)瞬间变换到对应的位置。然后,动态元素(move)进行匀速直线运动,最终停止在与静态元素(test)重合的位置

  动态元素(move)移出静态元素(test)的范围时,要注意的是,并不会触发静态元素(test)的mouseout事件。因为,此时鼠标一直处于动态元素(move)上。所以,触发的是动态元素(move)的mouseout事件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#box{overflow: hidden;position: relative;left: 100px;top: 100px;height: 100px;width: 300px;}
.test{width: 100px;height: 100px;position: absolute;font:20px/100px '宋体';text-align: center;}
</style>
</head>
<body>
<div id="box">
<div class="test" style="top: 0px;left: 0px;background-color: pink;">1</div>
<div class="test" style="top: 0px;left: 100px;background-color: lightcoral;">2</div>
<div class="test" style="top: 0px;left: 200px;background-color: lightgreen;">3</div>
<div id="move" style="width: 100px;height: 100px;background-color: lightblue;position: absolute;top: -100px;left: -100px;"></div>
</div>
<script>
var tests = box.getElementsByTagName('div');
for(var i = 0; i < tests.length; i++){
tests[i].onmouseover = fn;
}
//鼠标移出动态元素(move)时,再将fn()函数置于所有静态元素上
move.onmouseout = fn;
function fn(e){
e = e || event;
//阻止冒泡
if(e.stopPropagation){
e.stopPropagation();
}else{
e.cancelBubble = true;
}
for(var i = 0; i < tests.length; i++){
tests[i].onmouseover = fn;
}
var _this = this;
//鼠标移入动态元素(move)时,将静态元素上的mouseover事件置空
move.onmouseover = function(){
move.innerHTML = _this.innerHTML;
_this.onmouseover = null;
}
//声明坐标
var x = e.clientX;
var y = e.clientY;
//声明静态元素(test)左上角坐标(相对于父级)
var x11 = this.offsetLeft;
var y11 = this.offsetTop;
//声明静态元素(test)中心点坐标(相对于父级)
var x10 = x11 + this.offsetWidth/2;
var y10 = y11 + this.offsetHeight/2;
//声明静态元素(test)左上角坐标(相对于文档)
var x21 = this.parentNode.offsetLeft + x11;
var y21 = this.parentNode.offsetTop + y11;
//声明静态元素(test)中心点坐标(相对于文档)
var x20 = x21 + this.offsetWidth/2;
var y20 = y21 + this.offsetHeight/2;
//声明静态元素宽高
var height = this.offsetHeight;
var width = this.offsetWidth;
//声明并计算夹角
var a = Math.atan2(y20-y,x-x20)*180/Math.PI;
//声明并计算方向
var dir;
if(a > -45 && a < 45){
dir = 'right';
}else if(a > 45 && a < 135){
dir = 'top';
}else if(a > -135 && a < 45){
dir = 'bottom';
}else{
dir = 'left';
}
//鼠标移入时
if(e.type == 'mouseover'){
//更新动态元素(move)的初始位置
//移动动态元素(move)直到完全覆盖静态元素(test)
if(dir == 'right'){
move.style.left = x10 + width/2 + 'px';
move.style.top = y10 - height/2 + 'px';
fnMove(move,'left',x11)
}else if(dir == 'top'){
move.style.left = x10 - width/2 + 'px';
move.style.top = y10 - height/2 - height + 'px';
fnMove(move,'top',y11)
}else if(dir == 'left'){
move.style.left = x10 - width/2 - width + 'px';
move.style.top = y10 - height/2 + 'px';
fnMove(move,'left',x11)
}else{
move.style.left = x10 - width/2 + 'px';
move.style.top = y10 - height/2 + height + 'px';
fnMove(move,'top',y11)
}
}
if(e.type == 'mouseout'){
//鼠标移出时
if(dir == 'right'){
fnMove(move,'left',x11 + width);
}else if(dir == 'top'){
fnMove(move,'top',y11 - height);
}else if(dir == 'left'){
fnMove(move,'left',x11 - width);
}else{
fnMove(move,'top',y11 + height);
}
}
}
function getCSS(obj,style){
if(window.getComputedStyle){
return getComputedStyle(obj)[style];
}
return obj.currentStyle[style];
}
function fnMove(obj,attr,target){
var H = obj.offsetHeight;
if(obj.timer) return;
var cur = parseFloat(getCSS(obj,attr));
if(target > cur){
var step = H/4;
}else{
var step = -H/4;
}
obj.timer = setInterval(function(){
cur = parseFloat(getCSS(obj,attr));
cur = cur + step;
if((cur -target) * step >= 0){
cur = target;
}
obj.style[attr] = cur + 'px';
if(cur == target){
clearInterval(obj.timer);
obj.timer = 0;
}
},20);
}
</script>
</body>
</html>

3Dhover

  下面是一个3Dhover效果

<style>
.outer{perspective: 1000px;}
.inner{height: 200px;width: 200px;background-color: tan;box-shadow: 3px 3px 6px -3px black;}
</style>
<div class="outer">
<div class="inner"></div>
</div>
<script>
var oDiv = document.getElementsByClassName('inner')[0];
oDiv.onmousemove = function(e){
e = e || event;
var x = e.clientX - this.offsetLeft;
var y = e.clientY - this.offsetTop;
var x0 = this.offsetWidth/2;
var y0 = this.offsetHeight/2;
var percentX = (x - x0)/x0;
var percentY = (y - y0)/y0;
this.style.transform = 'rotateX('+ (5*-percentY) +'deg)' + 'rotateY('+ (5*percentX) +'deg)';
}
oDiv.onmouseleave = function(e){
this.style.transform = 'none';
}
</script>

javascript运动系列第七篇——鼠标跟随运动的更多相关文章

  1. javascript运动系列第八篇——碰壁运动

    × 目录 [1]匀速碰壁 [2]自由落体 [3]投掷碰壁[4]拖拽碰壁 前面的话 碰撞运动可能是运动系列里面比较复杂的运动了.碰撞可以分为碰壁和互碰两种形式,而碰撞前后的运动形式也可以分为变速和匀速两 ...

  2. javascript运动系列第四篇——抖动

    × 目录 [1]原理介绍 [2]代码实现 [3]实例应用 前面的话 在运动系列中,前面分别介绍了匀速运动.变速运动和曲线运动.下面介绍一种特殊的运动形式——抖动 原理介绍 抖动其实是往复运动的一种特殊 ...

  3. javascript运动系列第六篇——轨迹和投掷

    × 目录 [1]运动轨迹 [2]拖拽轨迹 [3]投掷 前面的话 一般地,不同的运动形式会产生不同的轨迹.但仅凭肉眼去识别运动轨迹,其实并不是很直观.因此,在页面中显示运动轨迹,是一个重要的问题.物体初 ...

  4. javascript运动系列第五篇——缓冲运动和弹性运动

    × 目录 [1]缓冲运动 [2]弹性运动 [3]距离分析[4]步长分析[5]弹性过界[6]弹性菜单[7]弹性拖拽 前面的话 缓冲运动指的是减速运动,减速到0的时候,元素正好停在目标点.而弹性运动同样是 ...

  5. javascript运动系列第三篇——曲线运动

    × 目录 [1]圆周运动[2]三维圆周 [3]钟摆运动 [4]抛物线[5]流体运动 前面的话 上一篇介绍了变速运动,但只实现了直线运动.如果元素的left和top同时运动,并遵循不同的曲线公式,则会进 ...

  6. javascript面向对象系列第三篇——实现继承的3种形式

    × 目录 [1]原型继承 [2]伪类继承 [3]组合继承 前面的话 学习如何创建对象是理解面向对象编程的第一步,第二步是理解继承.本文是javascript面向对象系列第三篇——实现继承的3种形式 [ ...

  7. 深入理解javascript函数系列第三篇——属性和方法

    × 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...

  8. 深入理解javascript作用域系列第四篇——块作用域

    × 目录 [1]let [2]const [3]try 前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用 ...

  9. 深入理解javascript作用域系列第三篇——声明提升(hoisting)

    × 目录 [1]变量 [2]函数 [3]优先 前面的话 一般认为,javascript代码在执行时是由上到下一行一行执行的.但实际上这并不完全正确,主要是因为声明提升的存在.本文是深入理解javasc ...

随机推荐

  1. SVN出现Invalid authz configuration解决方案

    思路: 1.检查是否为不存在的用户组或用户设置了权限(大部分为此问题,调整用户权限或删除账号后,但忘了去掉某个文件夹的权限) 2.检查authz文件的编码: 3.更改权限后是否未重启svn. 4.按照 ...

  2. MVC高级编程+C#高级编程

    本人今年的目标是学习MVC高级编程和C#高级编程,把自己的基础打的扎实,本文中值是一个开到,定期会在上面记录学习的技术点和心得就,加油吧!!!!!

  3. [转]字符型IP地址转换成数字IP的SQL函数

    使用SQL函数可以实现许多的功能,下面为您介绍的是字符型IP地址转换成数字IP的SQL函数示例,供您参考,希望对您学习SQL函数能够有所帮助.      /**//*--调用示例       sele ...

  4. linux下 SVN切换仓库地址命令

    svn switch --relocate (Old Repository Root) (New Repository Root)

  5. 关于.9.png格式图片的制作与使用

    .9.png图片其实就是png格式图片,不过它比普通的png图片外围多了1px(像素)的边框,另外就是使用这种格式的图片可以实现背景自适应大小且不失真的效果. 制作使用步骤: 1.制作属于你自己的pn ...

  6. 字符串、数组方法实战--charAt(),split(),indexOf(),substring()

    这篇随笔根据两个面试题来实战一下数组.字符串的一些方法. 题一:一个字符串中找出出现次数最多的字符次数 var str = 'fuuhuhuhufaihuhfnkjNKCNIO';
 function ...

  7. 通过arcgis在PostgreSQL中创建企业级地理数据库

    部署环境: Win7 64位旗舰版 软件版本: PostgreSQL-9.1.3-2-windows-x64 Postgis-pg91x64-setup-2.0.6-1 Arcgis 10.1 SP1 ...

  8. 对象的this引用

    Java中的this关键字总是指向调用该方法的对象.根据this出现位置的不同,this作为对象的默认引用有两个功能: 1.构造器中引用该构造器正在初始化的对象. 2.在方法中引用调用该方法的对象. ...

  9. 系统定位在iOS8中的改变

    CLLocationManager这个系统定位的类在iOS8之前要实现定位,只需要遵守CLLocationManagerDelegate这个代理即可: - (void)startLocate {   ...

  10. 谢欣伦 - 原创软件 - 工具软件 - 快速关机Shutdown

    快速关机Shutdown,含源码. 公司公用的笔记本电脑实在太烂,不知从什么时候开始关机永远都关不了,一直停留在“关闭系统中……”.忍无可忍之下,自己写了一个快速关机程序. 下载: Shutdown_ ...