【问题标题】:Show data labels inside donut pie chart p5js在圆环饼图 p5js 中显示数据标签
【发布时间】:2021-06-04 07:19:16
【问题描述】:

我正在构建一个 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

【问题讨论】:

标签: javascript p5.js donut-chart


【解决方案1】:

虽然理论上您可以使用get() function 检查鼠标光标下像素的颜色并将其与数据集中的一个条目相关联,但我认为您最好通过数学来确定哪个段鼠标当前已结束。并且方便地 p5.js 提供了帮助函数,使其变得非常简单。

在您展示的示例中,您仅检查鼠标光标是否位于矩形区域中。但实际上您想检查鼠标光标是否在一个圆圈内。为此,您可以使用dist(x1, y1, x2, y2) function。一旦确定鼠标光标位于饼图上方,您就需要确定它位于哪个段上。这可以通过找到从图表中心向右(或您开始绘制楔形的任何方向)绘制的线与从图表中心到鼠标光标绘制的线之间的角度来完成。这可以使用angleBetween() functionp5.Vector 来完成。

这是一个工作示例:

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, centerY, radius, 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]]}`, centerX, centerY);
        pop();
      }
    }

    start += angle;
  }
}
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"&gt;&lt;/script&gt;

【讨论】:

  • 嗨,保罗!非常感谢你!这正是我正在寻找的。我在使用 mouseAngle 时遇到了一些问题,它没有超过 PI,当它到达饼图的一半(3.14)时,它会倒退到 0,有什么想法为什么会发生这种情况?
  • 是的,对于二维向量,angleBetween 函数将返回介于 0 和 PI 之间的顺时针角度值,以及介于 0 和负 PI 之间的逆时针角度值。
  • 当我们使用:if (mouseAngle &lt; 0) { mouseAngle += TWO_PI; } 时不会解决吗?在您的示例中调试相同的东西时,它会超过 PI 到 2PI,然后可以匹配到起始角度。
  • 是的,我的示例中的代码旨在处理角度介于负 PI 之间的情况。由于我的示例有效,因此我可以确定您为什么会看到不同的行为。您可能想发布另一个问题,其中包含仅角度问题的最小可重复示例。
  • 当然!非常感谢你帮助保罗!
【解决方案2】:

我想我知道问题的根源是@thenewbie 经历过:它是正在使用的 p5 库。我正在使用 p5.min.js 并遇到同样的问题。一旦我开始使用完整的 p5.js 库,问题就解决了,@Paul 的脚本就可以工作了。 这是我在研究这个问题时遇到的一个链接,它让我找到了解决方案: https://github.com/processing/p5.js/issues/3973

感谢 Paul 上面的清晰解释和代码。

【讨论】:

    猜你喜欢
    • 2021-09-24
    • 1970-01-01
    • 2016-11-29
    • 1970-01-01
    • 2017-06-29
    • 2017-08-21
    • 2018-05-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多