前言
須要用到圖形繪製,沒有找到完整的圖形繪製實現,因此本身實現了一個 - -javascript
1、實現的功能
一、基於oop思想構建,支持座標點、線條(由座標點組成,包含方向)、多邊形(由多個座標點組成)、圓形(包含圓心座標點和半徑)等實體html
二、原生JavaScript實現,不依賴任何第三方js庫和插件java
三、多圖形繪製(支持畫筆、線條、箭頭、三角形、矩形、平行四邊形、梯形以及多邊形和圓形繪製)canvas
四、拖拽式繪製(鼠標移動過程當中不斷進行canvas重繪)數組
五、圖片繪製(做爲背景圖片時重繪會發生閃爍現象,暫時有點問題,後面繼續完善)瀏覽器
五、清空繪製功能ssh
六、新版本優化繪製性能(使用共享座標變量數組,減小了大量的對象建立操做)異步
七、新版本支持箭頭繪製功能ide
2、完整實現代碼
- 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.oncontextmenu=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,
- };
-
- 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,
- 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();
-
- }
-
-
- 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;
-
- 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);
- }
-
- 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);
- }
-
- 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();
-
- 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);
- }
-
- 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();
-
- 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();
-
- 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();
-
- 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()){
-
-
- 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);
-
- 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);
- }
- }
- })
3、使用方式
一、圖形類型工具
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};
二、初始化以及使用背景圖片和畫筆選擇
- var drawUtil=new DrawingTools();
- if(drawUtil.init({'id':'calibrationCanvas'})){
-
- var imgsrc='圖片地址';
- if(!drawUtil.isNull(imgsrc)){
- drawUtil.setBgPic(imgsrc,true);
- }
- }
- drawUtil.begin(1);
二、繪製箭頭
4、演示demo
點擊這裏跳轉demo