DrawChart = ( initialData, hoveredIndex, canvas, tooltip, maxLength ) =>
{
	const data = initialData.slice( 0, maxLength ).reverse();
	const maxCSR = data.reduce( ( a, b ) => a.csr > b.csr ? a : b ).csr;

	const rect = canvas.getBoundingClientRect();
	const width = rect.width * devicePixelRatio;
	const height = rect.height * devicePixelRatio;

	const ctx = canvas.getContext( '2d' );

	// Setting size clears the canvas
	canvas.width = width;
	canvas.height = height;

	// Draw gradient
	let i = 0;
	let lastTier = -1;
	let lastSeason = data[ 0 ].season;
	const paddedHeight = height * 0.95;
	const halfHeight = height / 2;
	const gap = width / ( data.length - 1 );


	/** @type {{season: string, x: number}[]} */
	const seasonChanges = [];

	ctx.beginPath();
	ctx.moveTo( 0, height );

	for( const point of data )
	{
		const val = 2 * ( point.csr / maxCSR - 0.5 );
		const x = i * gap;
		const y = ( -val * paddedHeight ) / 2 + halfHeight;

		const tier = Math.min( Math.floor( point.csr / 5000 ), tierColors.length - 1 );

		if( lastTier !== tier )
		{
			if( i > 0 )
			{
				ctx.lineTo( x, y );
				ctx.lineTo( x, height );
				ctx.fill();
				ctx.beginPath();
				ctx.moveTo( x, height );
			}

			const grd = ctx.createLinearGradient( 0, 0, 0, height );
			grd.addColorStop( 0, tierColors[ tier ] + '22' );
			grd.addColorStop( 1, 'transparent' );
			ctx.fillStyle = grd;

			ctx.lineTo( x, y );

			lastTier = tier;
		}
		else
		{
			ctx.lineTo( x, y );
		}

		if( lastSeason !== point.season )
		{
			lastSeason = point.season;

			seasonChanges.push( {
				x,
				season: lastSeason,
			} );
		}

		i += 1;
	}

	ctx.lineTo( width, height );
	ctx.fill();

	// Max tier dashed line
	ctx.strokeStyle = '#424857';
	ctx.lineWidth = 1 * devicePixelRatio;
	ctx.setLineDash( [ 7 * devicePixelRatio, 4 * devicePixelRatio ] );
	ctx.fillStyle = '#999';
	i = 0;

	for( let maxCSRClean = maxCSR - ( maxCSR % 5000 ); maxCSRClean >= 5000 && i < 2; maxCSRClean -= 5000, i++ )
	{
		const maxCSRTier = 2 * ( maxCSRClean / maxCSR - 0.5 );
		const maxCSRTierY = ( -maxCSRTier * paddedHeight ) / 2 + halfHeight;

		ctx.beginPath();
		ctx.moveTo( 0, maxCSRTierY );
		ctx.lineTo( width, maxCSRTierY );
		ctx.stroke();

		ctx.fillText( `${( maxCSRClean / 1000 ).toFixed( 0 )}k`, 0,	maxCSRTierY < 12 ? maxCSRTierY + 12 : maxCSRTierY - 4 );
	}

	ctx.setLineDash( [] );

	// Draw season changes
	for( const season of seasonChanges )
	{
		ctx.beginPath();
		ctx.moveTo( season.x, 0 );
		ctx.lineTo( season.x, height );
		ctx.stroke();

		ctx.fillText( `Season ${season.season}`, season.x + 5, height - 5 );
	}

	// Draw line
	ctx.beginPath();
	ctx.lineWidth = 2 * devicePixelRatio;

	let circleX = null;
	let circleY = null;
	let highlightedCSR = 0;
	let highlightedDate = '';
	i = 0;
	lastTier = -1;

	for( const point of data )
	{
		const val = 2 * ( point.csr / maxCSR - 0.5 );
		const x = i * gap;
		const y = ( -val * paddedHeight ) / 2 + halfHeight;
		const tier = Math.min( Math.floor( point.csr / 5000 ), tierColors.length - 1 );

		if( lastTier !== tier )
		{
			if( i > 0 )
			{
				ctx.lineTo( x, y );
				ctx.stroke();
				ctx.beginPath();
			}

			ctx.strokeStyle = tierColors[ tier ];
			ctx.moveTo( x, y );

			lastTier = tier;
		}
		else
		{
			ctx.lineTo( x, y );
		}

		if( hoveredIndex === i )
		{
			circleX = x;
			circleY = y;
			highlightedCSR = point.csr;
			highlightedDate = point.datetime;
		}

		i += 1;
	}

	ctx.stroke();

	if( circleX !== null && circleY !== null )
	{
		ctx.beginPath();
		ctx.fillStyle = '#fff';
		ctx.arc( circleX, circleY, 3 * devicePixelRatio, 0, Math.PI * 2 );
		ctx.fill();
		tooltip.textContent = `${highlightedCSR.toLocaleString()}\n${highlightedDate}`;
	}
}
@param {CSRArray} initialData
@param {number} hoveredIndex
@param {HTMLCanvasElement} canvas
@param {HTMLDivElement} tooltip
@param {number} maxLength