Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade line chart to amCharts 5 #277

Merged
merged 29 commits into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0acd4c1
amcharts5 upgrade
NXXR Jun 23, 2023
66aeac3
add export menu
NXXR Jun 29, 2023
16d2260
Merge remote-tracking branch 'origin/develop' into feature/amcharts5-…
NXXR Jun 29, 2023
43b606f
Merge remote-tracking branch 'origin/develop' into feature/amcharts5-…
NXXR Jun 29, 2023
9f89d0a
fix guard style
NXXR Jun 29, 2023
55c5e00
remove am4 code, ran formatter, moved percentile coloring, add backen…
NXXR Jun 30, 2023
05af8b5
format comments
NXXR Jun 30, 2023
1c40f83
fix group filter offset and resolve todo
NXXR Jun 30, 2023
70fc849
add vscode workspace settings
NXXR Jun 30, 2023
bd8fcff
reduce bundle size
NXXR Jun 30, 2023
bee306b
:arrow_down_small: remove obsolete amcharts4
NXXR Jun 30, 2023
3581953
resolve date format issues
NXXR Jul 4, 2023
0744a06
resolve date format issues
NXXR Jul 4, 2023
58436aa
reduce am5export import
NXXR Jul 4, 2023
a494007
resolve TODOs
NXXR Jul 4, 2023
6702c4e
reduce percentile opacity, fix effect triggers to redraw guide
NXXR Jul 4, 2023
a608c1d
change for loop to filter for finding series
NXXR Jul 4, 2023
c1a4b15
change for loop to filter for finding series
NXXR Jul 4, 2023
a7035b2
add error message if group filter data not available
NXXR Jul 4, 2023
1d46295
remove amcharts4 dependency
NXXR Jul 4, 2023
02d2bc8
apply format & lint
NXXR Jul 4, 2023
8096e1f
Apply suggestions from code review
NXXR Jul 6, 2023
d5eef7b
:memo: add changelog entries
NXXR Jul 6, 2023
68160db
change date select from dblclick to click
NXXR Jul 6, 2023
0869bb0
add effect conditions to date guide effect
NXXR Jul 11, 2023
b184d81
format and add todo
NXXR Jul 13, 2023
386f66b
reduce chart init effect so it only runs once
NXXR Jul 13, 2023
6455632
Merge branch 'develop' into feature/amcharts5-simulation-chart
NXXR Jul 14, 2023
694ab8f
Apply suggestions from code review
NXXR Jul 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions frontend/docs/changelog/changelog-de.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- Alle Texte sind nun in Englisch und in Deutsch verfügbar.
- Es wurden einige Verbesserungen gemacht, die das Laden der Seite beschleunigen.
- Wenn neue Funktionen zur Verfügung gestellt werden, wird der Browser-Cache nicht mehr verhindern, dass Benutzer:innen diese sehen.
- Das DLR-Logo wurde durch das LOKI-Logo ersetzt und verkleinert.
- Das Modul für das Liniendiagramm wurde von AmCharts 4 auf 5 gewechselt für eine bessere Leistung.

### Fehlerbehebungen
Expand Down
1 change: 1 addition & 0 deletions frontend/docs/changelog/changelog-en.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- All texts are now available in Englisch and German.
- Some improvements to page load speed have been made.
- If a new feature gets rolled out, the browser cache will no longer prevent the users from seeing it.
- The DLR logo was replaced by the LOKI logo and the size was reduced.
- The line chart module is upgraded from AmCharts 4 to 5 for better performance.

### Bug fixes
Expand Down
120 changes: 81 additions & 39 deletions frontend/src/components/SimulationChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,11 @@ export default function SimulationChart(): JSX.Element {
);

const {formatNumber} = NumberFormatter(i18n.language, 3, 8);
const numberFormat = '#,###.';

const rootRef = useRef<Root | null>(null);
const chartRef = useRef<XYChart | null>(null);

// Effect to create chart instance
// Effect to initialize root & chart
useEffect(
() => {
// Create root and chart
Expand All @@ -117,11 +116,8 @@ export default function SimulationChart(): JSX.Element {
})
);

// Set localization
root.locale = i18n.language === 'de' ? am5locales_de_DE : am5locales_en_US;

// Set number formatter
root.numberFormatter.set('numberFormat', numberFormat);
root.numberFormatter.set('numberFormat', '#,###.');

// Create x-axis
const xAxis = chart.xAxes.push(
Expand All @@ -146,14 +142,9 @@ export default function SimulationChart(): JSX.Element {
xRenderer.ticks.template.setAll({
location: 0.5,
});
// Change date formats for ticks & tooltip (use fallback object to suppress undefined object warnings as this cannot be undefined)
xAxis.get('dateFormats', {day: ''})['day'] = t('dayFormat');
xAxis.get('tooltipDateFormats', {day: ''})['day'] = t('dayFormat');
// Fix first date of the month falling back to wrong format (also with fallback object)
xAxis.get('periodChangeDateFormats', {day: ''})['day'] = t('dayFormat');

// Create y-axis
const yAxis = chart.yAxes.push(
chart.yAxes.push(
ValueAxis.new(root, {
renderer: AxisRendererY.new(root, {}),
// Fix lower end to 0
Expand All @@ -174,6 +165,64 @@ export default function SimulationChart(): JSX.Element {
})
);

// Add event on double click to select date
chart.events.on('click', (ev) => {
// Get date from axis position from cursor position
const date = xAxis.positionToDate(
xAxis.toAxisPosition(ev.target.get('cursor')?.getPrivate('positionX') as number)
);
// Remove time information to only have a date
date.setHours(0, 0, 0, 0);
// Set date in store
dispatch(selectDate(dateToISOString(date)));
});

// Set refs to be used in other effects
rootRef.current = root;
chartRef.current = chart;

// Clean-up before re-running this effect
return () => {
// Dispose old root and chart before creating a new instance
chartRef.current && chartRef.current.dispose();
rootRef.current && rootRef.current.dispose();
NXXR marked this conversation as resolved.
Show resolved Hide resolved
};
},
// This effect should only run once. dispatch should not change during runtime
[dispatch]
);

// Effect to change localization of chart if language changes
useEffect(
() => {
// Skip if root or chart is not initialized
if (!rootRef.current || !chartRef.current) return;
NXXR marked this conversation as resolved.
Show resolved Hide resolved

// Set localization
rootRef.current.locale = i18n.language === 'de' ? am5locales_de_DE : am5locales_en_US;

// Change date formats for ticks & tooltip (use fallback object to suppress undefined object warnings as this cannot be undefined)
const xAxis: DateAxis<AxisRendererX> = chartRef.current.xAxes.getIndex(0) as DateAxis<AxisRendererX>;
xAxis.get('dateFormats', {day: ''})['day'] = t('dayFormat');
xAxis.get('tooltipDateFormats', {day: ''})['day'] = t('dayFormat');
// Fix first date of the month falling back to wrong format (also with fallback object)
xAxis.get('periodChangeDateFormats', {day: ''})['day'] = t('dayFormat');
},
// Re-run effect if language changes
[i18n.language, t]
);

// Effect to add series to chart
useEffect(
() => {
// Skip if root or chart not initialized
if (!rootRef.current || !chartRef.current) return;
NXXR marked this conversation as resolved.
Show resolved Hide resolved

const chart: XYChart = chartRef.current;
const root: Root = rootRef.current;
const xAxis: DateAxis<AxisRendererX> = chart.xAxes.getIndex(0) as DateAxis<AxisRendererX>;
const yAxis: ValueAxis<AxisRendererY> = chart.yAxes.getIndex(0) as ValueAxis<AxisRendererY>;

// Add series for case data
const caseDataSeries = chart.series.push(
LineSeries.new(root, {
Expand Down Expand Up @@ -284,31 +333,14 @@ export default function SimulationChart(): JSX.Element {
});
}

// Add event on double click to select date
chart.events.on('click', (ev) => {
// Get date from axis position from cursor position
const date = xAxis.positionToDate(
xAxis.toAxisPosition(ev.target.get('cursor')?.getPrivate('positionX') as number)
);
// Remove time information to only have a date
date.setHours(0, 0, 0, 0);
// Set date in store
dispatch(selectDate(dateToISOString(date)));
});

// Set refs to be used in other effects
rootRef.current = root;
chartRef.current = chart;

// Clean-up before re-running this effect
// Clean-up function
return () => {
// Dispose old root and chart before creating a new instance
chartRef.current && chartRef.current.dispose();
rootRef.current && rootRef.current.dispose();
// Remove all series
chart.series.clear();
};
},
// Re-run effect when shown information changes (scenarios, group filters, or the selected scenario -> percentiles); dispatch, theme, or language (i18n & t) do not change after initialization
[scenarioList, groupFilterList, dispatch, i18n.language, t, theme, selectedScenario, tBackend]
// Re-run if scenario, group filter, or selected scenario (percentile series) change. (t, tBackend, and theme do not change during runtime).
[scenarioList, groupFilterList, selectedScenario, t, tBackend, theme]
);

// Effect to hide disabled scenarios (and show them again if not hidden anymore)
Expand Down Expand Up @@ -354,8 +386,8 @@ export default function SimulationChart(): JSX.Element {
// Effect to add Guide when date selected
useEffect(
() => {
// Skip effect if chart is not initialized yet or no date is selected
if (!chartRef.current || !selectedDate) return;
// Skip effect if chart (or root) is not initialized yet or no date is selected
if (!chartRef.current || !rootRef.current || !selectedDate) return;
NXXR marked this conversation as resolved.
Show resolved Hide resolved

// Get xAxis from chart
const xAxis = chartRef.current.xAxes.getIndex(0) as DateAxis<AxisRendererX>;
Expand Down Expand Up @@ -398,7 +430,7 @@ export default function SimulationChart(): JSX.Element {
day: '2-digit',
}),
location: 0.5,
background: RoundedRectangle.new(rootRef.current as Root, {
background: RoundedRectangle.new(rootRef.current, {
fill: color(theme.palette.primary.main),
}),
// Put Label to the topmost layer to make sure it is drawn on top of the axis tick labels
Expand All @@ -410,8 +442,18 @@ export default function SimulationChart(): JSX.Element {
xAxis.axisRanges.removeValue(range);
};
},
// Re-run effect when selection changes (date/scenario/compartment/district) (theme and translation do not change after initialization)
[selectedDate, selectedScenario, selectedCompartment, selectedDistrict, theme, t, i18n.language]
// Re-run effect when selection changes (date/scenario/compartment/district) or when the active scenarios/filters change (theme and translation do not change after initialization)
[
selectedDate,
selectedScenario,
selectedCompartment,
selectedDistrict,
activeScenarios,
groupFilterList,
theme,
t,
i18n.language,
]
);

// Effect to update Simulation and case data
Expand Down