簡體   English   中英

畫布lineTo中的更平滑的lineWidth變化

[英]smoother lineWidth changes in canvas lineTo

所以我試圖在HTML5畫布中創建一個繪圖工具,其中筆觸的權重增加了您移動鼠標的速度,而減少了移動的速度。 我正在使用ctx.lineTo(),但是在我第一次嘗試時發現,如果我移動得太快,則厚度的變化會記錄為明顯的平方增量(而不是平滑的重量增加)

第一次嘗試

所以我將ctx.lineJoin和ctx.lineCap更改為“ round”,效果更好

當前狀態

但這仍然不如我所願。 我正在拍攝這樣的東西

我想要什么

關於如何使體重變化更平穩的任何建議都將是很棒的! 這是一個有效的演示: http : //jsfiddle.net/0fhag522/1/

這是我的“點”對象(pen)和繪圖功能的預覽:

    var dot = {         
        start: false,
        weight: 1,
        open: function(x,y){
            ctx.lineJoin = "round";
            ctx.lineCap = "round";
            ctx.beginPath();
            ctx.moveTo(x,y);
        },
        connect: function(x,y){
            ctx.lineWidth = this.weight;
            ctx.lineTo(x,y);
            ctx.stroke();
            ctx.closePath();
            ctx.beginPath();
            ctx.moveTo(x,y);
        },
        close: function(){
            ctx.closePath();
        }
    }

    function draw(){
        if(down){
            if(!dot.start){ 
                dot.close();
                prevx = mx;  prevy = my;
                dot.open(mx,my); 
                dot.start=true;  
            }
            else { 
                var dx = (prevx>mx) ? prevx-mx : mx-prevx;
                var dy = (prevy>my) ? prevy-my : my-prevy;
                dot.weight = Math.abs(dx-dy)/2;
                dot.connect( mx,my );
                prevx = mx;  prevy = my;
            }
        }
    }

由於畫布沒有寬度可變的線,因此必須在線點之間繪制閉合路徑。

但是,這留下了可見的對接。

在此處輸入圖片說明

要平滑對接,可以在每個接點處繪制一個圓。

在此處輸入圖片說明

這是示例代碼和演示:

 var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); var cw = canvas.width; var ch = canvas.height; var $canvas = $("#canvas"); var canvasOffset = $canvas.offset(); var offsetX = canvasOffset.left; var offsetY = canvasOffset.top; var scrollX = $canvas.scrollLeft(); var scrollY = $canvas.scrollTop(); var isDown = false; var startX; var startY; var PI = Math.PI; var halfPI = PI / 2; var points = []; $("#canvas").mousedown(function(e) { handleMouseDown(e); }); function handleMouseDown(e) { e.preventDefault(); e.stopPropagation(); mx = parseInt(e.clientX - offsetX); my = parseInt(e.clientY - offsetY); var pointsLength = points.length; if (pointsLength == 0) { points.push({ x: mx, y: my, width: Math.random() * 5 + 2 }); } else { var p0 = points[pointsLength - 1]; var p1 = { x: mx, y: my, width: Math.random() * 5 + 2 }; addAngle(p0, p1); p0.angle = p1.angle; addEndcap(p0); addEndcap(p1); points.push(p1); extendLine(p0, p1); } } function addAngle(p0, p1) { var dx = p1.x - p0.x; var dy = p1.y - p0.y; p1.angle = Math.atan2(dy, dx); } function addEndcap(p) { p.x0 = px + p.width * Math.cos(p.angle - halfPI); p.y0 = py + p.width * Math.sin(p.angle - halfPI); p.x1 = px + p.width * Math.cos(p.angle + halfPI); p.y1 = py + p.width * Math.sin(p.angle + halfPI); } function extendLine(p0, p1) { ctx.beginPath(); ctx.moveTo(p0.x0, p0.y0); ctx.lineTo(p0.x1, p0.y1); ctx.lineTo(p1.x1, p1.y1); ctx.lineTo(p1.x0, p1.y0); ctx.closePath(); ctx.fillStyle = 'blue'; ctx.fill(); // draw a circle to cover the butt-joint ctx.beginPath(); ctx.moveTo(p1.x, p1.y); ctx.arc(p1.x, p1.y, p1.width, 0, Math.PI * 2); ctx.closePath(); ctx.fill(); } 
 body{ background-color: ivory; } #canvas{border:1px solid red;} 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <h4>Click to add line segments.</h4> <canvas id="canvas" width=300 height=300></canvas> 

這是創建帶有圓形線帽的 生長線的簡單功能:

 /* * this function returns a Path2D object * the path represents a growing line between two given points */ function createGrowingLine (x1, y1, x2, y2, startWidth, endWidth) { // calculate direction vector of point 1 and 2 const directionVectorX = x2 - x1, directionVectorY = y2 - y1; // calculate angle of perpendicular vector const perpendicularVectorAngle = Math.atan2(directionVectorY, directionVectorX) + Math.PI/2; // construct shape const path = new Path2D(); path.arc(x1, y1, startWidth/2, perpendicularVectorAngle, perpendicularVectorAngle + Math.PI); path.arc(x2, y2, endWidth/2, perpendicularVectorAngle + Math.PI, perpendicularVectorAngle); path.closePath(); return path; } const ctx = myCanvas.getContext('2d'); // create a growing line between P1(10, 10) and P2(250, 100) // with a start line width of 10 and an end line width of 50 let line1 = createGrowingLine(10, 10, 250, 100, 10, 50); ctx.fillStyle = 'green'; // draw growing line ctx.fill(line1); 
 <canvas width="300" height="150" id="myCanvas"></canvas> 

說明:函數createGrowingLine通過以下方法在兩個給定點之間構造形狀:

  1. 計算兩點的方向向量
  2. 計算垂直向量的弧度角
  3. 使用起點的中心和半徑創建一個從計算角度到計算角度+ 180度的半圓路徑
  4. 從計算的角度+ 180度到計算的角度以及終點的中心和半徑創建另一個半圓路徑
  5. 通過連接第一個圓的起點和第二個圓的終點來閉合路徑

如果您不想使用圓角線帽,請使用以下功能:

 /* * this function returns a Path2D object * the path represents a growing line between two given points */ function createGrowingLine (x1, y1, x2, y2, startWidth, endWidth) { const startRadius = startWidth/2; const endRadius = endWidth/2; // calculate direction vector of point 1 and 2 let directionVectorX = x2 - x1, directionVectorY = y2 - y1; // calculate vector length const directionVectorLength = Math.hypot(directionVectorX, directionVectorY); // normalize direction vector (and therefore also the perpendicular vector) directionVectorX = 1/directionVectorLength * directionVectorX; directionVectorY = 1/directionVectorLength * directionVectorY; // construct perpendicular vector const perpendicularVectorX = -directionVectorY, perpendicularVectorY = directionVectorX; // construct shape const path = new Path2D(); path.moveTo(x1 + perpendicularVectorX * startRadius, y1 + perpendicularVectorY * startRadius); path.lineTo(x1 - perpendicularVectorX * startRadius, y1 - perpendicularVectorY * startRadius); path.lineTo(x2 - perpendicularVectorX * endRadius, y2 - perpendicularVectorY * endRadius); path.lineTo(x2 + perpendicularVectorX * endRadius, y2 + perpendicularVectorY * endRadius); path.closePath(); return path; } const ctx = myCanvas.getContext('2d'); // create a growing line between P1(10, 10) and P2(250, 100) // with a start line width of 10 and an end line width of 50 let line1 = createGrowingLine(10, 10, 250, 100, 10, 50); ctx.fillStyle = 'green'; // draw growing line ctx.fill(line1); 
 <canvas width="300" height="150" id="myCanvas"></canvas> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM