Skip to content

Commit a50dc16

Browse files
committed
Split the pie chart into two controlled by the toggle and colored like the other charts.
1 parent 5c74693 commit a50dc16

File tree

3 files changed

+143
-51
lines changed

3 files changed

+143
-51
lines changed

web-ui/src/helpers/colors.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// pSBC - Shade Blend Convert - Version 4.1 - 01/7/2021
2+
// https://github.com/PimpTrizkit/PJs/blob/master/pSBC.js
3+
4+
export const pSBC=(p,c0,c1,l)=>{
5+
let r,g,b,P,f,t,h,m=Math.round,a=typeof(c1)=="string";
6+
if(typeof(p)!="number"||p<-1||p>1||typeof(c0)!="string"||(c0[0]!='r'&&c0[0]!='#')||(c1&&!a))return null;
7+
h=c0.length>9,h=a?c1.length>9?true:c1=="c"?!h:false:h,f=pSBC.pSBCr(c0),P=p<0,t=c1&&c1!="c"?pSBC.pSBCr(c1):P?{r:0,g:0,b:0,a:-1}:{r:255,g:255,b:255,a:-1},p=P?p*-1:p,P=1-p;
8+
if(!f||!t)return null;
9+
if(l)r=m(P*f.r+p*t.r),g=m(P*f.g+p*t.g),b=m(P*f.b+p*t.b);
10+
else r=m((P*f.r**2+p*t.r**2)**0.5),g=m((P*f.g**2+p*t.g**2)**0.5),b=m((P*f.b**2+p*t.b**2)**0.5);
11+
a=f.a,t=t.a,f=a>=0||t>=0,a=f?a<0?t:t<0?a:a*P+t*p:0;
12+
if(h)return"rgb"+(f?"a(":"(")+r+","+g+","+b+(f?","+m(a*1000)/1000:"")+")";
13+
else return"#"+(4294967296+r*16777216+g*65536+b*256+(f?m(a*255):0)).toString(16).slice(1,f?undefined:-2)
14+
}
15+
16+
pSBC.pSBCr=(d)=>{
17+
const i=parseInt;
18+
let n=d.length,x={};
19+
if(n>9){
20+
const [r, g, b, a] = (d = d.split(','));
21+
n = d.length;
22+
if(n<3||n>4)return null;
23+
x.r=i(r[3]=="a"?r.slice(5):r.slice(4)),x.g=i(g),x.b=i(b),x.a=a?parseFloat(a):-1
24+
}else{
25+
if(n==8||n==6||n<4)return null;
26+
if(n<6)d="#"+d[1]+d[1]+d[2]+d[2]+d[3]+d[3]+(n>4?d[4]+d[4]:"");
27+
d=i(d.slice(1),16);
28+
if(n==9||n==5)x.r=d>>24&255,x.g=d>>16&255,x.b=d>>8&255,x.a=Math.round((d&255)/0.255)/1000;
29+
else x.r=d>>16,x.g=d>>8&255,x.b=d&255,x.a=-1
30+
}return x
31+
};

web-ui/src/helpers/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ export * from './datetime';
44
export * from './query-parameters';
55
export * from './sanitizehtml';
66
export * from './strings';
7+
export * from './colors';

web-ui/src/pages/PulseReportPage.jsx

Lines changed: 111 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
CartesianGrid,
88
Legend,
99
Pie,
10+
Cell,
1011
PieChart,
1112
ResponsiveContainer,
1213
Tooltip,
@@ -40,6 +41,7 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
4041
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
4142
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
4243

44+
import { pSBC } from '../helpers/colors.js';
4345
import { getAvatarURL, resolve } from '../api/api.js';
4446
import MemberSelector from '../components/member_selector/MemberSelector';
4547
import { AppContext } from '../context/AppContext.jsx';
@@ -56,9 +58,8 @@ import './PulseReportPage.css';
5658
// Recharts doesn't support using CSS variables, so we can't
5759
// easily use color variables defined in variables.css.
5860
const ociDarkBlue = '#2c519e';
59-
const ociLightBlue = '#76c8d4';
60-
// const ociOrange = '#f8b576'; // too light
61-
const orange = '#b26801';
61+
//const ociLightBlue = '#76c8d4'; // not currently used
62+
const ociOrange = '#f8b576';
6263

6364
const ScoreOption = {
6465
INTERNAL: 'Internal',
@@ -121,7 +122,8 @@ const PulseReportPage = () => {
121122
const [selectedPulse, setSelectedPulse] = useState(null);
122123
const [showComments, setShowComments] = useState(false);
123124
const [teamMembers, setTeamMembers] = useState([]);
124-
const [pieChartData, setPieChartData] = useState([]);
125+
const [internalPieChartData, setInternalPieChartData] = useState([]);
126+
const [externalPieChartData, setExternalPieChartData] = useState([]);
125127

126128
/*
127129
// This generates random data to use in the line chart.
@@ -220,22 +222,37 @@ const PulseReportPage = () => {
220222
}
221223
}
222224

223-
let pieCounts = [
224-
{name: "veryDissatisfied", value: 0},
225-
{name: "dissatisfied", value: 0},
226-
{name: "neutral", value: 0},
227-
{name: "satisfied", value: 0},
228-
{name: "verySatisfied", value: 0},
225+
let internalPieCounts = [
226+
{name: "internalVeryDissatisfied", value: 0},
227+
{name: "internalDissatisfied", value: 0},
228+
{name: "internalNeutral", value: 0},
229+
{name: "internalSatisfied", value: 0},
230+
{name: "internalVerySatisfied", value: 0},
229231
];
230232
for(let day of scoreChartDataPoints) {
231233
day.datapoints.forEach(datapoint => {
232-
pieCounts[datapoint.internalScore - 1].value++;
233-
pieCounts[datapoint.externalScore - 1].value++;
234+
internalPieCounts[datapoint.internalScore - 1].value++;
234235
});
235236
}
236237
// Filter out data with a zero value so that the pie chart does not attempt
237238
// to display them.
238-
setPieChartData(pieCounts.filter((p) => p.value != 0));
239+
setInternalPieChartData(internalPieCounts.filter((p) => p.value != 0));
240+
241+
let externalPieCounts = [
242+
{name: "externalVeryDissatisfied", value: 0},
243+
{name: "externalDissatisfied", value: 0},
244+
{name: "externalNeutral", value: 0},
245+
{name: "externalSatisfied", value: 0},
246+
{name: "externalVerySatisfied", value: 0},
247+
];
248+
for(let day of scoreChartDataPoints) {
249+
day.datapoints.forEach(datapoint => {
250+
externalPieCounts[datapoint.externalScore - 1].value++;
251+
});
252+
}
253+
// Filter out data with a zero value so that the pie chart does not attempt
254+
// to display them.
255+
setExternalPieChartData(externalPieCounts.filter((p) => p.value != 0));
239256

240257
setScoreChartData(scoreChartDataPoints.map(day => {
241258
const iScores = {};
@@ -402,7 +419,7 @@ const PulseReportPage = () => {
402419
{(scoreType == ScoreOption.COMBINED || scoreType == ScoreOption.EXTERNAL) &&
403420
<Bar
404421
dataKey="external"
405-
fill={orange}
422+
fill={ociOrange}
406423
name={ScoreOptionLabel[ScoreOption.EXTERNAL]}
407424
/>
408425
}
@@ -448,16 +465,16 @@ const PulseReportPage = () => {
448465
};
449466

450467
const dataInfo = [
451-
{key: "internalVeryDissatisfied", stackId: "internal", color: "#273e58", },
452-
{key: "internalDissatisfied", stackId: "internal", color: "#1a3c6d", },
453-
{key: "internalNeutral", stackId: "internal", color: "#2c519e", },
454-
{key: "internalSatisfied", stackId: "internal", color: "#4b7ac7", },
455-
{key: "internalVerySatisfied", stackId: "internal", color: "#6fa3e6", },
456-
{key: "externalVeryDissatisfied", stackId: "external", color: "#704401", },
457-
{key: "externalDissatisfied", stackId: "external", color: "#8a5200", },
458-
{key: "externalNeutral", stackId: "external", color: "#b26801", },
459-
{key: "externalSatisfied", stackId: "external", color: "#d48a2c", },
460-
{key: "externalVerySatisfied", stackId: "external", color: "#e0a456", },
468+
{key: "internalVeryDissatisfied", stackId: "internal", color: ociDarkBlue, },
469+
{key: "internalDissatisfied", stackId: "internal", color: pSBC(.05, ociDarkBlue), },
470+
{key: "internalNeutral", stackId: "internal", color: pSBC(.10, ociDarkBlue), },
471+
{key: "internalSatisfied", stackId: "internal", color: pSBC(.15, ociDarkBlue), },
472+
{key: "internalVerySatisfied", stackId: "internal", color: pSBC(.2, ociDarkBlue), },
473+
{key: "externalVeryDissatisfied", stackId: "external", color: pSBC(-.8, ociOrange), },
474+
{key: "externalDissatisfied", stackId: "external", color: pSBC(-.6, ociOrange), },
475+
{key: "externalNeutral", stackId: "external", color: pSBC(-.4, ociOrange), },
476+
{key: "externalSatisfied", stackId: "external", color: pSBC(-.2, ociOrange), },
477+
{key: "externalVerySatisfied", stackId: "external", color: ociOrange, },
461478
];
462479

463480
const labelToSentiment = (label) => {
@@ -518,8 +535,8 @@ const PulseReportPage = () => {
518535
);
519536
};
520537

521-
const pulseScoresTitle = () => {
522-
let title = "Pulse scores for";
538+
const sectionTitle = (prefix) => {
539+
let title = `${prefix} for`;
523540
if (scoreType == ScoreOption.COMBINED ||
524541
scoreType == ScoreOption.INTERNAL) {
525542
title += ` "${ScoreOptionLabel[ScoreOption.INTERNAL]}"`;
@@ -535,16 +552,16 @@ const PulseReportPage = () => {
535552
};
536553

537554
const pieLabelToSentiment = (label) => {
538-
switch(label.toLowerCase()) {
539-
case "verydissatisfied":
555+
switch(label.replace("internal", "").replace("external", "")) {
556+
case "VeryDissatisfied":
540557
return "😦";
541-
case "dissatisfied":
558+
case "Dissatisfied":
542559
return "🙁";
543-
case "neutral":
560+
case "Neutral":
544561
return "😐";
545-
case "satisfied":
562+
case "Satisfied":
546563
return "🙂";
547-
case "verysatisfied":
564+
case "VerySatisfied":
548565
return "😀";
549566
}
550567
return "ERROR";
@@ -589,19 +606,28 @@ const PulseReportPage = () => {
589606
if (active && payload && payload.length) {
590607
return (
591608
<div className="custom-tooltip">
592-
<p className="label">{titleWords(payload[0].name)} : {payload[0].value}</p>
609+
<p className="label">
610+
{titleWords(payload[0].name
611+
.replace("internal", "")
612+
.replace("external", ""))} : {payload[0].value}</p>
593613
</div>
594614
);
595615
}
596616

597617
return null;
598618
};
599619

620+
const pieSliceColor = (entry, index) => {
621+
return <Cell
622+
key={`cell-${index}`}
623+
fill={dataInfo.find((value) => value.key == entry.name).color} />;
624+
};
625+
600626
const pulseScoresChart = () => (
601627
<>
602628
<Card>
603629
<CardHeader
604-
title={pulseScoresTitle()}
630+
title={sectionTitle("Pulse Scores")}
605631
titleTypographyProps={{ variant: 'h5', component: 'h2' }}
606632
/>
607633
<CardContent>
@@ -642,26 +668,60 @@ const PulseReportPage = () => {
642668
</Card>
643669
<Card>
644670
<CardHeader
645-
title="Total Responses"
671+
title={sectionTitle("Total Responses")}
646672
titleTypographyProps={{ variant: 'h5', component: 'h2' }}
647673
/>
648674
<CardContent>
649-
<ResponsiveContainer width="100%" aspect={3.0}>
650-
<PieChart width={300} height={300}>
651-
<Tooltip
652-
wrapperStyle={{ color: "black", backgroundColor: "white", paddingLeft: "10px", paddingRight: "10px" }}
653-
content={<CustomPieTooltip />}
654-
/>
655-
<Pie
656-
data={pieChartData}
657-
dataKey="value"
658-
nameKey="name"
659-
fill={ociLightBlue}
660-
labelLine={false}
661-
label={renderPieLabel}
662-
/>
663-
</PieChart>
664-
</ResponsiveContainer>
675+
<div style={{ display: 'flex', justifyContent: 'center'}}>
676+
{(scoreType == ScoreOption.COMBINED ||
677+
scoreType == ScoreOption.INTERNAL) &&
678+
<div style={{ width: '50%'}}>
679+
<ResponsiveContainer width="100%" aspect={2.0}>
680+
<PieChart>
681+
<Tooltip
682+
wrapperStyle={{ color: "black", backgroundColor: "white",
683+
paddingLeft: "10px", paddingRight: "10px",
684+
zIndex: 2 }}
685+
content={<CustomPieTooltip />}
686+
/>
687+
<Pie
688+
data={internalPieChartData}
689+
dataKey="value"
690+
nameKey="name"
691+
labelLine={false}
692+
label={renderPieLabel}
693+
>
694+
{internalPieChartData.map(pieSliceColor)}
695+
</Pie>
696+
</PieChart>
697+
</ResponsiveContainer>
698+
</div>
699+
}
700+
{(scoreType == ScoreOption.COMBINED ||
701+
scoreType == ScoreOption.EXTERNAL) &&
702+
<div style={{ width: '50%'}}>
703+
<ResponsiveContainer width="100%" aspect={2.0}>
704+
<PieChart width="50%">
705+
<Tooltip
706+
wrapperStyle={{ color: "black", backgroundColor: "white",
707+
paddingLeft: "10px", paddingRight: "10px",
708+
zIndex: 2 }}
709+
content={<CustomPieTooltip />}
710+
/>
711+
<Pie
712+
data={externalPieChartData}
713+
dataKey="value"
714+
nameKey="name"
715+
labelLine={false}
716+
label={renderPieLabel}
717+
>
718+
{externalPieChartData.map(pieSliceColor)}
719+
</Pie>
720+
</PieChart>
721+
</ResponsiveContainer>
722+
</div>
723+
}
724+
</div>
665725
</CardContent>
666726
</Card>
667727
</>

0 commit comments

Comments
 (0)