将文本放在多边形的中心
Put Text to center of polygons
我从具有多个多边形的数据库中获取了一组多边形。我想把文本放在多边形的中心。
可能是三角形也可能是长方形也可能是正方形也可能是多边形
字体大小必须根据多边形大小动态变化。
文字颜色与线条颜色相同。
来自数据库的示例:
var polygons = [
{
text: "ROI", color: "#00ff00",
jointLength: 5, lineWidth: 3,
X: [890, 893, 409, 21, 27], Y: [658, 205, 199, 556, 659],
}, {
text: "Lane 3", color: "#ff0000",
jointLength: 4, lineWidth: 3,
X: [915, 911, 643, 879], Y: [5, 682, 683, 2],
}, {
text: "Lane 4", color: "#ff0000",
jointLength: 4, lineWidth: 3,
X: [888, 656, 170, 701], Y: [2, 680, 682, 1],
}, {
text: "Lane 5", color: "#ff0000",
jointLength: 5, lineWidth: 3,
X: [712, 182, 4, 4, 590], Y: [1, 681, 682, 532, 1],
}, {
text: "Speed", color: "#0000ff",
jointLength: 4, lineWidth: 3,
X: [290, 911, 873, 5], Y: [367, 357, 668, 664],
}
];
polygons.forEach((polygon) => {
const ctx = document.getElementById("canvas").getContext("2d");
ctx.strokeStyle = polygon.color;
ctx.lineWidth = polygon.lineWidth;
ctx.beginPath();
ctx.moveTo(polygon.X[0], polygon.Y[0]);
for (let i = 1; i < polygon.jointLength; i++) {
ctx.lineTo(polygon.X[i], polygon.Y[i]);
}
ctx.closePath();
ctx.stroke();
});
<canvas id="canvas" width=999 height=999></canvas>
主要逻辑解释:
- 我用算术平均值公式计算的多边形中心
- 字体的大小我通过
font-size = 300
获取文本的宽度来计算(但是你可以根据需要更改第一个检查大小)然后检查text with是否大于最小的2 个最近的点之间的距离(如果文本位于多边形的中心,我认为这是一个很好的限制)。如果是,那么我将 font-size
减一(但您可以使用任何步长)
由于这个逻辑,第二个多边形中的文本比它应该的要小,因为我们在顶部有 2 个点,它们彼此非常接近
有一个代码(打开整页以获得更好的可见性):
const polygons = [
{
text: "ROI",
color: "red",
jointLength: 5,
lineWidth: 3,
X: [890, 893, 409, 21, 27],
Y: [658, 205, 199, 556, 659],
},
{
text: "Lane 3",
color: "blue",
jointLength: 4,
lineWidth: 3,
X: [915, 911, 643, 879],
Y: [5, 682, 683, 2],
},
{
text: "Lane 4",
color: "green",
jointLength: 4,
lineWidth: 3,
X: [888, 656, 170, 701],
Y: [2, 680, 682, 1],
},
{
text: "Lane 5",
color: "orange",
jointLength: 5,
lineWidth: 3,
X: [712, 182, 4, 4, 590],
Y: [1, 681, 682, 532, 1],
},
{
text: "Speed",
color: "purple",
jointLength: 4,
lineWidth: 3,
X: [290, 911, 873, 5],
Y: [367, 357, 668, 664],
},
];
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext("2d");
canvas.width = 1000;
canvas.height = 1000;
class Polygon {
#ctx;
#dots = [];
#text;
#color;
#lineWidth;
#dotsCount;
constructor(ctx, data) {
this.#ctx = ctx;
this.#text = data.text;
this.#color = data.color;
this.#lineWidth = data.lineWidth;
this.#dotsCount = data.jointLength;
for (let i = 0; i < this.#dotsCount; ++ i) {
this.#dots.push({x: data.X[i], y: data.Y[i]})
}
}
#getCenterCoords() {
const x = this.#dots.reduce((sum, dot) => sum += dot.x, 0) / this.#dotsCount;
const y = this.#dots.reduce((sum, dot) => sum += dot.y, 0) / this.#dotsCount;
return {x, y};
}
#distance = (dot1, dot2) => Math.sqrt((dot1.x - dot2.x) ** 2 + (dot1.y - dot2.y) ** 2);
#getMinimalDistanceBetweenDots() {
let minDist = Infinity;
for (let i = 0; i < this.#dotsCount; ++i) {
const dot1 = this.#dots[i];
for (let j = i + 1; j < this.#dotsCount; ++j) {
const dot2 = this.#dots[j];
const dist = this.#distance(dot1, dot2);
if (dist < minDist) minDist = dist;
}
}
return minDist;
}
#getTextSize() {
const minAvailableWidth = this.#getMinimalDistanceBetweenDots();
let rightBound = 300;
let leftBound = 0;
let fontSize = rightBound;
while (rightBound - leftBound > 1) {
fontSize = Math.round((leftBound + rightBound) / 2);
this.#ctx.font = `${fontSize}px verdana`;
const textSize = this.#ctx.measureText(this.#text).width;
if (textSize > minAvailableWidth) {
rightBound = fontSize;
continue;
}
if (textSize < minAvailableWidth) {
leftBound = fontSize;
continue;
}
if (textSize === minAvailableWidth) {
break;
}
}
return fontSize;
}
draw() {
const path = new Path2D();
const firstDot = this.#dots[0];
const center = this.#getCenterCoords();
this.#dots.forEach(dot => path.lineTo(dot.x, dot.y));
path.lineTo(firstDot.x, firstDot.y);
this.#ctx.strokeStyle = this.#color;
this.#ctx.lineWidth = this.#lineWidth;
this.#ctx.lineCap = 'round';
this.#ctx.lineJoin = 'round';
this.#ctx.stroke(path);
this.#ctx.font = `${this.#getTextSize()}px verdana`;
this.#ctx.fillStyle = this.#color;
this.#ctx.textAlign = 'center';
this.#ctx.fillText(this.#text, center.x, center.y);
}
}
polygons.forEach((polygon) => new Polygon(ctx, polygon).draw());
<canvas id="canvas"></canvas>
我从具有多个多边形的数据库中获取了一组多边形。我想把文本放在多边形的中心。
可能是三角形也可能是长方形也可能是正方形也可能是多边形
字体大小必须根据多边形大小动态变化。
文字颜色与线条颜色相同。
来自数据库的示例:
var polygons = [
{
text: "ROI", color: "#00ff00",
jointLength: 5, lineWidth: 3,
X: [890, 893, 409, 21, 27], Y: [658, 205, 199, 556, 659],
}, {
text: "Lane 3", color: "#ff0000",
jointLength: 4, lineWidth: 3,
X: [915, 911, 643, 879], Y: [5, 682, 683, 2],
}, {
text: "Lane 4", color: "#ff0000",
jointLength: 4, lineWidth: 3,
X: [888, 656, 170, 701], Y: [2, 680, 682, 1],
}, {
text: "Lane 5", color: "#ff0000",
jointLength: 5, lineWidth: 3,
X: [712, 182, 4, 4, 590], Y: [1, 681, 682, 532, 1],
}, {
text: "Speed", color: "#0000ff",
jointLength: 4, lineWidth: 3,
X: [290, 911, 873, 5], Y: [367, 357, 668, 664],
}
];
polygons.forEach((polygon) => {
const ctx = document.getElementById("canvas").getContext("2d");
ctx.strokeStyle = polygon.color;
ctx.lineWidth = polygon.lineWidth;
ctx.beginPath();
ctx.moveTo(polygon.X[0], polygon.Y[0]);
for (let i = 1; i < polygon.jointLength; i++) {
ctx.lineTo(polygon.X[i], polygon.Y[i]);
}
ctx.closePath();
ctx.stroke();
});
<canvas id="canvas" width=999 height=999></canvas>
主要逻辑解释:
- 我用算术平均值公式计算的多边形中心
- 字体的大小我通过
font-size = 300
获取文本的宽度来计算(但是你可以根据需要更改第一个检查大小)然后检查text with是否大于最小的2 个最近的点之间的距离(如果文本位于多边形的中心,我认为这是一个很好的限制)。如果是,那么我将font-size
减一(但您可以使用任何步长)
由于这个逻辑,第二个多边形中的文本比它应该的要小,因为我们在顶部有 2 个点,它们彼此非常接近
有一个代码(打开整页以获得更好的可见性):
const polygons = [
{
text: "ROI",
color: "red",
jointLength: 5,
lineWidth: 3,
X: [890, 893, 409, 21, 27],
Y: [658, 205, 199, 556, 659],
},
{
text: "Lane 3",
color: "blue",
jointLength: 4,
lineWidth: 3,
X: [915, 911, 643, 879],
Y: [5, 682, 683, 2],
},
{
text: "Lane 4",
color: "green",
jointLength: 4,
lineWidth: 3,
X: [888, 656, 170, 701],
Y: [2, 680, 682, 1],
},
{
text: "Lane 5",
color: "orange",
jointLength: 5,
lineWidth: 3,
X: [712, 182, 4, 4, 590],
Y: [1, 681, 682, 532, 1],
},
{
text: "Speed",
color: "purple",
jointLength: 4,
lineWidth: 3,
X: [290, 911, 873, 5],
Y: [367, 357, 668, 664],
},
];
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext("2d");
canvas.width = 1000;
canvas.height = 1000;
class Polygon {
#ctx;
#dots = [];
#text;
#color;
#lineWidth;
#dotsCount;
constructor(ctx, data) {
this.#ctx = ctx;
this.#text = data.text;
this.#color = data.color;
this.#lineWidth = data.lineWidth;
this.#dotsCount = data.jointLength;
for (let i = 0; i < this.#dotsCount; ++ i) {
this.#dots.push({x: data.X[i], y: data.Y[i]})
}
}
#getCenterCoords() {
const x = this.#dots.reduce((sum, dot) => sum += dot.x, 0) / this.#dotsCount;
const y = this.#dots.reduce((sum, dot) => sum += dot.y, 0) / this.#dotsCount;
return {x, y};
}
#distance = (dot1, dot2) => Math.sqrt((dot1.x - dot2.x) ** 2 + (dot1.y - dot2.y) ** 2);
#getMinimalDistanceBetweenDots() {
let minDist = Infinity;
for (let i = 0; i < this.#dotsCount; ++i) {
const dot1 = this.#dots[i];
for (let j = i + 1; j < this.#dotsCount; ++j) {
const dot2 = this.#dots[j];
const dist = this.#distance(dot1, dot2);
if (dist < minDist) minDist = dist;
}
}
return minDist;
}
#getTextSize() {
const minAvailableWidth = this.#getMinimalDistanceBetweenDots();
let rightBound = 300;
let leftBound = 0;
let fontSize = rightBound;
while (rightBound - leftBound > 1) {
fontSize = Math.round((leftBound + rightBound) / 2);
this.#ctx.font = `${fontSize}px verdana`;
const textSize = this.#ctx.measureText(this.#text).width;
if (textSize > minAvailableWidth) {
rightBound = fontSize;
continue;
}
if (textSize < minAvailableWidth) {
leftBound = fontSize;
continue;
}
if (textSize === minAvailableWidth) {
break;
}
}
return fontSize;
}
draw() {
const path = new Path2D();
const firstDot = this.#dots[0];
const center = this.#getCenterCoords();
this.#dots.forEach(dot => path.lineTo(dot.x, dot.y));
path.lineTo(firstDot.x, firstDot.y);
this.#ctx.strokeStyle = this.#color;
this.#ctx.lineWidth = this.#lineWidth;
this.#ctx.lineCap = 'round';
this.#ctx.lineJoin = 'round';
this.#ctx.stroke(path);
this.#ctx.font = `${this.#getTextSize()}px verdana`;
this.#ctx.fillStyle = this.#color;
this.#ctx.textAlign = 'center';
this.#ctx.fillText(this.#text, center.x, center.y);
}
}
polygons.forEach((polygon) => new Polygon(ctx, polygon).draw());
<canvas id="canvas"></canvas>