I have following example stage.
const rectangle = new Konva.Rect({
width: 300,
height: 100,
x: stage.width() / 2,
y: stage.height() / 2,
fill: 'blue',
rotation: 140
});
layer.add(rectangle);
layer.draw();
const tooltip = new Konva.Label({
x: rectangle.x() + (rectangle.width() / 2),
y: rectangle.y() + (rectangle.height() / 2),
opacity: 0.75
});
tooltip.add(
new Konva.Tag({
fill: 'green',
pointerDirection: 'down',
pointerWidth: 6,
pointerHeight: 4,
lineJoin: 'round'
})
);
tooltip.add(new Konva.Text({
text: 'Hello world',
fontSize: 12,
padding: 5,
fill: 'white',
}));
layer.add(tooltip);
layer.draw();
When the rectangle has no rotation I am able to place the tooltip correctly in the centre of the node. When the rectangle has some rotation the tooltip is not centred any more.
Without changing the attributes of the rectangle or rotating the tooltip, how can I place the tooltip in the centre of the rectangle node?
JSBIN example:
First, you need to update your declaration for Konva in the html script tag as you are referencing an old version.
<script src="https://unpkg.com/konva@7.0.3/konva.min.js"></script>
Because this shape is a rect you can call rectangle.getClientRect() to get the position on the stage, then use simple center-math to place your label. Slip this code in at the end of your current code where you do the last layer.draw();
const cliRect = rectangle.getClientRect();
let pos = {
x: cliRect.x + (cliRect.width )/2,
y: cliRect.y + (cliRect.height )/2
};
tooltip.x(pos.x)
tooltip.y(pos.y)
layer.draw();
This will leave the pointer of the label pointing at the centre of the rotated rectangle, with the label being non-rotated. Working snippet below - run it full screen.
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
draggable: true
});
const layer = new Konva.Layer();
stage.add(layer);
const rectangle = new Konva.Rect({
width: 300,
height: 100,
x: stage.width() / 2,
y: stage.height() / 2,
fill: 'blue',
rotation: 140
});
layer.add(rectangle);
layer.draw();
const tooltip = new Konva.Label({
x: rectangle.x() + (rectangle.width() / 2),
y: rectangle.y() + (rectangle.height() / 2),
opacity: 0.75
});
tooltip.add(
new Konva.Tag({
fill: 'green',
pointerDirection: 'down',
pointerWidth: 6,
pointerHeight: 4,
lineJoin: 'round'
})
);
tooltip.add(new Konva.Text({
text: 'Hello world',
fontSize: 12,
padding: 5,
fill: 'white',
}));
layer.add(tooltip);
const cliRect = rectangle.getClientRect();
// Extra red rect to illustrate client rect. Not needed in solution
const rectangle1 = new Konva.Rect({
width: cliRect.width,
height: cliRect.height,
x: cliRect.x,
y: cliRect.y,
stroke: 'red'
});
layer.add(rectangle1);
let pos = {
x: cliRect.x + (cliRect.width )/2,
y: cliRect.y + (cliRect.height )/2
};
// Set tooltip position taking account of stage draggind
tooltip.x(pos.x - stage.x())
tooltip.y(pos.y - stage.y())
console.log(pos)
layer.draw();
<script src="https://unpkg.com/konva@7.0.3/konva.min.js"></script>
<div id="container"></div>
EDIT: In a comment the OP pointed out that the real use case requires the stage to be draggable before the label is added and that after the drag the calc of the label position fails. This is because getClientRect() gives the position in the client container without adjustment for the stage movement. To make the code work with a dragged stage, change the two lines that set tooltip.x & y to adjust by the stage.x & y, as follows:
tooltip.x(pos.x - stage.x())
tooltip.y(pos.y - stage.y())