简易的canvas画板

没事仿照windows画板工具用canvas实现了一个简易版的画板。

html:

 1 <!doctype html>
 2 <html>
 3     <head>
 4         <meta charset="utf-8">
 5         <title>画板</title>
 6         <link rel="stylesheet" href="css/style.css">
 7     </head>
 8     <body>
 9         <div class="toolbar js-toolbar">
10             <div class="toolbar-box">
11                 <div class="toolbar-main">
12                     <div class="shape-box">
13                         <ul class="shape-lst js-tool-lst">
14                             <!-- <li data-tool="eraser">橡皮擦</li> -->
15                             <li data-tool="eraserAll">清除全部</li>
16                         </ul>
17                     </div>
18                 </div>
19                 <div class="toolbar-title">工具</div>
20             </div>
21             <div class="toolbar-split"></div>
22             <div class="toolbar-box">
23                 <div class="toolbar-main">
24                     <div class="shape-box">
25                         <ul class="shape-lst js-shape-lst">
26                             <li data-tool="line" class="selected">直线</li>
27                             <li data-tool="rect">矩形</li>
28                             <li data-tool="arc">圆形</li>
29                         </ul>
30                     </div>
31                     <div class="shape-chose">
32                         <ul>
33                             <li>轮廓</li>
34                             <li>填充</li>
35                         </ul>
36                     </div>
37                 </div>
38                 <div class="toolbar-title">形状</div>
39             </div>
40             <div class="toolbar-split"></div>
41             <div class="toolbar-box">
42                 <div class="toolbar-main toolbar-lineWidth-main">
43                     <ul class="line-width-lst js-line-width-lst">
44                         <li class="line-width-1 selected" data-lineWidth="1"><span></span></li>
45                         <li class="line-width-2" data-lineWidth="2"><span></span></li>
46                         <li class="line-width-3" data-lineWidth="3"><span></span></li>
47                         <li class="line-width-4" data-lineWidth="4"><span></span></li>
48                         <li class="line-width-5" data-lineWidth="5"><span></span></li>
49                     </ul>
50                 </div>
51                 <div class="toolbar-title">线条</div>
52             </div>
53             <div class="toolbar-split"></div>
54             <div class="toolbar-box">
55                 <div class="toolbar-main">
56                     <ul class="color-lst js-color-lst">
57                         <li class="black selected" data-color="#000"><span></span></li>
58                         <li class="red" data-color="#f00"><span></span></li>
59                         <li class="blue" data-color="#00f"><span></span></li>
60                         <li class="green" data-color="#0f0"><span></span></li>
61                         <li class="yellow" data-color="#ff0"><span></span></li>
62                     </ul>
63                 </div>
64                 <div class="toolbar-title">颜色</div>
65             </div>
66         </div>
67         <canvas id="canvas" class="canvas" width="800" height="600"></canvas>
68         <script src="js/drawBoard.js"></script>
69         <script>
70             window.onload=function(){
71                 var drawBoard=new DrawBoard();
72             }
73         </script>
74     </body>
75 </html>

style.css:

  1 *{
  2     margin:0;
  3     padding:0;
  4 }
  5 body{
  6     background:#c9d3e2;
  7 }
  8 ul,li{
  9     list-style:none;
 10 }
 11 .canvas{
 12   border:1px solid #ddd;
 13   background:#fff;
 14   box-shadow:5px 5px 5px rgba(9,93,224,.1);
 15   cursor:crosshair;
 16 }
 17 .toolbar{
 18     padding:7px 0;
 19     background:-webkit-linear-gradient(top,#fbfdff,#dce7f5);
 20     border-top:1px solid #bac9db;
 21     border-bottom:1px solid #bac9db;
 22     box-shadow:inset 0 -1px 1px #e5f0fb,inset 0 -1px 1px #cedbeb;
 23     overflow:hidden;
 24 }
 25 .toolbar-box{
 26     float:left;
 27     padding:0 6px;
 28 }
 29 .toolbar-main{
 30     height:80px;
 31     overflow:hidden;
 32 }
 33 .shape-box{
 34     float:left;
 35     width:150px;
 36     height:58px;
 37     border:1px solid #aabbd2;
 38     background:#f3f7fc;
 39     overflow-y:auto;
 40 }
 41 .shape-chose{
 42     float:left;
 43     margin-left:10px;
 44     width:50px;
 45 }
 46 .shape-chose li{
 47     color:#489de4;
 48     line-height:20px;
 49 }
 50 .shape-lst{
 51     overflow:hidden;
 52 }
 53 .shape-lst li{
 54     float:left;
 55     height:20px;
 56     line-height:20px;
 57     padding:0 10px;
 58     color:#1a6aab;
 59     cursor:default;
 60 }
 61 .shape-lst li:hover{
 62     background:#fbe7c2;
 63 }
 64 .shape-lst .selected,
 65 .shape-lst .selected:hover,
 66 .shape-lst li:active{
 67     background:#ffc762;
 68     box-shadow:inset 0 0 15px rgba(60,40,3,.2);
 69 }
 70 .toolbar-title{
 71     text-align:center;
 72     color:#738399;
 73     font-size:14px;
 74     font-family:"Microsoft Yahei";
 75 }
 76 .toolbar-split{
 77     float:left;
 78     width:1px;
 79     height:90px;
 80     background:#a5b7d0;
 81     box-shadow:0 0 0 1px #ecf1fa;
 82 }
 83 .color-lst{
 84     overflow:hidden;
 85 }
 86 .color-lst li{
 87     float:left;
 88     margin:0 10px 4px 0;
 89     padding:2px;
 90     background:#fff;
 91     border:1px solid #aabbd2;
 92 }
 93 .color-lst li span{
 94     display:block;
 95     width:22px;
 96     height:22px;
 97 }
 98 .color-lst .black span{
 99     background:#000;
100 }
101 .color-lst .red span{
102     background:#f00;
103 }
104 .color-lst .blue span{
105     background:#00f;
106 }
107 .color-lst .green span{
108     background:#0f0;
109 }
110 .color-lst .yellow span{
111     background:#ff0;
112 }
113 .color-lst .selected{
114     border-color:#ffc762;
115 }
116 .toolbar-lineWidth-main{
117     position:relative;
118     width:100px;
119     overflow:hidden;
120 }
121 .line-width-lst{
122 
123     width:100px;
124 }
125 
126 .toolbar-lineWidth-main:hover{
127     overflow:visible;
128 }
129 
130 .toolbar-lineWidth-main:hover .line-width-lst{
131     position:absolute;
132     top:0;
133     left:0;
134     background:#fff;
135 }
136 .line-width-lst li{
137     width:100px;
138     height:20px;
139     line-height:20px;
140 }
141 .line-width-lst li span{
142     display:inline-block;
143     vertical-align:middle;
144     width:100px;
145     background:#000;
146 }
147 .line-width-1 span{
148     height:1px;
149 }
150 .line-width-2 span{
151     height:2px;
152 }
153 .line-width-3 span{
154     height:3px;
155 }
156 .line-width-4 span{
157     height:4px;
158 }
159 .line-width-5 span{
160     height:5px;
161 }
162 .line-width-lst .selected{
163     background:#ffc762;
164 }

drawBoard.js:

  1 function DrawBoard(){
  2     this.oCanvas=document.getElementById("canvas");
  3       this.oCxt=this.oCanvas.getContext("2d");
  4       this.iCvsLeft=this.oCanvas.offsetLeft;
  5       this.iCvsTop=this.oCanvas.offsetTop;
  6     this.init();
  7 }
  8 
  9 DrawBoard.prototype={
 10     constructor: DrawBoard,
 11 
 12     /**
 13      * 初始化各种方法
 14      * 
 15     **/
 16     init:function(){
 17 
 18           this.scroll();
 19 
 20           //设置默认的工具
 21           this.colorChoose();
 22           this.lineWidthChoose();
 23           this.shapeChoose();
 24           this.toolChoose();
 25 
 26           //初始化工具事件
 27           this.colorFn();
 28           this.lineWidthFn();
 29           this.shapeFn();
 30           this.toolFn();
 31     },
 32 
 33     /**
 34      * 滚动条滚动后重新计算鼠标绘制位置
 35      * 
 36     **/
 37     scroll:function(){
 38           var _this=this;
 39           document.onscroll=function(){
 40               var scrollTop=document.documentElement.scrollTop||document.body.scrollTop;
 41               var scrollLeft=document.documentElement.scrollLeft||document.body.scrollLeft;
 42               _this.iCvsLeft=_this.oCanvas.offsetLeft - scrollLeft;
 43               _this.iCvsTop=_this.oCanvas.offsetTop - scrollTop;
 44           }
 45       },
 46 
 47       /**
 48      * 工具选择事件
 49      * 
 50     **/
 51       toolFn:function(){
 52           var _this=this;
 53           var aTool=document.querySelector(".js-tool-lst").children;
 54           for(var i=0;i<aTool.length;i++){
 55             aTool[i].onclick=function(){
 56                 _this.toolChoose(this.getAttribute("data-tool"));
 57             }
 58         }
 59       },
 60 
 61       /**
 62      * 选择工具判断
 63      * @param sTool
 64     **/
 65     toolChoose:function(sTool){
 66         if(sTool=="eraserAll"){
 67             this.clearRectAll();
 68         }else if(sTool=="eraser"){
 69             this.toolSwitch("pointer",sTool);
 70             this.clearRect();
 71         }
 72     },
 73 
 74     /**
 75      * 形状选择事件
 76      * 
 77     **/
 78     shapeFn:function(){
 79         var _this=this;
 80         var aShape=document.querySelector(".js-shape-lst").children;
 81         for(var i=0;i<aShape.length;i++){
 82             aShape[i].onclick=function(){
 83                 for(var j=0;j<aShape.length;j++){
 84                     aShape[j].classList.remove("selected");
 85                 }
 86                 this.classList.add("selected");
 87                 _this.shapeChoose(this.getAttribute("data-tool"));
 88             }
 89         }
 90     },
 91 
 92     /**
 93      * 形状选择判断
 94      * @param sShape
 95     **/
 96     shapeChoose:function(sShape){
 97         this.toolSwitch("crosshair",sShape);
 98         if(sShape=="rect"){
 99             this.drawRect();
100         }else if(sShape=="arc"){
101             this.drawArc();
102         }else{
103             this.drawLine();
104         }
105     },
106 
107     /**
108      * 颜色选择事件
109      * 
110     **/
111     colorFn:function(){
112         var _this=this;
113         var aColor=document.querySelector(".js-color-lst").children;
114         for(var i=0;i<aColor.length;i++){
115             aColor[i].onclick=function(){
116                 for(var j=0;j<aColor.length;j++){
117                     aColor[j].classList.remove("selected");
118                 }
119                 this.classList.add("selected");
120                 _this.colorChoose(this.getAttribute("data-color"));
121             }
122         }
123     },
124 
125     /**
126      * 颜色选择判断
127      * @param sColor
128     **/
129     colorChoose:function(sColor){
130         this.sColor=sColor?sColor:"#000";
131         this.oCxt.strokeStyle=this.sColor;
132     },
133 
134     /**
135      * 线条选择事件
136      * 
137     **/
138     lineWidthFn:function(){
139         var _this=this;
140         var aLineWidth=document.querySelector(".js-line-width-lst").children;
141         for(var i=0;i<aLineWidth.length;i++){
142             aLineWidth[i].onclick=function(){
143                 for(var j=0;j<aLineWidth.length;j++){
144                     aLineWidth[j].classList.remove("selected");
145                 }
146                 this.classList.add("selected");
147                 _this.lineWidthChoose(this.getAttribute("data-lineWidth"));
148             }
149         }
150     },
151 
152     /**
153      * 线条选择判断
154      * @param iLineWidth
155     **/
156     lineWidthChoose:function(iLineWidth){
157         this.iLineWidth=iLineWidth?iLineWidth:1;
158         this.oCxt.lineWidth=this.iLineWidth;
159     },
160 
161     /**
162      * 创建虚拟canvas--绘制矩形和圆形时,鼠标按下创建,鼠标抬起移除
163      * 
164     **/
165     virtualCanvasCreate:function(){
166         var vCs=this.oCanvas.cloneNode(true);
167         vCs.id="virtualCanvas";
168         vCs.style.background="transparent";
169         vCs.style.boxShadow="none";
170         vCs.style.position="absolute";
171         vCs.style.left=this.oCanvas.offsetLeft+"px";
172         vCs.style.top=this.oCanvas.offsetTop+"px";
173         var vCxt=vCs.getContext("2d");
174         document.querySelector("body").appendChild(vCs);
175         return {
176             vCanvas:vCs,
177             vCxt:vCxt
178         }
179     },
180 
181     /**
182      * 移除虚拟canvas
183      * 
184     **/
185     virtualCanvasRemove:function(vCs){
186         document.querySelector("body").removeChild(vCs);
187     },
188 
189     /**
190      * 绘制线条
191      * 
192     **/
193       drawLine:function(){
194           var _this=this;
195           this.oCanvas.onmousedown=function(event){
196             var oEvent=event||window.event;
197             var startX=oEvent.clientX-_this.iCvsLeft;
198             var startY=oEvent.clientY-_this.iCvsTop;
199             var endX=startX;
200             var endY=startY;
201 
202             _this.oCxt.beginPath();
203             _this.oCxt.moveTo(startX,startY);
204 
205             document.onmousemove=function(event){
206               var oEvent=event||window.event;
207               endX=oEvent.clientX-_this.iCvsLeft;
208               endY=oEvent.clientY-_this.iCvsTop;
209 
210               _this.oCxt.lineTo(endX,endY);
211               _this.oCxt.stroke();
212 
213               return false;
214             }
215             document.onmouseup=function(){
216               document.onmousemove=null;
217               document.onmouseup=null;
218             }
219         }
220       },
221 
222       /**
223      * 绘制矩形
224      * 
225     **/
226       drawRect:function(){
227           var _this=this;
228           this.oCanvas.onmousedown=function(event){
229               var oEvent=event||window.event;
230               var startX=oEvent.clientX-_this.iCvsLeft;
231             var startY=oEvent.clientY-_this.iCvsTop;
232             var endX=startX;
233             var endY=startY;
234 
235             var virtualCanvas=_this.virtualCanvasCreate();
236               virtualCanvas.vCxt.strokeStyle=_this.sColor;
237               virtualCanvas.vCxt.lineWidth=_this.iLineWidth;
238               var delta=0;
239             if(_this.iLineWidth%2==1){
240                 delta=.5;
241             }
242 
243             document.onmousemove=function(event){
244               var oEvent=event||window.event;
245               endX=oEvent.clientX-_this.iCvsLeft;
246               endY=oEvent.clientY-_this.iCvsTop;
247               
248               virtualCanvas.vCxt.clearRect(0,0,virtualCanvas.vCanvas.width,virtualCanvas.vCanvas.height);  //清除虚拟canvas
249               virtualCanvas.vCxt.strokeRect(startX+delta,startY+delta,endX-startX,endY-startY);   //在虚拟canvas上绘制
250 
251               return false;
252             }
253             document.onmouseup=function(){
254               if(endX-startX!=0&&endY-startY!=0){
255                   _this.oCxt.strokeRect(startX+delta,startY+delta,endX-startX,endY-startY);  //鼠标松开在真实canvas上绘制
256               }
257               _this.virtualCanvasRemove(virtualCanvas.vCanvas);
258 
259               document.onmousemove=null;
260               document.onmouseup=null;
261             }
262           }
263       },
264 
265       /**
266      * 绘制圆形
267      * 
268     **/
269       drawArc:function(){
270           var _this=this;
271           this.oCanvas.onmousedown=function(event){
272               var oEvent=event||window.event;
273               var startX=oEvent.clientX-_this.iCvsLeft;
274             var startY=oEvent.clientY-_this.iCvsTop;
275             var endX=startX;
276             var endY=startY;
277             var disX,disY,radius,coordsX,coordsY;
278 
279             var virtualCanvas=_this.virtualCanvasCreate();
280               virtualCanvas.vCxt.strokeStyle=_this.sColor;
281               virtualCanvas.vCxt.lineWidth=_this.iLineWidth;
282               
283             document.onmousemove=function(event){
284               var oEvent=event||window.event;
285               endX=oEvent.clientX-_this.iCvsLeft;
286               endY=oEvent.clientY-_this.iCvsTop;
287               disX=(endX-startX)/2;
288               disY=(endY-startY)/2;
289               radius=Math.min(Math.abs(disX),Math.abs(disY));
290               coordsX=disX < 0 ? -radius : radius;
291               coordsY=disY < 0 ? -radius : radius;
292               
293               virtualCanvas.vCxt.clearRect(0,0,virtualCanvas.vCanvas.width,virtualCanvas.vCanvas.height);  //清除虚拟canvas
294               virtualCanvas.vCxt.beginPath();
295               virtualCanvas.vCxt.arc(startX+coordsX,startY+coordsY,radius,0,2*Math.PI,false);   //在虚拟canvas上绘制
296               virtualCanvas.vCxt.stroke();
297 
298               return false;
299             }
300             document.onmouseup=function(){
301               if(endX-startX!=0&&endY-startY!=0){
302                   _this.oCxt.beginPath();
303                   _this.oCxt.arc(startX+coordsX,startY+coordsY,radius,0,2*Math.PI,false); //鼠标松开在真实canvas上绘制
304                   _this.oCxt.stroke();
305               }
306               _this.virtualCanvasRemove(virtualCanvas.vCanvas);
307 
308               document.onmousemove=null;
309               document.onmouseup=null;
310             }
311           }
312       },
313 
314       /**
315      * 工具切换后,鼠标样式的切换
316      * 
317     **/
318       toolSwitch:function(sCursorStyle,sTool){
319           this.oCanvas.style="cursor:"+sCursorStyle;
320       },
321 
322       /**
323      * 清楚画布
324      * 
325     **/
326       clearRectAll:function(){
327           this.oCxt.clearRect(0,0,this.oCanvas.width,this.oCanvas.height);
328       }
329 }
posted @ 2017-06-01 10:06  总是慢一拍  阅读(771)  评论(0编辑  收藏  举报