(function() {
const colors = {
white: "#ffffff",
navy: "#202565",
blue: "#4a56ee",
red: "#d76645",
yellow: "#f0a742",
purple: "#aeb1fd",
indicatoHighlight: "#626693",
indicatoInitial: "#363a74",
};
const content = {
heading: "Measuring progress towards a bolder Canadian future.",
"fa-c-1": {
heading: "Growing to 100 million",
subHeading: `A bigger Canada is a bolder Canada. With 100 million people, we will have the skills, ingenuity and drive to build a tax base and economy that can sustain our quality of life and grow our influence.`,
link: "/scorecard/growing-to-100-million",
},
"ind-c-0": {
link: "/scorecard/growing-to-100-million?detailsId=population-growth",
},
"ind-c-1": {
link: "/scorecard/growing-to-100-million?detailsId=immigrant-admissions",
},
"ind-c-2": {
link: "/scorecard/growing-to-100-million?detailsId=fertility-rate",
},
"ind-c-3": {
link: "/scorecard/growing-to-100-million?detailsId=life-expectancy",
},
"ind-c-4": {
link: "/scorecard/immigration?detailsId=global-reputation",
},
"fa-c-2": {
heading: "Immigration",
subHeading: `New Canadians bring their drive, their grit and their ingenuity to meet Canada's labour market needs, catalyze innovation in our economy and strengthen the fabric of our society.`,
link: "/scorecard/immigration",
},
"ind-c-5": {
link: "/scorecard/immigration?detailsId=public-support-for-immigration",
},
"ind-c-6": {
link: "/scorecard/immigration?detailsId=provincial-retention-of-immigrants",
},
"ind-c-7": {
link: "/scorecard/immigration?detailsId=migrant-integration-policy",
},
"ind-c-8": {
link: "/scorecard/immigration?detailsId=immigrant-income-gap",
},
"ind-c-9": {
link: "/scorecard/immigration?detailsId=international-students-transitioning",
},
"ind-c-10": {
link: "/scorecard/immigration?detailsId=temporary-foreign-workers",
},
"fa-c-3": {
heading: "Economy, innovation and entrepreneurship",
subHeading: `The modern economy rewards innovation, creativity and the willingness to build something new. This is a critical foundation for sustainable and shared prosperity.`,
link: "/scorecard/economy-innovation-entrepreneurship",
},
"ind-c-11": {
link: "/scorecard/economy-innovation-entrepreneurship?detailsId=early-stage-entrepreneurship",
},
"ind-c-12": {
link: "/scorecard/economy-innovation-entrepreneurship?detailsId=business-spending-on-rd",
},
"ind-c-13": {
link: "/scorecard/economy-innovation-entrepreneurship?detailsId=innovation",
},
"ind-c-14": {
link: "/scorecard/economy-innovation-entrepreneurship?detailsId=productivity",
},
"ind-c-15": {
link: "/scorecard/economy-innovation-entrepreneurship?detailsId=business-growth",
},
"ind-c-16": {
link: "/scorecard/economy-innovation-entrepreneurship?detailsId=diversity",
},
"ind-c-17": {
link: "/scorecard/economy-innovation-entrepreneurship?detailsId=strength-of-indigenous-economy",
},
"ind-c-18": {
link: "/scorecard/economy-innovation-entrepreneurship?detailsId=gdp-per-capita",
},
"ind-c-19": {
link: "/scorecard/economy-innovation-entrepreneurship?detailsId=household-debt",
},
"ind-c-20": {
link: "/scorecard/economy-innovation-entrepreneurship?detailsId=income-inequality",
},
"ind-c-21": {
link: "/scorecard/economy-innovation-entrepreneurship?detailsId=global-competitiveness",
},
"fa-c-4": {
heading: "Education skills & employment",
subHeading: `Canadians need the skills that tomorrow's economy requires if Canada is to compete and prosper. And they need to be able to use them. This means high-performing education and training systems, supports for lifelong learning, and creating good jobs.`,
link: "/scorecard/education-skills-employment",
},
"ind-c-22": {
link: "/scorecard/education-skills-employment?detailsId=performance-in-reading",
},
"ind-c-23": {
link: "/scorecard/education-skills-employment?detailsId=post-secondary-attainment",
},
"ind-c-24": {
link: "/scorecard/education-skills-employment?detailsId=youth-not-in-employment",
},
"ind-c-25": {
link: "/scorecard/education-skills-employment?detailsId=participation-in-adult-learning",
},
"ind-c-26": {
link: "/scorecard/education-skills-employment?detailsId=employment-rate",
},
"ind-c-27": {
link: "/scorecard/education-skills-employment?detailsId=low-wage-work",
},
"fa-c-5": {
heading: "Support for children and families",
subHeading: `A growing Canada means supports for Canadian families who choose to have children. Robust family supports mean more people working, more jobs, and more economic growth.`,
link: "/scorecard/support-for-children-and-families",
},
"ind-c-28": {
link: "/scorecard/support-for-children-and-families?detailsId=child-care",
},
"ind-c-29": {
link: "/scorecard/support-for-children-and-families?detailsId=parental-leave",
},
"ind-c-30": {
link: "/scorecard/support-for-children-and-families?detailsId=employment-rate-for-mothers",
},
"ind-c-31": {
link: "/scorecard/support-for-children-and-families?detailsId=child-poverty",
},
"ind-c-32": {
link: "/scorecard/support-for-children-and-families?detailsId=youth-well-being",
},
"fa-c-6": {
heading: "Infrastructure and environment",
subHeading: `A bigger and bolder future for Canada requires infrastructure to support it. It must keep pace with a growing population and be resilient to climate change.`,
link: "/scorecard/infrastructure-and-environment",
},
"ind-c-33": {
link: "/scorecard/infrastructure-and-environment?detailsId=investment-in-infrastructure",
},
"ind-c-34": {
link: "/scorecard/infrastructure-and-environment?detailsId=housing-affordability",
},
"ind-c-35": {
link: "/scorecard/infrastructure-and-environment?detailsId=rural-broadband-coverage",
},
"ind-c-36": {
link: "/scorecard/infrastructure-and-environment?detailsId=population-density",
},
"ind-c-37": {
link: "/scorecard/infrastructure-and-environment?detailsId=climate-change-performance",
},
"ind-c-38": {
link: "/scorecard/infrastructure-and-environment?detailsId=resilience",
},
"fa-c-7": {
heading: "Growing well",
subHeading: `Population growth must be environmentally sustainable; and the benefits of growth must be broadly shared by all Canadians.`,
link: "/scorecard/growing-well",
},
"ind-c-39": {
link: "/scorecard/growing-well??detailsId=freedom",
},
"ind-c-40": {
link: "/scorecard/growing-well??detailsId=social-progress",
},
[colors.blue]: {
id: "leading",
el: document.getElementById("leading"),
},
[colors.purple]: {
id: "on-track",
el: document.getElementById("on-track"),
},
[colors.yellow]: {
id: "needs-attention",
el: document.getElementById("needs-attention"),
},
[colors.red]: {
id: "falling-behind",
el: document.getElementById("falling-behind"),
},
};
const defs = ``;
const clickedWheel = localStorage.getItem("clickedWheel");
const overlay = clickedWheel
? ""
: `
`;
const svg =
window.innerWidth < 800
? ` ${overlay}`
: // WHEEL ON LARGE SCREENS
//this is the overarching SVG the clicked wheel terninary is to see if there's a blur overlaying
`
${overlay}
`;
// JS BEGINS
const wheelContainer = document.getElementById(
window.innerWidth < 800 ? "mobile-wheel" : "wheel-container"
);
const scoreWrap = document.getElementById("score-wrap");
const buttonWrap = document.getElementById("button-wrap");
wheelContainer.innerHTML = svg;
//this animates the wheel in over time
wheelContainer.animate(
[
{ transform: "scale(0)", opacity: 0 },
{ transform: "scale(0.2)" },
{ transform: "scale(0.4)" },
{ transform: "scale(0.6)" },
{ transform: "scale(0.8)" },
{ transform: "scale(1)", opacity: 1 },
{ transform: "scale(1.05)" },
{ transform: "scale(1)" },
],
1000
);
const heading = document.getElementById("heading");
const subHeading = document.getElementById("sub-heading");
const leftContent = document.getElementById("leftContent");
const filteringTypes = {
INDICATOR: "INDICATOR",
FOCUSAREA: "FOCUSAREA",
RATE: "RATE",
};
let lastFilteringType = "";
//this is to fade things in on the left side
function fadeInUp(el) {
el.animate(
[
{ opacity: 0, transform: "translateY(50px)" },
{ opacity: 1, transform: "translateY(0px)" },
],
500
);
}
//functions to set headings
function setHeading(text) {
heading.innerHTML = text;
}
function setSubHeading(text) {
subHeading.innerHTML = text;
}
setHeading(content.heading);
fadeInUp(leftContent);
//function to set the left subhead text
function setIndicatorText(color) {
let t = "";
if (colors.yellow === color)
t = `This indicator needs attention, but Canada could still meet its target in future years with intervention and support.`;
if (colors.purple === color)
t = `Canada is on track to meet the target for this indicator or has already achieved the set target. `;
if (colors.red === color)
t = `Canada is falling behind on this indicator compared to similar countries, or failing to meet its target. Significant work is needed.`;
if (colors.blue === color)
t = `Canada is leading on this indicator, either ranking among the best internationally or performing well against national goals.`;
setSubHeading(t);
}
if (clickedWheel) {
heading.style.transition = "none";
scoreWrap.style.transition = "none";
scoreWrap.style.opacity = 1;
scoreWrap.style.maxHeight = window.innerWidth < 800 ? "780px" : "500px";
heading.style.fontSize = window.innerWidth < 800 ? "28px" : "32px";
}
setTimeout(function () {
const focusAreas = [1, 2, 3, 4, 5, 6].map((i) =>
document.getElementById(`fa-c-${i}`)
);
const indicators = [0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
].map((i) => document.getElementById(`ind-c-${i}`));
//if you have not clicked the wheel
if (!clickedWheel) {
const overlayElem = document.getElementsByClassName("overlay")[0];
//add a click listener to the overlay element
overlayElem.addEventListener("click", function () {
heading.style.transition = "none";
localStorage.setItem("clickedWheel", true);
this.style.display = "none";
this.previousElementSibling.style.filter = "";
scoreWrap.style.maxHeight = window.innerWidth < 800 ? "600px" : "500px";
scoreWrap.style.opacity = 1;
heading.style.fontSize = window.innerWidth < 800 ? "28px" : "32px";
if (window.innerWidth < 800) scoreWrap.style.paddingBottom = "40px";
fadeInUp(leftContent);
});
}
//functio for checking active status
function isActive(el) {
return el.getAttribute("data-active") === "true";
}
//function for highlighting indicators, you pass in the first and last index yo want highlighted
function highlightIndicators(firstIndex, lastIndex) {
//if there is a last index
if (lastIndex)
//loop through the indexes
for (let i = firstIndex; i <= lastIndex; i++) {
// get the current fill
const currentFill = indicators[i].getAttribute("fill");
//if the currentFill does not equal the initial indicator and the highlight
if (
currentFill !== colors.indicatoInitial &&
currentFill !== colors.indicatoHighlight
)
continue;
// set the fill attirbute to the highlight
indicators[i].setAttribute("fill", colors.indicatoHighlight);
}
else {
indicators[firstIndex].setAttribute("fill", colors.indicatoHighlight);
}
}
//the highlightFocusArea function takes in an element, it sets that elements fill to white, then finds sibling elements, loops
function highlightFocusArea(el) {
el.setAttribute("fill", colors.white);
const texts = el.nextElementSibling.getElementsByTagName("path");
for (let i = 0; i < texts.length; i++)
texts[i].setAttribute("fill", colors.navy);
highlightIndicators(
parseInt(el.getAttribute("data-first-ind")),
parseInt(el.getAttribute("data-last-ind"))
);
}
function toggleIndicators(active, firstIndex, lastIndex, color) {
for (let i = firstIndex; i <= lastIndex; i++) {
const indicator = indicators[i];
const activeFill = indicator.getAttribute("data-active-fill");
// set each indicator
// if a color was passed
// if the slice is active set it to activeFill otherwise set it to colors.indicatoHighlight
indicator.setAttribute(
"fill",
color || (active ? activeFill : colors.indicatoHighlight)
);
// ADDED CODE
if (active && activeFill !== "#4a56ee") {
const sliceTextVectors = indicators[i].nextElementSibling.getElementsByTagName("path");
for (let i = 0; i < sliceTextVectors.length; i++) {
sliceTextVectors[i].setAttribute("fill", colors.navy);
}
}
const sliceTextVectors = indicators[i].nextElementSibling.getElementsByTagName("path");
if (!active) {
for (let i = 0; i < sliceTextVectors.length; i++) {
sliceTextVectors[i].setAttribute("fill", "white");
}
} else {
for (let i = 0; i < sliceTextVectors.length; i++) {
// sliceTextVectors[i].setAttribute("fill", "white");
}
}
// ADDED CODE
}
}
function toggleFocusArea(
el,
newActive = isActive(el) ? null : true,
indicatorColor
) {
//If active, get the currently clicked attribute by the ID and set the heading/subheading and reruns the fade in animation
//it also displays the button when appropriate
if (newActive) {
const cont = content[el.getAttribute("id")];
setHeading(cont.heading);
setSubHeading(cont.subHeading);
buttonWrap.style.display = "block";
buttonWrap.firstElementChild.setAttribute("href", cont.link);
fadeInUp(leftContent);
}
//set the data-active attribute to the new active variable
el.setAttribute("data-active", newActive);
if (newActive) highlightFocusArea(el);
else unhighlightFocusArea(el);
toggleIndicators(
newActive,
parseInt(el.getAttribute("data-first-ind")),
parseInt(el.getAttribute("data-last-ind")),
indicatorColor
);
}
function unhighlightIndicators(firstIndex, lastIndex) {
if (lastIndex) {
for (let i = firstIndex; i <= lastIndex; i++) {
const currentFill = indicators[i].getAttribute("fill");
if (
currentFill !== colors.indicatoInitial &&
currentFill !== colors.indicatoHighlight
)
continue;
indicators[i].setAttribute("fill", colors.indicatoInitial);
const sliceTextVectors = indicators[i].nextElementSibling.getElementsByTagName("path");
for (let i = 0; i < sliceTextVectors.length; i++) {
sliceTextVectors[i].setAttribute("fill", "white");
}
}
} else {
indicators[firstIndex].setAttribute("fill", colors.indicatoInitial);
}
}
function unhighlightFocusArea(el) {
el.setAttribute("fill", colors.indicatoHighlight);
const texts = el.nextElementSibling.getElementsByTagName("path");
for (let i = 0; i < texts.length; i++)
texts[i].setAttribute("fill", colors.white);
// here
unhighlightIndicators(
parseInt(el.getAttribute("data-first-ind")),
parseInt(el.getAttribute("data-last-ind"))
);
}
//when the page loads loop through the focus areas
focusAreas.forEach((elem) => {
//add an event listener for mouseOvers
//add the highlight color if the element does not already have an active state
elem.addEventListener("mouseenter", function () {
if (isActive(this)) return;
highlightFocusArea(this);
});
//add a click event listener
//if it's already clicked do nothing
//if the last filtering type is different from the current filteringtype
//reset the wheel and set the last filtering type to the current filtering type
// then run the toggleFocusArea function, which
elem.addEventListener("click", function () {
if (isActive(this)) return;
if (lastFilteringType !== filteringTypes.FOCUSAREA) {
resetWheel();
lastFilteringType = filteringTypes.FOCUSAREA;
}
toggleFocusArea(this);
resetButtons();
});
elem.addEventListener("mouseleave", function () {
if (isActive(this)) return;
unhighlightFocusArea(this);
});
});
function resetButtons() {
["blue", "red", "yellow", "purple"].forEach((color) => {
const className = content[colors[color]].el
.getAttribute("class")
.replace("active", "");
content[colors[color]].el.setAttribute("class", className);
});
scoreWrap.setAttribute("class", "");
}
function resetIndicators() {
indicators.forEach((indicator, i) => {
indicator.setAttribute("fill", colors.indicatoInitial);
const sliceTextVectors = indicators[i].nextElementSibling.getElementsByTagName("path");
for (let i = 0; i < sliceTextVectors.length; i++) {
sliceTextVectors[i].setAttribute("fill", "white");
}
});
}
function resetFocusAreas() {
focusAreas.forEach((el) => {
unhighlightFocusArea(el);
el.setAttribute("data-active", false);
});
}
function resetWheel() {
resetButtons();
buttonWrap.style.display = "none";
subHeading.innerText = "";
setHeading(content.heading);
for (let i = 0; i < focusAreas.length; i++) {
const focusArea = focusAreas[i];
toggleFocusArea(focusArea, false, colors.indicatoInitial);
}
fadeInUp(leftContent);
}
indicators.forEach((elem, i) => {
elem.addEventListener("mouseenter", function () {
if (this.getAttribute("fill").toLowerCase() !== colors.indicatoInitial)
return;
highlightIndicators(i);
});
elem.addEventListener("click", function () {
if (lastFilteringType !== filteringTypes.INDICATOR) {
lastFilteringType = filteringTypes.INDICATOR;
}
resetFocusAreas();
resetIndicators();
resetButtons();
const activeFill = this.getAttribute("data-active-fill").toLowerCase();
this.setAttribute("fill", activeFill);
const sliceTextVectors = this.nextElementSibling.getElementsByTagName("path");
for (let i = 0; i < sliceTextVectors.length; i++) {
if (activeFill !== "#4a56ee") {
sliceTextVectors[i].setAttribute("fill", "black");
} else {
sliceTextVectors[i].setAttribute("fill", "white");
}
}
buttonWrap.style.display = "block";
const id = this.getAttribute("id");
buttonWrap.firstElementChild.setAttribute("href", content[id].link);
setHeading(this.getAttribute("data-name"));
setIndicatorText(activeFill);
fadeInUp(leftContent);
});
elem.addEventListener("mouseleave", function () {
if (this.getAttribute("fill") !== colors.indicatoHighlight) return;
unhighlightIndicators(i);
});
});
document.getElementById("reset-btn").addEventListener("click", resetWheel);
["leading", "on-track", "needs-attention", "falling-behind"].forEach((id) => {
const el = document.getElementById(id);
el.addEventListener("click", function () {
if (lastFilteringType !== filteringTypes.RATE) {
resetWheel();
lastFilteringType = filteringTypes.RATE;
}
const className = this.getAttribute("class") || "";
const active = className.includes("active");
const newActive = !active;
const newClassName = active
? className.replace("active", "")
: className + " active";
this.setAttribute("class", newClassName);
const colorMap = {
leading: colors.blue,
"on-track": colors.purple,
"needs-attention": colors.yellow,
"falling-behind": colors.red,
};
const buttonFill = colorMap[id];
setHeading(content.heading);
subHeading.innerHTML = "";
buttonWrap.style.display = "none";
indicators.forEach((indicator, i) => {
const sliceTextVectors = indicator.nextElementSibling.getElementsByTagName("path");
const indActiveFill = indicator
.getAttribute("data-active-fill")
.toLowerCase();
if (indActiveFill === buttonFill) {
indicator.setAttribute(
"fill",
newActive ? buttonFill : colors.indicatoInitial
);
for (let i = 0; i < sliceTextVectors.length; i++) {
if (indActiveFill !== "#4a56ee") {
sliceTextVectors[i].setAttribute("fill", newActive ? "black" : "white");
} else {
sliceTextVectors[i].setAttribute("fill", newActive ? "white" : "white");
}
}
}
});
const scoreClassName = scoreWrap.getAttribute("class") || "";
const currentActive = scoreClassName.includes("active");
if (newActive && !currentActive)
scoreWrap.setAttribute("class", scoreClassName + " active");
else if (currentActive && !newActive) {
if (!document.querySelector(".button-container.active"))
scoreWrap.setAttribute("class", "");
}
if (newActive)
scoreWrap.setAttribute("class", scoreClassName + " active");
});
});
}, 500);
})()