• canvas画图--流畅没有齿痕的线,图像画线


    画图,首先要获取鼠标位置,当鼠标在画图板上移动时,随之画线。

    1.画图板canvas,监听鼠标事件

    2.获取鼠标事件,得到鼠标位置。

    var mouse = {x: 0, y: 0}; //起始鼠标位置,也就是mousedown
    var last_mouse = {x: 0, y: 0};
     
    /* Mouse Capturing Work */
    canvas.addEventListener('mousemove', function(e) { 
        last_mouse.x = mouse.x;
        last_mouse.y = mouse.y;
     
        mouse.x = e.pageX - this.offsetLeft; 
        mouse.y = e.pageY - this.offsetTop;
    }, false);

    以上,通过canvas.addEventListener使画图板canvas监听到鼠标事件。

    3. 画线

    var onPaint = function() {
        ctx.beginPath();
        ctx.moveTo(last_mouse.x, last_mouse.y); //moveTo 从一个点移动到另一个点。
        ctx.lineTo(mouse.x, mouse.y); //lineTo方法画直线; 方法接受终点的坐标(x,y)作为参数
        ctx.closePath();
        ctx.stroke();
    };

    第一步是用 beginPath 创建一个路径。在内存里,路径是以一组子路径(直线,弧线等)的形式储存的,它们共同构成一个图形。每次调用 beginPath,子路径组都会被重置,然后可以绘制新的图形。

    第二步就是实际绘制路径的部分,moveTo和lineTo。

    第三步是调用 closePath 方法,它会尝试用直线连接当前端点与起始端点来关闭路径,但如果图形已经关闭或者只有一个点,它会什么都不做。这一步不是必须的。

    最后一步是调用 stroke 或 fill 方法,这时,图形才是实际的绘制到 canvas 上去。stroke 是绘制图形的边框,fill 会用填充出一个实心图形。

    基础知识,请参考 https://developer.mozilla.org/zh-CN/docs/Canvas_tutorial/Drawing_shapes

    以下是完整的代码。

     1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     2 <html xmlns="http://www.w3.org/1999/xhtml">
     3 <head>
     4     <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
     5     <meta http-equiv="Content-Script-Type" content="text/javascript" />
     6     <meta http-equiv="Content-Style-Type" content="text/css" />
     7     <meta name="viewport" content=" initial-scale=0.80,user-scalable=no" />
     8     <link rel="stylesheet" href="http://code.jquery.com/ui/1.9.1/themes/base/jquery-ui.css" />   
     9     <script src="http://code.jquery.com/jquery-1.8.2.js"></script>
    10     <script src="http://code.jquery.com/ui/1.9.1/jquery-ui.js"></script>       
    11     <title>Pencil</title>
    12 
    13     <style type="text/css">
    14         html, body {
    15             width: 100%;
    16             height: 100%;
    17         }
    18         #sketch {
    19             border: 10px solid gray;
    20             height: 100%;
    21             position: relative;
    22         }
    23         #tmp_canvas {
    24             position: absolute;
    25             left: 0px; right: 0;
    26             bottom: 0; top: 0;
    27             cursor: crosshair;
    28         }
    29     </style>
    30      
    31     <script type="text/javascript">
    32     $(document).ready(function(){
    33         var canvas = document.querySelector('#paint');
    34         var ctx = canvas.getContext('2d');
    35         
    36         var sketch = document.querySelector('#sketch');
    37         var sketch_style = getComputedStyle(sketch);
    38         canvas.width = parseInt(sketch_style.getPropertyValue('width'));
    39         canvas.height = parseInt(sketch_style.getPropertyValue('height'));
    40 
    41         var mouse = {x: 0, y: 0};
    42         var last_mouse = {x: 0, y: 0};
    43         
    44         /* Mouse Capturing Work */
    45         canvas.addEventListener('mousemove', function(e) {
    46             last_mouse.x = mouse.x;
    47             last_mouse.y = mouse.y;
    48             
    49             mouse.x = e.pageX - this.offsetLeft;
    50             mouse.y = e.pageY - this.offsetTop;
    51         }, false);
    52         
    53         
    54         /* Drawing on Paint App */
    55         ctx.lineWidth = 5;
    56         ctx.lineJoin = 'round';
    57         ctx.lineCap = 'round';
    58         ctx.strokeStyle = 'blue';
    59         
    60         canvas.addEventListener('mousedown', function(e) {
    61             canvas.addEventListener('mousemove', onPaint, false);
    62         }, false);
    63         
    64         canvas.addEventListener('mouseup', function() {
    65             canvas.removeEventListener('mousemove', onPaint, false);
    66         }, false);
    67         
    68         var onPaint = function() {
    69             ctx.beginPath();
    70             ctx.moveTo(last_mouse.x, last_mouse.y);
    71             ctx.lineTo(mouse.x, mouse.y);
    72             ctx.closePath();
    73             ctx.stroke();
    74         };
    75     });
    76     </script>
    77 </head>
    78         
    79 
    80 <body>
    81     <div id="sketch">
    82         <canvas id="paint"></canvas>
    83     </div>
    84 
    85 </body>
    86 </html>

    这个代码很容易实现,但是它有个问题,就是画线不流畅,出现折断痕迹。

    4.画流畅的线

    可以根据二次贝塞尔曲线,连接2点画弧得到没有折痕的流畅曲线。

    可以参照:

    http://www.html5canvastutorials.com/labs/html5-canvas-modify-curves-with-anchor-points-using-kineticjs/

    http://www.cartogrammar.com/blog/actionscript-curves-update/

     1 tmp_ctx.beginPath();
     2 tmp_ctx.moveTo(ppts[0].x, ppts[0].y); //使用 beginPath() 和 moveTo() 方法来定义开始点
     3 
     4 for (var i = 1; i < ppts.length - 2; i++) {
     5     var c = (ppts[i].x + ppts[i + 1].x) / 2;
     6     var d = (ppts[i].y + ppts[i + 1].y) / 2;
     7  
     8     tmp_ctx.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d); //二次贝塞曲线函数   
     9 }
    10  
    11 // For the last 2 points
    12 tmp_ctx.quadraticCurveTo(
    13     ppts[i].x,
    14     ppts[i].y,
    15     ppts[i + 1].x,
    16     ppts[i + 1].y
    17 );
    18 tmp_ctx.stroke(); //这时,图形才是实际的绘制到 canvas 上去,stroke 是绘制图形的边框
    quadraticCurveTo(cpx, cpy, x, y);方法通过使用表示二次贝塞尔曲线的指定控制点,向当前路径添加一个点。第一个点是用于二次贝塞尔计算中的控制点,第二个点是曲线的结束点。曲线的开始点是当前路径中最后一个点。

    虽然这样子可以画出贝塞尔曲线,但是你可以发现,它还是有锯齿边缘的。但是在画图之前加一个clearRect()函数,则锯齿消失!我不晓得这是为什么。。。

    5.画没有齿痕的流畅曲线 

    tmp_ctx.beginPath();
    tmp_ctx.moveTo(ppts[0].x, ppts[0].y); 
    
    tmp_ctx.clearRect(0, 0, 2000, 2000);//它可以消除齿痕!
    
    for (var i = 1; i < ppts.length - 2; i++) {
        var c = (ppts[i].x + ppts[i + 1].x) / 2;
        var d = (ppts[i].y + ppts[i + 1].y) / 2;
     
        tmp_ctx.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d); 
    }
     
    // For the last 2 points
    tmp_ctx.quadraticCurveTo(
        ppts[i].x,
        ppts[i].y,
        ppts[i + 1].x,
        ppts[i + 1].y
    );
    tmp_ctx.stroke();

    6.接下来是橡皮的问题,虽然可以用相同背景色来代替,但是如果背景不单一,那就不管用了。所以,我们需要一个完完全全的橡皮,而不是相同背景,或者消除一块区域的痕迹。

    那么,我们可以简单的引用globalCompositeOperation()函数,这个函数是用来在画布上组合颜色,我们可以利用这个原理,叠加(数学上的"或"原理)来制作橡皮。

    同画笔一样,获得鼠标位置,叠加画板上已有的颜色,则为取消。

    globalCompositeOperation()函数,请参考 http://www.html5canvastutorials.com/advanced/html5-canvas-global-composite-operations-tutorial/

     画笔画图时: context.globalCompositeOperation = 'source-over'; //新的颜色覆盖之前的

     橡皮擦除时: context.globalCompositeOperation = 'destination-out'; //新的颜色与之前颜色,重叠的部分消失

    7. 画具有透明度的线

     http://css.dzone.com/articles/sketching-html5-canvas-and

    <!-- 
    Internet Explorer 9、Firefox、Opera、Chrome 以及 Safari 支持。
    From: http://www.cnblogs.com/muzijia/admin/EditPosts.aspx?postid=2841967
     -->
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
        <meta http-equiv="Content-Script-Type" content="text/javascript" />
        <meta http-equiv="Content-Style-Type" content="text/css" />
    
        <meta name="viewport" content=" initial-scale=0.80,user-scalable=no" />
        <link rel="stylesheet" href="http://code.jquery.com/ui/1.9.1/themes/base/jquery-ui.css" />   
        <script src="http://code.jquery.com/jquery-1.8.2.js"></script>
        <script src="http://code.jquery.com/ui/1.9.1/jquery-ui.js"></script>
        
        
        <title>Pencil</title>
        <style type="text/css">
            ul, li{
                clear:both;
                list-style:none;
                margin:0 auto;
                display: inline; 
            }
        
            html, body {
                width: 100%;
                height: 100%;
                 
            }    
            
            #sketch {
                border: 10px solid gray;
                height: 100%;
                position: relative;
                 
            }
            #tmp_canvas {
                position: absolute;
                left: 0px; right: 0;
                bottom: 0; top: 0;
                cursor: crosshair;
            }
        </style>
         
        <script type="text/javascript">
    
    
        $(document).ready(function(){
            var canvas = document.querySelector('#paint');
            var ctx = canvas.getContext('2d');
            
            var sketch = document.querySelector('#sketch');
            var sketch_style = getComputedStyle(sketch);
            canvas.width = parseInt(sketch_style.getPropertyValue('width'));
            canvas.height = parseInt(sketch_style.getPropertyValue('height'));
            
            
            // Creating a tmp canvas
            var tmp_canvas = document.createElement('canvas');
            var tmp_ctx = tmp_canvas.getContext('2d');
            tmp_canvas.id = 'tmp_canvas';
            tmp_canvas.width = canvas.width;
            tmp_canvas.height = canvas.height;
            
            sketch.appendChild(tmp_canvas);
    
            var mouse = {x: 0, y: 0};
            var last_mouse = {x: 0, y: 0};
            
            var paint = {
                init:function(canvasID_, canvas, context, brushImage){
                    this.canvasID_ = canvasID_;
                    this.canvasID = $("#"+canvasID_);
                    this.canvas = canvas;
                    this.context = context;
                        
                    /** Drawing on Line Paint App */
                    this.context.lineWidth = 5;
                    this.context.lineJoin = 'round';
                    this.context.lineCap = 'round';
                    this.context.strokeStyle = 'red';
                    this.context.fillStyle = 'red';        
    
                    this.color=["#000000","#9E9E9E","#FFFFFF","#8B5742","#FF0000","#FFC125","#00688B","#CDB38B","#CD8C95"];                    
                                    
                    this.lock = false;    
                    this.line = false;                
                    
                    ppts = [];        // Pencil Points                     
                    
                    this.brush = brushImage;
                    this.context.globalAlpha = 1;
                    
                    /** mouse event */                
                    if (this.touchSupported) {
                        this.mouseDownEvent = "touchstart";
                        this.mouseMoveEvent = "touchmove";
                        this.mouseUpEvent = "touchend";
                    }
                    else {
                        this.mouseDownEvent = "mousedown";
                        this.mouseMoveEvent = "mousemove";
                        this.mouseUpEvent = "mouseup";
                    }
                    
                    this.bind();
                },    
                bind:function(){
                    var t = this; //paint Instance     
                    this.canvasID.live({        
                        mousedown: function(e){        
                        
                            mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
                            mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;
                            
                            ppts.push({x: mouse.x , y: mouse.y}); 
                            
                            t.lock=true;
                        },
                        mousemove: function(e){                    
                            if(t.lock){                    
                                mouse.x = typeof e.offsetX !== 'undefined' ? e.offsetX : e.layerX;
                                mouse.y = typeof e.offsetY !== 'undefined' ? e.offsetY : e.layerY;                            
                                
                                ppts.push({x: mouse.x , y: mouse.y });
                                
                                //tmp_ctx.clearRect(0, 0, 2000, 2000);
                                
                                //if(t.line == true){ //draw line
                                    t.onPaint();                                                                
                                //}    
                                //if(t.line ==false){
                                    //t.drawPoint();    //draw image                                
                                //}
                                
                                
                            }            
                        },
                        mouseleave:function(e){
                            t.lock = false;    
                            //ctx.drawImage(tmp_canvas, 0, 0);
                            //tmp_ctx.clearRect(0, 0, 2000, 2000);        
                            ppts = [];
                        },
                        mouseup: function(e){            
                            t.lock = false;    
                            //ctx.drawImage(tmp_canvas, 0, 0);
                            //tmp_ctx.clearRect(0, 0, 2000, 2000);    
                            //tmp_ctx.drawImage(canvas, 0, 0);
                            ppts = [];                
                        }
                    });    
    
                },
                onPaint:function() 
                {
                    var tmp_ctx = this.context;                    
                    // Tmp canvas is always cleared up before drawing.
                    tmp_ctx.clearRect(0, 0, 2000, 2000);      //取消齿痕; 如果想用橡皮,则注释这句,因为绘图痕迹绘在两个图层中。          
                    
                    if (ppts.length < 3) {
                        var b = ppts[0];
                        tmp_ctx.beginPath();
    
                        tmp_ctx.arc(b.x, b.y, tmp_ctx.lineWidth / 2, 0, Math.PI * 2, !0);
                        tmp_ctx.fill();
                        tmp_ctx.closePath();
                        
                        return;
                    }                
                                    
                    tmp_ctx.beginPath();
                    tmp_ctx.moveTo(ppts[0].x, ppts[0].y);
                    
                    for (var i = 1; i < ppts.length - 2; i++) {
                        var c = (ppts[i].x + ppts[i + 1].x) / 2;
                        var d = (ppts[i].y + ppts[i + 1].y) / 2;                        
                        tmp_ctx.quadraticCurveTo(ppts[i].x, ppts[i].y, c, d);    
                    }
                                
                    // For the last 2 points
                    tmp_ctx.quadraticCurveTo(
                        ppts[i].x,
                        ppts[i].y,
                        ppts[i + 1].x,
                        ppts[i + 1].y
                    );                
                    tmp_ctx.stroke();                
                },
                changeColor:function(style,color)
                {          
                    var t=this;
                    var styleNum = style;
                    var colorNum = color;                
    
                    console.debug("pen ="+style+", color="+color);
                    
                    t.context.strokeStyle = t.color[colorNum];
                    t.context.fillStyle = t.color[colorNum];    
                    
                    if(styleNum == 0){  //mark pen    
                        t.line = true;    
                        t.context.lineWidth = 30;
                        t.context.globalAlpha = 0.5;
                        t.context.globalCompositeOperation = 'source-over';         
                        
                        console.debug("mark");    
                        
                    }
                    if(styleNum == 1){  //peicnl   
                        t.line = true;    
                        t.context.lineWidth = 5;
                        t.context.globalAlpha = 1;    
                        t.context.globalCompositeOperation = 'source-over';    
                        
                        console.debug("pencil");    
                        
                    }
                    if(styleNum == 2){  //resetEraser 
                        t.line = true;    
                        //t.context = ctx;
                        t.resetEraser();
                    }             
                        
                    
                },
                resetEraser:function()
                {         
                    var t=this; 
                    //t.context = ctx;
                    t.context.lineWidth = 30;
                    t.context.globalAlpha = 1;
                    t.context.globalCompositeOperation = 'destination-out';
                    console.debug("resetEraser");
                },
                clear:function()
                {
                    ppts = [];
                    this.context.globalAlpha = 0;
                    this.context.clearRect(0, 0, this.w, this.h);
                }
            };
                
            <!-- drawing -->
            var brush = new Image();    
            brush.src = "images/color_01.png";        //defalut red
            brush.onload = function(){     
                paint.init('tmp_canvas',tmp_canvas,tmp_ctx, brush); 
            };
            
        
            var style = 1;
            var color = 1;     
            $('.tool> li > a').click(function() {            
                var idx = $('.tool> li > a').index(this);            
                style = idx;
                paint.changeColor(style, color);    
                
                if(idx == 2){
                    //paint.init('paint',paint,ctx, brush);
                }
            });
    
            $('.brush > li > a').click(function() {            
                var idx = $('.brush > li > a').index(this);                
                var i = idx + 1;
                
                //brush.src = "images/color_0"+i+".png";                
                color = idx;
                paint.changeColor(style, color);    
            });
        
        });
        </script>
    </head>
            
    
    <body>
        
        <div class="pencil">    
            <ul class="tool">                                
                <li><a class="btn_pen" href="javascript:void(0)"><img src="images/crayon-outline.png" alt=""></a></li>            
                <li><a class="btn_mark" href="javascript:void(0)"><img src="images/marker-outline.png" alt=""></a></li>            
                <li><a class="btn_eraser" href="javascript:void(0)"><img src="images/eraser-outline.png" alt=""></a></li>    
                <li><a class="btn_mark" href="javascript:void(0)"><img src="images/image-outline.png" alt=""></a></li>            
            </ul>
            <ul class="brush">
                <li><a href="javascript: void(0);"><img src="images/color_01.png" /></a></li>
                <li><a href="javascript: void(0);"><img src="images/color_02.png" /></a></li>
                <li><a href="javascript: void(0);"><img src="images/color_03.png" /></a></li>
                <li><a href="javascript: void(0);"><img src="images/color_04.png" /></a></li>
                <li><a href="javascript: void(0);"><img src="images/color_05.png" /></a></li>
                <li><a href="javascript: void(0);"><img src="images/color_06.png" /></a></li>
                <li><a href="javascript: void(0);"><img src="images/color_07.png" /></a></li>
                <li><a href="javascript: void(0);"><img src="images/color_08.png" /></a></li>
                <li><a href="javascript: void(0);"><img src="images/color_09.png" /></a></li>
            </ul>            
        </div>
        <div id="sketch">
            <canvas id="paint"></canvas>
        </div>
    
    </body>
    </html>

        

  • 相关阅读:
    第一次作业
    机器学习第一次个人作业
    第02组 Beta版本演示
    第02组 Beta冲刺(4/4)
    第02组 Beta冲刺(3/4)
    微信小程序信息会话列表删除功能
    微信小程序自定义弹窗组件
    微信小程序使用Echarts
    uni.showModal,uni.showToast使用
    Array filter() 方法
  • 原文地址:https://www.cnblogs.com/nlyangtong/p/10033045.html
Copyright © 2020-2023  润新知