import * as echarts from 'echarts';
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option;
function normalRandom(mean, stdDev) {
let u = 0,
v = 0;
while (u === 0) u = Math.random();
while (v === 0) v = Math.random();
let num = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
return num * stdDev + mean;
}
function generateLapTime(iRating) {
const minTime = 99;
const maxTime = 117;
const range = maxTime - minTime;
let normalizedRating = (10000 - iRating) / 10000;
let baseTime = minTime + normalizedRating * range * 0.9;
// Increased variability for lower iRatings
let stdDev = 0.5 + normalizedRating * 2;
let randomFactor = normalRandom(0, stdDev);
return Math.max(minTime, Math.min(maxTime, baseTime + randomFactor));
}
function formatLapTime(seconds) {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = (seconds % 60).toFixed(3).padStart(6, '0');
return `${minutes}:${remainingSeconds}`;
}
function movingAverage(data, windowSize) {
const result = [];
for (let i = 0; i < data.length; i++) {
const start = Math.max(0, i - windowSize + 1);
const end = i + 1;
const window = data.slice(start, end);
const average = window.reduce((sum, num) => sum + num, 0) / window.length;
result.push(average);
}
return result;
}
// Generate data points
const sampleSize = 100;
const data = [];
for (let i = 0; i < sampleSize; i++) {
let iRating = Math.round(i * (10000 / sampleSize));
let normalizedRating = iRating / 10000;
let lapTime = generateLapTime(iRating);
// Calculate confidence interval based on iRating
let confidenceInterval = 0.5 + (1 - normalizedRating) * 2.5;
data.push({
iRating: iRating,
lapTime: lapTime,
lower: lapTime - confidenceInterval,
upper: lapTime + confidenceInterval
});
}
// Prepare data for ECharts
const xAxisData = data.map((item) => item.iRating);
const rawSeriesData = data.map((item) => item.lapTime);
const seriesData = movingAverage(rawSeriesData, 10); // Apply moving average
const lowerBound = data.map((item) => item.lower);
const upperBound = data.map((item) => item.upper - item.lower);
// ECharts option
option = {
backgroundColor: '#1e1e27',
title: {
text: 'iRating vs Lap Time Confidence Band',
left: 'center',
top: '20px',
textStyle: { color: '#fff', fontSize: 20 }
},
tooltip: {
trigger: 'axis',
formatter: function (params) {
const iRating = params[0].axisValue;
const lapTime = params[2].data;
const lower = params[0].data;
const upper = params[1].data + lower;
return `iRating: ${iRating}
Avg Lap Time: ${formatLapTime(lapTime)}
Range: ${formatLapTime(lower)} - ${formatLapTime(upper)}`;
}
},
xAxis: {
type: 'category',
data: xAxisData,
name: 'iRating',
nameLocation: 'middle',
nameGap: 30,
axisLabel: {
color: '#fff',
formatter: (value) => value.toLocaleString()
},
axisLine: { lineStyle: { color: '#fff' } },
splitLine: {
show: true,
lineStyle: { color: 'rgba(255, 255, 255, 0.1)' }
}
},
yAxis: {
type: 'value',
name: 'Lap Time',
nameLocation: 'middle',
nameGap: 40,
min: 98,
max: 118,
interval: 2,
axisLabel: {
formatter: function (value) {
return formatLapTime(value);
},
color: '#fff'
},
axisLine: { lineStyle: { color: '#fff' } },
splitLine: {
show: true,
lineStyle: { color: 'rgba(255, 255, 255, 0.1)' }
}
},
series: [
{
name: 'Lower Bound',
type: 'line',
data: lowerBound,
lineStyle: { opacity: 0 },
stack: 'confidence-band',
symbol: 'none'
},
{