用H5 Canvas 繪畫箭頭
阿新 • • 發佈:2019-02-16
最近做一個專案,需要最近繪畫一個箭頭,其實用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 **/
效果如下圖: