【问题标题】:HTML5 Canvas thick lineWidth ellipse has strange blankHTML5 Canvas 粗线宽椭圆有奇怪的空白
【发布时间】:2015-12-31 07:49:40
【问题描述】:

我正在使用 html5 画布制作绘图应用程序。 用户可以绘制椭圆并选择线条颜色和填充颜色。 (包括透明色)
当所选颜色不透明时,它可以正常工作。 But when transparent color is selected and border line width is thick, there are problems.(Q1 and Q2)

这是图片
http://tinypic.com/view.php?pic=28ry4z&s=9#.VoRs7U8jHSg

我正在使用下面的 drawEllipse() 方法。
the relation of the bezier Curve and ellipse?

有人解决这个问题吗? 任何帮助将不胜感激。

[Q1] 当lineWidth大于椭圆的宽度时,椭圆中出现奇怪的空白,lineWidth奇怪的细。 Internet Explorer 工作正常,但 Firefox 和 Safari 网络浏览器都有这个问题。 如何将空白区域更改为蓝色?

[Q2] 我正在使用透明颜色,我想用 2 种颜色绘制椭圆。
(描边为蓝色,填充为红色) 但是描边颜色和填充颜色混合在一起,椭圆中有洋红色区域。 如何用 2 种颜色绘制椭圆?
(我想将洋红色区域更改为蓝色)
如果可能,首选一次性填充。

这是我的代码

// this method is from
// https://stackoverflow.com/questions/14169234/the-relation-of-the-bezier-curve-and-ellipse
function _drawEllipse(ctx, x, y, w, h) {
  var width_over_2 = w / 2;
  var width_two_thirds = w * 2 / 3;
  var height_over_2 = h / 2;

  ctx.beginPath();
  ctx.moveTo(x, y - height_over_2);
  ctx.bezierCurveTo(x + width_two_thirds, y - height_over_2, x + width_two_thirds, y + height_over_2, x, y + height_over_2);
  ctx.bezierCurveTo(x - width_two_thirds, y + height_over_2, x - width_two_thirds, y - height_over_2, x, y - height_over_2);
  ctx.closePath();
  ctx.stroke();
}

function ellipse_test() {
  var canvas = document.getElementById('sample1');
  var ctx = canvas.getContext('2d');

  var x = 100;
  var y = 100;
  var w = 40;
  var h = 100;
  ctx.lineWidth = 30;
  ctx.fillStyle = "rgba(255,0,0,0.5)";
  ctx.strokeStyle = "rgba(0,0,255,0.5)";
  ctx.globalCompositeOperation = "source-over";

  for (var r = 0; r < 50; r++) {
    _drawEllipse(ctx, x, y, r, r * 2);
    ctx.fill();
    x += 60;

    if (x > 1000) {
      x = 100;
      y += 200;
    }
  }
}

ellipse_test();
&lt;canvas id="sample1" style="border:1px solid blue; background:black;" width="1200" height="800"&gt;&lt;/canvas&gt;

this is the image on firefox

【问题讨论】:

  • 对于 Q1:绘制一个半径为 2 且线宽为 30 的椭圆甚至会引起人类的疑问,因此结果很奇怪。 ==> 确保您要求一个有意义的绘图。我会用 r / r+30 的 2 个填充椭圆画出你的“眼睛”。对于 Q2:你正在使用不透明度,所以难怪颜色是混合的。使用剪裁,或在单独的画布上不透明地绘制,然后在主画布上使用不透明度来避免这种情况。
  • 如果覆盖 2 种不同的半透明填充,则始终会产生第 3 次填充。如果您不想让用户混合颜色,为什么要允许半透明填充?
  • @markE。感谢您的评论。我的问题如下。这是当前流程 1. 绘制(openPath 到 beginPath) 2. 描边 3. 填充 如果一次性绘制,一次描边和一次填充,有没有办法避免颜色与 globalCompositeOperation 混合? (或者这样做的唯一方法是剪辑?)
  • 显然我不明白你的问题。如果您将半透明颜色转换为不透明颜色(正如我的回答那样),您将不会得到不需要的第 3 和第 4“混合”颜色。请澄清你的问题。 :-)
  • @markE。感谢您的评论。我在firefox上上传了图片。你在浏览器上看到过这样的吗?关于Q1,不填,椭圆小时有洞。 Q2:我想用 globalCompositeOperation 解决这个问题,而不是额外的绘制(剪辑等)

标签: javascript html html5-canvas


【解决方案1】:

这两个问题都是由于在一个区域上多次描边/填充半透明颜色会导致该区域变成混合颜色(很像艺术家混合多种颜色)。

您可以通过将半透明颜色转换为不透明颜色来解决这两个问题:

function RGBAtoRGB(r, g, b, a, backgroundR,backgroundG,backgroundB){
  var r3 = Math.round(((1 - a) * backgroundR) + (a * r))
  var g3 = Math.round(((1 - a) * backgroundG) + (a * g))
  var b3 = Math.round(((1 - a) * backgroundB) + (a * b))
  return "rgb("+r3+","+g3+","+b3+")";
} 

// convert 50%-red foreground fill + 100% black background into opaque (=="red-brownish")
ctx.fillStyle = RGBAtoRGB(255,0,0,0.50, 0,0,0,1); // "rgba(255,0,0,0.5)";

// convert 50%-blue foreground stroke + 100% black background into opaque (=="blueish")
ctx.strokeStyle = RGBAtoRGB(0,0,255,0.50, 0,0,0,1); // "rgba(0,0,255,0.5)";

示例代码重构为使用不透明填充和描边:

ellipse_test();

// this method is from
// http://stackoverflow.com/questions/14169234/the-relation-of-the-bezier-curve-and-ellipse
function _drawEllipse(ctx, x, y, w, h) {
  var width_over_2 = w / 2;
  var width_two_thirds = w * 2 / 3;
  var height_over_2 = h / 2;

  ctx.beginPath();
  ctx.moveTo(x, y - height_over_2);
  ctx.bezierCurveTo(x + width_two_thirds, y - height_over_2, x + width_two_thirds, y + height_over_2, x, y + height_over_2);
  ctx.bezierCurveTo(x - width_two_thirds, y + height_over_2, x - width_two_thirds, y - height_over_2, x, y - height_over_2);
  ctx.closePath();
}

function ellipse_test() {
  var canvas = document.getElementById('sample1');
  var ctx = canvas.getContext('2d');

  var x = 100;
  var y = 100;
  var w = 40;
  var h = 100;
  ctx.lineWidth = 30;

  ctx.fillStyle = 'black';
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  ctx.fillStyle = RGBAtoRGB(255, 0, 0, 0.50, 0, 0, 0, 1); // "rgba(255,0,0,0.5)";
  ctx.strokeStyle = RGBAtoRGB(0, 0, 255, 0.50, 0, 0, 0, 1); // "rgba(0,0,255,0.5)";


  ctx.globalCompositeOperation = "source-over";

  for (var r = 0; r < 50; r++) {
    _drawEllipse(ctx, x, y, r, r * 2);
    ctx.stroke();
    ctx.fill();
    x += 60;

    if (x > 1000) {
      x = 100;
      y += 200;
    }
  }
}


function RGBAtoRGB(r, g, b, a, backgroundR, backgroundG, backgroundB) {
  var r3 = Math.round(((1 - a) * backgroundR) + (a * r))
  var g3 = Math.round(((1 - a) * backgroundG) + (a * g))
  var b3 = Math.round(((1 - a) * backgroundB) + (a * b))
  return "rgb(" + r3 + "," + g3 + "," + b3 + ")";
}
body {
  background-color: ivory;
}
#canvas {
  border: 1px solid red;
  background-color=black;
}
&lt;canvas id="sample1" width=1200 height=800&gt;&lt;/canvas&gt;

重叠

...显然,如果您将椭圆非常靠近地绘制在一起,它们最终会重叠。这就是导致您的 Q1 线变薄的原因。

【讨论】:

  • 感谢您的回答。你的回答非常翔实。但是很抱歉我的信息不够。我正在制作一个绘图应用程序,它可以选择线条颜色和填充颜色。 (including transparent colors) When selected color is not transparent, it works fine. But when transparent color is selected, there are problems.(Q1 and Q2) And Internet Explorer doesn't have Q1's problem.但是 Firefox 和 Safari 都有 Q1 的问题。
猜你喜欢
  • 2013-04-23
  • 2011-03-12
  • 1970-01-01
  • 2015-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
相关资源
最近更新 更多