• [js高手之路]html5 canvas动画教程


    这个绘图工具,我还没有做完,不过已经实现了总架构,以及常见的简易图形绘制功能:

    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              980px;
    219             margin: 20px auto;
    220             border: 1px solid #ccc;
    221             overflow: hidden;
    222         }
    223 
    224         .paint .paint-header ul {
    225              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              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              150px;
    246             height: 500px;
    247         }
    248 
    249         .paint .paint-body .item {
    250              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的应用

  • 相关阅读:
    .net中实现运行时从字符串动态创建对象
    C# 用 VB.net 函數庫 實現全角與半角轉換
    實現.net 加載插件方式
    VS2008下載
    Lotus Notes Send EMail from VB or VBA
    用C#写vs插件中的一些Tip
    SQL2005中异常处理消息框可直接使用
    C#路径/文件/目录/I/O常见操作汇总
    利用.net反射动态调用指定程序集的中的方法
    说说今年的计划
  • 原文地址:https://www.cnblogs.com/ghostwu/p/7684379.html
Copyright © 2020-2023  润新知