Js charts line animation

49 views Asked by At

I'm trying to get my graph line to animate like progressive line chart https://www.chartjs.org/docs/latest/samples/animations/progressive-line.html

I'm only able to get get default animation.

Here is my code

<script>
    // Define the data for the chart
    const data1 = [
        { x: "25", y: 65 },
        { x: "40", y: 60 },
        { x: "60", y: 30 },
        { x: ">70", y: 12 }
    ];

    const data2 = [
        { x: "25", y: 65 },
        { x: "40", y: 60 },
        { x: "60", y: 35 },
        { x: ">70", y: 45 }
    ];

    // Create labels and values arrays from the data
    const labels = data1.map(point => "Age " + point.x);

    // Get the canvas context
    const ctx = document.getElementById('myChart').getContext('2d');

    // Create a new Chart instance with the first dataset (data1)
    const myChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: labels,
            datasets: [
                {
                    label: 'NAD+ Level',
                    data: data1.map(point => point.y),
                    borderColor: 'white',
                    borderWidth: 2,
                    backgroundColor: 'rgba(0, 0, 0, 0)',
                    lineTension: 0.4,
                    pointBackgroundColor: 'white',
                    pointBorderColor: 'white',
                    pointBorderWidth: 1
                }
            ]
        },
        options: {
            animation: {
                duration: 5000, // Set the animation duration for data1
                easing: 'linear'
            },
            responsive: true,
            maintainAspectRatio: false,
            scales: {
                x: {
                    ticks: {
                        color: 'white',
                    },
                    grid: {
                        color: (context) => (context.tick.value === 0) ? 'white' : 'transparent',
                        display: true,
                        drawTicks: false
                    }
                },
                y: {
                    beginAtZero: true,
                    ticks: {
                        color: 'white',
                    },
                    grid: {
                        color: (context) => (context.tick.value === 0) ? 'white' : 'transparent',
                        display: true
                    }
                }
            },
            plugins: {
                legend: {
                    display: true,
                    position: 'bottom',
                    align: 'end',
                    labels: {
                        color: 'white'
                    }
                }
            },
            elements: {
                point: {
                    radius: 0,
                    backgroundColor: 'white',
                    borderColor: 'white',
                    borderWidth: 1
                }
            }
        }
    });

    // Function to check if the mouse hovers over the chart
    function isMouseOverChart(event) {
        const canvas = document.getElementById('myChart');
        const rect = canvas.getBoundingClientRect();
        const mouseX = event.clientX - rect.left;
        const mouseY = event.clientY - rect.top;
        return mouseX >= 0 && mouseX <= canvas.width && mouseY >= 0 && mouseY <= canvas.height;
    }

    // Function to render the second dataset (data2) when the mouse hovers over the chart
    function renderSecondDataset(event) {
        if (isMouseOverChart(event)) {
            if (myChart.data.datasets.length === 1) {
                myChart.data.datasets.push({
                    label: 'NAD+ Level (After Blue Helix)',
                    data: data2.map(point => point.y),
                    borderColor: '#B4FFBB',
                    borderWidth: 2,
                    backgroundColor: 'rgba(0, 0, 0, 0)',
                    lineTension: 0.4,
                    pointBackgroundColor: 'white',
                    pointBorderColor: 'white',
                    pointBorderWidth: 1
                });
                myChart.options.animation.duration = 1500; // Set the animation duration for data2
                myChart.update();
            }
        }
    }

    // Function to remove data2 when the mouse leaves the chart
    function removeData2() {
        if (!isMouseOverChart(event) && myChart.data.datasets.length > 1) {
            myChart.data.datasets.pop(); // Remove the last dataset (data2)
            myChart.options.animation.duration = 1500; // Restore the animation duration for data1
            myChart.update();
        }
    }

    // Add a mousemove listener to trigger the rendering of the second dataset (data2)
    const canvas = document.getElementById('myChart');
    canvas.addEventListener('mousemove', renderSecondDataset);

    // Add a mouseleave listener to remove data2 when the mouse leaves the chart
    canvas.addEventListener('mouseleave', removeData2);

    // Resize chart when window is resized
    window.addEventListener('resize', () => {
        myChart.resize();
    });

</script>

I try to create random points for both data sets to hit and start drawing the line from there but It doesn't seem to work

const data = [
    { x: "25", y: 65 },
    { x: "40", y: 60 },
    { x: "60", y: 30 },
    { x: ">70", y: 12 }
];

const data2 = [
    { x: "25", y: 65 },
    { x: "40", y: 60 },
    { x: "60", y: 35 },
    { x: ">70", y: 45 }
];

const randomData = [];
const randomData2 = [];

// Function to generate a random y value that doesn't exceed the next value
function generateRandomY(prevY, nextY) {
    if (nextY === undefined) {
        return prevY;
    }
    const randomY = prevY + Math.random() * (nextY - prevY);
    return randomY > nextY ? nextY : randomY;
}

// Generate random points for data
data.forEach((currentPoint, i) => {
    // Initialize with the predefined points
    randomData.push(currentPoint);

    // Generate more random points between current and next predefined points
    while (randomData.length < (i + 2) * 10) { // You can adjust the factor to generate more points
        const prevY = randomData[randomData.length - 1].y;
        const nextY = data[i + 1] ? data[i + 1].y : undefined;
        const randomY = generateRandomY(prevY, nextY);
        const x = (parseFloat(currentPoint.x) + (randomData.length - i - 1) / 10).toString();
        randomData.push({ x, y: randomY });
    }
});

// Generate random points for data2
data2.forEach((currentPoint, i) => {
    // Initialize with the predefined points
    randomData2.push(currentPoint);

    // Generate more random points between current and next predefined points
    while (randomData2.length < (i + 2) * 10) { // You can adjust the factor to generate more points
        const prevY = randomData2[randomData2.length - 1].y;
        const nextY = data2[i + 1] ? data2[i + 1].y : undefined;
        const randomY = generateRandomY(prevY, nextY);
        const x = (parseFloat(currentPoint.x) + (randomData2.length - i - 1) / 10).toString();
        randomData2.push({ x, y: randomY });
    }
});

// Define the animation options
const totalDuration = 10000;
const delayBetweenPoints = totalDuration / (randomData.length - 1);
const previousY = (ctx) => ctx.index === 0 ? ctx.chart.scales.y.getPixelForValue(100) : ctx.chart.getDatasetMeta(ctx.datasetIndex).data[ctx.index - 1].getProps(['y'], true).y;

const animation = {
    x: {
        type: 'number',
        easing: 'linear',
        duration: delayBetweenPoints,
        from: NaN, // the point is initially skipped
        delay(ctx) {
            if (ctx.type !== 'data' || ctx.xStarted) {
                return 0;
            }
            ctx.xStarted = true;
            return ctx.index * delayBetweenPoints;
        }
    },
    y: {
        type: 'number',
        easing: 'linear',
        duration: delayBetweenPoints,
        from: previousY,
        delay(ctx) {
            if (ctx.type !== 'data' || ctx.yStarted) {
                return 0;
            }
            ctx.yStarted = true;
            return ctx.index * delayBetweenPoints;
        }
    }
};

// Create the chart configuration
const config = {
    type: 'line',
    data: {
        datasets: [{
            borderColor: Utils.CHART_COLORS.red,
            borderWidth: 1,
            radius: 0,
            data: randomData, // Use the generated random data
        },
        {
            borderColor: Utils.CHART_COLORS.blue,
            borderWidth: 1,
            radius: 0,
            data: randomData2, // Use the generated random data for data2
        }]
    },
    options: {
        animation,
        interaction: {
            intersect: false
        },
        plugins: {
            legend: false
        },
        scales: {
            x: {
                type: 'linear'
            }
        }
    }
};

// Create the chart using Chart.js
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, config);

0

There are 0 answers