首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在画布中使用剪辑导致像素

在画布中使用剪辑导致像素
EN

Stack Overflow用户
提问于 2016-06-30 11:22:48
回答 3查看 200关注 0票数 2

我试图使用context.clip()从其他弧中剪辑一个绘制弧,并填充剪裁的结果。但是当我剪辑并填充它时,它会给出像素化的填充。

代码语言:javascript
复制
  var ctx = document.getElementById("canvas").getContext("2d");
  var x = 150 ; 
  var y = 150 ;
  var r = 100 ;

    ctx.save() ;
    ctx.translate(x,y) ;

    ctx.beginPath() ;
    ctx.arc(0,0,r,0,2*Math.PI);
    ctx.closePath() ;
    ctx.fillStyle = "cyan" ;
    ctx.fill() ;
    ctx.lineWidth = 10;
    ctx.stroke();
    ctx.restore() ;

    ctx.save() ;
    ctx.clip() ;
    ctx.translate(x,y);

    ctx.beginPath();
    ctx.moveTo(r,-r-10);
    ctx.arc(0,-r-10,r,0,Math.PI*2);
    ctx.closePath();
    ctx.fillStyle = "#f2f2f2";
    ctx.fill();
    ctx.lineWidth = 1;
    ctx.stroke();
    ctx.restore();

https://jsfiddle.net/x0d0n40z/1/

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-06-30 14:29:34

另一种消除对clip()/save()/restore()的需求的方法是使用几个合成步骤。

剪辑掩码在一些浏览器中是反别名的,而在另一些浏览器中则不是。为了获得一致性(在某些情况下也是性能,因为保存剪辑恢复是相对昂贵的操作),最好使用组合(如果可能)。

在这种情况下:

  • 填充目标颜色的主弧
  • 定义裁剪弧
  • 将复合模式更改为destination-out并填充(将剪切主)
  • 将复合模式更改为source-atop和笔画(将大纲剪裁)
  • 将复合模式转换为source-over和主圆笔画轮廓

示例

Update:简化步骤(最后一步合并到流程中,参考)。(评论)。我还选择了演示Path2D的使用,因为我们可以重用对象而不干扰普通上下文上的路径-

代码语言:javascript
复制
var ctx = c.getContext("2d"),
    p = new Path2D(),          // this will store main shape for reuse
    x = 75, y = 75, radius = 70;

// main arc
p.arc(x, y, radius, 0, 6.28);  // store to path object
ctx.fillStyle = "cyan";
ctx.fill(p);                   // fill path object

// clip top arc
ctx.globalCompositeOperation = "source-atop";
ctx.arc(x, y - radius, radius, 0, 6.28);
ctx.fillStyle = "#09f";
ctx.fill();
ctx.lineWidth = 5;
ctx.stroke();

// stroke main arc
ctx.globalCompositeOperation = "source-over";
ctx.stroke(p);                 // stroke path object
代码语言:javascript
复制
body {background:#e9e9e9}
代码语言:javascript
复制
<canvas id=c></canvas>

旧版本:

代码语言:javascript
复制
var ctx = c.getContext("2d"),
    x = 75, y = 75, radius = 70;

// main arc
ctx.arc(x, y, radius, 0, 6.28);
ctx.fillStyle = "cyan";
ctx.fill();

// clipping arc
ctx.beginPath();
ctx.arc(x, y - radius, radius, 0, 6.28);

// cut step
ctx.globalCompositeOperation = "destination-out";
ctx.fill();

// stroke gap step
ctx.globalCompositeOperation = "source-atop";
ctx.lineWidth = 10;
ctx.stroke();

// stroke whole outline
ctx.globalCompositeOperation = "source-over";
ctx.beginPath();
ctx.arc(x, y, radius, 0, 6.28);
ctx.lineWidth = 5;
ctx.stroke();

// if you want to color the clip then use this:
ctx.globalCompositeOperation = "destination-atop";
ctx.fillStyle = "#09f";
ctx.fill();
代码语言:javascript
复制
body {background:#e9e9e9}
代码语言:javascript
复制
<canvas id=c></canvas>

票数 2
EN

Stack Overflow用户

发布于 2016-06-30 12:59:13

问题是,剪辑边界没有被反制。

要解决这个问题,您可以不使用剪辑来呈现形状。ctx.arc方法允许您设置起始角和结束角,这样您就可以通过填充两个弧来获得嵌入。

你需要得到夹子圆和内嵌圆截取的角度。

在这种情况下,情况非常简单。首先得到圆圈之间的距离,以及从一个到另一个的角度。这只适用于两个半径相同的圆。

代码语言:javascript
复制
var c = {x:?,y:?}; // circle one location
var c1 = {x:?,y:?}; // circle two location
var radius = ?; // radius of both
var angle = Math.atan2(c1.y - c.y, c1.x - c.x);  // get the angle from one to the next
var dist = Math.hypot(c1.x - c.x, c1.y - c.y); // get the distance. NOTE IE does not have hypot so do it the normal way with Math.sqrt....

现在有角度和距离,拦截是距离和半径之间的一个简单的关系。

代码语言:javascript
复制
var iAngle = Math.acos(dist / 2 / radius); // the angle from the line between the circles
                                          // to the intercepts

现在你有了这个角度,你可以画出两个弧线

代码语言:javascript
复制
ctx.beginPath();
ctx.arc(c.x,c.y,radius,angle - iAngle , angle + iAngle); // first arc
ctx.arc(c1.x,c1.y, radius, angle + Math.PI - iAngle, angle + Math.PI + iAngle); // second arc
ctx.fill();
ctx.stroke();

没有什么你可以做的,以防止锯齿影响剪辑区。另一种实现剪辑的方法是使用ctx.globalCompositeOperation来呈现掩码。你可以屏蔽进出,还有更多的选择。当裁剪区域变得更加复杂时,这将是一个更好的解决方案。

票数 0
EN

Stack Overflow用户

发布于 2016-06-30 13:10:26

我终于想出了纠正错误的正确方法。这是我想要的https://jsfiddle.net/x0d0n40z/6/的干净的结果

代码:

代码语言:javascript
复制
var ctx = document.getElementById("canvas").getContext("2d");
var r = 50    
x = ctx.canvas.width/2;
y = ctx.canvas.height/2;
var offset = 60;

ctx.save();
ctx.setTransform(1,0,0,1.5,x,y);
ctx.beginPath();
ctx.arc(0,0,r,0,2*Math.PI);
ctx.stroke();
ctx.clip();


ctx.beginPath();
ctx.arc(0,0,r,0,2*Math.PI,false);
ctx.fillStyle = "cyan";
ctx.fill();

ctx.setTransform(1, 0, 0, 1, x, y);
ctx.beginPath();
ctx.arc(0,-offset,r,0,2*Math.PI,false);
ctx.fillStyle = "#f2f2f2";
ctx.fill();
ctx.lineWidth = 1 ;
ctx.stroke();

ctx.setTransform(1,0,0,1.5,x,y);
ctx.beginPath();
ctx.arc(0,0,r,0,2*Math.PI,false);
ctx.lineWidth = 3 ;
ctx.stroke();

ctx.restore();

资料来源:我学会使用剪辑:http://www.html5canvastutorials.com/advanced/html5-canvas-clipping-region-tutorial/

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38121679

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档