![](/img/trans.png)
[英]how to make a fast NOT anti-aliasing HTML5canvas basic drawing function?
[英]Fastest way to draw and fill a NOT anti-aliasing circle in HTML5Canvas
我需要为HTML5Canvas中的基本绘图应用程序绘制并填充一个非抗锯齿的圆,因为填充桶工具算法无法很好地填充抗锯齿形状的边框。
我采用了此页面的JavaScript算法https://en.wikipedia.org/wiki/Midpoint_circle_algorithm并实现了它来绘制实心圆,但是它很慢。
canvas = document.getElementById("canvas");
const CHANNELS_PER_PIXEL = 4; //rgba
function drawCircle (x0, y0, radius, canvas) {
var x = radius-1;
var y = 0;
var dx = 1;
var dy = 1;
var decisionOver2 = dx - (radius << 1); // Decision criterion divided by 2 evaluated at x=r, y=0
var imageWidth = canvas.width;
var imageHeight = canvas.height;
var context = canvas.getContext('2d');
var imageData = context.getImageData(0, 0, imageWidth, imageHeight);
var pixelData = imageData.data;
var makePixelIndexer = function (width) {
return function (i, j) {
var index = CHANNELS_PER_PIXEL * (j * width + i);
//index points to the Red channel of pixel
//at column i and row j calculated from top left
return index;
};
};
var pixelIndexer = makePixelIndexer(imageWidth);
var drawPixel = function (x, y) {
var idx = pixelIndexer(x,y);
pixelData[idx] = 152; //red
pixelData[idx + 1] = 152; //green
pixelData[idx + 2] = 152;//blue
pixelData[idx + 3] = 255;//alpha
};
while (x >= y) {
if(x0 + x>=0){drawPixel(x0 + x, y0 + y);}
if(x0 + y>=0){drawPixel(x0 + y, y0 + x);}
if(x0 - x>=0){drawPixel(x0 - x, y0 + y);}
if(x0 - y>=0){drawPixel(x0 - y, y0 + x);}
if(x0 - x>=0){drawPixel(x0 - x, y0 - y);}
if(x0 - y>=0){drawPixel(x0 - y, y0 - x);}
if(x0 + x>=0){drawPixel(x0 + x, y0 - y);}
if(x0 + y>=0){drawPixel(x0 + y, y0 - x);}
//fill circle code
var x1=x0-x;
var x2=x0+x;
var xx=x2-x1;
for(i=x2-x1;i>0; i--){
if((x1+(xx-i))>=0){
drawPixel(x1+(xx-i),y0+y);
}
}
var x1=x0-y;
var x2=x0+y;
var xx=x2-x1;
for(i=x2-x1;i>0; i--){
if((x1+(xx-i))>=0){
drawPixel(x1+(xx-i),y0+x);
}
}
var x1=x0-x;
var x2=x0+x;
var xx=x2-x1;
for(i=x2-x1;i>0; i--){
if((x1+(xx-i))>=0){
drawPixel(x1+(xx-i),y0-y);
}
}
var x1=x0-y;
var x2=x0+y;
var xx=x2-x1;
for(i=x2-x1;i>0; i--){
if((x1+(xx-i))>=0){
drawPixel(x1+(xx-i),y0-x);
}
}
//fill end
if (decisionOver2 <= 0)
{
y++;
decisionOver2 += dy; // Change in decision criterion for y -> y+1
dy += 2;
}
if (decisionOver2 > 0)
{
x--;
dx += 2;
decisionOver2 += (-radius << 1) + dx; // Change for y -> y+1, x -> x-1
}
}
context.putImageData(imageData, 0, 0);
}
也,
context.translate(0.5, 0.5);
和
context.imageSmoothingEnabled = !1;
不要工作一圈。
您是否拥有更好的功能,或者您知道如何压缩和连接此圆形算法?
谢谢
我制作了Breseham圆圈算法的此修改版本,以便为“复古”项目回填“混淆”圆圈。
修改是从8个切片中获取值并将其转换为4行。 我们可以使用rect()
创建一条线,但必须将绝对(x2,y2)坐标转换为宽度和高度。
该方法只需将rect
添加到相当快的路径中,您就不必通过慢速的getImageData()
/ putImageData()
(并且不会受到CORS问题的影响)。 最后,将调用一个填充操作。 这意味着您也可以直接在画布上使用它,而不必担心大多数情况下的现有内容。
重要的是,平移值和给定值是整数值,并且半径> 0。
要强制整数值,只需将值移动0:
xc = xc|0; // you can add these to the function below
yc = yc|0;
r = r|0;
(如果要制作轮廓(“描边的”)版本,则必须使用所有8个切片的位置,并将rect()
宽度更改为1。)
var ctx = c.getContext("2d"); ctx.fillStyle = "#09f"; aliasedCircle(ctx, 200, 200, 180); ctx.fill(); function aliasedCircle(ctx, xc, yc, r) { // NOTE: for fill only! var x = r, y = 0, cd = 0; // middle line ctx.rect(xc - x, yc, r<<1, 1); while (x > y) { cd -= (--x) - (++y); if (cd < 0) cd += x++; ctx.rect(xc - y, yc - x, y<<1, 1); // upper 1/4 ctx.rect(xc - x, yc - y, x<<1, 1); // upper 2/4 ctx.rect(xc - x, yc + y, x<<1, 1); // lower 3/4 ctx.rect(xc - y, yc + x, y<<1, 1); // lower 4/4 } }
<canvas id=c width=400 height=400></canvas>
放大演示:
var ctx = c.getContext("2d"); ctx.scale(4,4); ctx.fillStyle = "#09f"; aliasedCircle(ctx, 50, 50, 45); ctx.fill(); ctx.font = "6px sans-serif"; ctx.fillText("4x", 2, 8); function aliasedCircle(ctx, xc, yc, r) { var x = r, y = 0, cd = 0; // middle line ctx.rect(xc - x, yc, r<<1, 1); while (x > y) { cd -= (--x) - (++y); if (cd < 0) cd += x++; ctx.rect(xc - y, yc - x, y<<1, 1); // upper 1/4 ctx.rect(xc - x, yc - y, x<<1, 1); // upper 2/4 ctx.rect(xc - x, yc + y, x<<1, 1); // lower 3/4 ctx.rect(xc - y, yc + x, y<<1, 1); // lower 4/4 } }
<canvas id=c width=400 height=400></canvas>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.