1. 程式人生 > >用H5 Canvas 繪畫箭頭

用H5 Canvas 繪畫箭頭

最近做一個專案,需要最近繪畫一個箭頭,其實用Canvas繪畫很簡單,但是箭頭涉及到八個方向,上、下、左、右都很簡單,斜方向的箭頭就會有一個角度換算的問題,演算法稍微有點複雜,所以做下筆記,供參考;

html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        ul{padding: 0; margin: 0; color: #999999;list-style: none;}
        .quickConnectScreen{width: 100%;}
        .netPort{width: 100%; overflow: hidden; margin-bottom: 30px;}
        .netPort>ul.netPort-ul>li{padding: 5px; list-style: none;float: left;}
        .netPort>ul.netPort-ul>li button{padding: 8px 18px; font-size: 16px; color: #ffffff;border: none;}
        .ruler{position: relative; margin-left: 50px;  }
        .ruler .port-block .direction{width: 100%; height: 100%;}
        .ruler .port-block.border{border: 2px solid #cccccc}
        .ruler .port-list{margin-top: 25px; margin-left: 25px; overflow: hidden; float: left;}
        .ruler .ruler-h{ height: 27px; background: url("img/ruler-h.png"); position: absolute; z-index: -1; left: 24px;}
        .ruler .ruler-z{ width: 27px; background: url("img/ruler-z.png"); position: absolute; z-index: -1; top:24px;}
        .ruler .ruler-h ul{margin-top: -18px; margin-left: -5px;}
        .ruler .ruler-h ul li{float: left; width: 40px;}
        .ruler .ruler-z ul{margin-top: -8px; margin-left: -25px;}
        .ruler .ruler-z ul li{list-style: none;height: 40px;}
        .unitConversion{height: 60px; padding-left: 15px; line-height: 30px;}
        .unitConversion span{display: inline-block; float: left; }
        .unitConversion ul{float: left; border: 1px solid #b6b6b6; }
        .unitConversion ul li{float: left; width: 60px; height: 30px; text-align: center; cursor: pointer;  }
        .unitConversion ul li.active{background: #4f99c6; color: #ffffff; }
    </style>
</head>
<body>
<div class="quickConnectScreen">
    <div class="netPort">
        <ul class="netPort-ul">
        </ul>
    </div>

    <div class="unitConversion">
        <span>選擇單位: </span>
        <ul>
            <li class="active" onclick="initRuler(info[0].ruler[0],10)">畫素</li>
            <li onclick="initRuler(info[0].ruler[0],1)">箱體</li>
        </ul>
    </div>

    <div class="ruler">
        <div class="ruler-h">
            <ul>
            </ul>
        </div>
        <div class="ruler-z">
            <ul>
            </ul>
        </div>
        <div class="port-list">
        </div>
    </div>
</div>
<script  src="http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script>
<script  src="draw.js"></script>
<script>

    var unitSize = 40 ; //標尺每一大格的實際畫素

    var info =[{
        'ruler':[{'width':1000,'height':700,'unit':10}], //w 為標尺的寬 h 為標尺的高;unit 為標尺的單位 引數可為 1 10 100 ...
        'data' :[
            {width:120,height:30,direction:'right'},
            {width:70,height:20,direction:'bottom'},
            {width:150,height:10,direction:'left'},
            {width:130,height:15,direction:'rightBottom'},
            {width:120,height:25,direction:'bottom'},
            {width:150,height:15,direction:'top'},
            {width:150,height:15,direction:'leftTop'},
            {width:100,height:10,direction:'leftBottom'},
            {width:100,height:10,direction:'top'},
            {width:100,height:10,direction:'rightTop'},
            {width:100,height:20,direction:'right'},
            {width:100,height:15,direction:'bottom'}
        ]
    }];

    var color = ['#2a8bcc','#b4c2cc','#86b558','#ffb44b','#d3413b','#999999','#9889c1','#d54c7e','#444444','#68adde','#fee088','#797979'];

    $(function(){

        // 初始化
        initWalkLine(info);

        $('.unitConversion ul>li').click(function(){
            $(this).addClass('active');
            $(this).siblings().removeClass('active');
        })
    });


</script>
</body>

js:
//初始化標尺
function initRuler(data,u){
    var w = data.width;
    var h = data.height;
    if(arguments[1]==undefined){
        var u = data.unit;
    }
    $('.ruler-h').css('width',w +'px');
    $('.ruler-z').css('height',h +'px');
    $('.ruler-h ul').html('');
    $('.ruler-z ul').html('');
    for(var i=0; i<Math.floor(w/40); i++){
        $('.ruler-h ul').append('<li>'+ i*u +'</li>');
    }
    for(var j=0; j<Math.ceil(h/40); j++){
        $('.ruler-z ul').append('<li>'+ j*u +'</li>');
    }
}

//標尺每格畫素為4px
function conversion(x){
    return 4*x;
}


/**  走線方式js **/
//走線方式的初始化
function initWalkLine(info){
    initRuler(info[0].ruler[0]);
    initLine(info[0].data,color);
}

//初始化走線,走線方式頁面專用
function initLine(data,color){
    for(var i=0;i<data.length;i++){
        //按鈕初始化
        $('.netPort-ul').append('<li><button style="background: '+ color[i] +'">網口'+ (i+1) +'</button></li>');
        //埠面積
        $('.port-list').append('<div class="port-block border" style="width: '+ conversion(data[i].width)
            +'px;height: '+ conversion(data[i].height) + 'px;"><canvas id="canvas'+ i +'"></canvas></div>');

        drawArrow('canvas'+ i ,data[i].direction);
    }
}



//使用canvas繪畫箭頭 引數id為每個canvas的ID direction 為箭頭方向
function drawArrow(id,direction ){
    var s1 = 20 ; //箭頭頭部到末端的平行方向的位移
    var s2 = 10 ; //箭頭頭X部到末端的垂直方向的位移
    var c=document.getElementById(id);
    var Pwidth = c.parentNode.clientWidth;
    var Pheight = c.parentNode.clientHeight;
    resizeCanvas(id,Pwidth,Pheight);
    var cxt=c.getContext("2d");

    switch (direction){
        case 'right':
            cxt.moveTo(0,Pheight/2);
            cxt.lineTo(Pwidth,Pheight/2);
            cxt.lineTo((Pwidth-s1),(Pheight/2-s2));
            cxt.moveTo(Pwidth,Pheight/2);
            cxt.lineTo((Pwidth-s1),(Pheight/2+s2));
            break ;
        case 'left':
            cxt.moveTo(Pwidth,Pheight/2);
            cxt.lineTo(0,Pheight/2);
            cxt.lineTo(s1,(Pheight/2-s2));
            cxt.moveTo(0,Pheight/2);
            cxt.lineTo(s1,(Pheight/2+s2));
            break ;
        case 'top':
            cxt.moveTo(Pwidth/2,Pheight);
            cxt.lineTo(Pwidth/2,0);
            cxt.lineTo((Pwidth/2-s2),s1);
            cxt.lineTo(Pwidth/2,0);
            cxt.lineTo((Pwidth/2+s2),s1);
            break ;
        case 'bottom':
            cxt.moveTo(Pwidth/2,0);
            cxt.lineTo(Pwidth/2,Pheight);
            cxt.lineTo((Pwidth/2-s2),Pheight-s1);
            cxt.lineTo(Pwidth/2,Pheight);
            cxt.lineTo((Pwidth/2+s2),Pheight-s1);
            break ;
        case 'rightTop':
            cxt.moveTo(0,Pheight);
            cxt.lineTo(Pwidth,0);
            cxt.lineTo(getPosition(Pwidth,Pheight,s2,s1,'rightTop')[0].x,getPosition(Pwidth,Pheight,s2,s1,'rightTop')[0].y);
            cxt.moveTo(Pwidth,0);
            cxt.lineTo(getPosition(Pwidth,Pheight,s2,s1,'rightTop')[1].x,getPosition(Pwidth,Pheight,s2,s1,'rightTop')[1].y);
            break ;
        case 'leftTop':
            cxt.moveTo(Pwidth,Pheight);
            cxt.lineTo(0,0);
            cxt.lineTo(getPosition(Pwidth,Pheight,s2,s1,'leftTop')[0].x,getPosition(Pwidth,Pheight,s2,s1,'leftTop')[0].y);
            cxt.moveTo(0,0);
            cxt.lineTo(getPosition(Pwidth,Pheight,s2,s1,'leftTop')[1].x,getPosition(Pwidth,Pheight,s2,s1,'leftTop')[1].y);
            break ;
        case 'rightBottom':
            cxt.moveTo(0,0);
            cxt.lineTo(Pwidth,Pheight);
            cxt.lineTo(getPosition(Pwidth,Pheight,s2,s1,'rightBottom')[0].x,getPosition(Pwidth,Pheight,s2,s1,'rightBottom')[0].y);
            cxt.moveTo(Pwidth,Pheight);
            cxt.lineTo(getPosition(Pwidth,Pheight,s2,s1,'rightBottom')[1].x,getPosition(Pwidth,Pheight,s2,s1,'rightBottom')[1].y);
            break ;
        case 'leftBottom':
            cxt.moveTo(Pwidth,0);
            cxt.lineTo(0,Pheight);
            cxt.lineTo(getPosition(Pwidth,Pheight,s2,s1,'leftBottom')[0].x,getPosition(Pwidth,Pheight,s2,s1,'leftBottom')[0].y);
            cxt.moveTo(0,Pheight);
            cxt.lineTo(getPosition(Pwidth,Pheight,s2,s1,'leftBottom')[1].x,getPosition(Pwidth,Pheight,s2,s1,'leftBottom')[1].y);
            break ;
    }
    cxt.stroke();
}

//通過獲取方向為右上的斜向箭頭的座標位置,相應得到其它四個方向的位置
function getPosition(w,h,m,n,direction){
    var post,position=[],position1 = {}, position2 = {} ;
    post = getPost(w,h,m,n);
    switch (direction){
        case 'rightTop':
            position1  =  post[0] ;
            position2  =  post[1] ;
            break;
        case 'leftTop':
            position1.x = w - post[0].x;
            position1.y = post[0].y;
            position2.x = w - post[1].x;
            position2.y = post[1].y;
            break;
        case 'rightBottom':
            position1.x = post[0].x;
            position1.y = h - post[0].y;
            position2.x = post[1].x;
            position2.y = h - post[1].y;
            break;
        case 'leftBottom':
            position1.x = w - post[0].x;
            position1.y = h - post[0].y;
            position2.x = w - post[1].x;
            position2.y = h - post[1].y;
            break;
    }
    position.push(position1);
    position.push(position2);
    return position;

}

//獲取方向為右上的斜向箭頭的座標 w,h 為區域面試的寬高 m,n 為箭頭尾部相對於箭頭主線的位移
function getPost(w,h,m,n){
    var a = Math.atan(h/w);
    var b = Math.atan(m/n);
    var c = Math.atan(w/h);
    var  position=[],position1 = {}, position2 = {};
    if (b < a && b < c) {
        position1.x = w - Math.cos(a - b) * (Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2)));
        position1.y = Math.sin(a - b) * (Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2)));
        position2.x = w - Math.sin(c - b) * (Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2)));
        position2.y = Math.cos(c - b) * (Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2)));
    } else if (b >= a) {
        position1.x = w - Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2));
        position1.y = 1;
        position2.x = w - Math.sin(c - a) * (Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2)));
        position2.y = Math.cos(c - a) * (Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2)));
    }else if (b >= c) {
        position1.x = w - Math.cos(a - c) * (Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2)));
        position1.y = Math.sin(a - c) * (Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2)));
        position2.x = 1;
        position2.y = Math.sqrt(Math.pow(m, 2) + Math.pow(n, 2));
    }
    position.push(position1);
    position.push(position2);
    return position;
}


function resizeCanvas(id,w,h){
    $('#'+id).attr("width",w);
    $('#'+id).attr("height",h);

}


/** end  走線方式js **/


效果如下圖: