失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > java使用重绘实现拖动_原生JS使用Canvas实现拖拽式绘图功能

java使用重绘实现拖动_原生JS使用Canvas实现拖拽式绘图功能

时间:2023-03-13 18:15:42

相关推荐

java使用重绘实现拖动_原生JS使用Canvas实现拖拽式绘图功能

一、实现的功能

1、基于oop思想构建,支持坐标点、线条(由坐标点组成,包含方向)、多边形(由多个坐标点组成)、圆形(包含圆心坐标点和半径)等实体

2、原生JavaScript实现,不依赖任何第三方js库和插件

3、多图形绘制(支持画笔、线条、箭头、三角形、矩形、平行四边形、梯形以及多边形和圆形绘制)

4、拖拽式绘制(鼠标移动过程中不断进行canvas重绘)

5、图片绘制(作为背景图片时重绘会发生闪烁现象,暂时有点问题,后面继续完善)

5、清空绘制功能

6、新版本优化绘制性能(使用共享坐标变量数组,减少了大量的对象创建操作)

7、新版本支持箭头绘制功能

二、完整实现代码

DrawingTools =(function(){

//公共方法

var getDom=function(id){return document.getElementById(id)};

var isNull=function(s){return s==undefined||typeof(s)=='undefined'||s==null||s=='null'||s==''||s.length<1};

var hideDefRM=function(){document.οncοntextmenu=function(){return false}};//屏蔽浏览器默认鼠标事件

/**绘图容器*/

var cbtCanvas;

/**绘图对象*/

var cxt;

/**绘制的图形列表*/

var shapes=new Array();

var graphkind={'cursor':0,'pen':1,'line':2,'trian':3,'rect':4,'poly':5,'circle':6,'arrow':21,'parallel':41,'trapezoid':42};

//背景图片绘制配置

var bgPictureConfig={

pic:null,//背景图片地址或路径

repaint:true,//是否作为永久背景图,每次清除时会进行重绘

};

//加载并绘制图片(src:图片路径或地址),默认重绘背景图

var loadPicture=function(src){

if(isNull(bgPictureConfig.repaint)||bgPictureConfig.repaint){bgPictureConfig.pic=src}

var img = new Image();

img.onload = function(){cxt.drawImage(img,0,0)}

img.src =src;

}

//绘图基础配置

var paintConfig={lineWidth:1,//线条宽度,默认1

strokeStyle:'red',//画笔颜色,默认红色

fillStyle:'red',//填充色

lineJoin:"round",//线条交角样式,默认圆角

lineCap:"round",//线条结束样式,默认圆角

};

//重新载入绘制样式

var resetStyle=function(){

cxt.strokeStyle=paintConfig.strokeStyle;

cxt.lineWidth=paintConfig.lineWidth;

cxt.lineJoin=paintConfig.lineJoin;

cxt.lineCap=paintConfig.lineCap;

cxt.fillStyle=paintConfig.fillStyle;

}

//鼠标图形

var cursors=['crosshair','pointer'];

/** 切换鼠标样式*/

var switchCorser=function(b){

cbtCanvas.style.cursor=((isNull(b)?isDrawing():b)?cursors[0]:cursors[1]);

}

//操作控制变量组

var ctrlConfig={

kind:0,//当前绘画分类

isPainting:false,//是否开始绘制

startPoint:null,//起始点

cuGraph:null,//当前绘制的图像

cuPoint:null,//当前临时坐标点,确定一个坐标点后重新构建

cuAngle:null,//当前箭头角度

vertex:[],//坐标点

}

/**获取当前坐标点*/

var getCuPoint=function(i){

return ctrlConfig.cuPoint[i];

}

/**设置当前坐标点*/

var setCuPoint=function(p,i){

return ctrlConfig.cuPoint[i]=p;

}

/**设置当前临时坐标点值*/

var setCuPointXY=function(x,y,i){

if(isNull(ctrlConfig.cuPoint)){

var arr=new Array();

arr[i]=new Point(x,y);

ctrlConfig.cuPoint=arr;

}else if(isNull(ctrlConfig.cuPoint[i])){

setCuPoint(new Point(x,y),i);

}else{

ctrlConfig.cuPoint[i].setXY(x,y);

}

return getCuPoint(i);

}

/**是否正在绘制*/

var isDrawing=function (){

return ctrlConfig.isPainting;

}

/**开始绘制状态*/

var beginDrawing=function(){

ctrlConfig.isPainting=true;

}

/**结束绘制状态*/

var stopDrawing=function(){

ctrlConfig.isPainting=false;

}

/**是否有开始坐标点*/

var hasStartPoint=function(){

return !isNull(ctrlConfig.startPoint);

}

/**设置当前绘制的图形*/

var setCuGraph=function(g){

ctrlConfig.cuGraph=g;

}

/**获取当前绘制的图形*/

var getCuGraph=function(){

return ctrlConfig.cuGraph;

}

/**设置开始坐标点(线条的起始点,三角形的顶点,圆形的圆心,四边形的左上角或右下角,多边形的起始点)*/

var setStartPoint=function(p){

ctrlConfig.startPoint=p;

}

/**获取开始坐标点*/

var getStartPoint=function(){

return ctrlConfig.startPoint;

}

/**清空全部*/

var clearAll=function(){

cxt.clearRect(0,0,cbtCanvas.width,cbtCanvas.height);

}

/**重绘*/

var repaint=function(){

clearAll();

/*

if(bgPictureConfig.repaint){

loadPicture(bgPictureConfig.pic);

}*/

}

/**点(坐标,绘图的基本要素,包含x,y坐标)*/

var Point=(function(x1,y1){

var x=x1,y=y1;

return{

set:function(p){

x=p.x,y=p.y;

},

setXY:function(x2,y2){

x=x2;y=y2;

},

setX:function(x3){

x=x3;

},

setY:function(y3){

y=y3;

},

getX:function(){

return x;

},

getY:function(){

return y;

}

}

});

/**多角形(三角形、矩形、多边形),由多个点组成*/

var Poly=(function(ps1){

var ps=isNull(ps1)?new Array():ps1;

var size=ps.length;

return{

set:function(ps2){

ps=ps2;

},

getSize:function(){

return size;

},

setPoint:function(p,i){

if(isNull(p)&&isNaN(i)){

return;

}

ps[i]=p;

},

setStart:function(p1){

if(isNull(ps)){

ps=new Array();

return ps.push(p1);

}else{

ps[0]=p1;

}

},

add:function(p){

if(isNull(ps)){

ps=new Array();

}

return ps.push(p);

},

pop:function(){

if(isNull(ps)){

return;

}

return ps.pop();

},

shift:function(){

if(isNull(ps)){

return;

}

return ps.shift;

},

get:function(){

if(isNull(ps)){

return null;

}

return ps;

},

draw:function(){

cxt.beginPath();

for(i in ps){

if(i==0){

cxt.moveTo(ps[i].getX(),ps[i].getY());

}else{

cxt.lineTo(ps[i].getX(),ps[i].getY());

}

}

cxt.closePath();

cxt.stroke();

}

}

});

/*线条(由两个点组成,包含方向)*/

var Line=(function(p1,p2,al){

var start=p1,end=p2,angle=al;

var drawLine=function(){

cxt.beginPath();

cxt.moveTo(p1.getX(),p1.getY());

cxt.lineTo(p2.getX(),p2.getY());

cxt.stroke();

}

//画箭头

var drawArrow=function() {

var vertex =ctrlConfig.vertex;

var x1=p1.getX(),y1=p1.getY(),x2=p2.getX(),y2=p2.getY();

var el=50,al=15;

//计算箭头底边两个点(开始点,结束点,两边角度,箭头角度)

vertex[0] = x1,vertex[1] = y1, vertex[6] = x2,vertex[7] = y2;

//计算起点坐标与X轴之间的夹角角度值

var angle = Math.atan2(y2 - y1, x2 - x1) / Math.PI * 180;

var x = x2 - x1,y = y2 - y1,length = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));

if (length < 250) {

el/=2,al/2;

}else if(length<500){

el*=length/500,al*=length/500;

}

vertex[8] = x2 - el * Math.cos(Math.PI / 180 * (angle + al));

vertex[9] = y2- el * Math.sin(Math.PI / 180 * (angle + al));

vertex[4] = x2- el* Math.cos(Math.PI / 180 * (angle - al));

vertex[5] = y2 - el * Math.sin(Math.PI / 180 * (angle - al));

//获取另外两个顶点坐标

x=(vertex[4]+vertex[8])/2,y=(vertex[5]+vertex[9])/2;

vertex[2] = (vertex[4] + x) / 2;

vertex[3] = (vertex[5] + y) / 2;

vertex[10] = (vertex[8] +x) / 2;

vertex[11] = (vertex[9] +y) / 2;

//计算完成,开始绘制

cxt.beginPath();

cxt.moveTo(vertex[0], vertex[1]);

cxt.lineTo(vertex[2], vertex[3]);

cxt.lineTo(vertex[4], vertex[5]);

cxt.lineTo(vertex[6], vertex[7]);

cxt.lineTo(vertex[8], vertex[9]);

cxt.lineTo(vertex[10], vertex[11]);

cxt.closePath();

cxt.fill();

cxt.stroke();

}

return{

setStart:function(s){

start=s;

},

setEnd:function(e){

end=e;

},

getStart:function(){

return start;

},

getEnd:function(){

return end;

},

draw:function(){

if(angle){

drawArrow();

}else{

drawLine();

}

}

}

});

/**圆形(包含圆心点和半径)*/

var Circle=(function(arr){

//包含起始点(圆心)和结束点,以及圆半径

var startPoint=arr.start,endPoint=arr.end,radius=arr.radius;

/*绘制圆*/

var drawCircle=function(){

cxt.beginPath();

var x=startPoint.getX();

var y=startPoint.getY();

if(isNull(radius)){

radius=calculateRadius(startPoint,endPoint);

}

//x,y,半径,开始点,结束点,顺时针/逆时针

cxt.arc(x,y,radius,0,Math.PI*2,false); // 绘制圆

cxt.stroke();

}

//计算圆半径

var calculateRadius=function(p1,p2){

var width=p2.getX()-p1.getX();

var height=p2.getY()-p1.getY();

//如果是负数

if(width<0||height<0){

width=Math.abs(width);

}

//计算两点距离=平方根(width^2+height^2)

c=Math.sqrt(Math.pow(width,2)+Math.pow(height,2));

return c;

}

return{

set:function(params){

startPoint=params.start;

endPoint=params.end;

radius=params.radius;

},

setPoint:function(p1){

p=p1;

},

getPoint:function(){

return p;

},

setRadius:function(r1){

radius=r1;

},

getRadius:function(){

return radius;

},

calcRadius:calculateRadius,

//绘制

draw:drawCircle,

}

});

/**绘制线条工具方法*/

var drawLine=function(p){

cxt.beginPath();

cxt.moveTo(startPosition.getX(),startPosition.getY());

cxt.lineTo(p.getX(),p.getY());

cxt.stroke();

}

/**绘制三角形工具方法*/

var drawTrian=function(ps){

cxt.beginPath();

var a=ps.get();

cxt.moveTo(a[0].getX(),a[0].getY());

cxt.lineTo(a[1].getX(),a[1].getY());

cxt.lineTo(a[2].getX(),a[2].getY());

cxt.closePath();

cxt.stroke();

}

/**绘制矩形工具方法*/

var drawRect=function(p2){

var p=getStartPoint();

var width=p.getX()-p2.getX();

var height=p.getY()-p2.getY();

cxt.beginPath();

cxt.strokeRect(x,y,width,height);//绘制矩形

}

/*绘制多边形工具方法*/

var drawpolygon=function(ps){

if(ps.length>1){//保证只有两个坐标点才是矩形

cxt.beginPath();

var p=ctrlConfig.startPoint;

var x=p.getX();

var y=p.getY();

cxt.moveTo(x,y);

for(p1 in ps){

cxt.lineTo(p1.getX(),p1.getY());

}

cxt.stroke();

}

}

/*绘制圆角矩形工具方法*/

var drawRoundedRect=function(x,y,width,height,radius){

cxt.beginPath();

cxt.moveTo(x,y+radius);

cxt.lineTo(x,y+height-radius);

cxt.quadraticCurveTo(x,y+height,x+radius,y+height);

cxt.lineTo(x+width-radius,y+height);

cxt.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);

cxt.lineTo(x+width,y+radius);

cxt.quadraticCurveTo(x+width,y,x+width-radius,y);

cxt.lineTo(x+radius,y);

cxt.quadraticCurveTo(x,y,x,y+radius);

cxt.stroke();

}

/*绘制圆工具方法*/

var drawCircle=function(c){

var p=c.getPoint();//坐标点

var x=p.getX();

var y=p.getY();

var r=c.getRadius();

cxt.beginPath();

//x,y,半径,开始点,结束点,顺时针/逆时针

cxt.arc(x,y,r,0,Math.PI*2,false); // 绘制圆

cxt.stroke();

}

//计算圆半径工具方法

var calculateRadius=function(p1,p2){

var width=p2.getX()-p1.getX();

var height=p2.getY()-p1.getY();

//如果是负数

if(width<0||height<0){

width=Math.abs(width);

}

//计算两点距离=平方根(width^2+height^2)

c=Math.sqrt(Math.pow(width,2)+Math.pow(height,2));

return c;

}

//鼠标按键点击(首次点击确定开始坐标点,拖动鼠标不断进行图形重绘)

var mouseDown = function(e){

var btnNum = e.button;

if(btnNum==0){

console.log("选择:"+ctrlConfig.kind);

//设置起始点

switch(ctrlConfig.kind){

case graphkind.pen://画笔(不松开鼠标按键一直画)

beginDrawing();//开始绘制

cxt.beginPath();

cxt.moveTo(e.offsetX,e.offsetY);

break;

case graphkind.poly://多边形

var p=new Point(e.offsetX,e.offsetY);

if(isDrawing()){

getCuGraph().add(p);//添加到

}else{//第一次确定开始坐标

beginDrawing();//开始绘制

setStartPoint(p);

var poly=new Poly();

poly.add(p);

setCuGraph(poly);//设置当前绘制图形

}

break;

case graphkind.line://线条

case graphkind.arrow://方向

case graphkind.trian://三角形

case graphkind.rect://矩形

case graphkind.parallel://平行四边形

case graphkind.trapezoid://梯形

beginDrawing();//开始绘制

var p=new Point(e.offsetX,e.offsetY);

setStartPoint(p);

var poly=new Poly();

poly.add(p);

setCuGraph(poly);//设置当前绘制图形

break;

case graphkind.circle://圆

console.log("确定图形绘制开始坐标点:"+e.offsetX+","+e.offsetY);//点击确定图形的开始坐标点

beginDrawing();//开始绘制

var p=new Point(e.offsetX,e.offsetY);

setStartPoint(p);

var circle= new Circle({'start':p});

setCuGraph(circle);

break;

case ctrlConfig.cursor: //手型鼠标

default://默认是手型鼠标,不允许绘制

}

}else if(btnNum==2){

console.log("右键由于结束多边形绘制");

if(isDrawing()){

if(ctrlConfig.kind==graphkind.poly){

repaint();

getCuGraph().draw();

stopDrawing();//结束绘制

}

}

}

hideDefRM();//屏蔽浏览器默认事件

}

//鼠标移动(拖动,根据鼠标移动的位置不断重绘图形)

var mouseMove = function(e){

if(isDrawing()&&hasStartPoint()){//检查是否开始绘制,检查是否有开始坐标点

//画笔不需要重绘

if(ctrlConfig.kind>1){

repaint();//重绘

}

var p=setCuPointXY(e.offsetX,e.offsetY,0);//设置共享的临时坐标点,用于防止重复创建对象

switch(ctrlConfig.kind){

case graphkind.pen://画笔(一直画)

cxt.lineTo(e.offsetX,e.offsetY);

cxt.stroke();

break;

case graphkind.poly://多边形

var poly=getCuGraph(poly);

var size=poly.getSize();

poly.setPoint(p,(size-1));

poly.draw();

break;

case graphkind.line://线条

var line=new Line(getStartPoint(),p,false);

ctrlConfig.cuGraph=line;

line.draw();

break;

case graphkind.arrow://方向

var line=new Line(getStartPoint(),p,true);

ctrlConfig.cuGraph=line;

line.draw();

break;

case graphkind.trian://三角形

var lu=getStartPoint();

var x2=p.getX();

var x1=lu.getX();

//三角形左边的点坐标计算方法:(x1-(x2-x1),y2)

var x3=x1-(x2-x1);

var l=setCuPointXY(x3,p.getY(),1);//设置共享的临时坐标点,用于防止重复创建对象

var poly=getCuGraph();//获取当前图形

poly.set([lu,p,l]);

poly.draw();//即时绘制

break;

case graphkind.parallel://平行四边形

var lu=getStartPoint();

var x3=p.getX();

var x1=lu.getX();

//平行四边形两个未知坐标点计算方法:(x1-(x3-x1),y3),(x1+(x3-x1),y1)

var x2=x3+(x3-x1);

var x4=x1-(x3-x1);

var ld=setCuPointXY(x2,lu.getY(),1);//设置共享的临时坐标点,用于防止重复创建对象

var ru=setCuPointXY(x4,p.getY(),2);//设置共享的临时坐标点,用于防止重复创建对象

var poly=getCuGraph();//获取当前图形

poly.set([lu,ru,p,ld]);

poly.draw();//即时绘制

break;

case graphkind.trapezoid://梯形

var lu=getStartPoint();

var x3=p.getX();

var x1=lu.getX();

//梯形两个未知坐标点计算方法:(x3-(x3-x1)/2,y1),(x1-(x3-x1)/2,y3)

var x2=x3-(x3-x1)/2;

var x4=x1-(x3-x1)/2;

var ld=setCuPointXY(x2,lu.getY(),1);

var ru=setCuPointXY(x4,p.getY(),2);

var poly=getCuGraph();

poly.set([lu,ru,p,ld]);

poly.draw();

break;

case graphkind.rect://矩形

var lu=getStartPoint();

//矩形右上角和左上角坐标计算方法

var ld=setCuPointXY(lu.getX(),p.getY(),1);

var ru=setCuPointXY(p.getX(),lu.getY(),2);

var poly=getCuGraph();

poly.set([lu,ru,p,ld]);

poly.draw();

break;

case graphkind.circle://圆

var circle=getCuGraph();//获取当前图形

circle.set({'start':getStartPoint(),'end':p});

circle.draw();//即时绘制

break;

}

}

}

//鼠标按键松开

var mouseUp = function(e){

if(isDrawing()){

//console.log("松开鼠标按键:"+e.offsetX+","+e.offsetY);

//画笔不需要重绘

if(ctrlConfig.kind>1){

repaint();

getCuGraph().draw();

}

if(ctrlConfig.kind!=graphkind.poly){//多边形绘制鼠标按键松开不结束绘制,多边形只有右键点击才能结束绘制

stopDrawing();//结束绘制

}

}

}

//鼠标移出

var mouseOut = function(e){

console.log("鼠标移出绘制区域"+e.offsetX+","+e.offsetY);

if(isDrawing()){

console.log("停止绘制");

if(ctrlConfig.kind>1){

repaint();

getCuGraph().draw();

}

stopDrawing();//停止绘制

}

}

return{

isNull:isNull,

getDom:getDom,

clear:function(){

stopDrawing();//停止绘制

repaint();

},

/**初始化*/

init:function(params){

cbtCanvas=getDom(params.id);

//浏览器是否支持Canvas

if (cbtCanvas.getContext){

/**绘图对象*/

cxt=cbtCanvas.getContext("2d");

cbtCanvas.onmousedown = mouseDown;

cbtCanvas.onmouseup = mouseUp;

cbtCanvas.onmousemove = mouseMove;

cbtCanvas.onmouseout = mouseOut;

resetStyle();//载入样式

return true;

}else{

return false;

}

},

/**设置背景图片*/

setBgPic:loadPicture,

/**选择图形类型*/

begin:function(k){

console.log("选择绘制图形:"+k);

if(isNaN(k)){//如果不是数字,先转换为对应字符

ctrlConfig.kind=kind[k];

}else{

ctrlConfig.kind=k;

}

switchCorser(true);//切换鼠标样式

},

/*手型,并停止绘图*/

hand:function(){

ctrlConfig.kind=0;

stopDrawing();//停止绘制

switchCorser(false);//切换鼠标样式

}

}

})

三、使用方式

1、图形类型

0:鼠标,1:画笔,2:线条,3:三角形,4:矩形,5:多边形,6:圆形,21:箭头,41:平行四边形,42:梯形

var graphkind={'cursor':0,'pen':1,'line':2,'trian':3,'rect':4,'poly':5,'circle':6,'arrow':21,'parallel':41,'trapezoid':42};

2、初始化以及使用背景图片和画笔选择

var drawUtil=new DrawingTools();

//初始化,(如果浏览器不支持H5,会初始化失败,返回false)

if(drawUtil.init({'id':'calibrationCanvas'})){

//加载图片

var imgsrc='图片地址';

if(!drawUtil.isNull(imgsrc)){

drawUtil.setBgPic(imgsrc,true);//设置背景图片(异步加载图片)

}

}

drawUtil.begin(1);//选择画笔

2、绘制箭头

drawUtil.begin(21);

总结

以上所述是小编给大家介绍的原生JS使用Canvas实现拖拽式绘图功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

如果觉得《java使用重绘实现拖动_原生JS使用Canvas实现拖拽式绘图功能》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。