用图像代替文本填充画布(幸运轮)



我想用图片代替文字来显示价格。

我使用ctx.fillText(sector.label, rad - 50, 10);填充所有价格与他们的文本标签,但我想用图像代替文本!

然而,当我做ctax.drawImage(sector.image, rad - 50, 10)时,所有的图像都被渲染在同一个位置。

视图JSFiddle

我试着添加一个loadImage函数,像这样:

const loadImage = (ctx, sector, ang) => {
const img = new Image();
img.onload = function () {
ctx.drawImage(img, rad - 50, 10); // Or at whatever offset you like
};
img.src = sector.image;
};

,但它适用于同一位置的所有图像。

为什么ctx.fillText()正确定位文本,但图像不是?

我看到如何在幸运轮上画图像?,但我想使用画布,而不是css。

问题是你的图像是异步加载的。这意味着当它们被放置在画布上时,转换已经改变了。它们都将在最后一片中结束。

一种可能的解决方案是将当前的位移和旋转传递给绘图函数。然后,您可以重新应用图像所需的转换,而不依赖于加载顺序。

下面是一个示例实现:

const sectors = [
{color:"#b0f", label:"100",  image:"https://i.pinimg.com/originals/0f/74/64/0f7464a556edc8b48d43a8bb604dbc33.png"},
{color:"#f0b", label:"5",  image:"https://i.pinimg.com/originals/2a/19/13/2a1913368715b9a2dc1ac75e0f1fd67c.png"},
{color:"#bf0", label:"500",  image:"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTwhD7Fr24H5ogfjKHDukeqFd4BN2H2f8KPPP3WEa3LQRw_HhLWHSHw_Nr7CSWkME6XQXY&usqp=CAU"},
];
// Generate random float in range min-max:
const rand = (m, M) => Math.random() * (M - m) + m;
const tot = sectors.length;
const elSpin = document.querySelector("#spin");
const ctx = document.querySelector("#wheel").getContext`2d`;
ctx.canvas.width = 600;
ctx.canvas.height = 600;

const dia = ctx.canvas.width;

const rad = dia / 2;
const PI = Math.PI;
const TAU = 2 * PI;
const arc = TAU / sectors.length;
const friction = 0.991;  // 0.995=soft, 0.99=mid, 0.98=hard
const angVelMin = 0.002; // Below that number will be treated as a stop
let angVelMax = 0; // Random ang.vel. to acceletare to 
let angVel = 0;    // Current angular velocity
let ang = 0;       // Angle rotation in radians
let isSpinning = false;
let isAccelerating = false;
//* Get index of current sector */
const getIndex = () => Math.floor(tot - ang / TAU * tot) % tot;
const loadImage = (ctx, sector, rad, rot) => {
const img = new Image();
img.onload = function () {
ctx.save();
ctx.resetTransform();
ctx.translate(rad, rad);
ctx.rotate(rot);
ctx.drawImage(img, 150, -25, 50, 50); // Or at whatever offset you like
ctx.restore();
};
img.src = sector.image;
};

//* Draw sectors and prizes texts to canvas */
const drawSector = (sector, i) => {
const ang = arc * i;
// COLOR
ctx.beginPath();
ctx.fillStyle = sector.color;
ctx.moveTo(rad, rad);
ctx.arc(rad, rad, rad, ang, ang + arc);
ctx.lineTo(rad, rad);
ctx.fill();

// TEXT
const rot = ang + arc / 2;
ctx.save();
ctx.translate(rad, rad);
ctx.rotate(rot);
ctx.textAlign = "right";
ctx.fillStyle = "#fff";
ctx.font = "bold 30px sans-serif";
ctx.fillText(sector.label, rad - 10, 10);

// IMG
loadImage(ctx, sector, rad, rot);
ctx.restore();
};
//* CSS rotate CANVAS Element */
const rotate = () => {
const sector = sectors[getIndex()];
ctx.canvas.style.transform = `rotate(${ang - PI / 2}rad)`;
elSpin.textContent = !angVel ? "SPIN" : sector.label;
elSpin.style.background = sector.color;
};
const frame = () => {
if (!isSpinning) return;
if (angVel >= angVelMax) isAccelerating = false;
// Accelerate
if (isAccelerating) {
angVel ||= angVelMin; // Initial velocity kick
angVel *= 1.06; // Accelerate
}

// Decelerate
else {
isAccelerating = false;
angVel *= friction; // Decelerate by friction  
// SPIN END:
if (angVel < angVelMin) {
isSpinning = false;
angVel = 0; 
}
}
ang += angVel; // Update angle
ang %= TAU;    // Normalize angle
rotate();      // CSS rotate!
};
const engine = () => {
frame();
requestAnimationFrame(engine)
};
elSpin.addEventListener("click", () => {
if (isSpinning) return;
isSpinning = true;
isAccelerating = true;
angVelMax = rand(0.25, 0.40);
});
// INIT!
sectors.forEach(drawSector);
rotate(); // Initial rotation
engine(); // Start engine!
#wheelOfFortune {
display: inline-flex;
position: relative;
/* height: 720px;
width: 720px; */
overflow: hidden;
}
#wheel {
display: block;
}
#spin {
font: 1.5rem/0 sans-serif;
user-select: none;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
top: 50%;
left: 50%;
width: 30%;
height: 30%;
margin: -15%;
background: #fff;
color: #fff;
box-shadow: 0 0 0 8px currentColor, 0 0px 15px 5px rgba(0, 0, 0, 0.6);
border-radius: 50%;
transition: 0.8s;
}
#spin::after {
content: '';
position: absolute;
top: -17px;
border: 10px solid transparent;
border-bottom-color: currentColor;
border-top: none;
}
<div id="wheelOfFortune">
<canvas id="wheel" width="300" height="300"></canvas>
<div id="spin">SPIN asd asd asd as dasd as dasd asd asd as d</div>
</div>

最新更新