I'm making a menu for my Sudoku game to choose numbers for selected cells.
I managed to do a circular animated menu with X canvas elements each representing one number (+ one is empty). Then I rotate all these elements with CSS transform to create a perfect circle.
And here the problem appears - there are ugly transparent strokes between each element that I can't manage to remove.
This is how I draw it:
My app is a bit complicated but I managed to create a demo:
let parent = document.getElementsByClassName('menu')[0];
let elSize = parent.getBoundingClientRect().width;
let upscale = 2;
let total = 10;
let length = elSize / 2;
for (let i = 0; i < total; i++) {
// create new canvas
let val = document.createElement('canvas');
val.classList.add("value");
let deg = 360 / total;
//set sizes and rotation
val.height = length * upscale;
val.width = elSize * upscale;
val.style.width = elSize + "px";
val.style.height = length + "px";
val.style.setProperty("--rotation", (i / total * 360) + "deg");
// get context
let ctx = val.getContext("2d");
ctx.fillStyle = "blue";
ctx.imageSmoothingEnabled = true;
// full circle center
let center = {
x: length * upscale,
y: length * upscale
}
//function to fill the circle part (step 1 and 2 on the image)
const fillWedge = (cx, cy, radius, startAngle, endAngle, fillcolor, stroke = false) => {
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(cx, cy, radius, startAngle, endAngle);
ctx.closePath();
if (stroke) {
ctx.lineWidth = 1;
ctx.strokeStyle = fillcolor;
ctx.stroke();
} else {
ctx.fillStyle = fillcolor;
ctx.fill();
}
}
const degToAngle = (deg) => {
let start = -Math.PI / 2;
let fullCircle = Math.PI * 2;
return (start + fullCircle * (deg / 360));
}
ctx.save();
ctx.imageSmoothingEnabled = false;
ctx.globalCompositeOperation = "source-out"; {
//smaller circle
let cx = center.x;
let cy = center.y;
let radius = length * upscale / 3;
let startAngle = -((deg + 1) / 2) % 360;
let endAngle = ((deg + 1) / 2) % 360;
fillWedge(cx, cy, radius, degToAngle(startAngle), degToAngle(endAngle), ctx.fillStyle);
}
//make it semi-transparent
ctx.globalAlpha = 0.8; {
//bigger circle
let cx = center.x;
let cy = center.y;
let radius = length * upscale;
let startAngle = -(deg / 2) % 360;
let endAngle = (deg / 2) % 360;
fillWedge(cx, cy, radius, degToAngle(startAngle), degToAngle(endAngle), ctx.fillStyle);
}
ctx.restore();
//draw text
if (i !== 0) {
ctx.save();
ctx.translate(length * upscale, length / 3 * upscale);
ctx.rotate(-(i / total * 360) / 180 * Math.PI);
ctx.font = "600 " + (18 * upscale) + 'px Consolas';
ctx.textAlign = "center";
ctx.fillStyle = "white";
ctx.fillText((i) + "", 0, 5 * upscale);
ctx.restore()
}
//add element to menu
parent.appendChild(val);
}
html {
background: url(https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fcdn.cienradios.com%2Fwp-content%2Fuploads%2Fsites%2F13%2F2020%2F06%2FShrek-portada.jpg&f=1&nofb=1) no-repeat center;
display: flex;
justify-content: center;
align-content: center;
}
.menu {
width: 400px;
aspect-ratio: 1;
position: relative;
border-radius: 50%;
}
.menu .value {
--rotation: 0deg;
position: absolute;
top: 0;
bottom: 50%;
left: 50%;
transform-origin: bottom;
transform: translate(-50%, 0) rotate(var(--rotation));
}
p {
color: white;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sudoku Test</title>
</head>
<body>
<div class="menu">
</div>
<p>
See, it's semi-transparent and you can clearly see lines between elements
<br>
<b>How to fix it?!</b>
</p>
</body>
</html>
Any way to remove those spaces? I know it's a bit too much detailed question, but I really can't manage to fix it. Thanks.