Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drewkiimon/0aadfe943ee344e0bbffc8434ff0f6e2 to your computer and use it in GitHub Desktop.
Save drewkiimon/0aadfe943ee344e0bbffc8434ff0f6e2 to your computer and use it in GitHub Desktop.
[Highcharts] Grouped Stacked Bar Chart v2
const testJSON = [
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Jumping",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Dividing Cups",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Add within 1000",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Represent multiplication on the number line",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Subtract within 1000",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Unit fractions on the number line",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Fractions on the number line",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Find 1 on the number line",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Dividing A lot of Cups",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Identify quadrilaterals",
"Current Skill Mastery Level": "Familiar"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Write numbers in different forms",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Jumping",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Dividing Cups",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Add within 1000",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Represent multiplication on the number line",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Subtract within 1000",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Unit fractions on the number line",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Fractions on the number line",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Find 1 on the number line",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Dividing A lot of Cups",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Round to nearest 10 or 100",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Jumping",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Dividing Cups",
"Current Skill Mastery Level": "Familiar"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Compare fractions with the same numerator or denominator",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Add within 1000",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Represent multiplication on the number line",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Subtract within 1000",
"Current Skill Mastery Level": "Proficient"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Unit fractions on the number line",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Fractions on the number line",
"Current Skill Mastery Level": "Mastered"
},
{
"School Name": "Oceana High School",
"Course Name": "Ready to Party",
"Skill Name": "Dividing A lot of Cups",
"Current Skill Mastery Level": "Familiar"
}
];
const formatDataForSeries = (data) => {
const courses = {};
const formattedData = [];
const returnedSkills = [];
const returnedCourses = [];
for (var i = 0; i <= data.length - 1; i++) {
const course = data[i]["Course Name"];
const skill = data[i]["Skill Name"];
const mastery = data[i]["Current Skill Mastery Level"];
if (!courses[course]) {
courses[course] = {};
returnedCourses.push(course);
}
if (!courses[course][skill]) {
courses[course][skill] = {};
returnedSkills.push(skill);
}
if (!courses[course][skill][mastery]) {
courses[course][skill][mastery] = 0;
}
courses[course][skill][mastery]++;
}
const courseNames = Object.keys(courses);
const helper = {};
for (var i = 0; i <= courseNames.length - 1; i++) {
let c = courseNames[i];
let skills = Object.keys(courses[c]);
console.log(c, skills);
for (var j = 0; j <= skills.length - 1; j++) {
let s = skills[j];
let coolData = courses[c][s];
let levels = Object.keys(coolData);
if (!helper["Mastered"]) {
helper["Mastered"] = {
name: "Mastered",
data: [],
color: "#808080"
};
}
if (!helper["Familiar"]) {
helper["Familiar"] = {
name: "Familiar",
data: [],
color: "#D3D3D3"
};
}
if (!helper["Proficient"]) {
helper["Proficient"] = {
name: "Proficient",
data: [],
color: "#A9A9A9"
};
}
if (!helper["Attempted this skill"]) {
helper["Attempted this skill"] = {
name: "Attempted this skill",
data: [],
color: "#F5F5F5"
};
}
helper["Mastered"].data.push(coolData["Mastered"] || 0);
helper["Familiar"].data.push(coolData["Familiar"] || 0);
helper["Proficient"].data.push(coolData["Proficient"] || 0);
helper["Attempted this skill"].data.push(
coolData["Attempted this skill"] || 0
);
}
}
console.log(helper);
console.log(courses);
return [returnedCourses, returnedSkills, Object.values(helper)];
};
const [courses, skills, data] = formatDataForSeries(testJSON);
console.log(courses, skills, data);
// const skills = [
// "Algebra",
// "Chemistry",
// "Programming",
// "How to Smile",
// "How to listen",
// "Fib Numbers"
// ];
const images = [
"https://i.pinimg.com/originals/24/73/d9/2473d94cb7d607b461ecece38a0100bf.jpg",
"https://i.ibb.co/b3wVNYP/graph.png",
"https://tests4geeks.com/content/img/smp/java-programming-test-answer-1.png",
"https://smb.ibsrv.net/imageresizer/image/blog_images/1200x1200/59846/176287/0044181001582748537.jpg",
"https://www.incimages.com/uploaded_files/image/1920x1080/getty_464672063_2000160020009280233_339359.jpg",
"https://math.temple.edu/~reich/Fib/fibfamily.gif"
];
const chart = Highcharts.chart("container", {
chart: {
type: "column",
animation: false,
backgroundColor: "#f7f8fa",
events: {
load: function () {
const bands = document.getElementsByClassName("highcharts-plot-band");
for (var i = 0; i <= bands.length - 1; i++) {
let band = bands[i];
let bandElements = band.getBoundingClientRect();
let bandWidth = bandElements.width;
const bandLabel = document.getElementById("band" + (i + 1));
bandLabel.style.width = bandWidth - 16 + "px";
}
},
redraw: function () {
const bands = document.getElementsByClassName("highcharts-plot-band");
for (var i = 0; i <= bands.length - 1; i++) {
let band = bands[i];
let bandElements = band.getBoundingClientRect();
let bandWidth = bandElements.width;
const bandLabel = document.getElementById("band" + (i + 1));
bandLabel.style.width = bandWidth - 16 + "px";
}
}
}
},
credits: { enabled: false },
title: {
text: ""
},
tooltip: {
backgroundColor: null,
borderWidth: 0,
hideDelay: 100,
shadow: false,
useHTML: true,
outside: true,
// positioner: function (_, _, point) {
// console.log(this);
// console.log(point);
// },
formatter: function () {
const masteryLevel = this.series.name;
const { color } = this.point;
return `
<span class="tooltip-header">${skills[this.x]}</span><br/>
<span class="tooltip-subheader">Identifying coordinates</span><br/>
<div class="tooltip-info">
<div class="tooltip-box" style="background-color: ${color}"></div><span class="tooltip-category">${masteryLevel}</span>: <span class="tooltip-value">${
this.y
}</span>
</div>
<img class="tooltip-image" src="${images[this.x]}" alt="graph image"/>
`;
},
style: {
padding: 0
}
},
plotOptions: {
column: {
groupPadding: 0,
pointPadding: 0.15,
borderWidth: 0,
stacking: "normal",
states: {
inactive: {
enabled: false
},
hover: {
color: "#1865F2"
}
}
},
series: {
pointWidth: 26
}
},
legend: {
align: "right",
verticalAlign: "top",
layout: "vertical",
title: { text: "MASTERY LEVELS" },
backgroundColor: "white",
padding: 20,
x: -50,
y: 0,
symbolPadding: 15,
symbolRadius: 2,
itemMarginBottom: 8,
borderColor: "lightgray",
borderWidth: 1,
borderRadius: 2,
shadow: true
},
xAxis: {
title: {
text: "UNITS",
align: "right"
},
labels: {
enabled: false
},
plotLines: [
{
color: "black",
width: 1,
value: 2.5,
dashStyle: "ShortDot",
zIndex: 10
},
{
color: "black",
width: 1,
value: 4.5,
dashStyle: "ShortDot",
zIndex: 10
}
],
plotBands: [
{
borderWidth: 1,
from: -0.5,
to: 2.5,
color: "#f7f8fa",
label: {
align: "left",
text:
"<div id='band1' class='band'><b>SYSTEM OF EQUATIONS</b><br/><span>4 Skills</span></div>",
useHTML: true,
verticalAlign: "bottom"
}
},
{
borderWidth: 1,
from: 2.5,
to: 4.5,
color: "#f7f8fa",
label: {
align: "left",
text:
"<div id='band2' class='band'><b>FUNCTIONS</b><br/><span>2 Skills</span></div>",
useHTML: true,
verticalAlign: "bottom"
}
},
{
borderWidth: 1,
from: 4.5,
to: 5.5,
color: "#f7f8fa",
label: {
align: "left",
text:
"<div id='band3' class='band'><b>SEQUENCES</b><br/><span>1 Skill</span></div>",
useHTML: true,
verticalAlign: "bottom"
}
}
],
tickWidth: 0
},
yAxis: {
title: { enabled: false },
allowDecimals: false,
// min: 2 * 10,
// max: 300 * 1.1, // gives some buffer at top
gridLineWidth: 0,
tickAmount: 13,
tickWidth: 1,
tickLength: 16,
offset: 20,
labels: {
align: "left",
x: 4,
y: 4
}
},
series: data
// [
// // ["Skill 1", ...]
// {
// name: "Mastered",
// data: [12, 8, 34, 32, 64, 72],
// color: "#808080"
// },
// {
// name: "Proficient",
// data: [95, 88, 30, 122, 25, 45],
// color: "#A9A9A9"
// },
// {
// name: "Familiar",
// data: [100, 80, 70, 111, 25, 13],
// color: "#D3D3D3"
// },
// {
// name: "Attempted this skill",
// data: [10, 22, 2, 48, 51, 66],
// color: "#F5F5F5"
// }
// ]
});
.highcharts-tooltip > span {
background: rgba(255, 255, 255, 0.85);
border: 1px solid silver;
border-radius: 3px;
box-shadow: 1px 1px 2px #888;
padding: 24px;
}
.tooltip-header {
font-family: Lato;
font-size: 12px;
font-style: normal;
font-weight: 700;
line-height: 16px;
letter-spacing: 0.6px;
text-align: left;
color: rgba(33, 36, 44, 0.64);
margin-bottom: 4px;
}
.tooltip-subheader {
font-family: Lato;
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 22px;
letter-spacing: 0em;
text-align: left;
color: background: rgba(0, 0, 0, 1);
margin-bottom: 8px;
}
.tooltip-info {
height: 8px;
border-bottom: 1px solid rgba(33, 36, 44, 0.16);
padding-bottom: 24px;
}
.tooltip-box {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 2px;
margin-right: 8px;
}
.tooltip-category {
font-family: Lato;
font-size: 12px;
font-style: normal;
font-weight: 700;
line-height: 16px;
letter-spacing: 0em;
text-align: left;
}
.tooltip-value {
font-family: Lato;
font-size: 12px;
font-style: normal;
font-weight: 400;
line-height: 16px;
letter-spacing: 0em;
text-align: left;
}
.tooltip-image {
max-width: 230px;
margin-top: 14px;
}
.band {
overflow: hidden;
text-overflow: ellipsis;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment