我想编写一个可以在画布上绘制各种图案的小库。我遇到一个问题,当我画两个彼此相邻的三角形时,它们不会相互粘连并留下一点间隙。
你可以在那里看到https://jsfiddle.net/dufia/8ggwn9mq/1/
function drawEquilateralTriangleB(ctx, startingPoint, size, color, opacity, row, column) {
var h = size * Math.cos(Math.PI/6);
ctx.beginPath();
ctx.moveTo(startingPoint.x - (size / 2) + 0.5, startingPoint.y + 0.5);
ctx.lineTo(startingPoint.x - (size / 2) + (size / 2) + 0.5, startingPoint.y + h + 0.5);
ctx.lineTo(startingPoint.x + (size / 2) + 0.5, startingPoint.y + 0.5);
ctx.lineTo(startingPoint.x + (size / 2) + 0.5, startingPoint.y + 0.5);
ctx.fillStyle = color;
ctx.globalAlpha = opacity;
ctx.fill();
};
在三角形之间,您可以看到白线,实际上是背景,问题不会影响正方形。
我尝试使用0.5坐标并且用笔画搞砸了。当不透明度为100%时,笔划可以完成工作,但是当图案透明时,看起来全部搞砸了。
有没有可靠的解决方案?
答案 0 :(得分:4)
这是最烦人的。在SVG中也是如此。在花费了大量精力使所有内容排好后,它可以破坏图像。
甚至没有将像素四舍五入到像素边界,或者帮助中心。我发现最终有助于在填充中添加0.5像素笔划并将协调偏移0.5像素。数学没有意义,但结果才是最重要的。
贝娄是我用过的问题和解决方案的一个例子。将鼠标移到图像上以查看缩放视图并查看各种工件。
仍存在一个问题,即连接像素变暗。这是由于(所有)浏览器使用不正确的颜色模型来混合颜色。他们使用
平均一个频道colorCh = (colorC1 + colorC2) / 2; // incorrect
颜色通道值表示显示设备输出的平方根。使用的公式会使所有混合变暗。 (我真的希望他们能解决这个问题)。您可以在示例中看到它。底部两个有相邻的像素太暗。
正确的混合
colorCh = sqrt( (pow(colorC1, 2 ) + pow(colorC2, 2)) / 2); // correct
并且会解决最后一点(大问题)问题。
// get a canvas
var canvas = document.getElementById("canV");
var ctx = canvas.getContext("2d");
// mouse stuff
var mouse = {x:0,y:0} // mouse pos on canvas
function mouseMove(event){ // mouse event listener
mouse.x = event.offsetX; mouse.y = event.offsetY;
if(mouse.x === undefined){ mouse.x = event.clientX; mouse.y = event.clientY;}
}
// add the mouse listener
canvas.addEventListener('mousemove',mouseMove);
// clear the background with white
ctx.fillStyle = "white";
ctx.fillRect(0,0,canvas.width/2,canvas.height);
// thing to draw
// 4 tri polys with four colours
var points = [-50,-50,50,-50,50,50,-50,50,0,0]
var polys = [[0,1,4],[1,2,4],[2,3,4],[3,0,4]];
var cols = ["red","green","blue","purple"];
// draws the polys normaly at the location x,y
function drawPolysAt(x,y){
for(var i = 0; i < polys.length; i++){
var p = polys[i];
ctx.fillStyle = cols[i];
ctx.beginPath();
ctx.moveTo(points[p[0]*2]+x,points[p[0]*2+1]+y)
for(var j = 1; j< p.length; j++){
ctx.lineTo(points[p[j]*2]+x,points[p[j]*2+1]+y);
}
ctx.fill();
}
}
// draws the polys with outlining stroke 0.5 pixels
// wide.
function drawPolysAtFix(x,y){
ctx.lineWith = 0.5;
for(var i = 0; i < polys.length; i++){
var p = polys[i];
ctx.fillStyle = cols[i];
ctx.strokeStyle = cols[i];
ctx.beginPath();
ctx.moveTo(points[p[0]*2]+x,points[p[0]*2+1]+y)
for(var j = 1; j< p.length; j++){
ctx.lineTo(points[p[j]*2]+x,points[p[j]*2+1]+y);
}
ctx.stroke();
ctx.fill();
}
}
// draws the help text
ctx.font = "12px verdana";
function text(text,x,y,col){
ctx.textAlign = "center";
ctx.textBaseline = "top";
ctx.fillStyle = col;
ctx.fillText(text,x,y);
}
// draw the first example
var posX = 60;
var posY = 60;
drawPolysAt(posX,posY);
text("Drawn on pixel",posX,posY+52,"black");
text("boundaries.",posX,posY+52+14,"black");
// draw the second example offest by 0.5 pixels
posX += 120;
drawPolysAt(posX+0.5,posY+0.5);
text("Drawn offset by",posX,posY+52,"black");
text("0.5 pixels",posX,posY +52+14,"black");
posX -= 60;
text("Makes no differance",posX,posY+55+12+16,"black");
text("Appart from one pixel bleed ",posX,posY+55+12*2+16,"black");
text("on right due to offset ",posX,posY+55+12*3+16,"black");
// draw the thrid example with the stroke but not offset
posX = 60;
posY = 240;
drawPolysAtFix(posX,posY);
text("With 0.5 pixel",posX,posY+52,"black");
text("stroke. But Bleeds!",posX,posY+52+14,"black");
// draw with stroke and 0.5 pixel offset
posX += 120
drawPolysAtFix(posX+0.5,posY+0.5);
text("With 0.5 Stroke",posX,posY+52,"black");
text("and offset 0.5 pixels",posX,posY +52+14,"black");
posX -= 60;
text("Right side is best solution ",posX,posY+55+14+16,"black");
function update(){
// to keep the zoom crisp
ctx.imageSmoothingEnabled = false;
// zoom around mouse on right side
ctx.drawImage(canvas,mouse.x-20,mouse.y-20,40,40,canvas.width/2,0,canvas.width/2,canvas.height)
requestAnimationFrame(update)
}
update();
.canC { width:500px; height:400px;}
.info {
font-size:x-small;
}
<div class="info"> Top left drawn normaly at pixel boundaries, with white pixels showing through joins.<br>
Top right drawn normaly at pixel centers (offset 0.5,0.5 pixels) bleeds into sourounding pixels.<br>
Bottom left drawn with 0.5 pixel stroke at pixel boundaries. Creates a blured (bleeding) edge<br>
Bottom right. Drawn with 0.5 pixel stroke and offset by 0.5 pixels. Note that there is no bleeding around the outside and the joins are the best posible.
<canvas class="canC" id="canV" width=500 height=400></canvas>