zoukankan      html  css  js  c++  java
  • javascript运动系列第六篇——轨迹和投掷

    前面的话

      一般地,不同的运动形式会产生不同的轨迹。但仅凭肉眼去识别运动轨迹,其实并不是很直观。因此,在页面中显示运动轨迹,是一个重要的问题。物体初始态时,受到外力大小不同,则初速度不同。如何在网页中模拟投掷效果,也需要解决。接下来,将详细介绍轨迹和投掷

    运动轨迹

      元素在运动过程中,不同的运动形式会产生不同的轨迹。如果不把轨迹表示出来,我们只能通过肉眼来区分运动形式。表示轨迹通常有两种方式:创建小元素和使用canvas

    创建小元素

      创建小元素原理上比较简单,但是性能较差。在元素移动时,创建一个2px*2px的小元素,并添加到页面上。以最简单的匀速运动为例

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
    .track{
        width: 2px;
        height: 2px;
        background-color:#000;
        position:absolute;
    }
    </style>
    </head>
    <body>
    <button id="btn1">开始运动</button>
    <button id="btn2">删除轨迹</button>
    <button id="reset">还原</button>
    <div id="test" style="height: 50px; 50px;background:pink;position:absolute;top:40px;left:0;"></div>
    <script>
    function getCSS(obj,style){
        if(window.getComputedStyle){
            return getComputedStyle(obj)[style];
        }
        return obj.currentStyle[style];
    } 
    function move(obj,attr,target,step,fn){
        //如果没有建立定时器对象,则在obj下建立定时器对象
        if(!obj.timers){obj.timers = {};}
        //清除定时器
        clearInterval(obj.timers[attr]);
        //声明当前值变量cur
        var cur;
        //判断步长step的正负值
        step = parseInt(getCSS(obj,attr)) < target ? step : -step;
        //开启定时器
        obj.timers[attr] = setInterval(function(){
            //获取样式当前值并赋值给cur
            cur = parseFloat(getCSS(obj,attr));
            ////若步长设置值使得元素超过目标点时,将步长设置值更改为目标点值 - 当前值
            if((cur + step - target)*step > 0){
                step = target - cur;
            }
            //将合适的步长值赋值给元素的样式
            obj.style[attr] = cur + step + 'px';
            //设置轨迹
            createTracks(obj.offsetLeft,obj.offsetTop)
            //当元素到达目标点后,停止定时器
            if(step == target - cur){
                clearInterval(obj.timers[attr]);
                obj.timers[attr] = 0;
                fn && fn.call(obj);    
            }       
        },20);        
    } 
    function createTracks(x,y){
        var ele = document.createElement('div');
        ele.className = 'track';
        ele.style.left = x + 'px';
        ele.style.top = y + 'px';
        document.body.appendChild(ele);
    }
    function deleteTracks(){
        var eles = document.getElementsByTagName('div');
        for(var i = 0 ;i < eles.length; i++){
            if(eles[i].className == 'track'){
                document.body.removeChild(eles[i]);
                i--;
            }
        }
    }
    btn1.onclick = function(){
        move(test,'left',300,10)
    } 
    btn2.onclick = function(){
        deleteTracks()
    }     
    reset.onclick = function(){
        history.go();
    }
    </script>
    </body>
    </html> 

    使用canvas

      使用canvas也可以实现运动轨迹,且性能较好,只不过需要掌握canvas的一些基础知识

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    </head>
    <body>
    <button id="btn1">开始运动</button>
    <button id="btn2">删除轨迹</button>
    <button id="reset">还原</button>
    <div id="test" style="height: 50px; 50px;background:pink;position:absolute;top:40px;left:0;"></div>
    <canvas id="drawing" style="position:absolute;left:0;top:0;z-index:-1"></canvas>
    <script>
    var context;
    backupCanvas();
    function backupCanvas(){
        var drawing = document.getElementById('drawing');
        drawing.setAttribute('width',document.documentElement.clientWidth);
        drawing.setAttribute('height',document.documentElement.clientHeight);
        if(drawing.getContext){
            context = drawing.getContext('2d');
            context.beginPath();
            context.moveTo(test.offsetLeft,test.offsetTop);
        }
    }
    function getCSS(obj,style){
        if(window.getComputedStyle){
            return getComputedStyle(obj)[style];
        }
        return obj.currentStyle[style];
    } 
    function move(obj,attr,target,step,fn){
        //如果没有建立定时器对象,则在obj下建立定时器对象
        if(!obj.timers){obj.timers = {};}
        //清除定时器
        clearInterval(obj.timers[attr]);
        //声明当前值变量cur
        var cur;
        //判断步长step的正负值
        step = parseInt(getCSS(obj,attr)) < target ? step : -step;
        //开启定时器
        obj.timers[attr] = setInterval(function(){
            //获取样式当前值并赋值给cur
            cur = parseFloat(getCSS(obj,attr));
            ////若步长设置值使得元素超过目标点时,将步长设置值更改为目标点值 - 当前值
            if((cur + step - target)*step > 0){
                step = target - cur;
            }
            //将合适的步长值赋值给元素的样式
            obj.style[attr] = cur + step + 'px';
            createCanvasTracks(obj.offsetLeft,obj.offsetTop);
            //当元素到达目标点后,停止定时器
            if(step == target - cur){
                clearInterval(obj.timers[attr]);
                obj.timers[attr] = 0;
                fn && fn.call(obj);    
            }       
        },20);        
    } 
    function createCanvasTracks(x,y){
        context.lineTo(x,y);
        context.stroke();        
    }
    function deleteCanvasTracks(){
        drawing.height = drawing.height;
    }
    btn1.onclick = function(){
        move(test,'left',300,10)
    } 
    btn2.onclick = function(){
        deleteCanvasTracks()
    }     
    reset.onclick = function(){
        history.go();
    }
    </script>
    </body>
    </html>

    拖拽轨迹

      物体在拖拽的时候,同样也存在着拖拽轨迹。由于拖拽的运动形式不固定,因此轨迹也不固定

      同样地,拖拽轨迹也有创建小元素和使用canvas两种方法

    【创建小元素】

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
    .track{
        width: 2px;
        height: 2px;
        background-color:#000;
        position:absolute;
    }
    </style>
    </head>
    <body>
    <button id="btn">删除轨迹</button>
    <button id="reset">还原</button>
    <div id="test" style="height: 50px; 50px;background:pink;position:absolute;top:40px;left:0;"></div>
    
    <script>
    function createTracks(x,y){
        var ele = document.createElement('div');
        ele.className = 'track';
        ele.style.left = x + 'px';
        ele.style.top = y + 'px';
        document.body.appendChild(ele);
    }
    function deleteTracks(){
        var eles = document.getElementsByTagName('div');
        for(var i = 0 ;i < eles.length; i++){
            if(eles[i].className == 'track'){
                document.body.removeChild(eles[i]);
                i--;
            }
        }
    }
    btn.onclick = function(){
        deleteTracks()
    }     
    reset.onclick = function(){
        history.go();
    }
    test.onmousedown = function(e){
        e = e || event;
        //获取元素距离定位父级的x轴及y轴距离
        var x0 = this.offsetLeft;
        var y0 = this.offsetTop;
        //获取此时鼠标距离视口左上角的x轴及y轴距离
        var x1 = e.clientX;
        var y1 = e.clientY;
        document.onmousemove = function(e){
            e = e || event;
            //获取此时鼠标距离视口左上角的x轴及y轴距离
            x2 = e.clientX;
            y2 = e.clientY;    
            //计算此时元素应该距离视口左上角的x轴及y轴距离
            var X = x0 + (x2 - x1);
            var Y = y0 + (y2 - y1);
            //将X和Y的值赋给left和top,使元素移动到相应位置
            test.style.left = X + 'px';
            test.style.top = Y + 'px';
            //创建轨迹
            createTracks(X,Y);
        }
    
        document.onmouseup = function(e){
            //当鼠标抬起时,拖拽结束,则将onmousemove赋值为null即可
            document.onmousemove = null;
            //释放全局捕获
            if(test.releaseCapture){
                test.releaseCapture();
            }
        }
        //阻止默认行为
        return false;
        //IE8-浏览器阻止默认行为
        if(test.setCapture){
            test.setCapture();
        }
    }
    </script>    
    </body>
    </html>

    【使用canvas】

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    </head>
    <body>
    <button id="btn">删除轨迹</button>
    <button id="reset">还原</button>
    <div id="test" style="height: 50px; 50px;background:pink;position:absolute;top:40px;left:0;"></div>
    <canvas id="drawing" style="position:absolute;left:0;top:0;z-index:-1"></canvas>
    <script>
    var context;
    backupCanvas();
    function backupCanvas(){
        var drawing = document.getElementById('drawing');
        drawing.setAttribute('width',document.documentElement.clientWidth);
        drawing.setAttribute('height',document.documentElement.clientHeight);
        if(drawing.getContext){
            context = drawing.getContext('2d');
            context.beginPath();
            context.moveTo(test.offsetLeft,test.offsetTop);
        }
    }
    function createCanvasTracks(x,y){
        context.lineTo(x,y);
        context.stroke();        
    }
    function deleteCanvasTracks(){
        drawing.height = drawing.height;
    }
    btn.onclick = function(){
        deleteCanvasTracks()
    }     
    reset.onclick = function(){
        history.go();
    }
    test.onmousedown = function(e){
        e = e || event;
        //获取元素距离定位父级的x轴及y轴距离
        var x0 = this.offsetLeft;
        var y0 = this.offsetTop;
        //获取此时鼠标距离视口左上角的x轴及y轴距离
        var x1 = e.clientX;
        var y1 = e.clientY;
        document.onmousemove = function(e){
            e = e || event;
            //获取此时鼠标距离视口左上角的x轴及y轴距离
            x2 = e.clientX;
            y2 = e.clientY;    
            //计算此时元素应该距离视口左上角的x轴及y轴距离
            var X = x0 + (x2 - x1);
            var Y = y0 + (y2 - y1);
            //将X和Y的值赋给left和top,使元素移动到相应位置
            test.style.left = X + 'px';
            test.style.top = Y + 'px';
            //创建轨迹
            createCanvasTracks(X,Y);
        }
    
        document.onmouseup = function(e){
            //当鼠标抬起时,拖拽结束,则将onmousemove赋值为null即可
            document.onmousemove = null;
            //释放全局捕获
            if(test.releaseCapture){
                test.releaseCapture();
            }
        }
        //阻止默认行为
        return false;
        //IE8-浏览器阻止默认行为
        if(test.setCapture){
            test.setCapture();
        }
    }
    </script>    
    </body>
    </html>

    投掷

      如何使用javascript模拟出投掷的效果呢?javascript里面并没有力的概念。我们可以使用投掷速度为基准,当投掷速度快时,元素的速度也快;投掷速度慢时,元素速度同样也慢

      问题来了,投掷速度如何确定。在javascript中模拟运动通常是使用一定频率的定时器来实现,投掷速度也同样如此。速度就相当于是一定时间的位移(或称为步长)。在定时器频率确定的情况下同,位移的确定其实就是找起始点和结束点这两个点的坐标位置

      拖拽共涉及到三个鼠标事件:mousedown、mousemove和mouseup。结束点的位置是mouseup事件的鼠标位置(注意:mouseup事件的鼠标位置和最后一次mousemove事件的鼠标位置是相同的),而开始点的位置可以是mousemove事件倒数第二次的鼠标位置。这两个位置是拖拽运动的最后两个运动位置,通过确定他们就可以确定投掷步长了

      下面以匀速运动为例,来进行实现

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    </head>
    <body>
    <button id="reset">还原</button>
    <div id="test" style="height: 50px; 50px;background:pink;position:absolute;top:40px;left:0;"></div>
    <script>
    function getCSS(obj,style){
        if(window.getComputedStyle){
            return getComputedStyle(obj)[style];
        }
        return obj.currentStyle[style];
    } 
    function move(obj,attr,target,step,fn){
        //如果没有建立定时器对象,则在obj下建立定时器对象
        if(!obj.timers){obj.timers = {};}
        //清除定时器
        clearInterval(obj.timers[attr]);
        //声明当前值变量cur
        var cur;
        //判断步长step的正负值
        step = parseInt(getCSS(obj,attr)) < target ? step : -step;
        //开启定时器
        obj.timers[attr] = setInterval(function(){
            //获取样式当前值并赋值给cur
            cur = parseFloat(getCSS(obj,attr));
            //若步长设置值使得元素超过目标点时,将步长设置值更改为目标点值 - 当前值
            if((cur + step - target)*step > 0){
                step = target - cur;
            }
            //将合适的步长值赋值给元素的样式
            obj.style[attr] = cur + step + 'px';
            //当元素到达目标点后,停止定时器
            if(step == target - cur){
                clearInterval(obj.timers[attr]);
                obj.timers[attr] = 0;
                fn && fn.call(obj);    
            }       
        },30);        
    }  
    reset.onclick = function(){
        history.go();
    }
    test.onmousedown = function(e){
        e = e || event;
        //声明投掷步长值
        var stepX,stepY;
        //声明上一次mousemove事件的坐标位置
        var lastX2 = e.clientX;
        var lastY2 = e.clientY;
        //获取元素距离定位父级的x轴及y轴距离
        var x0 = this.offsetLeft;
        var y0 = this.offsetTop;
        //获取此时鼠标距离视口左上角的x轴及y轴距离
        var x1 = e.clientX;
        var y1 = e.clientY;
        document.onmousemove = function(e){
            e = e || event;
            //获取此时鼠标距离视口左上角的x轴及y轴距离
            var x2 = e.clientX;
            var y2 = e.clientY; 
            stepX = x2 - lastX2;
            stepY = y2 - lastY2;  
            lastX2 = e.clientX;
            lastY2 = e.clientY;
            //计算此时元素应该距离视口左上角的x轴及y轴距离
            var X = x0 + (x2 - x1);
            var Y = y0 + (y2 - y1);
            //将X和Y的值赋给left和top,使元素移动到相应位置
            test.style.left = X + 'px';
            test.style.top = Y + 'px';
        }
        document.onmouseup = function(e){
            e = e || event;
            var maxHeight = document.documentElement.clientHeight - test.offsetHeight;
            var maxWidth = document.documentElement.clientWidth - test.offsetWidth;
            //以设置的投掷速度来进行匀速运动
            //向右投掷
            if(stepX > 0){
                 move(test,'left',maxWidth,stepX);           
            //向左投掷
            }else{
                move(test,'left',0,stepX); 
            }
            //向下投掷
            if(stepY > 0){
                move(test,'top',maxHeight,stepY);            
            //向上投掷
            }else{
                move(test,'top',0,stepY);  
            }
            //当鼠标抬起时,拖拽结束,则将onmousemove赋值为null即可
            document.onmousemove = null;
            //释放全局捕获
            if(test.releaseCapture){
                test.releaseCapture();
            }
        }
        //阻止默认行为
        return false;
        //IE8-浏览器阻止默认行为
        if(test.setCapture){
            test.setCapture();
        }
    }
    </script>    
    </body>
    </html>

  • 相关阅读:
    转:Web Service介绍
    CodeIgniter网页缓存
    CodeIgniter管理你的应用程序
    CodeIgniter自动装载资源
    python feedparser 使用
    HTC文件的使用
    动态执行javascript代码
    jQuery获取文本节点之text()/val()/html() 方法区别
    style,runtimeStyle与currentStyle的定义及用法
    File,FileStream,byte[]3者互相转换总结(转)
  • 原文地址:https://www.cnblogs.com/xiaohuochai/p/5990247.html
Copyright © 2011-2022 走看看