Skip to content

Instantly share code, notes, and snippets.

@pabloselin
Created April 16, 2018 21:38
Show Gist options
  • Save pabloselin/5b7631c7619d0f81d5e79939dfb09247 to your computer and use it in GitHub Desktop.
Save pabloselin/5b7631c7619d0f81d5e79939dfb09247 to your computer and use it in GitHub Desktop.
import React, { Component } from "react";
import DownloadButton from "./mini/DownloadButton.js";
import {
VictoryPie,
VictoryLegend,
VictorySharedEvents,
VictoryLabel,
VictoryContainer,
VictoryGroup,
Point
} from "victory";
class Pie extends Component {
constructor(props) {
super(props);
this.state = {
data: this.props.data.data,
title: this.props.data.chart_title,
subtitle: this.props.data.chart_subtitle,
currentPercent: 0,
activeColor: this.props.theme.interactions.active,
clicked: false,
activeKey: undefined,
svgrefs: []
};
}
makeLegend(data) {
let sum = 0;
data.map(item => {
sum += Number(item.y);
return true;
});
let legData = data.map((item, idx) => {
let percent = Number(item.y) / sum * 100;
let activeStyle = () => {
if (idx === Number(this.state.activeKey)) {
return {
fill: this.state.activeColor,
fontWeight: "bold",
fontSize: 20,
fontColor: this.state.activeColor
};
} else {
return {
fill: this.props.colorscale[idx],
fontWeight: "normal",
fontColor: "#555"
};
}
};
return {
name: item.x,
percent: percent.toFixed(1),
symbol: { fill: activeStyle().fill },
labels: {
fontWeight: activeStyle().fontWeight,
fontSize: activeStyle().fontSize,
fill: activeStyle().fontColor
}
};
});
return legData;
}
getData(data) {
return data;
}
componentDidMount() {
this.setState({
svgrefs: [this.viewBox, this.legendref]
});
}
render() {
const percentPortal = () => {
if (this.state.currentPercent !== 0) {
return this.state.currentPercent + "%";
}
};
const piecolor = key => {
if (Number(this.state.activeKey) === key) {
return this.state.activeColor;
} else {
return this.props.colorscale[key];
}
};
const clicked = key => {
if (
this.state.clicked === true &&
Number(this.state.activeKey) === Number(key)
) {
return false;
} else {
return true;
}
};
return (
<div className="Pie chart-widget">
<div style={{ padding: "5px" }}>
<p
style={{
fontFamily: "Asap",
fontSize: 14,
display: "block",
margin: 0
}}
>
{this.state.title.toUpperCase()}
</p>
<p
style={{
margin: 0,
fontFamily: "Asap",
fontSize: 12,
fontWeight: "normal",
display: "block"
}}
>
{this.state.subtitle}
</p>
</div>
<VictorySharedEvents
className="pieWrapper"
events={[
{
childName: ["pie", "legend"],
target: "data",
eventHandlers: {
onMouseOver: (evt, obj, key) => {
if (this.state.clicked === false) {
return [
{
childName: ["pie", "legend"],
mutation: props => {
this.setState({
currentPercent:
props.datum.percent,
activeKey: key
});
}
}
];
}
},
onMouseOut: () => {
if (this.state.clicked === false) {
return [
{
childName: ["pie", "legend"],
mutation: () => {
this.setState({
currentPercent: 0,
activeKey: undefined
});
return null;
}
}
];
}
},
onClick: (evt, obj, key) => {
return [
{
childName: ["pie", "legend"],
mutation: props => {
this.setState({
currentPercent:
props.datum.percent,
clicked: clicked(key),
activeKey: Number(key)
});
}
}
];
}
}
}
]}
>
<div
style={{
display: "flex",
flexWrap: "wrap"
}}
>
<VictoryGroup
style={{
parent: { maxWidth: "65%", marginTop: 12 }
}}
>
<svg viewBox={"0 0 400 400"}>
<VictoryPie
ref={Pie => (this.Pie = Pie)}
theme={this.props.theme}
name="pie"
style={{
data: {
fill: d => piecolor(d.eventKey)
}
}}
padAngle={0}
innerRadius={85}
data={this.getData(this.state.data)}
standalone={false}
labels={d => ""}
containerComponent={
<VictoryContainer
containerRef={pieref =>
(this.pieref = pieref)
}
/>
}
/>
<VictoryLabel
className="percent"
theme={this.props.theme}
animate={{ duration: 500 }}
text={percentPortal()}
textAnchor="middle"
verticalAnchor="middle"
x={200}
y={200}
style={{
fontSize: 42,
fill: this.state.activeColor,
fontFamily: "Asap",
fontWeight: "bold"
}}
ref={percent => (this.percent = percent)}
/>
</svg>
</VictoryGroup>
<VictoryLegend
theme={this.props.theme}
name="legend"
centerTitle
orientation="vertical"
borderPadding={{ top: 40 }}
width={300}
height={450}
rowGutter={-15}
style={{
labels: {
fontFamily: "Asap",
fontSize: 20
},
parent: { maxWidth: "35%" }
}}
data={this.makeLegend(this.state.data)}
dataComponent={<Point size={10} />}
containerComponent={
<VictoryContainer
containerRef={legendref =>
(this.legendref = legendref)
}
/>
}
/>
</div>
</VictorySharedEvents>
<DownloadButton
type="pie"
data={this.props.data}
fields={[
{ label: "Tipo", value: "x" },
{ label: "Porcentaje", value: "y" }
]}
unwind={["data"]}
/>
</div>
);
}
}
export default Pie;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment