热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Canvas实现绘制图表

这里用canvas实现了两个简单的图表,用到了canvas的基本用法,效果如下新建chart.js文件,封装绘制方法构造方法functionmyChart(

这里用canvas实现了两个简单的图表,用到了canvas的基本用法,效果如下

 

 

新建 chart.js 文件,封装绘制方法

构造方法

function myChart(config){
    this.width = config.width > 300 ? config.width : 200        //图表宽度
    this.height = config.height > 200 ? config.height : 200        //图表高度
    this.el = config.el         //容器DOM元素
    this.data = config.data     //数据
    this.title = config.title     //title
    this.type = config.type     //类型 line、pie
}

初始化方法

        init: function(){
            this.canvas = document.createElement('canvas')
            this.canvas.width = this.width
            this.canvas.height = this.height
            document.querySelector(this.el).append(this.canvas)
            this.ctx = this.canvas.getContext('2d')
            switch(this.type){
                case 'line':
                    this.drawLineChart()
                    break;
                case 'pie':
                    this.drawPieChart()
                    break;
                default :
                    this.drawLineChart()
                    break;
            }
        },

绘制折线图

        //绘制折线图
        drawLineChart: function(){
            var height = this.height
            this.max = 0
            this.min = Infinity
            this.startPoint = { x: 30, y: height - 15 }    //原点位置
            this.innerHieght = this.height - 30 - 15        
            this.innerWidth = this.width - 30
            this.findTerminal()
            this.drawCoordinate()
            this.drawLine()
        },
        //找到最大值和最小值
        findTerminal: function(){
            this.data.map((item, index) => {
                this.max = item.val > this.max ? item.val : this.max
                this.min = item.val <this.min ? item.val : this.min
            })
        },
        //绘制坐标轴
        drawCoordinate: function(){
            //绘制坐标轴
            this.ctx.clearRect(0, 0, this.width, this.height)
            this.ctx.beginPath()
            this.ctx.moveTo(this.startPoint.x, this.startPoint.y)
            this.ctx.lineTo(this.startPoint.x, this.startPoint.y - this.innerHieght)
            this.ctx.moveTo(this.startPoint.x, this.startPoint.y)
            this.ctx.lineTo(this.startPoint.x + this.innerWidth, this.startPoint.y)
            this.ctx.stroke()
            //绘制横向标尺
            var distance = Math.floor(this.innerWidth / this.data.length)
            this.ctx.beginPath()
            this.ctx.strokeStyle = "#999"
            for(let i = 0; i <this.data.length; i++){
                let curX = this.startPoint.x + distance*i
                this.ctx.moveTo(curX , this.startPoint.y)
                this.ctx.lineTo(curX , this.startPoint.y - 5)
                this.ctx.moveTo(curX , this.startPoint.y + 15)
                this.ctx.textAlign = "center"
                this.ctx.fillText(this.data[i]['key'] , curX , this.startPoint.y + 15 )
            }
            this.ctx.stroke()
            //绘制横向坐标
            var unit = Math.floor((this.max - this.min) / 20)
            this.ctx.beginPath()
            this.ctx.strokeStyle = "#999"
            for(let y = 0; y <20; y++){
                let curY = Math.floor(this.startPoint.y - this.innerHieght / 20 * y)
                let curVal = Math.floor(this.min + unit*y)
                this.ctx.moveTo(this.startPoint.x, curY)
                this.ctx.lineTo(this.startPoint.x + 5, curY)
                this.ctx.moveTo(this.startPoint.x - 30, curY)
                this.ctx.fillText(curVal, this.startPoint.x - 15 , curY + 3 )
            }
            this.ctx.stroke()
            //绘制title
            this.ctx.beginPath()
            this.ctx.fOnt= "20px Arial"
            this.ctx.fillText(this.title, this.width / 2 - 30 , 20)
            this.ctx.stroke()
        },
        //绘制折线
        drawLine: function(){
            var distance = Math.floor(this.innerWidth / this.data.length)
            this.ctx.beginPath()
            this.ctx.moveTo(this.startPoint.x, this.startPoint.y)
            for(let i = 0; i <this.data.length; i++){
                let curY = this.startPoint.y - (((this.data[i].val - this.min)/(this.max - this.min)) * this.innerHieght)
                this.ctx.lineTo(this.startPoint.x + i*distance, curY)
                this.ctx.strokeStyle = "#000"
                this.ctx.fOnt= "10px Arial"
                this.ctx.fillText(Math.floor(this.data[i].val), this.startPoint.x + i*distance, curY + 10 )
                this.ctx.stroke()
                this.ctx.beginPath()
                this.ctx.fill
                this.ctx.arc(this.startPoint.x + i*distance, curY,3,0,2*Math.PI);
                this.ctx.fill()
                this.ctx.beginPath()
                this.ctx.moveTo(this.startPoint.x + i*distance, curY)
            }
        }

绘制饼状图

        //绘制饼状图
        drawPieChart: function(){
            var shortAxis = this.width <this.height ? this.width : this.height
            this.radius = 0.4 * shortAxis
            var width = this.width
            var height = this.height
            this.centerPoint = { x: width/2, y: height/2 + 20}
            this.drawPieLegend()
            this.calcPercentage()
            this.drawPie()
        },
        //计算饼状图比例
        calcPercentage: function(){
            var total = 0
            this.data.map((item,index) => {
                total += item.val
            })
            this.data.map((item,index) => {
                item.proportion = Math.floor(item.val / total * 100000) / 100000
            })
        },
        //绘制饼状图内容
        drawPie: function(){
            var offset = 0
            for(let i = 0; i <this.data.length; i++){
                this.ctx.beginPath()
                this.ctx.moveTo(this.centerPoint.x, this.centerPoint.y)
                this.ctx.arc(this.centerPoint.x, this.centerPoint.y, this.radius, 2*Math.PI*offset, 2*Math.PI*(this.data[i].proportion + offset))
                this.ctx.closePath()
                this.ctx.fillStyle = this.data[i].bg
                this.ctx.fill()
                this.ctx.beginPath()
                let x = this.centerPoint.x + Math.cos(2*Math.PI*(this.data[i].proportion/2 + offset))*this.radius
                let y = this.centerPoint.y + Math.sin(2*Math.PI*(this.data[i].proportion/2 + offset))*this.radius
                this.ctx.moveTo(x, y)
                let x1 = this.centerPoint.x + Math.cos(2*Math.PI*(this.data[i].proportion/2 + offset))*(this.radius + 50)
                let y1 = this.centerPoint.y + Math.sin(2*Math.PI*(this.data[i].proportion/2 + offset))*(this.radius + 50)
                this.ctx.lineTo(x1, y1)
                this.ctx.stroke()
                this.ctx.fillText(this.data[i].proportion + '%', x1 - 10, y1)
                offset += this.data[i].proportion
            }
        },
        //绘制饼状图图例
        drawPieLegend: function(){
            for(let i = 0; i <this.data.length; i++){
                let color = '#'+Math.floor(Math.random()*0xffffff).toString(16)
                this.data[i].bg = color
                this.ctx.fillStyle = color
                this.ctx.fillRect(this.width - 100, 30 * i + 50, 40, 20)
                this.ctx.fillText(this.data[i].key, this.width - 50 , 30 * i + 65)
            }
        },

 使用:

引入 chart.js 文件

 
    var chart = new myChart({
        width: document.body.clientWidth,
        height: 500,
        el: '#app',
        data: arr,
        title: `${data.name}(${data.symbol})`,
        type: 'line'
    })
    chart.init()

推荐阅读
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了关系型数据库和NoSQL数据库的概念和特点,列举了主流的关系型数据库和NoSQL数据库,同时描述了它们在新闻、电商抢购信息和微博热点信息等场景中的应用。此外,还提供了MySQL配置文件的相关内容。 ... [详细]
  • 本文介绍了Cocos2dx学习笔记中的更新函数scheduleUpdate、进度计时器CCProgressTo和滚动视图CCScrollView的用法。详细介绍了scheduleUpdate函数的作用和使用方法,以及schedule函数的区别。同时,还提供了相关的代码示例。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
  • Spring框架《一》简介
    Spring框架《一》1.Spring概述1.1简介1.2Spring模板二、IOC容器和Bean1.IOC和DI简介2.三种通过类型获取bean3.给bean的属性赋值3.1依赖 ... [详细]
  • OpenMap教程4 – 图层概述
    本文介绍了OpenMap教程4中关于地图图层的内容,包括将ShapeLayer添加到MapBean中的方法,OpenMap支持的图层类型以及使用BufferedLayer创建图像的MapBean。此外,还介绍了Layer背景标志的作用和OMGraphicHandlerLayer的基础层类。 ... [详细]
author-avatar
我爱左_470
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有