1/** 2 * Logic for overview scorecards. 3 * 4 * @license BSD, see LICENSE.md 5 */ 6 7 8/** 9 * Presenter for the scorecards which show high level goal metrics on the overview tab. 10 */ 11class ScorecardPresenter { 12 /** 13 * Create a new scorecard presenter. 14 * 15 * @param targetDiv Div in which the scorecards are rendered. 16 * @param onGoalChange Callback if the user changes the highlighted goal metric. 17 * @param prefix Flag indicating if the plus / minus sign should be forced to be shown. 18 */ 19 constructor(targetDiv, onGoalChange, prefix) { 20 const self = this; 21 22 self._targetDiv = targetDiv; 23 self._onGoalChange = onGoalChange; 24 self._prefix = prefix; 25 self._tippyPrior = null; 26 27 self._targetDiv.querySelectorAll(".card").forEach((card) => { 28 card.addEventListener("click", () => { 29 card.querySelector(".overview-radio").checked = true; 30 self._onGoalChange(card.getAttribute("goal")); 31 }); 32 }); 33 } 34 35 /** 36 * Render the card or update it if already present. 37 * 38 * @param year Year for which the metrics are to be shown. 39 * @param goals The goal metric calculations. 40 * @param selectedGoal Goal currently highlighted by the user. 41 */ 42 render(year, goals, selectedGoal) { 43 const self = this; 44 45 if (self._tippyPrior === null) { 46 // eslint-disable-next-line no-undef 47 self._tippyPrior = tippy( 48 self._targetDiv.querySelectorAll(".info-target"), 49 ); 50 } 51 52 const updateYear = () => { 53 self._targetDiv.querySelector(".year").innerHTML = year; 54 }; 55 56 const updateBody = () => { 57 const setBody = (cardClass, value) => { 58 const valueRounded = Math.round(value * 10) / 10; 59 const prefix = self._prefix && valueRounded >= 0 ? "+" : ""; 60 const valueStr = prefix + valueRounded; 61 62 const target = self._getD3().select("#" + self._targetDiv.id) 63 .select("." + cardClass) 64 .select(".body"); 65 66 if (target.text() !== valueStr) { 67 target.text(valueStr); 68 target.style("opacity", 0) 69 .transition() 70 .duration(750) 71 .style("opacity", 1); 72 } 73 }; 74 75 setBody( 76 "mismanaged-waste-card", 77 goals.get("global").get("mismanagedWaste"), 78 ); 79 80 setBody( 81 "landfill-waste-card", 82 goals.get("global").get("landfillWaste"), 83 ); 84 85 setBody( 86 "incinerated-waste-card", 87 goals.get("global").get("incineratedWaste"), 88 ); 89 90 setBody( 91 "recycling-card", 92 goals.get("global").get("recycling"), 93 ); 94 95 setBody( 96 "ghg-card", 97 goals.get("global").get("ghg"), 98 ); 99 }; 100 101 const updateHighlight = () => { 102 self._targetDiv.querySelectorAll(".card").forEach((card) => { 103 if (card.getAttribute("goal") === selectedGoal) { 104 card.classList.add("active"); 105 card.querySelector(".overview-radio").checked = true; 106 } else { 107 card.classList.remove("active"); 108 card.querySelector(".overview-radio").checked = false; 109 } 110 }); 111 }; 112 113 updateYear(); 114 updateBody(); 115 updateHighlight(); 116 } 117 118 _getD3() { 119 const self = this; 120 // eslint-disable-next-line no-undef 121 return d3; 122 } 123} 124 125 126export {ScorecardPresenter};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.