Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

141
Vistas
How do I create a canvas circle with a image on it?

So, I followed a tutorial to make a game. Obviously, that isn't the best way to learn to code so I began to modify it. Currently the game has enemies that slowly move towards the player, but these enemies are colored circles and nothing else. I'd like to add a picture that I can put on the enemies, but I have no Idea how. Here's some code that you might like to know:

The enemy class (update is called every frame):

class Enemy {
    constructor(x, y, radius, color, velocity) {
        this.x = x;
        this.y = y;
        this.radius = radius;
        this.color = color;
        this.velocity = velocity;
    }

    draw() {
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
        ctx.fillStyle = this.color;
        ctx.fill();
    }

    update() {
        this.draw();
        this.x = this.x + this.velocity.x;
        this.y = this.y + this.velocity.y;
    }
}

The function for creating enemies:

function spawnEnemies() {
    setInterval(() => {
        const radius = Math.random() * (30 - 4) + 4;
        let x;
        let y;
        if (Math.random() < 0.5) {
            x = Math.random() < 0.5 ? 0 - radius : canvas.width + radius;
            y = Math.random() * canvas.height;
        } else {
            y = Math.random() < 0.5 ? 0 - radius : canvas.height + radius;
            x = Math.random() * canvas.width;
        }
        const color = `hsl(${Math.random() * 360}, 50%, 50%)`;
        const angle = Math.atan2(canvas.height / 2 - y, canvas.width / 2 - x);
    const velocity = {
        x: Math.cos(angle),
        y: Math.sin(angle)
    }
        enemies.push(new Enemy(x, y, radius, color, velocity));
    }, 1000)
}

This code is ran in the animate function:

enemies.forEach((enemy, index) => {
        enemy.update();
        const dist = Math.hypot(player.x - enemy.x, player.y - enemy.y);
        
        if (isHacking) {
            if (dist - enemy.radius - player.radius < 11) {
                setTimeout(() => {
                for (let i = 0; i < enemy.radius * 2; i++) {
                    particles.push(new Particle(enemy.x, enemy.y, Math.random() * 2, enemy.color, {
                        x: (Math.random() - 0.5) * (Math.random() * 8),
                        y: (Math.random() - 0.5) * (Math.random() * 8)}
                    ));
                }}, 0)
                score += 25;
                scoreEl.innerHTML = score;
                setTimeout(() => {
                    enemies.splice(index, 1);
                    projectiles.splice(proIndex, 1);
                }, 0)
            }         
        } else if (dist - enemy.radius - player.radius < 1) {
            cancelAnimationFrame(animationId);
            modal.style.display = 'flex';
            modalScore.innerHTML = score;
        }

Also, this is my first time posting on stack overflow, so if there's something I should've done that I didn't, or vice versa, please let me know!

about 4 years ago · Juan Pablo Isaza
2 Respuestas
Responde la pregunta

0

There are many ways to do what you want. Circle with image.

From what I can guess from your question and comments you want a dynamic circle that shows a loaded image.

Create a pattern using the image.

const imgPat = ctx.createPattern(image, "no-repeat");

Use the image size to workout the max radius you can have without going outside the image.

const minRadius = Math.min(image.width, image.height) / 2;

To draw the circle at any radius you will need to use the 2D context setTransform function. The following function will do that

function drawImageCircle(imgPat, minRadius, x, y, radius) {

     // get scale of circle image
     const scale = radius / minRadius;

     // transform to put origin at top left of bounding rectangle scaling to fit image pattern
     ctx.setTransform(scale, 0, 0, scale, x - radius, y - radius);
     ctx.fillStyle = imgPat;
     ctx.beginPath();
     ctx.arc(minRadius, minRadius, minRadius, 0, Math.PI * 2);  
     ctx.fill();

     // reset the default transform 
     ctx.setTransform(1, 0, 0, 1, 0, 0);

}

Demo

Demo loads an image. Then gets its size creates a pattern from it and animates it changing the radius and putting a 4 pixel outline around it.

const image = new Image;
image.src = "https://i.stack.imgur.com/C7qq2.png?s=256&g=1";
image.addEventListener("load", imageReady);
const ctx = canvas.getContext("2d");
var w = canvas.width, h = canvas.height, cw = w / 2, ch = h / 2;
var imgPat, minRadius;

function imageReady() {
    imgPat = ctx.createPattern(image, "no-repeat");
    minRadius = Math.min(image.width, image.height) / 2;
    requestAnimationFrame(renderLoop);
}

function drawImageCircle(imgPat, minRadius, x, y, radius) {
     const scale = radius / minRadius;
     ctx.setTransform(scale, 0, 0, scale, x - radius, y - radius);
     ctx.strokeStyle = "#F00";
     ctx.lineWidth = 8 / scale;
     ctx.fillStyle = imgPat;
     ctx.beginPath();
     ctx.arc(minRadius, minRadius, minRadius, 0, Math.PI * 2); 
     ctx.stroke();
     ctx.fill();
     ctx.setTransform(1, 0, 0, 1, 0, 0);
}

function renderLoop(time) {
    ctx.setTransform(1,0,0,1,0,0);
    ctx.clearRect(0, 0, w, h);
    var x = Math.cos(time / 500) * (cw - 80) + cw;
    var y = Math.sin(time / 600) * (ch - 80) + ch;
    var rad = Math.sin(time / 333) * 10 + 30;
    drawImageCircle(imgPat, minRadius, x, y, rad);
    requestAnimationFrame(renderLoop);
}
canvas {
   background: #888;
   border: 2px solid black;
}
<canvas id="canvas" width="256" height="256"></canvas>

about 4 years ago · Juan Pablo Isaza Denunciar

0

If supportable by your use case, I suggest using a png with pre-cropped circular transparency to improve performance and avoid having to code this.

But let's carry on and answer your question from the comment. I felt this was different enough from Canvas clip image with two quadraticCurves to add a new answer, but that thread shows the general approach: use context.clip() after a path with a context.arc, then finish with context.drawImage.

Since you're drawing other things as well, wrap your clip with context.save() and context.restore() to prevent your clip from affecting everything you draw afterwards.

Here's a minimal example:

const canvas = document.createElement("canvas");
canvas.height = canvas.width = 100;
const {width: w, height: h} = canvas;
document.body.appendChild(canvas);
const ctx = canvas.getContext("2d");
const img = new Image();
img.onload = function () {
  ctx.fillRect(10, 0, 20, 20); // normal drawing before save()  
  ctx.save();
  ctx.beginPath();
  ctx.arc(w / 2, h / 2, w / 2, 0, Math.PI * 2);
  ctx.clip();
  ctx.drawImage(this, 0, 0);
  ctx.restore();
  ctx.fillRect(0, 10, 20, 20); // back to normal drawing after restore()
};
img.src = `http://placekitten.com/${w}/${h}`;

If you have multiple images, I suggest using promises as described in Images onload in one function.

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda