在 HTML canvas 线向量的左侧或右侧绘制不同宽度的线

Draw line with different widths on left or right side of line vector in HTML canvas

我正在 html canvas 上工作,我正在 canvas 上画一些线。这个过程很简单。但现在我想在相同坐标处绘制两条线,但宽度不同,但一条在实际线坐标的右侧,另一条在左侧。为了更清楚让我们看看这个例子 https://jsfiddle.net/am2222/2oqhLfd9/

如您所见,当我们绘制一条宽度为 x 的线时,它将围绕线延伸 x/2 像素。我想得到这样的东西:

如您所见,第二个示例线宽仅在一侧延伸。我知道我可以通过在一侧偏移 x/2 的线来得到这个,但我不确定计算如何在 canvas 上进行。 Ps: 我想在具有相同坐标的不同样式的 end.Two 行中得到类似的东西

在这个例子中,我采用了另一种方法。我创建了一个 SVG 图像,将其加载到一个图像对象中,然后将其绘制在 canvas 上。 SVG 当然可以是 hidden/only JS 中的字符串。

我不知道它的性能,所以它可能不适用于您的上下文——我只是觉得这是解决问题的一种有趣方式。

var svg = document.querySelector('svg');
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');

var img = new Image(300, 30);

img.addEventListener('load', e => {
  ctx.drawImage(e.target, 0, 0);
});

var imagesrc = btoa(svg.outerHTML);

img.src = `data:image/svg+xml;base64,${imagesrc}`;
<svg viewBox="0 0 200 20" width="300" height="30" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <linearGradient id="lg1" gradientUnits="userSpaceOnUse">
      <stop offset="0"  stop-color="orange" />
      <stop offset="1" stop-color="red" />
    </linearGradient>
    <linearGradient id="lg2" gradientUnits="userSpaceOnUse">
      <stop offset="0"  stop-color="navy" />
      <stop offset="1" stop-color="darkgreen" />
    </linearGradient>
  </defs>
  <line x1="0" y1="5" x2="200" y2="5" stroke-width="10" stroke="url(#lg1)" />
  <line x1="0" y1="15" x2="200" y2="15" stroke-width="10" stroke="url(#lg2)" />
  <line x1="0" y1="10" x2="200" y2="10" stroke-width="2" stroke="black" />
</svg>

<canvas width="300" height="30"></canvas>

这可能会有所帮助。我用一个标志功能化了渐变线的绘制以绘制黑色下划线。

该函数采用坐标、线宽和渐变颜色。

这可能是您探索的起点。可能有一些边缘情况我错过了这个功能会崩溃的地方。

var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');

function distance( a, b ) {
  return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) );
}

function drawGradientLine( line_width, grad_1, grad_2, xy1, xy2, underline ) {
  var grad = ctx.createLinearGradient(xy1.x, xy1.y, xy2.x, xy2.y);
  grad.addColorStop(0, grad_1);
  grad.addColorStop(1, grad_2);
  
    ctx.save();  
  ctx.lineWidth = line_width;
  ctx.strokeStyle = grad;
  ctx.beginPath();
    ctx.moveTo(xy1.x, xy1.y);
    ctx.lineTo(xy2.x, xy2.y);
    ctx.stroke();
  ctx.restore();
  
  if ( underline ) {
    const linelen = distance( xy1, xy2);
    const hyp1 = line_width / 2;
    const angle = Math.asin( (xy2.y - xy1.y) / (linelen) );
    const dy = (angle < 0) ? -1 * hyp1 * Math.cos( angle ) : hyp1 * Math.cos( angle );
    const dx = (angle < 0) ? -1 * hyp1 * Math.sin( angle ) : hyp1 * Math.sin( angle );
 
    const c1 = {
        x: xy1.x - dx, 
      y: xy1.y + dy
    };
    const c2 = {
        x:xy2.x - dx, 
      y: xy2.y + dy
    };
    
    ctx.save();  
    ctx.lineWidth = 1;
    ctx.strokeStyle = 'black';
    ctx.beginPath();
    ctx.moveTo(c1.x, c1.y);
    ctx.lineTo(c2.x, c2.y);
    ctx.stroke();
    ctx.restore();
  }
}



drawGradientLine( 20, 'red', 'green', {x:50, y: 150}, {x:150, y:150}, true);


drawGradientLine( 20, 'pink', 'orange', {x:10, y: 10}, {x:50, y:50}, true);

drawGradientLine( 20, 'pink', 'orange', {x:200, y: 100}, {x:250, y:20}, true);


drawGradientLine( 10, 'blue', 'green', {x: 50, y: 350}, {x:150, y:450}, false);


drawGradientLine( 40, 'pink', 'aquamarine', {x: 100, y: 200}, {x: 150, y:350}, false);
<canvas id=canvas1 width=300 height=600></canvas>

只需在 canvas 周围移动并画线即可。我在这里画了三条线,其中两条是渐变的,一条是黑色的。

线条的替代方法可以是 CanvasRenderingContext2D.fillRect(),您可以在其中定义 x、y、宽度和高度。这样就更容易计算出线条的位置。

var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');


let gradient1 = ctx.createLinearGradient(0, 0, 280, 0);
gradient1.addColorStop(0, 'green');
gradient1.addColorStop(1, 'blue');
ctx.strokeStyle = gradient1;
ctx.lineWidth = 10;

ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(290, 10);
ctx.stroke();

let gradient2 = ctx.createLinearGradient(0, 0, 280, 0);
gradient2.addColorStop(0, 'red');
gradient2.addColorStop(1, 'green');
ctx.strokeStyle = gradient2;
ctx.lineWidth = 10;

ctx.beginPath();
ctx.moveTo(10, 20);
ctx.lineTo(290, 20);
ctx.stroke();

ctx.strokeStyle = 'black';
ctx.lineWidth = 1;

ctx.beginPath();
ctx.moveTo(10, 15);
ctx.lineTo(290, 15);
ctx.stroke();
<canvas width="300" height="200"></canvas>

这也是我自己的方法



function distance( a, b ) {
  return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) );
}

function drawRec(width, grad_1, grad_2, a, b, direction=1,underline  ){

var l = distance(a,b);

var ao = Math.pow(l,2)+Math.pow(width,2);
var v={x:b.x - a.x,y:b.y - a.y};
var normalized = {
x: (b.x - a.x )/l,
y: (b.y- a.y )/l
}

var uv = {
x: - normalized.y,
y: normalized.x
}


var c = {
x: b.x + (direction)* (width*uv.x),
y: b.y + (direction)* (width*uv.y),
}

var d = {
x: a.x + (direction)* (width*uv.x),
y: a.y + (direction)* (width*uv.y),
}
  var grad = ctx.createLinearGradient(a.x, a.y, b.x, b.y);
  grad.addColorStop(0, grad_1);
  grad.addColorStop(1, grad_2);


// First path
let region = new Path2D();
region.moveTo(a.x, a.y);
region.lineTo(b.x, b.y);
region.lineTo(c.x, c.y);
region.lineTo(d.x, d.y);
region.closePath();

ctx.fillStyle = grad;
ctx.fill(region, 'evenodd');
ctx.lineWidth = 2;
ctx.strokeStyle = 'orange';
ctx.stroke(region);

if(underline){

ctx.lineWidth = 3;

// linear gradient from start to end of line

ctx.strokeStyle = 'white';

ctx.beginPath();
ctx.moveTo(a.x,a.y);
ctx.lineTo(b.x,b.y);


ctx.stroke();
}
}



var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');

drawRec(30,'green','blue',{x:50, y: 150},{x:150, y:20},1,true);
drawRec(30,'green','red',{x:50, y: 150},{x:150, y:20},-1);

查看实际效果 https://jsfiddle.net/am2222/6zgh2ub0/41/