问题描述
我正在构建一个 p5js 圆环图,但我正在努力在中间显示数据标签。我想我已经设法为它设置了正确的边界,但是如何匹配我所处的角度?或者有没有办法只通过颜色来搭配?
https://i.stack.imgur.com/enTBo.png
我首先尝试将图表的边界与指针相匹配,我设法使用 mouseX 和 mouseY 来实现。请问有什么建议吗?
if(mouseX >= width / 2 - width * 0.2 && mouseY >= height / 2 - width * 0.2
&& mouseX <= width / 2 + width * 0.2 && mouseY <= height / 2 + width * 0.2)
{
//console.log("YAY!!! I'm inside the pie chart!!!");
}
else
{
textSize(14);
text('Hover over to see the labels',width / 2,height / 2);
}
};
[1]: https://i.stack.imgur.com/enTBo.png
解决方法
虽然理论上您可以使用 get()
function 检查鼠标光标下像素的颜色并将其与数据集中的条目之一相关联,但我认为您最好通过数学来确定鼠标当前位于哪个段。并且方便地 p5.js 提供了帮助函数,使其变得非常容易。
在您展示的示例中,您只检查鼠标光标是否位于矩形区域内。但实际上你想检查鼠标光标是否在一个圆圈内。为此,您可以使用 dist(x1,y1,x2,y2)
function。确定鼠标光标位于饼图上方后,您将需要确定它位于哪个段上。这可以通过找到从图表中心向右绘制的线(或您开始绘制楔形的方向)与从图表中心到鼠标光标绘制的线之间的角度来完成。这可以使用 p5.Vector
的 angleBetween()
function 来完成。
这是一个工作示例:
const colors = ['red','green','blue'];
const thickness = 40;
let segments = {
foo: 34,bar: 55,baz: 89
};
let radius = 80,centerX,centerY;
function setup() {
createCanvas(windowWidth,windowHeight);
noFill();
strokeWeight(thickness);
strokeCap(SQUARE);
ellipseMode(RADIUS);
textAlign(CENTER,CENTER);
textSize(20);
centerX = width / 2;
centerY = height / 2;
}
function draw() {
background(200);
let keys = Object.keys(segments);
let total = keys.map(k => segments[k]).reduce((v,s) => v + s,0);
let start = 0;
// Check the mouse distance and angle
let mouseDist = dist(centerX,centerY,mouseX,mouseY);
// Find the angle between a vector pointing to the right,and the vector
// pointing from the center of the window to the current mouse position.
let mouseAngle =
createVector(1,0).angleBetween(
createVector(mouseX - centerX,mouseY - centerY)
);
// Counter clockwise angles will be negative 0 to PI,switch them to be from
// PI to TWO_PI
if (mouseAngle < 0) {
mouseAngle += TWO_PI;
}
for (let i = 0; i < keys.length; i++) {
stroke(colors[i]);
let angle = segments[keys[i]] / total * TWO_PI;
arc(centerX,radius,start,start + angle);
// Check mouse pos
if (mouseDist > radius - thickness / 2 &&
mouseDist < radius + thickness / 2) {
if (mouseAngle > start && mouseAngle < start + angle) {
// If the mouse is the correct distance from the center to be hovering over
// our "donut" and the angle to the mouse cursor is in the range for the
// current slice,display the slice information
push();
noStroke();
fill(colors[i]);
text(`${keys[i]}: ${segments[keys[i]]}`,centerY);
pop();
}
}
start += angle;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script>