叠加文本标签
我试图在鼠标悬停在它们上面时显示我的许多气泡的文本,但是当多个气泡叠加时,显示的文本也是如此。我正试图找到一种方法来"检测"当我有多个文本命令显示信息时,我可以在屏幕上对它们进行排列和排序,而不会发生冲突。下面是我根据我的实际项目编写的一小段代码,说明了这个问题。我试过将所有检测到的索引发送到一个数组,但结果是一个永不结束的数组…我希望我的解释清楚。我对编码比较陌生,现在很迷茫。任何方向或想法将非常感激!
let bubbles = {
pos: [],
diam: [],
color: [],
id: []
}
let initialR = 0;
function setup() {
createCanvas(600, 400);
for (var i = 0; i < 60; i++) {
bubbles.pos.push(createVector(random(0, width), random(0, height)));
bubbles.color.push(color(random(0, 255), random(0, 255), random(0, 255), 120));
bubbles.diam.push(random(0, 80));
bubbles.id.push(round(random(0, 1000)));
}
console.log(bubbles)
}
function draw() {
background(10);
mX = mouseX;
mY = mouseY;
for (var i = 0; i < 60; i++) {
initialR += 0.01;
consR = constrain(initialR, 0, bubbles.diam[i]);
stroke(0);
fill(bubbles.color[i]);
ellipse(bubbles.pos[i].x, bubbles.pos[i].y, consR);
dBubbles = dist(mX, mY, bubbles.pos[i].x, bubbles.pos[i].y);
if (dBubbles < bubbles.diam[i] / 2) {
textX = bubbles.pos[i].x;
textY = bubbles.pos[i].y;
textSize(20);
fill(255);
text(bubbles.id[i], textX, textY);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
这里有一个可能的解决方案:
let bubbles = {
pos: [],
diam: [],
color: [],
id: []
}
let initialR = 0;
function setup() {
createCanvas(600, 400);
textAlign(CENTER, CENTER);
for (var i = 0; i < 60; i++) {
bubbles.pos.push(createVector(random(0, width), random(0, height)));
bubbles.color.push(color(random(0, 255), random(0, 255), random(0, 255), 120));
bubbles.diam.push(random(0, 80));
bubbles.id.push(round(random(0, 1000)));
}
}
function draw() {
background(10);
let mX = mouseX;
let mY = mouseY;
// Use a local variable to tack the hovered bubbles for each frame
let hovered = [];
for (var i = 0; i < 60; i++) {
initialR += 0.01;
consR = constrain(initialR, 0, bubbles.diam[i]);
stroke(0);
fill(bubbles.color[i]);
ellipse(bubbles.pos[i].x, bubbles.pos[i].y, consR);
dBubbles = dist(mX, mY, bubbles.pos[i].x, bubbles.pos[i].y);
if (dBubbles < bubbles.diam[i] / 2) {
// Don't draw the labels yet, just add the bubble index to the hovered list.
hovered.push(i);
}
}
textSize(20);
fill(255);
// Find the center of the hovered spheres
let center =
hovered.map(ix => bubbles.pos[ix])
// This reduce function computes an running average of all the
// hovered bubble centers. It is basically using a weighted
// average formula (avgₙ = (avgₙ₋₁ * count + valueₙ) / (count + 1))
// with the terms rearranged to prevent a loss of precision for very large lists.
.reduce(
(acc, pos) => ({
center:
acc.center.mult(acc.count / (acc.count + 1))
.add(p5.Vector.mult(pos, 1 / (acc.count + 1))),
count: acc.count + 1
}), {
center: createVector(0, 0),
count: 0
}
).center;
// Find the width and displacement direction for each label
let labels = hovered.map(ix => ({
pos: bubbles.pos[ix].copy(),
width: textWidth(bubbles.id[ix]),
text: bubbles.id[ix],
offsetDirection: p5.Vector.sub(bubbles.pos[ix], center).normalize()
}));
// There are probably better ways to displace the labels so that they don't overlap
for (let i = 0; i < labels.length; i++) {
// offset the current label until it doesn't collide with any other labels
while (true) {
let overlapping = false;
for (let j = 0; j < labels.length; j++) {
if (i !== j) {
if (abs(labels[j].pos.x - labels[i].pos.x) < (labels[j].width + labels[i].width) / 2 &&
abs(labels[j].pos.y - labels[i].pos.y) < 20) {
overlapping = true;
break;
}
}
}
if (overlapping) {
// At the very least we could jump by exactly the required offset to prevent
// the currently detected overlap, but this just increases the offset
// by ~1 pixel at a time
labels[i].pos.add(labels[i].offsetDirection);
} else {
break;
}
}
}
for (const lbl of labels) {
text(lbl.text, lbl.pos.x, lbl.pos.y);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>