[js高手之路]html5 canvas动画教程 - 自己动手做一个类似windows的画图软件

本文主要是介绍[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>
View Code

关于流程设计,后期要做的功能,思路基本上已经有了,好了,圆规正传,想要完成这个终极目标,完成一个画图工具应该就能接近目标了。先体验下目前的简易功能,下面是可以正常画图的,【需要你的浏览器支持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的画图软件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1076906

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

软件设计师备考——计算机系统

学习内容源自「软件设计师」 上午题 #1 计算机系统_哔哩哔哩_bilibili 目录 1.1.1 计算机系统硬件基本组成 1.1.2 中央处理单元 1.CPU 的功能 1)运算器 2)控制器 RISC && CISC 流水线控制 存储器  Cache 中断 输入输出IO控制方式 程序查询方式 中断驱动方式 直接存储器方式(DMA)  ​编辑 总线 ​编辑

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

Vue3项目开发——新闻发布管理系统(六)

文章目录 八、首页设计开发1、页面设计2、登录访问拦截实现3、用户基本信息显示①封装用户基本信息获取接口②用户基本信息存储③用户基本信息调用④用户基本信息动态渲染 4、退出功能实现①注册点击事件②添加退出功能③数据清理 5、代码下载 八、首页设计开发 登录成功后,系统就进入了首页。接下来,也就进行首页的开发了。 1、页面设计 系统页面主要分为三部分,左侧为系统的菜单栏,右侧

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件