您的位置:首页 > Web前端 > HTML5

用H5 Canvas 绘画箭头

2016-11-30 11:39 211 查看
最近做一个项目,需要最近绘画一个箭头,其实用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;

8c1c
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 **/


效果如下图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  html canvas 算法