peity icon indicating copy to clipboard operation
peity copied to clipboard

Add ability to use CSS classes on SVG charts

Open LordMike opened this issue 2 years ago • 2 comments

Hey,

I was wondering if it was possible to replace this:

<span data-peity='{ "fill": ["red", "#eeeeee"],    "innerRadius": 10, "radius": 40 }'>1/7</span>

With perhaps this:

<span data-peity='{ "class": "my-class",    "innerRadius": 10, "radius": 40 }'>1/7</span>
.. or
<span data-peity='{ "class": ["my-class", "my-class2"],    "innerRadius": 10, "radius": 40 }'>1/7</span>

This way I can move all my colors etc. to other systems, like SASS.

I checked the code, and it seems like there explicitly isn't a way to add attributes to the rendered SVG elements, so I can't even workaround it :). Also, I noted that SVG is optional, so of course classes wouldn't work if Peity fell back to canvas rendering.. but I'm willing to lose that support :).

Mike.

LordMike avatar Nov 15 '22 10:11 LordMike

That's a really good idea (both adding a class option and exposing the added elements), I can't believe it hasn't been suggested before now 💯

You're right, there's nothing available that exposes the added elements directly but there is a possible workaround using the official (but undocumented 😬) after hook. The following includes two cases, styling based the segment position (simple and generic), and styling based on the value of the segment (a bit more complicated and app-specific).

CodeSandbox: https://codesandbox.io/s/happy-sara-y08767

$(".donut").peity("donut", {
  radius: 40,
  after() {
    const children = this.$svg.children();
    children.each(function () {
      this.removeAttribute("fill");
      let className;
      if (children.length === 2) {
        className = "slice";
      } else {
        const value = parseInt(this.getAttribute("data-value"));
        className = value > 30 ? "large" : "medium";
      }
      this.setAttribute("class", className);
    });
  }
});
.slice:nth-child(odd) {
  fill: purple;
}
.slice:nth-child(even) {
  fill: pink;
}

.medium:nth-child(odd) {
  fill: yellow;
}
.medium:nth-child(even) {
  fill: orange;
}

.large {
  fill: red;
}

If you only want to style based on the position of the segment then you'd only remove all fills in the after hook and could rely entirely on CSS selectors:

.donut + svg > path:nth-child(odd) {
  fill: yellow;
}

benpickles avatar Nov 18 '22 11:11 benpickles

You could also add attributes or classes (by default) to the rendered items, which I can affect w/ CSS. Something like:

<svg ..>
  <path .. data-peity-part="1" /> <-- one slice of pie
  <path .. data-peity-part="2" /> <-- two slice of pie
</svg>

This could allow others to also interact with the SVG elements, like adding click handlers and whatnot. :)

LordMike avatar Nov 21 '22 16:11 LordMike