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

Chart.js折线图从Firestore取数据后Y轴数据点定位异常

问题:Firestore数据在Chart.js折线图Y轴定位错误,但Tooltip显示正常

从Firestore获取的数据在Chart.js折线图中Y轴定位异常——例如某数据实际值为23,却被渲染到100+的位置,但Tooltip显示的数值是正确的。手动输入数据时,数据点定位完全正常。已确认获取后的数据类型为number,仍无法定位问题原因。

折线图Y轴定位错误示例

相关代码

<script>
    import {
        auth,
        db
    } from "../../src/main";
    import Sidebar from "../components/Navigation/Sidebar.vue";
    import Topbar from "../components/Navigation/Topbar.vue";
    import ChartTest from "../components/ProgressPage/ChartTest.vue";
    import Chart from 'chart.js/auto';
    import {
        getFirestore,
        doc,
        updateDoc,
        getDoc,
        setDoc,
        collection,
        addDoc,
        deleteDoc,
        deleteField,
        arrayUnion,
        arrayRemove
    } from "firebase/firestore";
    export default {
        name: "Progress",
        components: {
            Sidebar,
            Topbar,
            ChartTest
        },
        mounted() {
            const progressChart = new Chart(document.getElementById("progress-chart"), {
                type: 'line',
                data: {
                    labels: ['CA1', 'SA1', 'CA2', 'SA2'],
                    datasets: []
                },
                options: {
                    plugins: {
                        title: {
                            display: true,
                            text: this.title
                        }
                    },
                    scales: {
                        y: {
                            display: true,
                            stacked: true,
                            title: {
                                display: true,
                                text: 'Your Score (%)'
                            }
                        }
                    }
                }
            });

            this.getData().then((data) => {
                progressChart.data.datasets = data
                console.log(typeof(data[0].data[0])) // 输出number
                this.getCount(data)
                progressChart.update()
            })
        },
        methods: {
            getCount(data) {
                this.count = data.length
            },
            async getData() {
                var email = localStorage.getItem("email");
                var ref = doc(db, 'users', email);
                const docSnap = await getDoc(ref)
                if (docSnap.exists()) {
                    var data = docSnap.data().progressResults
                    return data
                } else {
                    console.log('does not exist')
                }
            },
            async addResult() {
                let count = this.existingSubjects.length
                var email = localStorage.getItem("email");
                var ref = doc(db, 'users', email);

                if (!this.existingSubjects.includes(this.subject)) {
                    this.existingSubjects.push(this.subject)
                  
                    const newData = {
                        data: [{ x: this.examType,y:this.score}],
                        label: this.subject,
                        borderColor: this.colors[this.count],
                        fill: false
                    }
                    await updateDoc(
                        ref, {
                            progressResults: arrayUnion(newData)
                        }
                    )
                    console.log(newData)
                } else {
                    // 待实现
                }
            }
        },
        data() {
            return {
                score: '',
                examType: '',
                subject: '',
                count:0,
                existingSubjects: [],
                colors: ["#3e95cd", "#8e5ea2", "#3cba9f", "#e8c3b9", "#c45850","#21c095","#bbc021","#1a993a","##904b23","#a01359","#a04913","#534270"],
                title: '',
                data: {
                    labels: ['CA1', 'SA1', 'CA2', 'SA2'],
                    datasets: []
                },
                tabs: [{
                        link: '',
                        name: "subject",
                        dropdown: true,
                        dropdownTabs: [{
                                name: 'math',
                                link: '#',
                            },
                            {
                                name: 'science',
                                link: '#',
                            },
                        ]
                    },
                    {
                        link: '#',
                        name: "test",
                        dropdown: false,
                        dropdownTabs: []
                    },
                ]
            }
        }
    }
</script>

问题原因及解决办法

核心原因:Y轴堆叠模式导致数值累加

你的Chart配置中Y轴开启了stacked: true,但数据结构是每个dataset仅包含单个{x,y}数据点(比如数学科目只有CA1的分数)。堆叠模式会将所有dataset在同一X轴位置的Y值累加,导致单个数据点被“推”到很高的位置——而Tooltip显示的是原始数据值,所以看起来正常。

解决步骤

  1. 关闭Y轴堆叠
    修改Chart配置中Y轴的stacked属性为false,因为你的场景是展示不同科目在各考试的独立分数,不需要堆叠:

    scales: {
        y: {
            display: true,
            stacked: false, // 此处修改为false
            title: {
                display: true,
                text: 'Your Score (%)'
            }
        }
    }
    
  2. 统一数据格式(可选)
    如果手动输入数据时使用的是纯Y值数组(如data: [23, null, null, null]),建议将Firestore获取的数据转换为对应格式,确保和手动输入的结构一致:

    async getData() {
        var email = localStorage.getItem("email");
        var ref = doc(db, 'users', email);
        const docSnap = await getDoc(ref)
        if (docSnap.exists()) {
            const labels = ['CA1', 'SA1', 'CA2', 'SA2'];
            return docSnap.data().progressResults.map(dataset => {
                // 转换为对应labels顺序的Y值数组,不存在的考试填null
                const dataArray = labels.map(label => {
                    const point = dataset.data.find(p => p.x === label);
                    return point ? Number(point.y) : null;
                });
                return {
                    ...dataset,
                    data: dataArray
                };
            });
        } else {
            console.log('does not exist')
        }
    }
    
  3. 强制确保数据类型为Number
    虽然你已确认数据类型为number,但可以在获取数据时再强制转换一次,避免潜在的类型问题:

    async getData() {
        var email = localStorage.getItem("email");
        var ref = doc(db, 'users', email);
        const docSnap = await getDoc(ref)
        if (docSnap.exists()) {
            return docSnap.data().progressResults.map(dataset => ({
                ...dataset,
                data: dataset.data.map(point => ({
                    x: point.x,
                    y: Number(point.y) // 强制转换为Number
                }))
            }));
        } else {
            console.log('does not exist')
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 04:01:19