KonvaJS 始终在标签中居中文本
KonvaJS always center text in label
我为代码道歉,它处于我正在积极使用的状态。
在 Konva JS 中,我正在创建标签。这基本上是一个组,它有一个形状和文本元素。形状是从数据库中动态绘制的,每个数据库行都有坐标、形状(正方形、圆形等)、大小和旋转。这些乘以一个比例取决于屏幕尺寸。我有一个有效的解决方案,我已经使用了数周,但我还有一个改变形状形状的功能。所以我按下一个按钮,它会更新数据库(例如,将正方形更改为圆形),然后重绘 canvas。因为从正方形到圆形会从从左上角绘制的形状变为从中心绘制的形状,所以会弄乱坐标。我决定切换到偏移量为 width/2 的绘制矩形,以便矩形也从中心绘制。
我后来不断地破坏它,现在我根本无法让文本居中。 无论形状、大小或旋转如何,我都需要文本居中。
当前代码
//Gets table array from SQL
tables = callPhpFunction('getTablesInRoom', room);
tables = JSON.parse(tables);
numberOfTables = tables.length;
index = 0;
tableLayer = new Konva.Layer();
tableLayer.add(transformer);
//For every table
while(index < numberOfTables){
tableNumber = tables[index]['tablenumber'];
offset_x = 0;
offset_y = 0;
pos_x = parseInt(tables[index]['posx']) * scale;
pos_y = parseInt(tables[index]['posy']) * scale;
shape = tables[index]['shape'];
tableWidth = parseInt(tables[index]['width']) * scale;
tableHeight = parseInt(tables[index]['height']) * scale;
rotation = parseInt(tables[index]['rotation']);
fillColor = "gray";
strokeColor = "black";
var table = new Konva.Label({
x: pos_x,
y: pos_y,
draggable:canDrag
});
pos_x = 0;
pos_y = 0 ;
//If the shape is a square, rectangle, or undefined
if(shape != "circle" && shape != "ellipse" && shape != "longellipse"){
offset_x = tableWidth/2
offset_y = tableHeight/2
table.add(new Konva.Rect({
width: tableWidth,
height: tableHeight,
offsetX: offset_y,
offsetY: offset_y,
height: tableHeight,
fill: fillColor,
stroke: strokeColor,
strokeWidth: 4
}));
//If shape is a circle or ellipse
} else {
table.add(new Konva.Ellipse({
radiusX: tableWidth/2,
radiusY: tableHeight/2,
fill: fillColor,
stroke: strokeColor,
strokeWidth: 4
}));
//Can't remember why this is here, but it seems to work/ Think if these are reused when the text is drawn it centers them.
pos_x = -tableWidth/2;
pos_y = -tableHeight/2;
}
//Gets the first shape (ellipse or rectangle) in the label. I think is equivalent to getTag()
innerShape = getInnerShape(table);
//Rotates the inner shape, while leaving text unRotated.
if(rotation != 0){
canvasX = pos_x + (tableWidth/2)
canvasY = pos_y + (tableHeight/2)
rotateAroundPoint(innerShape, rotation, {x:canvasX, y:canvasY });
}
//Currently approach is to get center based on the client rectangle. It's not working
box = table.getClientRect();
box_x = box.x + box.width / 2;
box_y = box.y + box.height / 2;
table.add(new Konva.Text({
width: tableWidth,
height: tableHeight,
x: box_x,
y: box_y,
text: tableNumber,
verticalAlign: 'middle',
align: 'center',
fontSize: 24,
fontFamily: 'Calibri',
fill: 'black',
listening: false
}))
这是视觉效果
我稍微重写了你的创作程序;看起来像这样工作得很好。这里的本质是形状 + 标签组合在一起,全局 [缩放] 位置应用于这些组,而不是单个图形元素。
代码:
const tableLayer = new Konva.Layer();
const scale = 1.0; // position scale factor
const mockData = [
{
label: "45",
shape: "circle",
x: 100,
y: 150,
w: 100,
h: 100,
r: 0
},
{
label: "46",
shape: "rect",
x: 200,
y: 170,
w: 150,
h: 100,
r: -30
},
{
label: "47",
shape: "rect",
x: 70,
y: 200,
w: 50,
h: 100,
r: 15
},
{
label: "48",
shape: "ellipse",
x: 400,
y: 300,
w: 250,
h: 150,
r: 30
}
];
function createShapeElement( data ) {
// Create container group
let element = new Konva.Group( {
x: data.x * scale,
y: data.y * scale,
draggable: true,
listening: true,
} );
// Create background shape
let shape;
switch ( data.shape ) {
case "circle": // fall-through
case "ellipse": // fall-through
case "longellipse":
shape = new Konva.Ellipse( {
x: 0,
y: 0,
radiusX: data.w * 0.5,
radiusY: data.h * 0.5,
rotation: data.r,
fill: "gray",
stroke: "black",
strokeWidth: 4,
draggable: false,
listening: true
} );
break;
default:
shape = new Konva.Rect( {
x: 0,
y: 0,
offsetX: data.w * 0.5,
offsetY: data.h * 0.5,
width: data.w,
height: data.h,
rotation: data.r,
fill: "gray",
stroke: "black",
strokeWidth: 4,
draggable: false,
listening: true
} );
break;
} // End switch
// Create label
let label = new Konva.Text( {
x: data.w * -0.5,
y: data.h * -0.5,
width: data.w,
height: data.h,
text: data.label,
fontSize: 24,
fill: "black",
align: "center",
verticalAlign: "middle",
draggable: false,
listening: false
} );
element.add( shape, label );
return element;
}
// Loop your data and call the creation method for each data item.
mockData.forEach( itemData => {
tableLayer.add( createShapeElement( itemData ) );
} );
我为代码道歉,它处于我正在积极使用的状态。
在 Konva JS 中,我正在创建标签。这基本上是一个组,它有一个形状和文本元素。形状是从数据库中动态绘制的,每个数据库行都有坐标、形状(正方形、圆形等)、大小和旋转。这些乘以一个比例取决于屏幕尺寸。我有一个有效的解决方案,我已经使用了数周,但我还有一个改变形状形状的功能。所以我按下一个按钮,它会更新数据库(例如,将正方形更改为圆形),然后重绘 canvas。因为从正方形到圆形会从从左上角绘制的形状变为从中心绘制的形状,所以会弄乱坐标。我决定切换到偏移量为 width/2 的绘制矩形,以便矩形也从中心绘制。
我后来不断地破坏它,现在我根本无法让文本居中。 无论形状、大小或旋转如何,我都需要文本居中。
当前代码
//Gets table array from SQL
tables = callPhpFunction('getTablesInRoom', room);
tables = JSON.parse(tables);
numberOfTables = tables.length;
index = 0;
tableLayer = new Konva.Layer();
tableLayer.add(transformer);
//For every table
while(index < numberOfTables){
tableNumber = tables[index]['tablenumber'];
offset_x = 0;
offset_y = 0;
pos_x = parseInt(tables[index]['posx']) * scale;
pos_y = parseInt(tables[index]['posy']) * scale;
shape = tables[index]['shape'];
tableWidth = parseInt(tables[index]['width']) * scale;
tableHeight = parseInt(tables[index]['height']) * scale;
rotation = parseInt(tables[index]['rotation']);
fillColor = "gray";
strokeColor = "black";
var table = new Konva.Label({
x: pos_x,
y: pos_y,
draggable:canDrag
});
pos_x = 0;
pos_y = 0 ;
//If the shape is a square, rectangle, or undefined
if(shape != "circle" && shape != "ellipse" && shape != "longellipse"){
offset_x = tableWidth/2
offset_y = tableHeight/2
table.add(new Konva.Rect({
width: tableWidth,
height: tableHeight,
offsetX: offset_y,
offsetY: offset_y,
height: tableHeight,
fill: fillColor,
stroke: strokeColor,
strokeWidth: 4
}));
//If shape is a circle or ellipse
} else {
table.add(new Konva.Ellipse({
radiusX: tableWidth/2,
radiusY: tableHeight/2,
fill: fillColor,
stroke: strokeColor,
strokeWidth: 4
}));
//Can't remember why this is here, but it seems to work/ Think if these are reused when the text is drawn it centers them.
pos_x = -tableWidth/2;
pos_y = -tableHeight/2;
}
//Gets the first shape (ellipse or rectangle) in the label. I think is equivalent to getTag()
innerShape = getInnerShape(table);
//Rotates the inner shape, while leaving text unRotated.
if(rotation != 0){
canvasX = pos_x + (tableWidth/2)
canvasY = pos_y + (tableHeight/2)
rotateAroundPoint(innerShape, rotation, {x:canvasX, y:canvasY });
}
//Currently approach is to get center based on the client rectangle. It's not working
box = table.getClientRect();
box_x = box.x + box.width / 2;
box_y = box.y + box.height / 2;
table.add(new Konva.Text({
width: tableWidth,
height: tableHeight,
x: box_x,
y: box_y,
text: tableNumber,
verticalAlign: 'middle',
align: 'center',
fontSize: 24,
fontFamily: 'Calibri',
fill: 'black',
listening: false
}))
这是视觉效果
我稍微重写了你的创作程序;看起来像这样工作得很好。这里的本质是形状 + 标签组合在一起,全局 [缩放] 位置应用于这些组,而不是单个图形元素。
代码:
const tableLayer = new Konva.Layer();
const scale = 1.0; // position scale factor
const mockData = [
{
label: "45",
shape: "circle",
x: 100,
y: 150,
w: 100,
h: 100,
r: 0
},
{
label: "46",
shape: "rect",
x: 200,
y: 170,
w: 150,
h: 100,
r: -30
},
{
label: "47",
shape: "rect",
x: 70,
y: 200,
w: 50,
h: 100,
r: 15
},
{
label: "48",
shape: "ellipse",
x: 400,
y: 300,
w: 250,
h: 150,
r: 30
}
];
function createShapeElement( data ) {
// Create container group
let element = new Konva.Group( {
x: data.x * scale,
y: data.y * scale,
draggable: true,
listening: true,
} );
// Create background shape
let shape;
switch ( data.shape ) {
case "circle": // fall-through
case "ellipse": // fall-through
case "longellipse":
shape = new Konva.Ellipse( {
x: 0,
y: 0,
radiusX: data.w * 0.5,
radiusY: data.h * 0.5,
rotation: data.r,
fill: "gray",
stroke: "black",
strokeWidth: 4,
draggable: false,
listening: true
} );
break;
default:
shape = new Konva.Rect( {
x: 0,
y: 0,
offsetX: data.w * 0.5,
offsetY: data.h * 0.5,
width: data.w,
height: data.h,
rotation: data.r,
fill: "gray",
stroke: "black",
strokeWidth: 4,
draggable: false,
listening: true
} );
break;
} // End switch
// Create label
let label = new Konva.Text( {
x: data.w * -0.5,
y: data.h * -0.5,
width: data.w,
height: data.h,
text: data.label,
fontSize: 24,
fill: "black",
align: "center",
verticalAlign: "middle",
draggable: false,
listening: false
} );
element.add( shape, label );
return element;
}
// Loop your data and call the creation method for each data item.
mockData.forEach( itemData => {
tableLayer.add( createShapeElement( itemData ) );
} );