chart.js----初次使用遇到的坑

本文详细介绍如何在项目中正确安装和使用Chart.js,包括避免常见错误,如引用文件问题,以及如何配置图表类型、数据和选项,实现数据可视化。

近日试着在项目中使用Chart.js,在尝试了很多次以后,终于把表格放在了页面上,这里简单介绍一下使用的过程。

这里先附上Chart.js的官方使用文档

https://www.chartjs.org/docs/latest/

安装及引用

      一开始,我选择了从GitHub上下载的Chart.js,但是页面并没有正确的引用,出现了报错Chrome保存信息

      在徘徊良久以后,发现了原因,因为从GitHub上面直接下在文件中,不包括dist文件,而像我这样的小白就直接在页面中引用了src目录下的chart.js,所以出现了上面的报错信息。找到原因后,解决问题就变得很简单。这里说两种将Chart.js添加到项目中的方式:

        之后会看到文件中出现了node_modules文件夹 ,我们在页面上需要引用这个目录下的/chart.js/dist/chart.js或       着/chart.js/dist/chart.min.js。

  1. npm安装,这也是官方推荐的安装方式,在命令行中找打项目对应的位置,然后键入
    npm install chart.js --save
  2. 从GitHub中下载,着样做的话,需要在对应的目录下进行构建,具体方法是在chart.js的目录下执行
     npm install

        之后直接在页面中引用chart.js或chart.min.js即可。

使用 

       关于使用方法及个格式,网上有很多的版本,这是由于版本原因,chart.js在更新版本之后改变了很多JS的语法,这里介绍一下当前下官方给出的用法。

       首先我们在页面上添加对应的元素:

<canvas id="myChart" width="400" height="400"></canvas>

      之后我们在JS中获取该元素:

var ctx = document.getElementById("myChart");

     最后我们设置对应的属性及数据:

var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
        datasets: [{
            label: '# of Votes',
            data: [12, 19, 3, 5, 2, 3],
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
                'rgba(255,99,132,1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                }
            }]
        }
    }
});

上述代码的结构为

         new  Chart (ctx , {

                  type: 表格的类型,

                 data: 表格的数据集,

                 options:对表格进行一些设置

        } ) 

这里重点说一下数据集的问题,上述例子中有一个labels,这个属性用来告诉页面我们的统计项,注意的是他的顺序必须和后面数据的顺序相同,以此来实现在统计图中是数据和统计项一一对应。datasets中是一个对象数组,在datasets中每一个对象代表一张表格的数据,我们也可以通过添加两个对象,在一张统计图中显示两张统计图的内容。在datasets的每一个对象中包含label、data以及其他的一些属性,这里的label,再条形图等的中,会显示在表格外面,用来告诉用户,对应该颜色的数据代表着什么,但是,在饼状图中并不会显示。这里的data属性即代表了具体的数据,同样用数组表示,前面已经说过了,这里的数组中数据的顺序必须和labels中的顺序相对应。除此之外,你可以在data中添加更多的属性来控制表格的样式,这些都可以在chart.js的官方文档中找到,值得一提的是chart.js的很多属性可以写成本数组,例如上述代码中的backgroundColor等,这样意味着我们可以对每一条数据设置对应的样式,当然,数组中的顺序要和上面的labels一一对应。

最后一提,我在使用时,返现很多刚开始接触的人可能会弄混data的结构,这里强调在data的对象数组中,一个对象就是一个统计图的数据。因为很多人喜欢使用雷达图来比较数据,所以弄清楚结构非常重要。

 

 

 

<template> <!-- 八大主题右侧 --> <div id="indicatorPanel" style="width: 100%;height: 100%;"> <!-- 左侧导航 --> <div class="left-div" v-if="!isExpand"> <div :class="getDivStyle('title', index)" v-for="(item,index) in useList" :key="item.name || index" @click="handleChange(index)"> <div class="text-title"> {{ item.name }} </div> </div> </div> <!-- 右侧内容:指标卡片 --> <div :class="isExpand ? 'right-div right-div-width2' : 'right-div right-div-width1'"> <div style="width: 70%; height: 6%;" class="div-title"> <el-image v-if="title" style="width: 17px; height: 24px; margin-right: 5px;" :src="require('@/src/images/gdGridMap/homePage/eightMajorThemes/location.png')" fit="contain"> </el-image> <span>{{ title }}</span> </div> <div class="div-expand"> <el-link type="info" @click="handleExpand"> {{ title ? (isExpand ? '收起 >>' : '展开全部 <<') : '' }} </el-link> </div> <div :style="'width: 100%; height: 1%;' + (title && !isExpand ? 'border-top: 1px dashed #a6a9ad;' : '')"></div> <div class="theme-content" @scroll="handleScroll"> <div :id="'theme_'+index" v-for="(item, index) in loadList" :key="item.name || index" style="width: 100%;"> <div class="cardNameClass" v-if="isExpand"> {{ item.name }} </div> <theme-items :items="getCard(item.cardList)" :ref="'themeItemsRef'+index" :year-month="yearMonth"></theme-items> </div> </div> </div> </div> </template> <script> import {myMixins} from "../../mixins/myMixins"; import {targetCardData} from "../../themecard/targetCardData" import themeItems from "../../themecard/ThemeItems"; export default { mixins: [myMixins], name: 'eightMajorThemesRight', components: { themeItems }, props:{ yearMonth: { // 年月 type: String, default: '202508' } }, data() { return { isExpand: false, // 展开全部 activeName: 0, //默认展开面板 title: '', nodeBm: '', themeList: [ { name: '供电质量', cardList: [ {cardName: '', name: 'powerQualityCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '基础管理', cardList: [ {cardName: '', name: 'baseManageCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '诉求处置', cardList: [ {cardName: '', name: 'appealHandCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '停电处置', cardList: [ {cardName: '', name: 'outageHandCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '外部协同', cardList: [ {cardName: '', name: 'externalCollaborationCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '网格建设', cardList: [ {cardName: '', name: 'gridConstructCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '业务受理', cardList: [ {cardName: '', name: 'businessAcceptanceCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] }, { name: '主动服务', cardList: [ {cardName: '', name: 'activeServiceCardEMT', level: [0, 1, 2, 3, 4, 5, 6]}, ] } ], useList: [], loadList: [], observer: null, isManualScroll: false, // 是否正在手动点击跳转 } }, mounted() { window.addEventListener('resize', () => { for (const key in this.loadList) { let themeItemsRefName = 'themeItemsRef' + key; if (this.$refs[themeItemsRefName]) { setTimeout(() => this.$refs[themeItemsRefName][0].$emit("resize"), 500); } } }) }, watch: { loadList: { handler(newValue, oldValue) { this.$nextTick(() => this.observeTheme()); }, immediate: true, // 创建时立即执行一次 handler 回调 deep: true //深度监听 loadList 内部嵌套属性的变化 }, }, methods: { /* 数据来源,必须与myMixins方法同名 */ changeData(val) { this.title = val.nodeMc this.$nextTick(() => { this.useList = JSON.parse(JSON.stringify(this.themeList)); this.loadList = this.useList; }); if (this.nodeBm != val.nodeBm) { //地址切换面板滚到顶部 this.nodeBm = val.nodeBm; if (!val.roll) { this.handleChange(0); } } }, handleChange(val, name) { /* if (this.loadList.length != this.useList.length) { if (val > this.activeName) { this.loadList = this.useList.slice(0, val + 1); } } */ this.activeName = val; this.isManualScroll = true; // 标记为手动操作,防止 Observer 干扰 this.$nextTick(() => { let mainContainer = $('.theme-content') let scrollToContainer = mainContainer.find('#theme_' + val); if (name) { scrollToContainer = mainContainer.find('#' + name); } mainContainer.animate({ scrollTop: scrollToContainer.offset().top - mainContainer.offset().top + mainContainer.scrollTop() }, 1000); // 手动滚动结束后,清除标志(防抖) setTimeout(() => { this.isManualScroll = false; }, 1000); // 与滚动动画时间一致 }) }, getDivStyle(style, index) { if (style == "title") { return index === this.activeName ? 'theme-title title-highlight' : 'theme-title'; } }, /* 展开全部 */ handleExpand() { this.isExpand = !this.isExpand; this.$store.state.isExpand = this.isExpand; }, handleScroll(event) { const {scrollTop, clientHeight, scrollHeight} = event.target; if (scrollTop + clientHeight >= scrollHeight) { /* if (this.loadList.length != this.useList.length) { this.loadList = this.useList.slice(0, this.activeName + 2); } */ } }, getCard(cardList) { let list = cardList.filter(item => item.level.includes(parseInt(this.$store.state.indicatorData.nodeJbdm))); list.forEach(item => { let find = targetCardData().targetCardArr.find(it => it.name == item.name); item.id = find.id; if (!item.hasOwnProperty('space')) { item.space = find.space; } if (!item.hasOwnProperty('isShow')) { item.isShow = true; } }); return list; }, /* 滚动监听,用于动态更新 activeName */ observeTheme() { // (0) 清理之前的观察器(避免重复创建) if (this.observer) { this.observer.disconnect(); } // (1)配置观察器选项 const options = { root: document.querySelector('.theme-content'), // 观察的根元素(滚动容器) rootMargin: "0px", // 根元素的外边距(无扩展) threshold: 0.5, // 触发回调的交叉比例阈值(50%可见) }; // (2)收集目标元素 let sections = []; for (let i = 0; i < this.loadList.length; i++) { sections.push(document.querySelector('#theme_' + i)); } sections = sections.filter(item => item != null); // 过滤无效元素 // (3)回调函数 const callback = (entries, observer) => { if (this.isManualScroll) return; // 手动滚动时不更新 //entries:代表观察到的目标元素的集合。 observer:代表观察者对象。 entries.forEach((entry) => { if (entry.isIntersecting) { // 判断目标元素是否进入视口 const target = entry.target; // 获取当前目标元素 let index = sections.findIndex((section) => section === target); this.activeName = index; } }); }; // (4)创建观察器并监听元素 /* let thresholds = Array(sections.length).fill(0.5); sections.forEach((value, index) => { options.threshold = thresholds[index]; this.observer = new IntersectionObserver(callback, options); this.observer.observe(value); }); */ this.observer = new IntersectionObserver(callback, options); sections.forEach(value => this.observer.observe(value)); }, } } </script> <style scoped> #indicatorPanel { display: flex; } .left-div { height: 100%; width: 10%; } .theme-title { height: 12.2%; width: 100%; display: flex; justify-content: center; align-items: center; background: #E6EDFE; border-radius: 10px; border: 1px snow solid; } .theme-title:hover { cursor: pointer; } .title-highlight { background: #ADCFFD !important; } .text-title { width: 0.1875rem; color: #192C7D; font-size: 0.18rem; font-weight: bold; } .right-div-width1 { width: 82%; /* 100%-左侧10%-左右内边距4%*2 */ } .right-div-width2 { width: 96%; /* 100%-上下内边距2%*2 */ } .right-div { height: 98%; box-shadow: 0 0 10px gainsboro; border-radius: 10px; background-color: white !important; overflow: hidden; padding: 2% 4%; text-align: center; position: relative; } .div-title, .div-expand { display: flex; align-items: center; /* 上下居中 */ } .div-title span { text-align: left; color: #354387; font-size: 0.3rem; font-weight: bold; } .div-expand { position: absolute; top: .25rem; right: .4rem; } .div-expand .el-link { font-size: 12px !important; } .theme-content { width: 100%; height: 93%; overflow-y: scroll; overflow-x: hidden; } .cardNameClass { width: 30%; color: #354387; font-size: .25rem; font-weight: bold; border-bottom: solid 1px #354387; padding-left: .2rem; text-align: left; } </style>这是我的代码,主要问题出在theme_2和theme_4,因为echart图过多,内容很长
08-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值