前言 需要用到圖形繪製,沒有找到完整的圖形繪製實現,所以自己實現了一個 - - 一、實現的功能 1、基於oop思想構建,支持坐標點、線條(由坐標點組成,包含方向)、多邊形(由多個坐標點組成)、圓形(包含圓心坐標點和半徑)等實體 2、原生JavaScript實現,不依賴任何第三方js庫和插件 3、多圖 ...
前言
需要用到圖形繪製,沒有找到完整的圖形繪製實現,所以自己實現了一個 - -
一、實現的功能
1、基於oop思想構建,支持坐標點、線條(由坐標點組成,包含方向)、多邊形(由多個坐標點組成)、圓形(包含圓心坐標點和半徑)等實體
2、原生JavaScript實現,不依賴任何第三方js庫和插件
3、多圖形繪製(支持畫筆、線條、箭頭、三角形、矩形、平行四邊形、梯形以及多邊形和圓形繪製)
4、拖拽式繪製(滑鼠移動過程中不斷進行canvas重繪)
5、圖片繪製(作為背景圖片時重繪會發生閃爍現象,暫時有點問題,後面繼續完善)
5、清空繪製功能
6、新版本優化繪製性能(使用共用坐標變數數組,減少了大量的對象創建操作)
7、新版本支持箭頭繪製功能
二、完整實現代碼
[javascript] view plain copy- 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,//是否作為永久背景圖,每次清除時會進行重繪
- };
- //載入並繪製圖片(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;