From 3fa5a1441a9f117299485df48217dcda37520d5b Mon Sep 17 00:00:00 2001 From: "Jan-Peter v. Hunnius" Date: Sat, 6 Jun 2026 08:16:10 +0200 Subject: [PATCH] feat: add RPM vs. Force and Speed vs. RPM charts to shift point analysis --- src/views/ShiftPointsView.vue | 79 +++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/src/views/ShiftPointsView.vue b/src/views/ShiftPointsView.vue index 06f76ed..49f9d5b 100644 --- a/src/views/ShiftPointsView.vue +++ b/src/views/ShiftPointsView.vue @@ -43,10 +43,41 @@ onMounted(async () => { } }) +const colors = ['#4f8ff7', '#34d399', '#fbbf24', '#f87171', '#a78bfa', '#60a5fa', '#f472b6'] + +const rpmVsAccelChartData = computed(() => { + if (!analysis.value) return null + const curves = analysis.value.gear_curves.filter((g) => g.gear >= 2) + return { + datasets: curves.map((curve, i) => ({ + label: `${curve.gear_display} (${curve.run_label})`, + data: curve.data_points.map((p) => ({ x: p.rpm, y: p.acceleration_g })), + borderColor: colors[i % colors.length], + backgroundColor: colors[i % colors.length] + '20', + showLine: true, + fill: false, + tension: 0.3, + pointRadius: 0, + borderWidth: 2, + })), + } +}) + +const rpmVsAccelChartOptions = { + responsive: true, + plugins: { + legend: { labels: { color: '#8b8fa3' } }, + title: { display: true, text: 'RPM vs. Force', color: '#e2e4ea' }, + }, + scales: { + x: { ticks: { color: '#8b8fa3' }, grid: { color: '#2a2e3f' }, title: { display: true, text: 'RPM', color: '#8b8fa3' } }, + y: { ticks: { color: '#8b8fa3' }, grid: { color: '#2a2e3f' }, title: { display: true, text: 'Force (g)', color: '#8b8fa3' } }, + }, +} + const gearCurvesChartData = computed(() => { if (!analysis.value) return null const curves = analysis.value.gear_curves.filter((g) => g.gear >= 2) - const colors = ['#4f8ff7', '#34d399', '#fbbf24', '#f87171', '#a78bfa', '#60a5fa', '#f472b6'] return { datasets: curves.map((curve, i) => ({ label: `${curve.gear_display} (${curve.run_label})`, @@ -66,11 +97,41 @@ const gearCurvesOptions = { responsive: true, plugins: { legend: { labels: { color: '#8b8fa3' } }, - title: { display: true, text: 'Gear Acceleration Curves', color: '#e2e4ea' }, + title: { display: true, text: 'Speed vs. Force', color: '#e2e4ea' }, }, scales: { x: { ticks: { color: '#8b8fa3' }, grid: { color: '#2a2e3f' }, title: { display: true, text: 'Speed (km/h)', color: '#8b8fa3' } }, - y: { ticks: { color: '#8b8fa3' }, grid: { color: '#2a2e3f' }, title: { display: true, text: 'Acceleration (g)', color: '#8b8fa3' } }, + y: { ticks: { color: '#8b8fa3' }, grid: { color: '#2a2e3f' }, title: { display: true, text: 'Force (g)', color: '#8b8fa3' } }, + }, +} + +const speedVsRpmChartData = computed(() => { + if (!analysis.value) return null + const curves = analysis.value.gear_curves.filter((g) => g.gear >= 2) + return { + datasets: curves.map((curve, i) => ({ + label: `${curve.gear_display} (${curve.run_label})`, + data: curve.data_points.map((p) => ({ x: p.speed_kmh, y: p.rpm })), + borderColor: colors[i % colors.length], + backgroundColor: colors[i % colors.length] + '20', + showLine: true, + fill: false, + tension: 0.3, + pointRadius: 0, + borderWidth: 2, + })), + } +}) + +const speedVsRpmChartOptions = { + responsive: true, + plugins: { + legend: { labels: { color: '#8b8fa3' } }, + title: { display: true, text: 'Speed vs. RPM (Gear Ratios)', color: '#e2e4ea' }, + }, + scales: { + x: { ticks: { color: '#8b8fa3' }, grid: { color: '#2a2e3f' }, title: { display: true, text: 'Speed (km/h)', color: '#8b8fa3' } }, + y: { ticks: { color: '#8b8fa3' }, grid: { color: '#2a2e3f' }, title: { display: true, text: 'RPM', color: '#8b8fa3' } }, }, } @@ -157,11 +218,21 @@ const crossoverChartOptions = { - + +
+ +
+ +
+ +
+ +
+