@aclymatepackages/modules 1.0.25 → 1.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,27 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
require("core-js/modules/es.symbol.description.js");
|
|
4
4
|
require("core-js/modules/es.object.assign.js");
|
|
5
|
+
require("core-js/modules/es.weak-map.js");
|
|
5
6
|
Object.defineProperty(exports, "__esModule", {
|
|
6
7
|
value: true
|
|
7
8
|
});
|
|
8
9
|
exports.default = void 0;
|
|
9
10
|
require("core-js/modules/es.array.reduce.js");
|
|
10
|
-
require("core-js/modules/es.object.from-entries.js");
|
|
11
11
|
require("core-js/modules/web.dom-collections.iterator.js");
|
|
12
|
-
|
|
12
|
+
require("core-js/modules/es.object.from-entries.js");
|
|
13
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
13
14
|
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
14
|
-
var _dayOfYear = _interopRequireDefault(require("dayjs/plugin/dayOfYear"));
|
|
15
15
|
var _recharts = require("recharts");
|
|
16
16
|
var _material = require("@mui/material");
|
|
17
17
|
var _formatters = require("@aclymatepackages/formatters");
|
|
18
18
|
var _otherHelpers = require("@aclymatepackages/other-helpers");
|
|
19
|
-
var
|
|
20
|
-
var _useChartWarningLabels = _interopRequireDefault(require("./useChartWarningLabels"));
|
|
19
|
+
var _converters = require("@aclymatepackages/converters");
|
|
21
20
|
var _chartHelpers = require("@aclymatepackages/chart-helpers");
|
|
22
21
|
var _subcategories = require("@aclymatepackages/subcategories");
|
|
22
|
+
var _EmissionsCustomTooltip = _interopRequireDefault(require("./EmissionsCustomTooltip"));
|
|
23
|
+
var _useChartWarningLabels = _interopRequireDefault(require("./useChartWarningLabels"));
|
|
23
24
|
const _excluded = ["totalEmissionsSumTons"],
|
|
24
|
-
_excluded2 = ["
|
|
25
|
+
_excluded2 = ["viewBox", "labels", "setLabels", "label"],
|
|
26
|
+
_excluded3 = ["subcategory", "color"];
|
|
25
27
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
28
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
29
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
26
30
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
27
31
|
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
|
28
32
|
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
|
@@ -31,7 +35,6 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
31
35
|
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
32
36
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
|
|
33
37
|
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
34
|
-
_dayjs.default.extend(_dayOfYear.default);
|
|
35
38
|
const findObjectValuesSum = object => Object.values(object).reduce((sum, value) => sum + value, 0);
|
|
36
39
|
const buildGroupedChartData = _ref => {
|
|
37
40
|
let {
|
|
@@ -40,7 +43,7 @@ const buildGroupedChartData = _ref => {
|
|
|
40
43
|
viewMode
|
|
41
44
|
} = _ref;
|
|
42
45
|
return groupedEmissions.map((emissionsArray, idx) => {
|
|
43
|
-
const subcategoriesObj = buildRealDataObj(emissionsArray, _subcategories.
|
|
46
|
+
const subcategoriesObj = buildRealDataObj(emissionsArray, [..._subcategories.subcategories, _subcategories.otherSubcategoryObj]);
|
|
44
47
|
const buildWarningObj = () => {
|
|
45
48
|
const singleEmissionWarning = emissionsArray.find(_ref2 => {
|
|
46
49
|
let {
|
|
@@ -111,17 +114,70 @@ const addTrendlineToChartData = chartData => {
|
|
|
111
114
|
});
|
|
112
115
|
});
|
|
113
116
|
};
|
|
114
|
-
const
|
|
117
|
+
const ReferenceLineLabelChips = _ref8 => {
|
|
118
|
+
let {
|
|
119
|
+
x,
|
|
120
|
+
y,
|
|
121
|
+
label
|
|
122
|
+
} = _ref8;
|
|
123
|
+
const CHIP_HEIGHT_PX = 24;
|
|
124
|
+
const {
|
|
125
|
+
palette
|
|
126
|
+
} = (0, _material.useTheme)();
|
|
127
|
+
const [chipWidth, setChipWidth] = (0, _react.useState)(0);
|
|
128
|
+
const chipRef = (0, _react.useRef)();
|
|
129
|
+
(0, _react.useEffect)(() => {
|
|
130
|
+
if (chipRef.current) {
|
|
131
|
+
setChipWidth(chipRef.current.offsetWidth);
|
|
132
|
+
}
|
|
133
|
+
}, [chipRef]);
|
|
134
|
+
return /*#__PURE__*/_react.default.createElement(_material.Chip, {
|
|
135
|
+
elevation: 3,
|
|
136
|
+
ref: chipRef,
|
|
137
|
+
label: label,
|
|
138
|
+
style: {
|
|
139
|
+
position: "absolute",
|
|
140
|
+
top: y - CHIP_HEIGHT_PX / 2,
|
|
141
|
+
left: x - chipWidth / 2,
|
|
142
|
+
background: (0, _converters.hexToRgba)(palette.backgroundGray.main, 0.85)
|
|
143
|
+
},
|
|
144
|
+
size: "small"
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
const ChartLineLabelSetter = _ref9 => {
|
|
148
|
+
let {
|
|
149
|
+
viewBox,
|
|
150
|
+
labels,
|
|
151
|
+
setLabels,
|
|
152
|
+
label
|
|
153
|
+
} = _ref9,
|
|
154
|
+
otherProps = _objectWithoutProperties(_ref9, _excluded2);
|
|
155
|
+
(0, _react.useEffect)(() => {
|
|
156
|
+
const {
|
|
157
|
+
y
|
|
158
|
+
} = viewBox;
|
|
159
|
+
if (!labels.find(existingLabel => existingLabel.label === label)) {
|
|
160
|
+
setLabels(existingLabels => [...existingLabels, _objectSpread({
|
|
161
|
+
y,
|
|
162
|
+
label
|
|
163
|
+
}, otherProps)]);
|
|
164
|
+
}
|
|
165
|
+
}, [viewBox, label, labels, setLabels, otherProps]);
|
|
166
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null);
|
|
167
|
+
};
|
|
168
|
+
const LabeledEmissionsChart = _ref10 => {
|
|
115
169
|
var _data$, _data;
|
|
116
170
|
let {
|
|
171
|
+
graphPeriod,
|
|
117
172
|
data,
|
|
118
|
-
chartRef,
|
|
119
173
|
type,
|
|
120
174
|
displayUnitLabel,
|
|
121
175
|
chartArray,
|
|
122
176
|
aspect = 3,
|
|
123
|
-
showTooltip
|
|
124
|
-
|
|
177
|
+
showTooltip,
|
|
178
|
+
netZeroPercentage,
|
|
179
|
+
baseline
|
|
180
|
+
} = _ref10;
|
|
125
181
|
const {
|
|
126
182
|
palette
|
|
127
183
|
} = (0, _material.useTheme)();
|
|
@@ -133,17 +189,66 @@ const LabeledEmissionsChart = _ref8 => {
|
|
|
133
189
|
warningField: "warning",
|
|
134
190
|
barSumField: "totalEmissionsSumTons"
|
|
135
191
|
});
|
|
192
|
+
const [chartWidth, setChartWidth] = (0, _react.useState)(0);
|
|
193
|
+
const [referenceLineLabels, setReferenceLineLabels] = (0, _react.useState)([]);
|
|
194
|
+
const chartContainerRef = (0, _react.useRef)();
|
|
195
|
+
(0, _react.useEffect)(() => {
|
|
196
|
+
if (chartContainerRef.current) {
|
|
197
|
+
setChartWidth(chartContainerRef.current.offsetWidth);
|
|
198
|
+
}
|
|
199
|
+
}, [chartContainerRef]);
|
|
136
200
|
const isTrendLineGood = ((_data$ = data[0]) === null || _data$ === void 0 ? void 0 : _data$.trendLine) > ((_data = data[data.length - 1]) === null || _data === void 0 ? void 0 : _data.trendLine);
|
|
137
201
|
const ChartElement = type === "bar" ? _recharts.Bar : _recharts.Area;
|
|
202
|
+
const buildReferenceLinesArray = () => {
|
|
203
|
+
if (!baseline) {
|
|
204
|
+
return [];
|
|
205
|
+
}
|
|
206
|
+
const baselineReferenceLine = {
|
|
207
|
+
value: baseline,
|
|
208
|
+
label: "".concat((0, _formatters.ucFirstLetters)(graphPeriod), "ly Baseline"),
|
|
209
|
+
labelPosition: "top"
|
|
210
|
+
};
|
|
211
|
+
const ghgReductionLine = {
|
|
212
|
+
value: baseline * 0.5,
|
|
213
|
+
label: "GHG Reduction Mandate (50% by 2030)",
|
|
214
|
+
labelPosition: "top"
|
|
215
|
+
};
|
|
216
|
+
const companyPledgeLabel = "Company pledge to reduce emissions by ".concat(netZeroPercentage, "% by 2030");
|
|
217
|
+
const pledgeReductionValue = baseline * (1 - netZeroPercentage / 100);
|
|
218
|
+
if (!netZeroPercentage) {
|
|
219
|
+
return [baselineReferenceLine, ghgReductionLine];
|
|
220
|
+
}
|
|
221
|
+
if (netZeroPercentage >= 55) {
|
|
222
|
+
return [baselineReferenceLine, ghgReductionLine, {
|
|
223
|
+
value: pledgeReductionValue,
|
|
224
|
+
label: companyPledgeLabel,
|
|
225
|
+
labelPosition: "bottom"
|
|
226
|
+
}];
|
|
227
|
+
}
|
|
228
|
+
return [baselineReferenceLine, {
|
|
229
|
+
label: companyPledgeLabel,
|
|
230
|
+
value: pledgeReductionValue,
|
|
231
|
+
labelPosition: "bottom"
|
|
232
|
+
}];
|
|
233
|
+
};
|
|
234
|
+
const referenceLines = buildReferenceLinesArray();
|
|
235
|
+
|
|
236
|
+
//This weird hack is needed because for some reason every label shows up in referenceLineLabels twice.
|
|
237
|
+
const uniqueReferenceLineLabels = [...new Set(referenceLineLabels.map(_ref11 => {
|
|
238
|
+
let {
|
|
239
|
+
label
|
|
240
|
+
} = _ref11;
|
|
241
|
+
return label;
|
|
242
|
+
}))].map(label => referenceLineLabels.find(lineLabel => lineLabel.label === label));
|
|
138
243
|
return /*#__PURE__*/_react.default.createElement(_material.Box, {
|
|
139
|
-
position: "relative"
|
|
244
|
+
position: "relative",
|
|
245
|
+
ref: chartContainerRef
|
|
140
246
|
}, /*#__PURE__*/_react.default.createElement(_recharts.ResponsiveContainer, {
|
|
141
247
|
aspect: aspect
|
|
142
248
|
}, /*#__PURE__*/_react.default.createElement(_recharts.ComposedChart, {
|
|
143
249
|
width: 500,
|
|
144
250
|
height: 300,
|
|
145
|
-
data: data
|
|
146
|
-
ref: chartRef
|
|
251
|
+
data: data
|
|
147
252
|
}, /*#__PURE__*/_react.default.createElement(_recharts.XAxis, {
|
|
148
253
|
dataKey: "label",
|
|
149
254
|
interval: "preserveStartEnd",
|
|
@@ -161,12 +266,12 @@ const LabeledEmissionsChart = _ref8 => {
|
|
|
161
266
|
categoriesArray: chartArray,
|
|
162
267
|
displayUnitLabel: displayUnitLabel
|
|
163
268
|
})
|
|
164
|
-
}), chartArray.map(
|
|
269
|
+
}), chartArray.map(_ref12 => {
|
|
165
270
|
let {
|
|
166
271
|
subcategory,
|
|
167
272
|
color
|
|
168
|
-
} =
|
|
169
|
-
otherProps = _objectWithoutProperties(
|
|
273
|
+
} = _ref12,
|
|
274
|
+
otherProps = _objectWithoutProperties(_ref12, _excluded3);
|
|
170
275
|
return /*#__PURE__*/_react.default.createElement(ChartElement, _extends({
|
|
171
276
|
key: "emissions-chart-element-".concat(subcategory),
|
|
172
277
|
type: "monotone",
|
|
@@ -184,26 +289,45 @@ const LabeledEmissionsChart = _ref8 => {
|
|
|
184
289
|
strokeWidth: 4,
|
|
185
290
|
dot: false,
|
|
186
291
|
strokeDasharray: "5 5"
|
|
187
|
-
})
|
|
292
|
+
}), !!referenceLines.length && referenceLines.map((_ref13, idx) => {
|
|
293
|
+
let {
|
|
294
|
+
label,
|
|
295
|
+
value,
|
|
296
|
+
labelPosition
|
|
297
|
+
} = _ref13;
|
|
298
|
+
return /*#__PURE__*/_react.default.createElement(_recharts.ReferenceLine, {
|
|
299
|
+
key: "chart-reference-line-".concat(idx),
|
|
300
|
+
y: value,
|
|
301
|
+
strokeWidth: 2,
|
|
302
|
+
stroke: palette.backgroundGray.dark,
|
|
303
|
+
label: /*#__PURE__*/_react.default.createElement(ChartLineLabelSetter, {
|
|
304
|
+
label: label,
|
|
305
|
+
labels: referenceLineLabels,
|
|
306
|
+
setLabels: setReferenceLineLabels
|
|
307
|
+
})
|
|
308
|
+
});
|
|
309
|
+
}))), warningLabels, !!uniqueReferenceLineLabels.length && uniqueReferenceLineLabels.map((label, idx) => /*#__PURE__*/_react.default.createElement(ReferenceLineLabelChips, _extends({
|
|
310
|
+
key: "reference-line-label-chip-".concat(idx),
|
|
311
|
+
x: chartWidth / 2
|
|
312
|
+
}, label))));
|
|
188
313
|
};
|
|
189
|
-
const EmissionsChart =
|
|
314
|
+
const EmissionsChart = _ref14 => {
|
|
190
315
|
let {
|
|
191
316
|
dataArray: emissions,
|
|
192
317
|
type,
|
|
193
318
|
viewMode = "subcategories",
|
|
194
319
|
graphPeriod,
|
|
195
|
-
chartRef,
|
|
196
320
|
showTrendline,
|
|
197
321
|
displayUnit,
|
|
198
|
-
unitConverter,
|
|
199
322
|
aspect,
|
|
200
323
|
isPercentageChart,
|
|
201
324
|
showTooltip = true,
|
|
202
325
|
startDate,
|
|
203
|
-
convertCarbonUnits,
|
|
326
|
+
convertCarbonUnits = tons => tons,
|
|
204
327
|
displayUnitLabel,
|
|
205
|
-
branding
|
|
206
|
-
|
|
328
|
+
branding,
|
|
329
|
+
netZeroPercentage
|
|
330
|
+
} = _ref14;
|
|
207
331
|
const {
|
|
208
332
|
chartLabelsArray,
|
|
209
333
|
scopesArray,
|
|
@@ -217,8 +341,8 @@ const EmissionsChart = _ref10 => {
|
|
|
217
341
|
buildRealDataObj,
|
|
218
342
|
viewMode
|
|
219
343
|
});
|
|
220
|
-
const convertChartDataObject = (chartDataObj, converter) => Object.fromEntries(Object.entries(chartDataObj).map(
|
|
221
|
-
let [key, value] =
|
|
344
|
+
const convertChartDataObject = (chartDataObj, converter) => Object.fromEntries(Object.entries(chartDataObj).map(_ref15 => {
|
|
345
|
+
let [key, value] = _ref15;
|
|
222
346
|
if (typeof value !== "number") {
|
|
223
347
|
return [key, value];
|
|
224
348
|
}
|
|
@@ -229,35 +353,35 @@ const EmissionsChart = _ref10 => {
|
|
|
229
353
|
}));
|
|
230
354
|
if (isPercentageChart) {
|
|
231
355
|
const percentageConvertedChartData = preliminaryChartData.map(chartDataObj => {
|
|
232
|
-
const objectSubcategoryProperties = Object.keys(chartDataObj).filter(key => _subcategories.subcategories.find(
|
|
356
|
+
const objectSubcategoryProperties = Object.keys(chartDataObj).filter(key => _subcategories.subcategories.find(_ref16 => {
|
|
233
357
|
let {
|
|
234
358
|
subcategory
|
|
235
|
-
} =
|
|
359
|
+
} = _ref16;
|
|
236
360
|
return subcategory === key;
|
|
237
361
|
}));
|
|
238
362
|
const objectSubcategoryValues = objectSubcategoryProperties.map(subcategory => ({
|
|
239
363
|
key: subcategory,
|
|
240
364
|
value: chartDataObj[subcategory]
|
|
241
365
|
}));
|
|
242
|
-
const periodEmissionsSum = objectSubcategoryValues.reduce((sum,
|
|
366
|
+
const periodEmissionsSum = objectSubcategoryValues.reduce((sum, _ref17) => {
|
|
243
367
|
let {
|
|
244
368
|
value
|
|
245
|
-
} =
|
|
369
|
+
} = _ref17;
|
|
246
370
|
return value + sum;
|
|
247
371
|
}, 0);
|
|
248
372
|
const percentageConverter = value => value / periodEmissionsSum * 100;
|
|
249
|
-
const newObject = Object.fromEntries(objectSubcategoryValues.map(
|
|
373
|
+
const newObject = Object.fromEntries(objectSubcategoryValues.map(_ref18 => {
|
|
250
374
|
let {
|
|
251
375
|
key,
|
|
252
376
|
value
|
|
253
|
-
} =
|
|
377
|
+
} = _ref18;
|
|
254
378
|
return [key, value];
|
|
255
379
|
}));
|
|
256
380
|
return convertChartDataObject(newObject, percentageConverter);
|
|
257
381
|
});
|
|
258
382
|
return labelChartData(percentageConvertedChartData);
|
|
259
383
|
}
|
|
260
|
-
const unitConvertedChartData = preliminaryChartData.map(chartDataObj => convertChartDataObject(chartDataObj,
|
|
384
|
+
const unitConvertedChartData = preliminaryChartData.map(chartDataObj => convertChartDataObject(chartDataObj, convertCarbonUnits));
|
|
261
385
|
const labeledChartData = labelChartData(unitConvertedChartData);
|
|
262
386
|
if (showTrendline) {
|
|
263
387
|
return addTrendlineToChartData(labeledChartData);
|
|
@@ -265,6 +389,26 @@ const EmissionsChart = _ref10 => {
|
|
|
265
389
|
return labeledChartData;
|
|
266
390
|
};
|
|
267
391
|
const chartData = buildChartData();
|
|
392
|
+
const findFirstYearBaseline = () => {
|
|
393
|
+
if ((0, _dayjs.default)().diff((0, _dayjs.default)(startDate), "month") < 12) {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
const {
|
|
397
|
+
groupedEmissions: firstYearBaselineMonthlyEmissions
|
|
398
|
+
} = (0, _chartHelpers.buildEmissionGroupData)(emissions, "month", startDate);
|
|
399
|
+
const firstYearMonthlyGroupedEmissions = [...new Array(11)].map((_, idx) => firstYearBaselineMonthlyEmissions[idx]);
|
|
400
|
+
const firstYearMonthlyEmissionsSum = firstYearMonthlyGroupedEmissions.map(emissions => ({
|
|
401
|
+
tonsCo2e: (0, _otherHelpers.sumTonsCo2e)(emissions)
|
|
402
|
+
}));
|
|
403
|
+
const monthlyBaselineTons = (0, _otherHelpers.sumTonsCo2e)(firstYearMonthlyEmissionsSum) / 12;
|
|
404
|
+
if (graphPeriod === "year") {
|
|
405
|
+
return convertCarbonUnits(monthlyBaselineTons * 12);
|
|
406
|
+
}
|
|
407
|
+
if (graphPeriod === "quarter") {
|
|
408
|
+
return convertCarbonUnits(monthlyBaselineTons * 3);
|
|
409
|
+
}
|
|
410
|
+
return convertCarbonUnits(monthlyBaselineTons);
|
|
411
|
+
};
|
|
268
412
|
const chartArray = viewMode === "scopes" ? scopesArray : subcategoriesArray;
|
|
269
413
|
return /*#__PURE__*/_react.default.createElement(_material.Grid, {
|
|
270
414
|
container: true,
|
|
@@ -273,14 +417,16 @@ const EmissionsChart = _ref10 => {
|
|
|
273
417
|
item: true
|
|
274
418
|
}, /*#__PURE__*/_react.default.createElement(LabeledEmissionsChart, {
|
|
275
419
|
data: chartData,
|
|
276
|
-
chartRef: chartRef,
|
|
277
420
|
type: type,
|
|
278
421
|
displayUnitLabel: isPercentageChart ? "%" : displayUnit || displayUnitLabel,
|
|
279
422
|
chartArray: chartArray.map(obj => _objectSpread(_objectSpread({}, obj), {}, {
|
|
280
423
|
viewMode
|
|
281
424
|
})),
|
|
282
425
|
aspect: aspect,
|
|
283
|
-
showTooltip: showTooltip
|
|
426
|
+
showTooltip: showTooltip,
|
|
427
|
+
graphPeriod: graphPeriod,
|
|
428
|
+
netZeroPercentage: netZeroPercentage,
|
|
429
|
+
baseline: findFirstYearBaseline()
|
|
284
430
|
})));
|
|
285
431
|
};
|
|
286
432
|
var _default = exports.default = EmissionsChart;
|
package/package.json
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useEffect, useState, useRef } from "react";
|
|
2
2
|
import dayjs from "dayjs";
|
|
3
|
-
import dayOfYear from "dayjs/plugin/dayOfYear";
|
|
4
3
|
|
|
5
4
|
import {
|
|
6
5
|
XAxis,
|
|
@@ -11,17 +10,15 @@ import {
|
|
|
11
10
|
Bar,
|
|
12
11
|
ComposedChart,
|
|
13
12
|
Line,
|
|
13
|
+
ReferenceLine,
|
|
14
14
|
Tooltip as ChartTooltip,
|
|
15
15
|
} from "recharts";
|
|
16
16
|
|
|
17
|
-
import { Grid, Box, useTheme } from "@mui/material";
|
|
17
|
+
import { Grid, Box, Chip, useTheme } from "@mui/material";
|
|
18
18
|
|
|
19
|
-
import { formatDecimal } from "@aclymatepackages/formatters";
|
|
19
|
+
import { formatDecimal, ucFirstLetters } from "@aclymatepackages/formatters";
|
|
20
20
|
import { sumTonsCo2e } from "@aclymatepackages/other-helpers";
|
|
21
|
-
|
|
22
|
-
import EmissionsCustomTooltip from "./EmissionsCustomTooltip";
|
|
23
|
-
import useChartWarningLabels from "./useChartWarningLabels";
|
|
24
|
-
|
|
21
|
+
import { hexToRgba } from "@aclymatepackages/converters";
|
|
25
22
|
import {
|
|
26
23
|
buildScopesRealDataObj,
|
|
27
24
|
buildSubcategoriesDataObj,
|
|
@@ -29,10 +26,11 @@ import {
|
|
|
29
26
|
} from "@aclymatepackages/chart-helpers";
|
|
30
27
|
import {
|
|
31
28
|
subcategories,
|
|
32
|
-
|
|
29
|
+
otherSubcategoryObj,
|
|
33
30
|
} from "@aclymatepackages/subcategories";
|
|
34
31
|
|
|
35
|
-
|
|
32
|
+
import EmissionsCustomTooltip from "./EmissionsCustomTooltip";
|
|
33
|
+
import useChartWarningLabels from "./useChartWarningLabels";
|
|
36
34
|
|
|
37
35
|
const findObjectValuesSum = (object) =>
|
|
38
36
|
Object.values(object).reduce((sum, value) => sum + value, 0);
|
|
@@ -43,10 +41,10 @@ const buildGroupedChartData = ({
|
|
|
43
41
|
viewMode,
|
|
44
42
|
}) => {
|
|
45
43
|
return groupedEmissions.map((emissionsArray, idx) => {
|
|
46
|
-
const subcategoriesObj = buildRealDataObj(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
);
|
|
44
|
+
const subcategoriesObj = buildRealDataObj(emissionsArray, [
|
|
45
|
+
...subcategories,
|
|
46
|
+
otherSubcategoryObj,
|
|
47
|
+
]);
|
|
50
48
|
|
|
51
49
|
const buildWarningObj = () => {
|
|
52
50
|
const singleEmissionWarning = emissionsArray.find(
|
|
@@ -110,14 +108,67 @@ const addTrendlineToChartData = (chartData) => {
|
|
|
110
108
|
}));
|
|
111
109
|
};
|
|
112
110
|
|
|
111
|
+
const ReferenceLineLabelChips = ({ x, y, label }) => {
|
|
112
|
+
const CHIP_HEIGHT_PX = 24;
|
|
113
|
+
|
|
114
|
+
const { palette } = useTheme();
|
|
115
|
+
|
|
116
|
+
const [chipWidth, setChipWidth] = useState(0);
|
|
117
|
+
const chipRef = useRef();
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
if (chipRef.current) {
|
|
121
|
+
setChipWidth(chipRef.current.offsetWidth);
|
|
122
|
+
}
|
|
123
|
+
}, [chipRef]);
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<Chip
|
|
127
|
+
elevation={3}
|
|
128
|
+
ref={chipRef}
|
|
129
|
+
label={label}
|
|
130
|
+
style={{
|
|
131
|
+
position: "absolute",
|
|
132
|
+
top: y - CHIP_HEIGHT_PX / 2,
|
|
133
|
+
left: x - chipWidth / 2,
|
|
134
|
+
background: hexToRgba(palette.backgroundGray.main, 0.85),
|
|
135
|
+
}}
|
|
136
|
+
size="small"
|
|
137
|
+
/>
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const ChartLineLabelSetter = ({
|
|
142
|
+
viewBox,
|
|
143
|
+
labels,
|
|
144
|
+
setLabels,
|
|
145
|
+
label,
|
|
146
|
+
...otherProps
|
|
147
|
+
}) => {
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
const { y } = viewBox;
|
|
150
|
+
|
|
151
|
+
if (!labels.find((existingLabel) => existingLabel.label === label)) {
|
|
152
|
+
setLabels((existingLabels) => [
|
|
153
|
+
...existingLabels,
|
|
154
|
+
{ y, label, ...otherProps },
|
|
155
|
+
]);
|
|
156
|
+
}
|
|
157
|
+
}, [viewBox, label, labels, setLabels, otherProps]);
|
|
158
|
+
|
|
159
|
+
return <></>;
|
|
160
|
+
};
|
|
161
|
+
|
|
113
162
|
const LabeledEmissionsChart = ({
|
|
163
|
+
graphPeriod,
|
|
114
164
|
data,
|
|
115
|
-
chartRef,
|
|
116
165
|
type,
|
|
117
166
|
displayUnitLabel,
|
|
118
167
|
chartArray,
|
|
119
168
|
aspect = 3,
|
|
120
169
|
showTooltip,
|
|
170
|
+
netZeroPercentage,
|
|
171
|
+
baseline,
|
|
121
172
|
}) => {
|
|
122
173
|
const { palette } = useTheme();
|
|
123
174
|
|
|
@@ -127,14 +178,80 @@ const LabeledEmissionsChart = ({
|
|
|
127
178
|
barSumField: "totalEmissionsSumTons",
|
|
128
179
|
});
|
|
129
180
|
|
|
181
|
+
const [chartWidth, setChartWidth] = useState(0);
|
|
182
|
+
const [referenceLineLabels, setReferenceLineLabels] = useState([]);
|
|
183
|
+
|
|
184
|
+
const chartContainerRef = useRef();
|
|
185
|
+
|
|
186
|
+
useEffect(() => {
|
|
187
|
+
if (chartContainerRef.current) {
|
|
188
|
+
setChartWidth(chartContainerRef.current.offsetWidth);
|
|
189
|
+
}
|
|
190
|
+
}, [chartContainerRef]);
|
|
191
|
+
|
|
130
192
|
const isTrendLineGood = data[0]?.trendLine > data[data.length - 1]?.trendLine;
|
|
131
193
|
|
|
132
194
|
const ChartElement = type === "bar" ? Bar : Area;
|
|
133
195
|
|
|
196
|
+
const buildReferenceLinesArray = () => {
|
|
197
|
+
if (!baseline) {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const baselineReferenceLine = {
|
|
202
|
+
value: baseline,
|
|
203
|
+
label: `${ucFirstLetters(graphPeriod)}ly Baseline`,
|
|
204
|
+
labelPosition: "top",
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const ghgReductionLine = {
|
|
208
|
+
value: baseline * 0.5,
|
|
209
|
+
label: "GHG Reduction Mandate (50% by 2030)",
|
|
210
|
+
labelPosition: "top",
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const companyPledgeLabel = `Company pledge to reduce emissions by ${netZeroPercentage}% by 2030`;
|
|
214
|
+
const pledgeReductionValue = baseline * (1 - netZeroPercentage / 100);
|
|
215
|
+
|
|
216
|
+
if (!netZeroPercentage) {
|
|
217
|
+
return [baselineReferenceLine, ghgReductionLine];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (netZeroPercentage >= 55) {
|
|
221
|
+
return [
|
|
222
|
+
baselineReferenceLine,
|
|
223
|
+
ghgReductionLine,
|
|
224
|
+
{
|
|
225
|
+
value: pledgeReductionValue,
|
|
226
|
+
label: companyPledgeLabel,
|
|
227
|
+
labelPosition: "bottom",
|
|
228
|
+
},
|
|
229
|
+
];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return [
|
|
233
|
+
baselineReferenceLine,
|
|
234
|
+
{
|
|
235
|
+
label: companyPledgeLabel,
|
|
236
|
+
value: pledgeReductionValue,
|
|
237
|
+
labelPosition: "bottom",
|
|
238
|
+
},
|
|
239
|
+
];
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const referenceLines = buildReferenceLinesArray();
|
|
243
|
+
|
|
244
|
+
//This weird hack is needed because for some reason every label shows up in referenceLineLabels twice.
|
|
245
|
+
const uniqueReferenceLineLabels = [
|
|
246
|
+
...new Set(referenceLineLabels.map(({ label }) => label)),
|
|
247
|
+
].map((label) =>
|
|
248
|
+
referenceLineLabels.find((lineLabel) => lineLabel.label === label)
|
|
249
|
+
);
|
|
250
|
+
|
|
134
251
|
return (
|
|
135
|
-
<Box position="relative">
|
|
252
|
+
<Box position="relative" ref={chartContainerRef}>
|
|
136
253
|
<ResponsiveContainer aspect={aspect}>
|
|
137
|
-
<ComposedChart width={500} height={300} data={data}
|
|
254
|
+
<ComposedChart width={500} height={300} data={data}>
|
|
138
255
|
<XAxis dataKey="label" interval="preserveStartEnd" height={20} />
|
|
139
256
|
<YAxis
|
|
140
257
|
tickFormatter={(tick) =>
|
|
@@ -179,9 +296,33 @@ const LabeledEmissionsChart = ({
|
|
|
179
296
|
dot={false}
|
|
180
297
|
strokeDasharray="5 5"
|
|
181
298
|
/>
|
|
299
|
+
{!!referenceLines.length &&
|
|
300
|
+
referenceLines.map(({ label, value, labelPosition }, idx) => (
|
|
301
|
+
<ReferenceLine
|
|
302
|
+
key={`chart-reference-line-${idx}`}
|
|
303
|
+
y={value}
|
|
304
|
+
strokeWidth={2}
|
|
305
|
+
stroke={palette.backgroundGray.dark}
|
|
306
|
+
label={
|
|
307
|
+
<ChartLineLabelSetter
|
|
308
|
+
label={label}
|
|
309
|
+
labels={referenceLineLabels}
|
|
310
|
+
setLabels={setReferenceLineLabels}
|
|
311
|
+
/>
|
|
312
|
+
}
|
|
313
|
+
/>
|
|
314
|
+
))}
|
|
182
315
|
</ComposedChart>
|
|
183
316
|
</ResponsiveContainer>
|
|
184
317
|
{warningLabels}
|
|
318
|
+
{!!uniqueReferenceLineLabels.length &&
|
|
319
|
+
uniqueReferenceLineLabels.map((label, idx) => (
|
|
320
|
+
<ReferenceLineLabelChips
|
|
321
|
+
key={`reference-line-label-chip-${idx}`}
|
|
322
|
+
x={chartWidth / 2}
|
|
323
|
+
{...label}
|
|
324
|
+
/>
|
|
325
|
+
))}
|
|
185
326
|
</Box>
|
|
186
327
|
);
|
|
187
328
|
};
|
|
@@ -191,17 +332,16 @@ const EmissionsChart = ({
|
|
|
191
332
|
type,
|
|
192
333
|
viewMode = "subcategories",
|
|
193
334
|
graphPeriod,
|
|
194
|
-
chartRef,
|
|
195
335
|
showTrendline,
|
|
196
336
|
displayUnit,
|
|
197
|
-
unitConverter,
|
|
198
337
|
aspect,
|
|
199
338
|
isPercentageChart,
|
|
200
339
|
showTooltip = true,
|
|
201
340
|
startDate,
|
|
202
|
-
convertCarbonUnits,
|
|
341
|
+
convertCarbonUnits = (tons) => tons,
|
|
203
342
|
displayUnitLabel,
|
|
204
343
|
branding,
|
|
344
|
+
netZeroPercentage,
|
|
205
345
|
}) => {
|
|
206
346
|
const {
|
|
207
347
|
chartLabelsArray,
|
|
@@ -271,9 +411,7 @@ const EmissionsChart = ({
|
|
|
271
411
|
}
|
|
272
412
|
|
|
273
413
|
const unitConvertedChartData = preliminaryChartData.map((chartDataObj) =>
|
|
274
|
-
convertChartDataObject(chartDataObj,
|
|
275
|
-
unitConverter ? unitConverter(value) : convertCarbonUnits(value)
|
|
276
|
-
)
|
|
414
|
+
convertChartDataObject(chartDataObj, convertCarbonUnits)
|
|
277
415
|
);
|
|
278
416
|
|
|
279
417
|
const labeledChartData = labelChartData(unitConvertedChartData);
|
|
@@ -287,6 +425,33 @@ const EmissionsChart = ({
|
|
|
287
425
|
|
|
288
426
|
const chartData = buildChartData();
|
|
289
427
|
|
|
428
|
+
const findFirstYearBaseline = () => {
|
|
429
|
+
if (dayjs().diff(dayjs(startDate), "month") < 12) {
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const { groupedEmissions: firstYearBaselineMonthlyEmissions } =
|
|
434
|
+
buildEmissionGroupData(emissions, "month", startDate);
|
|
435
|
+
|
|
436
|
+
const firstYearMonthlyGroupedEmissions = [...new Array(11)].map(
|
|
437
|
+
(_, idx) => firstYearBaselineMonthlyEmissions[idx]
|
|
438
|
+
);
|
|
439
|
+
const firstYearMonthlyEmissionsSum = firstYearMonthlyGroupedEmissions.map(
|
|
440
|
+
(emissions) => ({ tonsCo2e: sumTonsCo2e(emissions) })
|
|
441
|
+
);
|
|
442
|
+
const monthlyBaselineTons = sumTonsCo2e(firstYearMonthlyEmissionsSum) / 12;
|
|
443
|
+
|
|
444
|
+
if (graphPeriod === "year") {
|
|
445
|
+
return convertCarbonUnits(monthlyBaselineTons * 12);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (graphPeriod === "quarter") {
|
|
449
|
+
return convertCarbonUnits(monthlyBaselineTons * 3);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return convertCarbonUnits(monthlyBaselineTons);
|
|
453
|
+
};
|
|
454
|
+
|
|
290
455
|
const chartArray = viewMode === "scopes" ? scopesArray : subcategoriesArray;
|
|
291
456
|
|
|
292
457
|
return (
|
|
@@ -294,7 +459,6 @@ const EmissionsChart = ({
|
|
|
294
459
|
<Grid item>
|
|
295
460
|
<LabeledEmissionsChart
|
|
296
461
|
data={chartData}
|
|
297
|
-
chartRef={chartRef}
|
|
298
462
|
type={type}
|
|
299
463
|
displayUnitLabel={
|
|
300
464
|
isPercentageChart ? "%" : displayUnit || displayUnitLabel
|
|
@@ -302,6 +466,9 @@ const EmissionsChart = ({
|
|
|
302
466
|
chartArray={chartArray.map((obj) => ({ ...obj, viewMode }))}
|
|
303
467
|
aspect={aspect}
|
|
304
468
|
showTooltip={showTooltip}
|
|
469
|
+
graphPeriod={graphPeriod}
|
|
470
|
+
netZeroPercentage={netZeroPercentage}
|
|
471
|
+
baseline={findFirstYearBaseline()}
|
|
305
472
|
/>
|
|
306
473
|
</Grid>
|
|
307
474
|
</Grid>
|