用JavaScript作一個簡單的框選圖表

故事背景:這幾天遇到一個客戶,是作會議記錄的,每次會議過程當中,都會有特定設備記錄下講話人的位置以角度值顯示。他給我角度值,讓我給他作一個圖表來展現每一個人的一個大概位置。javascript

客戶想到的是用Echarts圖表來作,我首先想到的也是用Echarts,可是思考了他的要求之後,發現就一個簡單的框選圖表用Echarts來作是否是大材小用了,並且還要導入那麼多的沒用的代碼。css

因而我想到了用canvas畫布來仿着作,但又考慮了一下,canvas操做起來不順手;究竟可不能夠用普通的css結合javascript來把它作出來呢?此番思考驗證了:任何事情必定要多動腦,才能 到更簡單的解決問題的方式。html

考慮到也許某天你們用得着,因此發佈出來。注:擁有可移植性,可移到頁面任何位置,效果不會改變

先看最終效果吧:
圖一:
溜溜豬java

圖二:
溜溜豬canvas

這個小東西會涉及的知識點很少,概括一下:js的三角函數CSS3的transform鼠標的座標軸XY的計算...啊哈,差很少大致就這三方面的知識吧,若是你都只是有過了解也不要緊,由於都只用的到皮毛因此沒必要擔憂。可是若是徹底沒聽過,那就請您再去了解一下這方面知識。後端

代碼區域

<!doctype html>
<html>
<head>
    <meta charset="utf-8" />
    <title>仿Echarts圖表</title>
    <style>
        * {
            padding:0;
            margin:0;
        }
        #getcharts {
            position:relative;
            width:510px;
            height:510px;

        }
        #wrapcharts {
            list-style:none;
            height:500px;
            width:500px;
            border:2px solid #aaa;
            border-radius:50%;
            position:relative;
            margin:20px auto;
        }
        #wrapcharts li {
            height:10px;
            width:10px;
            diaplay:block;
            position:absolute;
            cursor:pointer;
            left:247px;
            top:2px;
            height:10px;
            width:10px;
            transition:0.2s;
            background:red;
            border-radius:50%;
        }
        #boxshadow {
            position:absolute;
            background:blue;
            opacity:0.2;
            height:0;
            width:0;
            left:0;
            top:0;
        }
    </style>
</head>
<body>

    <ul id="wrapcharts"></ul>
    <div id="boxshadow"></div>
    
<script>
    /*
     **模擬從後端取值過來的【角度】和相對應的【人名】數組
     **/
    var degArr = [25,88,252,323,33,28,30,90,290,100,300,50,180,205,220,331,195,97,102,77,62,38,32,79];
    var nameArr = ['內衣天使','小惡魔','金正恩','奧巴馬','duolaA夢','午夜激情','梁靜茹','劉亦菲','琪琪','大熊','小靜','小屁孩','張三','李四','王五','麻六','小明','小張','麗麗','多多','瑾瑾','biubiu','Mr.boluo','Hanson'];
    /*
     **聲明 getPos(param)函數: 利用三角函數定理根據傳入的角度值獲取對邊和臨邊的x,y值
     **/
    function getPos(deg)
    {
        var X = Math.sin(deg*Math.PI/180)*250 + 245;
        var Y = -Math.cos(deg*Math.PI/180)*250 + 245;
        return {x:X,y:Y};
    }
    /*
     **這裏不用說吧,獲取頁面中的ul,和ul中的li對象,以及框選時的那個任意變更大小的小方塊對象
     **/
    var oWrap = document.getElementById('wrapcharts');
    var aLi = oWrap.getElementsByTagName('li');
    var oBox =document.getElementById('boxshadow');
    var allLi = '';
    var posArr = [];
    /*
     **for循環中調用getPos(param)來獲取degArr數組中的全部角度對應的x,y值(就是每一個角度對應的x,y座標),並傳入到一個數組中保存,方便取用
     **/
    for(var i=0;i<degArr.length; i++)
    {
        posArr.push(getPos(degArr[i]));
    }
    /*
     **for循環根據度數數組degArr的長度插入li小圓點到ul中,並將以前獲取的每一個點對應的x,y左邊插入到行內樣式
     **/
    for(var i=0; i<degArr.length; i++)
    {
        allLi += '<li style="left:'+posArr[i].x+'px;top:'+posArr[i].y+'px;" title="'+degArr[i]+'°;姓名:'+nameArr[i]+'"></li>';
    }
    oWrap.innerHTML = allLi;
    /*
     **遍歷最終獲得的ul中的li
     **/
    for(var i=0; i<aLi.length; i++)
    {
        aLi[i].index = i;
        /*
         **封裝鼠標移入每一個小圓點時的放大事件,這裏用到了matrix矩陣,爲的事想兼容ie9如下瀏覽器,可是好像出了點問題
         */
        function focusOn(_this,color, size)
        {
            _this.style.background = color;
            _this.style.WebkitTransform = 'matrix('+size+', 0, 0, '+size+', 0, 0)';
            _this.style.MozTransform = 'matrix('+size+', 0, 0, '+size+', 0, 0)';
            _this.style.transform = 'matrix('+size+', 0, 0, '+size+', 0, 0)';
            _this.style.filter="progid:DXImageTransform.Microsoft.Matrix( M11= "+size+", M12= 0, M21= 0 , M22="+size+",SizingMethod='auto expend')";
        }
        aLi[i].onmouseover = function()
        {
            //alert(this.offsetLeft);
            _this = this;
            focusOn(_this,'blue', 2);
        }
        aLi[i].onmouseout = function()
        {
            //alert(this.offsetLeft);
            _this = this;
            focusOn(_this,'red', 1);

        }
    }
    /***框選***/
    /*
     **拖拽框選代碼區域,這個我就不解釋了,明白人都一眼知道什麼意思,這就像是公式,
     */
    var allSelect = {};
    document.onmousedown = function(ev)
    {
        var ev = ev || window.event;
        var disX = ev.clientX;
        var disY = ev.clientY;
        var H = W = clientleft = clienttop =  clientright = clientbottom = 0;
        oBox.style.cssText = 'left:'+disX+'px;top:'+disY+'px;';
        //console.log(disX+';'+disY);
        function again(f)
        {
            for(var i=0; i<posArr.length; i++)
            {
                if(posArr[i].x > clientleft && posArr[i].y > clienttop  && (posArr[i].x + 10) < clientright && (posArr[i].y +10) < clientbottom)
                {
                    //console.log(clientleft+';'+ clienttop +';'+ clientright +';' +  clientbottom);
                    if(f){allSelect[i] = i;}else{
                        aLi[i].style.background = 'blue';
                    }
                } else
                {
                    aLi[i].style.background = 'red';
                }
            }

        }

        document.onmousemove = function(ev)
        {
            var ev = ev || window.event;
            /*
             **當鼠標向四個方向拖拉的時候進行方向判斷,並相應的改變小方塊的left,top以及width,height
             **其實我這裏有個問題,那就是,代碼重複了一些,本想着合併一下,可是做者有點懶,嘿嘿,大家也能夠嘗試一下
             **修改後大家拿去當作大家的發佈,做者不會介意的
             */
            if(ev.clientX > disX && ev.clientY > disY)
            {
                W = ev.clientX - disX;
                H = ev.clientY - disY;

                oBox.style.width = W + 'px';
                oBox.style.height = H + 'px';

                clienttop  = disY-oWrap.offsetTop;
                clientleft = disX-oWrap.offsetLeft;

            }else if(ev.clientX < disX && ev.clientY < disY)
            {
                W = disX - ev.clientX;
                H = disY - ev.clientY;

                oBox.style.top  = ev.clientY + 'px';
                oBox.style.left = ev.clientX + 'px';

                oBox.style.width  = W + 'px';
                oBox.style.height = H + 'px';

                clienttop  = ev.clientY - oWrap.offsetTop;
                clientleft = ev.clientX - oWrap.offsetLeft;

            }else if(ev.clientX > disX && ev.clientY < disY)
            {
                W = ev.clientX - disX;
                H = disY - ev.clientY;

                oBox.style.top  = ev.clientY + 'px';

                oBox.style.width = W + 'px';
                oBox.style.height = H + 'px';

                clienttop  = ev.clientY - oWrap.offsetTop;
                clientleft = disX - oWrap.offsetLeft;

            }else if(ev.clientX < disX && ev.clientY > disY)
            {
                W = disX - ev.clientX;
                H = ev.clientY - disY;

                oBox.style.left = ev.clientX + 'px';

                oBox.style.width  = W + 'px';
                oBox.style.height = H + 'px';

                clienttop  = disY-oWrap.offsetTop;
                clientleft = ev.clientX - oWrap.offsetLeft;
            }


            clientright  = clientleft+ W;
            clientbottom = clienttop + H;

            W = '';
            H = '';

            again();

        }
        document.onmouseup = function()
        {
            again(1);

            document.onmouseup = document.onmousemove = null;
            oBox.style.cssText = 'height:0;width:0;';
            if(JSON.stringify(allSelect) == '{}'){return;}
            console.log(allSelect);

            var lastSelect = [];
            for(var attr in allSelect){
                lastSelect.push(nameArr[attr]);
            }
            allSelect = {};

            console.log(lastSelect);
            alert('你選中的人是:\n\n'+lastSelect+'\n\n');

            for(var i=0; i<aLi.length; i++)
            {
                aLi[i].style.background = 'red';
            }
        }
        return false;
    }
</script>
</body>
</html>

會用到的一些知識點拓展

注:在js中設置Transform的時候我用到的不是scale()方法,由於我想兼容ie9如下的版本因此用了矩陣變化。固然,大家也能夠改成scale(),毫無影響。
  1. 在標準瀏覽器下的矩陣函數matix(a,b,c,d,e,f)、ie下的矩陣函數progid:DXImageTransform.Microsoft.Matrix( M11= 1, M12= 0, M21= 0 , M22=1,SizingMethod='auto expend')
    他們的共同點:M11 == a; M12 == c; M21 == b; M22 == d
    不同的地方:ie下的矩陣函數沒有ef兩個參數,在矩陣函數中ef是用來位移的,也就是說ie下無法經過矩陣函數來實現位移[ 不過咱們這裏好像不須要位移,嘿嘿 ]數組

  2. 在標準瀏覽器下矩陣函數matrix中a,b,c,d,e,f 一一對應的的初始值爲:matix(1,0,0,1,0,0)瀏覽器

  3. 經過矩陣實現縮放:
    x軸縮放:a = xa c = xc e = x*e
    y軸縮放:b = yb d = yd f = y*f函數

  4. 經過矩陣實現位移:[ie下沒位移]
    x軸位移:e = e+x
    y軸位移:f = f+ythis

  5. 經過矩陣實現傾斜:
    x軸傾斜:c = Math.tan(xDeg/180*Math.PI)
    y軸傾斜:b = Math.tan(yDeg/180*Math.PI)

  6. 經過矩陣實現旋轉:
    a = Math.cos(deg/180*Math.PI);
    b = Math.sin(deg/180*Math.PI);
    c = -Math.sin(deg/180*Math.PI);
    d = Math.cos(deg/180*Math.PI);

  7. 至於三角函數我就不介紹了,百度一大把:
    三角函數

相關文章
相關標籤/搜索