You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chart.js点击横向柱状图滚动到区域报错:Uncaught TypeError求助

问题:点击Chart.js横向柱状图报错并无法跳转对应区块

问题场景

用Chart.js制作了展示各国交通数据的横向堆叠柱状图,希望点击图表柱子时页面平滑滚动到下方对应ID的section,但一直弹出错误:Uncaught TypeError: Cannot read properties of undefined (reading 'link'),尝试多种写法24小时仍未解决。

报错原因分析

  1. Link与Section ID不匹配:部分dataset的link属性值和页面section的ID不一致,既会导致跳转失效,也可能触发后续逻辑的隐性错误
  2. 事件绑定方式不可靠:直接给canvas元素绑定onclick事件,配合getElementsAtEventForMode获取点击元素,在堆叠柱状图场景下可能获取到无效的datasetIndex,导致读取dataset.link时出现undefined错误
  3. 缺少严谨的空值校验:未对dataset做存在性校验,当firstPoint的datasetIndex超出数据集范围时,直接访问dataset.link会抛出异常

修复方案

  1. 修正Link与Section ID的对应关系:确保每个dataset的link值和页面section的ID完全匹配
  2. 改用Chart.js内置事件回调:在图表配置的options中添加onClick回调,Chart.js会自动处理点击事件并传递正确的点击元素信息
  3. 增加多层空值校验:依次校验点击元素、数据集的存在性,避免访问undefined属性

完整修正代码

<script>
    var xValues = [['California', 'United States'], ['New York City', 'United States'], ['London','United Kingdom'], ['Paris','France'], ['Shanghai', 'China'], ['Hong Kong'], ['Kuala Lumpur', 'Malaysia'], "Singapore"];

Chart.defaults.global.backgroundColor = '#f9f9f9'
Chart.defaults.global.defaultFontColor = '#f9f9f9'
const config = {
    
    type: "horizontalBar",

    data: {
        labels: xValues,
        datasets: [
            {
                label: 'Bicycle/Electric Bikes',
                backgroundColor: "rgba(160, 206, 128, 0.8)",
                data: [0.8, 1.5, 5.6, 3.25, 20, 1, 0.3, 2.08],
                maxBarThickness: 30,
                link: '#data-bicycle'
            },
            {
                label: 'Electric Car',
                backgroundColor: "rgba(249, 199, 132, 0.8)",
                data: [25, 2.5, 34.3, 25.26, 4.87, 1.1, 1.15, 0.2], 
                maxBarThickness: 30,
                link: '#data-car' // 修正:匹配section的ID
            },
            {
                label: 'Electric Bus/Trolley Bus',
                backgroundColor: "rgba(237, 106, 90, 0.8)",
                data: [4.7, 12, 5.15, 7.64, 11.11, 0.83, 0.77, 0.79], 
                maxBarThickness: 30,
                link: '#data-bus'
            },
            {
                label: 'Tram',
                backgroundColor: "rgba(205, 160, 204, 0.8)",
                data: [2, 0.08, 1.81, 16.3, 0, 3.1, 0, 0], 
                maxBarThickness: 30,
                link: '#data-tram'
            },
            {
                label: 'Metro/Trains',
                backgroundColor: "rgba(81, 163, 163, 0.8)",
                data: [2.68, 66.59, 49.22, 32.6, 49.39, 56, 19.14, 62.4], 
                maxBarThickness: 30,
                link: '#data-trains' // 修正:匹配section的ID
            },
            {
                label: 'Electric Ships',
                backgroundColor: "rgba(52, 107, 134, 0.8)",
                data: [0.002, 0.24, 0.16, 0.06, 0.04, 0.2, 0, 0.02], 
                maxBarThickness: 30,
                link: '#data-ship'
            },
            {
                label: 'Others',
                backgroundColor: "rgba(249, 249, 249, 0.2)",
                data: [64.818, 17.09, 3.76, 14.89, 14.59, 37.77, 78.64, 34.51],
                maxBarThickness: 30,
                link: '#data-other'
            }
        ],
    },

    options: {
        legend: {
            display: true,
        },

        title: {
            display: false,
        },

        scales: {
            xAxes: [{
                ticks: {
                    min: 0,
                    max: 100,
                },
                type: 'linear',
                stacked: true,
                gridLines: {
                    color: 'rgba(255, 255, 255, 0.1)'
                },
                afterTickToLabelConversion : function(q){
                    for(var tick in q.ticks){
                        q.ticks[tick] += '%';
                    }
                },
            }],
            yAxes: [{
                stacked: true,
                gridLines: {
                    display: false,
                },
            }],
        },
        responsive: true,
        maintainAspectRatio: false,
        // 改用Chart.js内置的onClick回调
        onClick: function(event, elements) {
            if (elements.length > 0) {
                const firstElement = elements[0];
                const dataset = this.data.datasets[firstElement._datasetIndex];
                // 增加dataset存在性校验
                if (dataset && dataset.link) {
                    scrollToSection(dataset.link);
                }
            }
        }
    }
};

document.addEventListener('DOMContentLoaded', function() {
    const ctx = document.getElementById('hero-chart');
    const heroChart = new Chart(ctx, config);

    function scrollToSection(sectionId) {
        const section = document.querySelector(sectionId);
        if (section) {
            section.scrollIntoView({ behavior: 'smooth' });
        }
    }
});
 
</script>

<section id="data-bicycle"></section>
<section id="data-car"></section>
<section id="data-bus"></section>
<section id="data-tram"></section>
<section id="data-trains"></section>
<section id="data-ship"></section>
<section id="data-other"></section>

内容的提问来源于stack exchange,提问作者Addy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 12:59:55