I am trying to make resizable image with content fully fitted in rect. I found solution how to emulate object-fit: cover, but I need contain. I made some solution:
const width = size.width;
const height = size.height;
var scalex = image.width / width;
var scaley = image.height / height;
var scale = Math.max(scalex, scaley);
return {
cropWidth: width * scale,
cropHeight: height * scale,
};
But it not centered the image inside
Have any ideas how to make it centered?
You can't do that with just Konva.Image
and crop. Konva can cut content with cropping. But it can't render it with empty spaces. For that case, we can use external canvas.
// Create a new Konva stage with the dimensions of the window
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight
});
// Create a new layer to hold the image and transformer
const layer = new Konva.Layer();
// Add the layer to the stage
stage.add(layer);
// Define a function to fit and center an image within a canvas element
function fitContain({canvas, image, canvasWidth, canvasHeight}) {
// Get the 2D rendering context for the canvas
const ctx = canvas.getContext('2d');
// Set the dimensions of the canvas
canvas.width = canvasWidth;
canvas.height = canvasHeight;
// Calculate the aspect ratios of the image and the canvas
const imageAspect = image.naturalWidth / image.naturalHeight;
const canvasAspect = canvasWidth / canvasHeight;
let renderWidth, renderHeight;
// Determine the dimensions to render the image at to maintain aspect ratio
if (imageAspect > canvasAspect) {
renderWidth = canvasWidth;
renderHeight = canvasWidth / imageAspect;
} else {
renderWidth = canvasHeight * imageAspect;
renderHeight = canvasHeight;
}
// Calculate the position to center the image in the canvas
const offsetX = (canvasWidth - renderWidth) / 2;
const offsetY = (canvasHeight - renderHeight) / 2;
// Draw the image on the canvas at the calculated dimensions and position
ctx.drawImage(image, offsetX, offsetY, renderWidth, renderHeight);
// Return the canvas element
return canvas;
}
// Create a new image element
const image = new window.Image();
// Set the source of the image
image.src = 'https://i.imgur.com/ktWThtZ.png';
// Define an onload handler to execute once the image has loaded
image.onload = () => {
// Create a new canvas element
const canvas = document.createElement('canvas');
// Create a new Konva Image to hold the canvas
const img = new Konva.Image({
image: canvas,
x: 50,
y: 60,
width: 200,
height: 100,
draggable: true
});
// Add the Konva Image to the layer
layer.add(img);
// Call fitContain to fit and center the image in the canvas
fitContain({canvas, image, canvasWidth: img.width(), canvasHeight: img.height() });
// Create a new transformer to allow the Konva Image to be resized
const tr = new Konva.Transformer({
flipEnabled: false,
nodes: [img]
});
// Add the transformer to the layer
layer.add(tr);
// Define a transform event handler to update the canvas when the Konva Image is resized
img.on('transform', () => {
// Update the dimensions of the Konva Image to reflect the scaling transformation
img.setAttrs({
width: img.width() * img.scaleX(),
height: img.height() * img.scaleY(),
scaleX: 1,
scaleY: 1
});
// Call fitContain to fit and center the image in the canvas again
fitContain({canvas, image, canvasWidth: img.width(), canvasHeight: img.height() });
})
}
<script src="https://unpkg.com/konva@^9/konva.min.js"></script>
<div id="container"></div>