μ΄λ² ν¬μ€ν
μμλ HTML Canvas
λ₯Ό μ¬μ©νμ¬ μ§λ μμ μ€μκ° μμΉμ λ°©ν₯μ νμνλ λ°©λ²μ λν΄ κ³΅μ νλ €κ³ ν©λλ€.
μλ₯Ό λ€μ΄, μ§λ μμ μ¬μ©μ λλ κ°μ²΄μ μμΉμ κ·Έ λ°©ν₯μ λνλΌ μ μλ λ°©λ²μ ꡬνν΄λ΄€μ΅λλ€.
μ΄ κ³Όμ μμ μ€μν μ μ μμΉ νμλΏλ§ μλλΌ λ°©ν₯ νμκΉμ§ μΆκ°νλ κ²μ΄μμ΅λλ€.
λ¨Όμ , μμΉλ₯Ό νμν λ λ€μ¨ ν¨κ³Όλ₯Ό μ£ΌκΈ° μν΄ μμ κ·Έλ Έμ΅λλ€.
μ΄ μμ μ€ λ 벨μ λ°λΌ ν¬κΈ°κ° μ‘°μ λλλ‘ μ€μ νμΌλ©°, μμ μμμ νλμμΌλ‘ μμνκ² λνλλλ‘ νμ΅λλ€.
μ΄λ₯Ό μν΄ createRadialGradient
λ₯Ό μ¬μ©νμ¬ μ μμμ μμμ΄ μ μ ν¬λͺ
ν΄μ§λλ‘ λ§λ€μ΄μ€¬μ΅λλ€.
const radius = zoom * 3; // μμ λ°μ§λ¦ (μ€ λ 벨μ λ°λΌ ν¬κΈ° μ‘°μ )
const gradient = ctx.createRadialGradient(point.x, point.y, 0, point.x, point.y, radius);
gradient.addColorStop(0, 'rgba(0, 0, 255, 0.5)'); // μμ μ€μ
gradient.addColorStop(1, 'rgba(0, 0, 255, 0)'); // μμ λ°κΉ₯μͺ½
ctx.beginPath();
ctx.arc(point.x, point.y, radius, 0, 2 * Math.PI);
ctx.fillStyle = gradient;
ctx.fill();
μ΄μ μ€μν λΆλΆμΈ λ°©ν₯ νμλ₯Ό μΆκ°νμ΅λλ€. λ°©ν₯μ μΈλͺ¨ λͺ¨μμ μμ΄μ½μ μ¬μ©νκΈ°λ νμ§λ§, λ μ§κ΄μ μΈ μ΄λ―Έμ§λ₯Ό μ¬μ©νκΈ° μν΄ μ΄λ―Έμ§λ‘ λ°©ν₯μ νμνλ λ°©λ²μ μ ννμ΅λλ€.
μ΄λ―Έμ§λ μ€μ¬μΌλ‘λΆν° offset
λ§νΌ λ¨μ΄μ§ μμΉμ λ°°μΉλ ν, μ¬μ©μμ λ°©ν₯μ λ°λΌ νμ ν©λλ€.
νμ λ λ°©ν₯μ μ λλ‘ λνλ΄κΈ° μν΄, direction
κ°μ λ§μΆ° μ΄λ―Έμ§λ₯Ό νμ μμΌ°μ΅λλ€. μ€μ¬μμλΆν° μΌμ 거리λ§νΌ λ¨μ΄μ§ μμΉμ μ΄λ―Έμ§λ₯Ό λκ³ , κ·Έ μ΄λ―Έμ§λ μ§λ μμμ μ€μ λ°©ν₯μ λ§κ² νμ νλλ‘ νμ΅λλ€.
const triangleSize = zoom * 2; // μ΄λ―Έμ§ ν¬κΈ° (μ€ λ 벨μ λ°λΌ ν¬κΈ° μ‘°μ )
const offset = zoom * 2; // μ΄λ―Έμ§κ° μ€μ¬μμ λ²μ΄λλλ‘ ν 거리
ctx.save();
ctx.translate(point.x, point.y); // μ€μ¬ μμΉλ‘ μ΄λ
ctx.rotate(direction); // λ°©ν₯μ λ§μΆ° νμ
const xOffset = 0; // 12μ λ°©ν₯ (xμΆ)
const yOffset = -offset; // 12μ λ°©ν₯μΌλ‘ μμͺ½μΌλ‘ μ΄λ
ctx.beginPath();
ctx.drawImage(
footStepsRef.current!, // μ΄λ―Έμ§ (λ‘컬 νμΌλ‘ λ‘λ©)
xOffset - triangleSize / 2, // μ΄λ―Έμ§ μμΉ
yOffset - triangleSize / 2,
triangleSize, // μ΄λ―Έμ§ ν¬κΈ°
triangleSize,
);
ctx.restore();
μ΄λ―Έμ§κ° μ νν 12μ λ°©ν₯μμ 0λ
λ‘ μμν μ μλλ‘ νμ 보μ λ μΆκ°νμ΅λλ€.
κΈ°λ³Έμ μΌλ‘, direction
κ°μ΄ 320λμμ μμνλλ‘ μ€μ νμκ³ , μ΄ κ°μ 보μ νμ¬ μ΄λ―Έμ§λ₯Ό μ νν 0λ λ°©ν₯μΌλ‘ νμ νλλ‘ νμ΅λλ€.
μ΄λ κ² νλ©΄ μ΄λ―Έμ§κ° 12μ λ°©ν₯μμ μμνλ©°, μ΄ν νμ ν λ μμ°μ€λ½κ² μμ§μ λλ€.
const correctedDirection = (direction - 320 + 360) % 360; // λ°©ν₯ 보μ
const radian = (correctedDirection * Math.PI) / 180; // λΌλμ κ°μΌλ‘ λ³ν
ctx.rotate(radian); // 보μ λ λ°©ν₯μΌλ‘ νμ
μ λ΄μ©μ μ’ ν©ν μ΅μ’ μ½λλ λ€μκ³Ό κ°μ΅λλ€.
μ΄ μ½λλ₯Ό ν΅ν΄ μ§λ μμ μ€μκ°μΌλ‘ μμΉμ νμ νλ λ°©ν₯μ ν¨κ» νμν μ μμμ΅λλ€.
const drawNeonCircleAndDirection = (
ctx: CanvasRenderingContext2D,
point: { x: number; y: number } | null,
zoom: number,
direction: number,
) => {
if (!point) return;
// μ 그리기 (λ€μ¨ ν¨κ³Ό)
const radius = zoom * 3;
const gradient = ctx.createRadialGradient(point.x, point.y, 0, point.x, point.y, radius);
gradient.addColorStop(0, 'rgba(0, 0, 255, 0.5)');
gradient.addColorStop(1, 'rgba(0, 0, 255, 0)');
ctx.beginPath();
ctx.arc(point.x, point.y, radius, 0, 2 * Math.PI);
ctx.fillStyle = gradient;
ctx.fill();
// λ°©ν₯ νμ
const triangleSize = zoom * 2;
const offset = zoom * 2;
ctx.save();
ctx.translate(point.x, point.y);
// λ°©ν₯ 보μ (320λλ₯Ό κΈ°μ€μΌλ‘ 0λλ‘ λ³΄μ )
const correctedDirection = (direction - 320 + 360) % 360;
const radian = (correctedDirection * Math.PI) / 180;
ctx.rotate(radian);
const xOffset = 0;
const yOffset = -offset;
ctx.beginPath();
ctx.drawImage(
footStepsRef.current!,
xOffset - triangleSize / 2,
yOffset - triangleSize / 2,
triangleSize,
triangleSize,
);
ctx.restore();
};
μ΄ λ°©λ²μ ν΅ν΄ μ€μκ°μΌλ‘ μ§λ μμ μμΉμ λ°©ν₯μ νμνλ κΈ°λ₯μ ꡬνν μ μμμ΅λλ€.
HTML Canvas
μ μ΄λ―Έμ§ νμ , λ€μ¨ ν¨κ³Ό λ±μ νμ©νμ¬ λ μ§κ΄μ μ΄κ³ μκ°μ μΈ νμκ° κ°λ₯ν΄μ‘μ΅λλ€.
canvasμ λν΄ λ§μ μμ μ ν΄λ³Έ μ μ΄ μμλλ°, μ΄λ κ² μμκ² μμ±λλ κ²μ 보λβ¦β¦ λ무 μμλλΌκ³ μβ¦.
νμ€ν μ λ νμ κ°λ°μμΈκ° λ΄ λλ€β¦β¦β¦β¦β¦β¦