本文主要是介绍[js高手之路]html5 canvas动画教程 - 自己动手做一个类似windows的画图软件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
这个绘图工具,我还没有做完,不过已经实现了总架构,以及常见的简易图形绘制功能:
1,可以绘制直线,圆,矩形,正多边形【已完成】
2,填充颜色和描边颜色的选择【已完成】
3,描边和填充功能的选择【已完成】
后续版本:
橡皮擦,坐标系,线形设置,箭头,其他流程图形,裁剪与调整图形。。。。。
终极目标:
流程绘制软件
我是之前看见一位朋友在我的博客中留言说:
非常感谢这个朋友,今天终于抽出时间完成非常非常小的雏形!
完整的雏形代码,请自行打开,复制到本地测试.
1 <head>
2 <meta charset="UTF-8">
3 <meta name="viewport" content="width=device-width, initial-scale=1.0">
4 <meta http-equiv="X-UA-Compatible" content="ie=edge">
5 <title>windows简易画图工具 - by ghostwu</title>
6 </head>
7
8 <body>
9 <div class="paint">
10 <div class="paint-header">
11 <ul>
12 <li class="active">形状</li>
13 <li>颜色</li>
14 <li>绘制类型</li>
15 <li>线条宽度</li>
16 <li>橡皮擦</li>
17 </ul>
18 </div>
19 <div class="paint-body">
20 <div class="siderbar">
21 <div class="item active" data-type="paint-shape">
22 <ul>
23 <li class="active" data-role="line">线条</li>
24 <li data-role="circle">圆形</li>
25 <li data-role="rect">矩形</li>
26 <li data-role="polygon">正多边形</li>
27 <li data-role="arrow">箭头</li>
28 </ul>
29 </div>
30 <div class="item" data-type="paint-color">
31 <ul>
32 <li data-role="strokeStyle">
33 <input type="color" data-role="strokeStyle">
34 </li>
35 <li data-role="fillStyle">
36 <input type="color" data-role="fillStyle">
37 </li>
38 </ul>
39 </div>
40 <div class="item" data-type="paint-type">
41 <ul>
42 <li data-role="stroke">描边</li>
43 <li data-role="fill">填充</li>
44 </ul>
45 </div>
46 <div class="item" data-type="paint-line">
47 <ul>
48 <li data-role="1">小号</li>
49 <li data-role="4">中号</li>
50 <li data-role="7">大号</li>
51 <li>
52 <input type="number" data-role="line-size" placeholder="请输入数字">
53 </li>
54 </ul>
55 </div>
56 <div class="item" data-type="paint-erase">
57 <ul>
58 <li>
59 <input type="number" data-role="erase-size" placeholder="请输入数字">
60 </li>
61 </ul>
62 </div>
63 </div>
64 </div>
65 </div>
66 <script>// <![CDATA[
67 var oPaintBody = document.querySelector( '.paint-body' );
68 var oC = document.createElement( 'canvas' );
69 oC.setAttribute( 'width', '830' );
70 oC.setAttribute( 'height', '500' );
71 oPaintBody.appendChild( oC );
72 var aHeaderLi = document.querySelectorAll('.paint-header li'),
73 aItem = document.querySelectorAll('.paint-body .item'),
74 oCanvas = document.querySelector('.paint canvas'),
75 oGc = oCanvas.getContext('2d'),
76 cWidth = oCanvas.width, cHeight = oCanvas.height,
77 curItem = aItem[0],
78 aItemLi = curItem.querySelectorAll('li');
79
80 for (let i = 0, len = aHeaderLi.length; i < len; i ) { //头部选项卡切换功能
81 aHeaderLi[i].onclick = function () {
82 for (let j = 0; j < len; j ) {
83 aHeaderLi[j].classList.remove('active');
84 aItem[j].style.display = 'none';
85 }
86 aItem[i].style.display = "block";
87 this.classList.add('active');
88 curItem = aItem[i];
89 aItemLi = curItem.querySelectorAll('li');
90 activeItem(aItemLi);
91 }
92 }
93 activeItem(aItemLi);
94 var role = null;
95 function activeItem(aItemLi) { //canvas左侧选项卡切换功能
96 for (let i = 0, len = aItemLi.length; i < len; i ) {
97 aItemLi[i].onclick = function () {
98 checkPaintType(this); //绘制类型
99 for (let j = 0; j < len; j ) {
100 aItemLi[j].classList.remove('active');
101 }
102 this.classList.add('active');
103 }
104 }
105 }
106
107 function Shape(canvasObj, cxtObj, w, h) {
108 this.oCanvas = canvasObj;
109 this.oGc = cxtObj;
110 this.oCanvas.width = w;
111 this.oCanvas.height = h;
112 this.fillStyle = '#000';
113 this.storkeStyle = '#000';
114 this.lineWidth = 1;
115 this.drawType = 'line';
116 this.paintType = 'stroke';
117 this.nums = 6; //正多边形的边数
118 }
119
120 Shape.prototype = {
121 init: function () {
122 this.oGc.fillStyle = this.fillStyle;
123 this.oGc.strokeStyle = this.strokeStyle;
124 this.oGc.lineWidth = this.lineWidth;
125 },
126 draw: function () {
127 var _this = this;
128 this.oCanvas.onmousedown = function (ev) {
129 _this.init();
130 var oEvent = ev || event,
131 startX = oEvent.clientX - _this.oCanvas.offsetLeft,
132 startY = oEvent.clientY - _this.oCanvas.offsetTop;
133 _this.oCanvas.onmousemove = function (ev) {
134 _this.oGc.clearRect(0, 0, _this.oCanvas.width, _this.oCanvas.height);
135 var oEvent = ev || event,
136 endX = oEvent.clientX - _this.oCanvas.offsetLeft,
137 endY = oEvent.clientY - _this.oCanvas.offsetTop;
138 _this[_this.drawType](startX, startY, endX, endY);
139 };
140 _this.oCanvas.onmouseup = function () {
141 _this.oCanvas.onmousemove = null;
142 _this.oCanvas.onmouseup = null;
143 }
144 }
145 },
146 line: function (x1, y1, x2, y2) {
147 this.oGc.beginPath();
148 this.oGc.moveTo(x1, y1);
149 this.oGc.lineTo(x2, y2);
150 this.oGc.closePath();
151 this.oGc.stroke();
152 },
153 circle: function (x1, y1, x2, y2) {
154 this.oGc.beginPath();
155 var r = Math.sqrt(Math.pow(x2 - x1, 2) Math.pow(y2 - y1, 2));
156 this.oGc.arc(x1, y1, r, 0, 2 * Math.PI, false);
157 this.oGc.closePath();
158 this.oGc[this.paintType]();
159 },
160 rect: function (x1, y1, x2, y2) {
161 this.oGc.beginPath();
162 this.oGc.rect(x1, y1, x2 - x1, y2 - y1);
163 this.oGc[this.paintType]();
164 },
165 polygon: function (x1, y1, x2, y2) {
166 var angle = 360 / this.nums * Math.PI / 180;//边对应的角的弧度
167 var r = Math.sqrt(Math.pow(x2 - x1, 2) Math.pow(y2 - y1, 2));
168 this.oGc.beginPath();
169 for (var i = 0; i < this.nums; i ) {
170 this.oGc.lineTo(x1 r * Math.cos(angle * i), y1 r * Math.sin(angle * i));
171 }
172 this.oGc.closePath();
173 this.oGc[this.paintType]();
174 }
175 }
176
177 var oShape = new Shape(oCanvas, oGc, cWidth, cHeight);
178 function checkPaintType(liType) {
179 var dataType = liType.parentNode.parentNode.dataset.type;
180 var curType = liType.dataset.role;
181 switch (dataType) {
182 case 'paint-shape': //形状
183 oShape.drawType = curType;
184 if (curType == 'polygon') {
185 oShape.nums = prompt("请输入边数", 6);
186 }
187 oShape.draw();
188 break;
189 case 'paint-color': //绘制颜色
190 liType.children[0].onchange = function () {
191 oShape[this.dataset.role] = this.value;
192 }
193 oShape.draw();
194 break;
195 case 'paint-type': //绘制类型
196 oShape.paintType = curType;
197 oShape.draw();
198 break;
199 }
200 }
201 // ]]></script>
202 <style>
203 .paint * {
204 margin: 0;
205 padding: 0;
206 }
207
208 .paint ul,
209 .paint li {
210 list-style: none;
211 }
212
213 .paint li:hover {
214 cursor: pointer;
215 }
216
217 .paint {
218 width: 980px;
219 margin: 20px auto;
220 border: 1px solid #ccc;
221 overflow: hidden;
222 }
223
224 .paint .paint-header ul {
225 width: 980px;
226 height: 40px;
227 line-height: 40px;
228 border-bottom: 1px solid #ccc;
229 }
230
231 .paint .paint-header li {
232 float: left;
233 width: 120px;
234 height: 40px;
235 line-height: 40px;
236 text-align: center;
237 }
238
239 .paint li.active {
240 box-shadow: #666 0px 1px 8px inset;
241 }
242
243 .paint .paint-body .siderbar {
244 float: left;
245 width: 150px;
246 height: 500px;
247 }
248
249 .paint .paint-body .item {
250 width: 150px;
251 overflow: hidden;
252 display: none;
253 height: 500px;
254 border-right: 1px solid #ccc;
255 }
256
257 .paint .paint-body canvas {
258 float: right;
259 }
260
261 .paint .paint-body .item li {
262 height: 40px;
263 text-align: center;
264 border-bottom: 1px solid #ccc;
265 line-height: 40px;
266 }
267
268 .paint .paint-body .active {
269 display: block;
270 }
271 </style>
272 </body>
关于流程设计,后期要做的功能,思路基本上已经有了,好了,圆规正传,想要完成这个终极目标,完成一个画图工具应该就能接近目标了。先体验下目前的简易功能,下面是可以正常画图的,【需要你的浏览器支持canvas才可以额】
- 形状
- 颜色
- 绘制类型
- 线条宽度
- 橡皮擦
主要来讲下目标的雏形架构:
1,图形绘制部分,我封装了一个类Shape
1 function Shape(canvasObj, cxtObj, w, h) {
2 this.oCanvas = canvasObj;
3 this.oGc = cxtObj;
4 this.oCanvas.width = w;
5 this.oCanvas.height = h;
6 this.fillStyle = '#000';
7 this.storkeStyle = '#000';
8 this.lineWidth = 1;
9 this.drawType = 'line';
10 this.paintType = 'stroke';
11 this.nums = 6; //正多边形的边数
12 }
canvasObj: 就是canvas画布对象
cxtObj: 就是上下文绘图环境
w: canvas的宽度
h: canvas的高度
fillStyle: 填充颜色
strokeStyle: 描边颜色
lineWidth: 线宽
drawType: 默认为画直线
paintType: stroke/fill 两种选择( 描边/填充)
2,在原型对象上扩展一个公共方法draw用来绘制图形
draw方法,主要获取起始点坐标(startX, startY),以及终点坐标( endX, endY );
然后调用init方法来获取绘制状态,绘制具体的图形靠下面这个关键方法:
_this[_this.drawType](startX, startY, endX, endY)
这个方法的drawType会根据界面的实时选择,变换对应的绘制类型,如:
_this['line']( startX, startY, endX, endY )
调用的就是oShape对象中的line,画直线的方法
1 Shape.prototype = {
2 init: function () {
3 this.oGc.fillStyle = this.fillStyle;
4 this.oGc.strokeStyle = this.strokeStyle;
5 this.oGc.lineWidth = this.lineWidth;
6 },
7 draw: function () {
8 var _this = this;
9 this.oCanvas.onmousedown = function ( ev ) {
10 _this.init();
11 var oEvent = ev || event,
12 startX = oEvent.clientX - _this.oCanvas.offsetLeft,
13 startY = oEvent.clientY - _this.oCanvas.offsetTop;
14 _this.oCanvas.onmousemove = function ( ev ) {
15 _this.oGc.clearRect( 0, 0, _this.oCanvas.width, _this.oCanvas.height );
16 var oEvent = ev || event,
17 endX = oEvent.clientX - _this.oCanvas.offsetLeft,
18 endY = oEvent.clientY - _this.oCanvas.offsetTop;
19 _this[_this.drawType](startX, startY, endX, endY);
20 };
21 _this.oCanvas.onmouseup = function(){
22 _this.oCanvas.onmousemove = null;
23 _this.oCanvas.onmouseup = null;
24 }
25 }
26 },
27 line: function ( x1, y1, x2, y2 ) {
28 this.oGc.beginPath();
29 this.oGc.moveTo( x1, y1 );
30 this.oGc.lineTo( x2, y2 );
31 this.oGc.closePath();
32 this.oGc.stroke();
33 },
34 circle : function( x1, y1, x2, y2 ){
35 this.oGc.beginPath();
36 var r = Math.sqrt( Math.pow( x2 - x1, 2 ) Math.pow( y2 - y1, 2 ) );
37 this.oGc.arc( x1, y1, r, 0, 2 * Math.PI, false );
38 this.oGc.closePath();
39 this.oGc[this.paintType]();
40 },
41 rect : function( x1, y1, x2, y2 ){
42 this.oGc.beginPath();
43 this.oGc.rect( x1, y1, x2 - x1, y2 - y1 );
44 this.oGc[this.paintType]();
45 },
46 polygon : function( x1, y1, x2, y2 ){
47 var angle = 360 / this.nums * Math.PI / 180;//边对应的角的弧度
48 var r = Math.sqrt( Math.pow( x2 - x1, 2 ) Math.pow( y2 - y1, 2 ) );
49 this.oGc.beginPath();
50 for( var i = 0; i < this.nums; i ){
51 this.oGc.lineTo( x1 r * Math.cos( angle * i ), y1 r * Math.sin( angle * i ) );
52 }
53 this.oGc.closePath();
54 this.oGc[this.paintType]();
55 }
56 }
3,界面操作很简单,基本是选项卡的操作 html5的自定义属性 classList的应用
这篇关于[js高手之路]html5 canvas动画教程 - 自己动手做一个类似windows的画图软件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!