平滑画布线和光标起点 [英] Smooth canvas line and on curser start point

查看:30
本文介绍了平滑画布线和光标起点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个画布 Web 应用程序,但遇到两个主要问题.我想让钢笔工具画得更流畅.其次,每次我清除草图并再次开始绘制时,线条都从光标/鼠标的不同点开始.

I am attempting to create a canvas web application and having two main problems. I would love to make the pen tool draw more smoothly. Secondly, each time I clear the sketch and begin to draw again the line begins in a different point to the curser/mouse.

这是我的绘图工具的 javascript:

Here is javascript for my drawing tool:

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');

var radius = 10;
var dragging = false;

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

context.lineWidth = radius*2;

var putPoint = function(e){
if(dragging){
context.lineTo(e.clientX, e.clientY);
context.stroke();
context.beginPath();
context.arc(e.clientX, e.clientY, radius, 0, Math.PI*2);
context.fill();
context.beginPath();
context.moveTo(e.clientX, e.clientY);
}}

var engage = function(){
dragging = true;
}

var disengage = function(){
dragging = false;
}

canvas.addEventListener('mousedown', engage);
canvas.addEventListener('mousemove', putPoint);
canvas.addEventListener('mouseup', disengage);

这就是我清理草图的方式:

and this is how I am clearing the sketch:

// JavaScript Document

  // bind event handler to clear button
  document.getElementById('clear').addEventListener('click', function() {
    context.clearRect(0, 0, canvas.width, canvas.height);
  }, false);

可以在以下位置查看实时预览:http://www.sarahemily.net/canvas/

A live preview can be seen at: http://www.sarahemily.net/canvas/

感谢您的帮助!

推荐答案

首先是行起始位置不对的问题.您忘记完成您创建的路径.您有 beginPathmoveTo,但您将其搁置.当鼠标按钮向上时,您需要调用一次 stroke.

First the problem of the line starting in the wrong spot. You are forgetting to finish the path you create. You have beginPath, and moveTo but you leave it hanging. You need to call stroke once when the mouse button is up.

平滑.

线条平滑是一件非常复杂的事情,许多专业绘图应用程序通过各种解决方案来解决这个问题.似乎没有一种商定的方法.最大的问题是..你如何平滑一条线但不破坏所需的线?以及你如何快速做到这一点????

Line smoothing is a very complicated thing to do with many professional drawing apps tackling the problem with a variety of solutions. There does not seem to be one agreed upon method. The big problem is.. How do you smooth a line but not destroy the desired line? and How do you do it quickly????

这里我介绍了一个两阶段的过程.

Here I present a two stage process.

降低线路复杂度

第一步,降低线路复杂度.对鼠标进行采样让位于许多点.所以我需要减少点数,但不能丢失任何细节.

Step one, reduce the line complexity. Sampling the mouse gives way to many points. So I need to reduce the number of points, but not lose any details.

我使用 Ramer–Douglas–Peucker算法.它很快,并且在降低线的复杂性(点数)方面做得很好.您可以在下面找到我对算法的实现.它不是最好的,因为它可以通过一些优化来实现.您很可能会在其他语言中找到它并将其移植到 javascript.

I use the Ramer–Douglas–Peucker algorithm. It's quick and does a good job of reducing the complexity (number of points) of a line. Below you can find my implementation of the algorithm. It's not the best as it could do with some optimisation. You could most likely find it in some other language and port it to javascript.

它使用递归函数根据线段之间的长度和角度来降低复杂性.其核心是两条线段的点积,它是确定两条线段之间角度的快速方法.有关详细信息,请参阅上面提供的链接.

It uses a recursive function to reduce complexity based on length and angle between line segments. At its core is the dot product of two line segments, it is a quick way of determining the angle between the two segments. See the supplied link above for more details.

// Line simplification based on
// the Ramer–Douglas–Peucker algorithm
// referance https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
// points: are and array of arrays consisting of [[x,y],[x,y],...,[x,y]]
// length: is in pixels and is the square of the actual distance.
// returns array of points of the same form as the input argument points.
var simplifyLineRDP = function(points, length) {
    var simplify = function(start, end) { // recursive simplifies points from start to end
        var maxDist, index, i, xx , yy, dx, dy, ddx, ddy, p1, p2, p, t, dist, dist1;
        p1 = points[start];
        p2 = points[end];   
        xx = p1[0];
        yy = p1[1];
        ddx = p2[0] - xx;
        ddy = p2[1] - yy;
        dist1 = (ddx * ddx + ddy * ddy);
        maxDist = length;
        for (var i = start + 1; i < end; i++) {
            p = points[i];
            if (ddx !== 0 || ddy !== 0) {
               // dot product
                t = ((p[0] - xx) * ddx + (p[1] - yy) * ddy) / dist1;
                if (t > 1) {
                    dx = p[0] - p2[0];
                    dy = p[1] - p2[1];
                } else 
                if (t > 0) {
                    dx = p[0] - (xx + ddx * t);
                    dy = p[1] - (yy + ddy * t);
                } else {
                    dx = p[0] - xx;
                    dy = p[1] - yy;
                }
            }else{
                dx = p[0] - xx;
                dy = p[1] - yy;
            }
            dist = dx * dx + dy * dy 
            if (dist > maxDist) {
                index = i;
                maxDist = dist;
            }
        }

        if (maxDist > length) { // continue simplification while maxDist > length
            if (index - start > 1){
                simplify(start, index);
            }
            newLine.push(points[index]);
            if (end - index > 1){
                simplify(index, end);
            }
        }
    }    
    var end = points.length - 1;
    var newLine = [points[0]];
    simplify(0, end);
    newLine.push(points[end]);
    return newLine;
}

使用贝塞尔曲线平滑

接下来是平滑.由于线条已被简化,因此如果合理快速地比较多条线条之间的角度,并在角度低于所需阈值时创建贝塞尔曲线.

Next the smoothing. As the line has been simplified it if reasonably quick to then compare the angles between the many lines and create a bezier if the angle is below a required threshold.

下面是我如何做的一个例子.虽然这不适合原始线,但它只与平滑有关.就我而言,这又是一个黑客,而不是基于任何经过试验和测试的算法.我还有一个贝塞尔曲线拟合,但对于这个例子来说太慢了.

Below is a example of how I do it. Though this will not fit the original line it is just concerned with smoothing. It is again a bit of a hack on my part and not based on any tried and tested algorithm. I have another one that does a bezier fit but that is too slow for the example.

基本上它通过线段并计算两条线段之间的角度,如果角度低于阈值,则沿着两条线段的切线添加贝塞尔控制点,根据以下情况制作二阶或三阶贝塞尔曲线是否平滑了两个连续的点.这是一个更复杂的算法的精简版,所以请原谅我的混乱.

Basicly it steps through the line segments and calculates the angle between two segments, if the angle is below the threshold it then adds bezier control points along the tangent of the two line segments, making either 2nd order or 3rd order beziers depending on whether two consecutive points are smoothed. This is a stripped down version of a much more complicated algorithm so excuse the mess.

// This is my own smoothing method The blindman`s smoother
// It creates a set of bezier control points either 2nd order or third order 
// bezier curves.
// points: list of points [[x,y],[x,y],...,[x,y]]
// cornerThres: when to smooth corners and represents the angle between to lines. 
//     When the angle is smaller than the cornerThres then smooth.
// match: if true then the control points will be balanced.
// Function will make a copy of the points
// returns [[x,y],[x,y,bx,by],[x,y,b1x,b1y,b2x,b2y],.....] with x and y line points
// bx,by control points for 2nd order bezier and b1x,b1y,b2x,b2y the control
// points for 3rd order bezier. These are mixed as needed. Test the length of
// each point array to work out which bezier if any to use.

var smoothLine = function(points,cornerThres,match){  // adds bezier control points at points if lines have angle less than thres
    var  p1, p2, p3, dist1, dist2, x, y, endP, len, angle, i, newPoints, aLen, closed, bal, cont1, nx1, nx2, ny1, ny2, np;
    function dot(x, y, xx, yy) {  // get do product
        // dist1,dist2,nx1,nx2,ny1,ny2 are the length and  normals and used outside function
        // normalise both vectors
        dist1 = Math.sqrt(x * x + y * y); // get length
        if (dist1  > 0) {  // normalise
            nx1 = x / dist1 ;
            ny1 = y / dist1 ;
        }else {
            nx1 = 1;  // need to have something so this will do as good as anything
            ny1 = 0;
        }
        dist2  = Math.sqrt(xx * xx + yy * yy);
        if (dist2  > 0) {
            nx2 = xx / dist2;
            ny2 = yy / dist2;
        }else {
            nx2 = 1;
            ny2 = 0;
        }
       return Math.acos(nx1 * nx2 + ny1 * ny2 ); // dot product
    }
    newPoints = []; // array for new points
    aLen = points.length;
    if(aLen <= 2){  // nothing to if line too short
        for(i = 0; i < aLen; i ++){  // ensure that the points are copied          
            newPoints.push([points[i][0],points[i][1]]);
        }
        return newPoints;
    }
    p1 = points[0];
    endP =points[aLen-1];
    i = 0;  // start from second poitn if line not closed
    closed = false;
    len = Math.hypot(p1[0]- endP[0], p1[1]-endP[1]);
    if(len < Math.SQRT2){  // end points are the same. Join them in coordinate space
        endP =  p1;
        i = 0;             // start from first point if line closed
        p1 = points[aLen-2];
        closed = true;
    }       
    newPoints.push([points[i][0],points[i][1]])
    for(; i < aLen-1; i++){
        p2 = points[i];
        p3 = points[i + 1];
        angle = Math.abs(dot(p2[0] - p1[0], p2[1] - p1[1], p3[0] - p2[0], p3[1] - p2[1]));
        if(dist1 !== 0){  // dist1 and dist2 come from dot function
            if( angle < cornerThres*3.14){ // bend it if angle between lines is small
                  if(match){
                      dist1 = Math.min(dist1,dist2);
                      dist2 = dist1;
                  }
                  // use the two normalized vectors along the lines to create the tangent vector
                  x = (nx1 + nx2) / 2;  
                  y = (ny1 + ny2) / 2;
                  len = Math.sqrt(x * x + y * y);  // normalise the tangent
                  if(len === 0){
                      newPoints.push([p2[0],p2[1]]);                                  
                  }else{
                      x /= len;
                      y /= len;
                      if(newPoints.length > 0){
                          var np = newPoints[newPoints.length-1];
                          np.push(p2[0]-x*dist1*0.25);
                          np.push(p2[1]-y*dist1*0.25);
                      }
                      newPoints.push([  // create the new point with the new bezier control points.
                            p2[0],
                            p2[1],
                            p2[0]+x*dist2*0.25,
                            p2[1]+y*dist2*0.25
                      ]);
                  }
            }else{
                newPoints.push([p2[0],p2[1]]);            
            }
        }
        p1 = p2;
    }  
    if(closed){ // if closed then copy first point to last.
        p1 = [];
        for(i = 0; i < newPoints[0].length; i++){
            p1.push(newPoints[0][i]);
        }
        newPoints.push(p1);
    }else{
        newPoints.push([points[points.length-1][0],points[points.length-1][1]]);      
    }
    return newPoints;    
}

由于我没有考虑到易用性,因此您必须使用以下函数来呈现结果线.

As I did not put that much thought into ease of use you will have to use the following function to render the resulting line.

var drawSmoothedLine = function(line){
    var i,p;
    ctx.beginPath()
    ctx.moveTo(line[0][0],line[0][1])
    for(i = 0; i < line.length-1; i++){
       p = line[i];
       p1 = line[i+1]
       if(p.length === 2){ // linear 
            ctx.lineTo(p[0],p[1])
       }else
       if(p.length === 4){ // bezier 2nd order
           ctx.quadraticCurveTo(p[2],p[3],p1[0],p1[1]);
       }else{              // bezier 3rd order
           ctx.bezierCurveTo(p[2],p[3],p[4],p[5],p1[0],p1[1]);
       }
    }
    if(p.length === 2){
        ctx.lineTo(p1[0],p1[1])
    }
    ctx.stroke();
}

所以用这些来平滑一条线.只需在绘制时捕获鼠标点即可.完成后,将点依次发送到两个函数.擦除绘制的线条并将其替换为新线条.上笔和平滑结果之间有点滞后,但两个功能都有很大的改进空间.

So to use these to smooth a line. Simply capture the mouse points as you draw. When the done, then send the points to both functions in turn. Erase the drawn line and replace it with the new line. The is a bit of a lag between pen up and the smoothed result, but there is plenty of room for improvement in both functions.

为了把它们放在一起,我在下面添加了一个片段.左上角的两个条控制平滑和细节.底部栏控制上述第一个功能,顶部控制平滑(贝塞尔曲线),您看到的红色越多,线条越平滑,细节减少的越多.

To put it all together I have added a snippet below. The two bars at the top left control the smoothing and detail. The bottom bar controls the first function described above and the top controls the smoothing (bezier) the more red you see the smoother the lines and greater the detail reduction.

鼠标中键清除或重新启动.

Middle mouse button clears or just restart.

抱歉,这比我预期的要多,所以评论有点少.我会在时间允许的情况下改进评论..

Sorry, this was more work than I expected so the comments are a little sparse. I will improve the comments as time permits..

var canvas = document.getElementById("canV"); 
var ctx = canvas.getContext("2d");


// mouse stuff
var mouse = {
    x:0,
    y:0,
    buttonLastRaw:0, // user modified value 
    buttonRaw:0,
    buttons:[1,2,4,6,5,3], // masks for setting and clearing button raw bits;
};
function mouseMove(event){
    mouse.x = event.offsetX;  mouse.y = event.offsetY; 
    if(mouse.x === undefined){ mouse.x = event.clientX;  mouse.y = event.clientY;}    
    if(event.type === "mousedown"){ mouse.buttonRaw |= mouse.buttons[event.which-1];
    }else if(event.type === "mouseup"){mouse.buttonRaw &= mouse.buttons[event.which+2];
    }else if(event.type === "mouseout"){ mouse.buttonRaw = 0; mouse.over = false;
    }else if(event.type === "mouseover"){ mouse.over = true; }
    event.preventDefault();
}
canvas.addEventListener('mousemove',mouseMove);
canvas.addEventListener('mousedown',mouseMove);
canvas.addEventListener('mouseup'  ,mouseMove); 
canvas.addEventListener('mouseout'  ,mouseMove); 
canvas.addEventListener('mouseover'  ,mouseMove); 
canvas.addEventListener("contextmenu", function(e){ e.preventDefault();}, false);


// Line simplification based on
// the Ramer–Douglas–Peucker algorithm
// referance https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
// points are and array of arrays consisting of [[x,y],[x,y],...,[x,y]]
// length is in pixels and is the square of the actual distance.
// returns array of points of the same form as the input argument points.
var simplifyLineRDP = function(points, length) {
    var simplify = function(start, end) { // recursize simplifies points from start to end
        var maxDist, index, i, xx , yy, dx, dy, ddx, ddy, p1, p2, p, t, dist, dist1;
        p1 = points[start];
        p2 = points[end];   
        xx = p1[0];
        yy = p1[1];
        ddx = p2[0] - xx;
        ddy = p2[1] - yy;
        dist1 = (ddx * ddx + ddy * ddy);
        maxDist = length;
        for (var i = start + 1; i < end; i++) {
            p = points[i];
            if (ddx !== 0 || ddy !== 0) {
                t = ((p[0] - xx) * ddx + (p[1] - yy) * ddy) / dist1;
                if (t > 1) {
                    dx = p[0] - p2[0];
                    dy = p[1] - p2[1];
                } else 
                if (t > 0) {
                    dx = p[0] - (xx + ddx * t);
                    dy = p[1] - (yy + ddy * t);
                } else {
                    dx = p[0] - xx;
                    dy = p[1] - yy;
                }
            }else{
                dx = p[0] - xx;
                dy = p[1] - yy;
            }
            dist = dx * dx + dy * dy 
            if (dist > maxDist) {
                index = i;
                maxDist = dist;
            }
        }

        if (maxDist > length) { // continue simplification while maxDist > length
            if (index - start > 1){
                simplify(start, index);
            }
            newLine.push(points[index]);
            if (end - index > 1){
                simplify(index, end);
            }
        }
    }    
    var end = points.length - 1;
    var newLine = [points[0]];
    simplify(0, end);
    newLine.push(points[end]);
    return newLine;
}



// This is my own smoothing method 
// It creates a set of bezier control points either 2nd order or third order 
// bezier curves.
// points: list of points
// cornerThres: when to smooth corners and represents the angle between to lines. 
//     When the angle is smaller than the cornerThres then smooth.
// match: if true then the control points will be balanced.
// Function will make a copy of the points

var smoothLine = function(points,cornerThres,match){  // adds bezier control points at points if lines have angle less than thres
    var  p1, p2, p3, dist1, dist2, x, y, endP, len, angle, i, newPoints, aLen, closed, bal, cont1, nx1, nx2, ny1, ny2, np;
    function dot(x, y, xx, yy) {  // get do product
        // dist1,dist2,nx1,nx2,ny1,ny2 are the length and  normals and used outside function
        // normalise both vectors
        dist1 = Math.sqrt(x * x + y * y); // get length
        if (dist1  > 0) {  // normalise
            nx1 = x / dist1 ;
            ny1 = y / dist1 ;
        }else {
            nx1 = 1;  // need to have something so this will do as good as anything
            ny1 = 0;
        }
        dist2  = Math.sqrt(xx * xx + yy * yy);
        if (dist2  > 0) {
            nx2 = xx / dist2;
            ny2 = yy / dist2;
        }else {
            nx2 = 1;
            ny2 = 0;
        }
       return Math.acos(nx1 * nx2 + ny1 * ny2 ); // dot product
    }
    newPoints = []; // array for new points
    aLen = points.length;
    if(aLen <= 2){  // nothing to if line too short
        for(i = 0; i < aLen; i ++){  // ensure that the points are copied          
            newPoints.push([points[i][0],points[i][1]]);
        }
        return newPoints;
    }
    p1 = points[0];
    endP =points[aLen-1];
    i = 0;  // start from second poitn if line not closed
    closed = false;
    len = Math.hypot(p1[0]- endP[0], p1[1]-endP[1]);
    if(len < Math.SQRT2){  // end points are the same. Join them in coordinate space
        endP =  p1;
        i = 0;             // start from first point if line closed
        p1 = points[aLen-2];
        closed = true;
    }       
    newPoints.push([points[i][0],points[i][1]])
    for(; i < aLen-1; i++){
        p2 = points[i];
        p3 = points[i + 1];
        angle = Math.abs(dot(p2[0] - p1[0], p2[1] - p1[1], p3[0] - p2[0], p3[1] - p2[1]));
        if(dist1 !== 0){  // dist1 and dist2 come from dot function
            if( angle < cornerThres*3.14){ // bend it if angle between lines is small
                  if(match){
                      dist1 = Math.min(dist1,dist2);
                      dist2 = dist1;
                  }
                  // use the two normalized vectors along the lines to create the tangent vector
                  x = (nx1 + nx2) / 2;  
                  y = (ny1 + ny2) / 2;
                  len = Math.sqrt(x * x + y * y);  // normalise the tangent
                  if(len === 0){
                      newPoints.push([p2[0],p2[1]]);                                  
                  }else{
                      x /= len;
                      y /= len;
                      if(newPoints.length > 0){
                          var np = newPoints[newPoints.length-1];
                          np.push(p2[0]-x*dist1*0.25);
                          np.push(p2[1]-y*dist1*0.25);
                      }
                      newPoints.push([  // create the new point with the new bezier control points.
                            p2[0],
                            p2[1],
                            p2[0]+x*dist2*0.25,
                            p2[1]+y*dist2*0.25
                      ]);
                  }
            }else{
                newPoints.push([p2[0],p2[1]]);            
            }
        }
        p1 = p2;
    }  
    if(closed){ // if closed then copy first point to last.
        p1 = [];
        for(i = 0; i < newPoints[0].length; i++){
            p1.push(newPoints[0][i]);
        }
        newPoints.push(p1);
    }else{
        newPoints.push([points[points.length-1][0],points[points.length-1][1]]);      
    }
    return newPoints;    
}

// creates a drawable image
var createImage = function(w,h){
    var image = document.createElement("canvas");
    image.width = w;
    image.height =h; 
    image.ctx = image.getContext("2d"); 
    return image;
}  

// draws the smoothed line with bezier control points.
var drawSmoothedLine = function(line){
    var i,p;
    ctx.beginPath()
    ctx.moveTo(line[0][0],line[0][1])
    for(i = 0; i < line.length-1; i++){
       p = line[i];
       p1 = line[i+1]
       if(p.length === 2){ // linear 
            ctx.lineTo(p[0],p[1])
       }else
       if(p.length === 4){ // bezier 2nd order
           ctx.quadraticCurveTo(p[2],p[3],p1[0],p1[1]);
       }else{              // bezier 3rd order
           ctx.bezierCurveTo(p[2],p[3],p[4],p[5],p1[0],p1[1]);
       }
    }
    if(p.length === 2){
        ctx.lineTo(p1[0],p1[1])
    }
    ctx.stroke();
}

// smoothing settings
var lineSmooth = {};
lineSmooth.lengthMin = 8;  // square of the pixel length
lineSmooth.angle = 0.8;      // angle threshold
lineSmooth.match = false;  // not working.
// back buffer to save the canvas allowing the new line to be erased
var backBuffer = createImage(canvas.width,canvas.height);
var currentLine = [];
mouse.lastButtonRaw = 0;  // add mouse last incase not there
ctx.lineWidth = 3;
ctx.lineJoin = "round";
ctx.lineCap = "round";
ctx.strokeStyle = "black";
ctx.clearRect(0,0,canvas.width,canvas.height);
var drawing = false;  // if drawing
var input = false;  // if menu input
var smoothIt = false;  // flag to allow feedback that smoothing is happening as it takes some time.
function draw(){
    // if not drawing test for menu interaction and draw the menus
    if(!drawing){      
        if(mouse.x < 203 && mouse.y < 24){
            if(mouse.y < 13){
                if(mouse.buttonRaw === 1){
                    ctx.clearRect(3,3,200,10);
                    lineSmooth.angle = (mouse.x-3)/200;
                    input = true;
                }
            }else
            if(mouse.buttonRaw === 1){
                ctx.clearRect(3,14,200,10);
                lineSmooth.lengthMin = (mouse.x-3)/10;
                input = true;
            }
                
            canvas.style.cursor = "pointer";
        }else{
            canvas.style.cursor = "crosshair";
            
        }
        if(mouse.buttonRaw === 0 && input){
            input = false;
            mouse.lastButtonRaw = 0;
        }
        ctx.lineWidth = 1;
        ctx.fillStyle = "red";
        ctx.fillRect(3,3,lineSmooth.angle*200,10);
        ctx.fillRect(3,14,lineSmooth.lengthMin*10,10);

        ctx.textAlign = "left";
        ctx.textBaseline = "top";
        ctx.fillStyle = "#5F2"
        ctx.strokeRect(3,3,200,10);
        ctx.fillText("Smooth",5,2)
        ctx.strokeRect(3,14,200,10);
        ctx.fillText("Detail",5,13);

    }else{
        canvas.style.cursor = "crosshair"; 
    }
    if(!input){
         ctx.lineWidth = 3;

        if(mouse.buttonRaw === 1 && mouse.lastButtonRaw === 0){
            currentLine = [];
            drawing  = true;

            backBuffer.ctx.clearRect(0,0,canvas.width,canvas.height);
            backBuffer.ctx.drawImage(canvas,0,0);
            currentLine.push([mouse.x,mouse.y])
        }else
        if(mouse.buttonRaw === 1){
            var lp = currentLine[currentLine.length-1]; // get last point
            // dont record point if no movement
            if(mouse.x !== lp[0] || mouse.y !== lp[1] ){
                currentLine.push([mouse.x,mouse.y]);
                ctx.beginPath();
                ctx.moveTo(lp[0],lp[1])
                ctx.lineTo(mouse.x,mouse.y);
                ctx.stroke();
            }
        }else
        if(mouse.buttonRaw === 0 && mouse.lastButtonRaw === 1){
            ctx.textAlign = "center"
            ctx.fillStyle = "red"
            ctx.fillText("Smoothing...",canvas.width/2,canvas.height/5);
            smoothIt = true;
        }else
        if(smoothIt){
            smoothIt = false;
            
            var newLine = smoothLine(
                simplifyLineRDP(
                    currentLine,
                    lineSmooth.lengthMin
                ),
                lineSmooth.angle,
                lineSmooth.match
            );
            ctx.clearRect(0,0,canvas.width,canvas.height);
            ctx.drawImage(backBuffer,0,0);
            drawSmoothedLine(newLine);
            drawing  = false;
            
        }
    }
    // middle button clear
    if(mouse.buttonRaw === 2){
        ctx.clearRect(0,0,canvas.width,canvas.height);
    }
    mouse.lastButtonRaw = mouse.buttonRaw;

    requestAnimationFrame(draw);

}

draw();

.canC { width:1000px;  height:500px;}

<canvas class="canC" id="canV" width=1000 height=500></canvas>

这篇关于平滑画布线和光标起点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆