文章出處

前面的話

  運動除了直線運動曲線運動兩種運動形式外,還有一種運動形式是鼠標跟隨運動,而這種跟隨運動需要用到三角函數的相關內容或者需要進行比例運算。本文將以幾個小實例來介紹鼠標跟隨運動的相關內容

 

眼球轉動

  在很多網頁中,都存在著跟隨運動,比如眼球轉動。鼠標在網頁中移動時,眼球也會跟著朝相應方向轉動

  上面是眼球轉動的示意圖,(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:0;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>

 


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()