I have created pulse animation using html canvas. There is two rectangles. Rectangle's positions is updated dynamically. The smaller rectangle has pulse animation. I have problem calculate it's center position value. Without scaling I get correct position. But when scaling position is incorrect. How to calculate scaled X and Y?
const canvas = document.createElement("canvas");
canvas.setAttribute("width", "500px");
canvas.setAttribute("height", "500px");
const ctx = canvas.getContext("2d");
const wrapper = document.getElementsByClassName("wrap")[0];
wrapper.appendChild(canvas);
let scale = 1;
let angle = 0;
const blockSize = 45; // Rectangle size
const pos = {x: 2, y: 1}; // Rectangle position
function anim(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.setTransform(1, 0, 0, 1, 0, 0);
draw(ctx, pos)
update();
requestAnimationFrame(anim);
}
anim();
function draw(ctx, position){
ctx.fillStyle = "#000";
ctx.fillRect((position.x * blockSize - blockSize), (position.y * blockSize - blockSize), blockSize, blockSize);
// Smaller rectangle with pulse
ctx.fillStyle = "red";
const centerX = (position.x * blockSize - blockSize) / 2;
const centerY = (position.y * blockSize - blockSize) / 2;
const scaledX = centerX - (centerX * scale);
const scaledY = centerY - (centerY * scale);
ctx.setTransform(scale, 0, 0, scale, centerX, scaledY);
const recSize = 30;
const x = (position.x * blockSize - blockSize) + ((blockSize - recSize) / 2);
const y = (position.y * blockSize - blockSize) + ((blockSize - recSize) / 2);
ctx.fillRect(x, y, recSize, recSize);
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
function update(){
angle += Math.PI / 140;
scale = 0.5 + Math.abs(Math.cos(angle));
}
<div class="wrap">
</div>
const canvas = document.createElement("canvas");
canvas.setAttribute("width", "500px");
canvas.setAttribute("height", "500px");
const ctx = canvas.getContext("2d");
const wrapper = document.getElementsByClassName("wrap")[0];
wrapper.appendChild(canvas);
let scale = 1;
let angle = 0;
const blockSize = 45; // Rectangle size
const pos = {x: 2, y: 1}; // Rectangle position
function anim(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.setTransform(1, 0, 0, 1, 0, 0);
draw(ctx, pos)
update();
requestAnimationFrame(anim);
}
anim();
function draw(ctx, position){
// Draw the larger black rectangle
ctx.fillStyle = "#000";
const largeRectX = position.x * blockSize - blockSize;
const largeRectY = position.y * blockSize - blockSize;
ctx.fillRect(largeRectX, largeRectY, blockSize, blockSize);
// Calculate the center of the larger rectangle
const centerX = largeRectX + blockSize / 2;
const centerY = largeRectY + blockSize / 2;
// Save the current context state
ctx.save();
// Translate to the center, scale, then translate back
ctx.translate(centerX, centerY);
ctx.scale(scale, scale);
ctx.translate(-centerX, -centerY);
// Draw the smaller red rectangle
ctx.fillStyle = "red";
const recSize = 30;
const smallRectX = largeRectX + (blockSize - recSize) / 2;
const smallRectY = largeRectY + (blockSize - recSize) / 2;
ctx.fillRect(smallRectX, smallRectY, recSize, recSize);
// Restore the context state
ctx.restore();
}
function update(){
angle += Math.PI / 140;
scale = 0.5 + Math.abs(Math.cos(angle));
}
<div class="wrap">
</div>
Here's what this code does:
It draws the larger black rectangle as before. It calculates the center of the larger rectangle. It saves the current context state. It applies the scaling transformation:
First, it translates to the center of the larger rectangle. Then it applies the scaling. Finally, it translates back.
It draws the smaller red rectangle. It restores the context state.