热门标签 | 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()

推荐阅读
  • Gradle 是 Android Studio 中默认的构建工具,了解其基本配置对于开发效率的提升至关重要。本文将详细介绍如何在 Gradle 中定义和使用共享变量,以确保项目的一致性和可维护性。 ... [详细]
  • 【MySQL】frm文件解析
    官网说明:http:dev.mysql.comdocinternalsenfrm-file-format.htmlfrm是MySQL表结构定义文件,通常frm文件是不会损坏的,但是如果 ... [详细]
  • 本文探讨了互联网服务提供商(ISP)如何可能篡改或插入用户请求的数据流,并提供了有效的技术手段来防止此类劫持行为,确保网络环境的安全与纯净。 ... [详细]
  • 本文详细介绍了如何使用C#实现不同类型的系统服务账户(如Windows服务、计划任务和IIS应用池)的密码重置方法。 ... [详细]
  • C/C++ 应用程序的安装与卸载解决方案
    本文介绍了如何使用Inno Setup来创建C/C++应用程序的安装程序,包括自动检测并安装所需的运行库,确保应用能够顺利安装和卸载。 ... [详细]
  • 本文详细介绍了如何在 Ubuntu 14.04 系统上搭建仅使用 CPU 的 Caffe 深度学习框架,包括环境准备、依赖安装及编译过程。 ... [详细]
  • 尽管在WPF中工作了一段时间,但在菜单控件的样式设置上遇到了一些基础问题,特别是关于如何正确配置前景色和背景色。 ... [详细]
  • 解决Win10 1709版本文件共享安全警告问题
    每当Windows 10发布新版本时,由于兼容性问题往往会出现各种故障。近期,一些用户在升级至1709版本后遇到了无法访问共享文件夹的问题,系统提示‘文件共享不安全,无法连接’。本文将提供多种解决方案,帮助您轻松解决这一难题。 ... [详细]
  • Fiddler 安装与配置指南
    本文详细介绍了Fiddler的安装步骤及配置方法,旨在帮助用户顺利抓取用户Token。文章还涵盖了一些常见问题的解决方案,以确保安装过程顺利。 ... [详细]
  • 深入解析C语言中的关键字及其分类
    本文将全面介绍C语言中的关键字,并按照功能将其分为数据类型关键字、控制结构关键字、存储类别关键字和其他关键字四大类,旨在帮助读者更好地理解和运用这些基本元素。C语言中共有32个关键字。 ... [详细]
  • 本文探讨了Linux环境下线程私有数据(Thread-Specific Data, TSD)的概念及其重要性,介绍了如何通过TSD技术避免多线程间全局变量冲突的问题,并提供了具体的实现方法和示例代码。 ... [详细]
  • 本文介绍了Tomcat的基本操作,包括启动、关闭及首次访问的方法,并详细讲解了如何在IDEA中创建Web项目,配置Servlet及其映射,以及如何将项目部署到Tomcat。 ... [详细]
  • 本文详细介绍如何在SSM(Spring + Spring MVC + MyBatis)框架中实现分页功能。包括分页的基本概念、数据准备、前端分页栏的设计与实现、后端分页逻辑的编写以及最终的测试步骤。 ... [详细]
  • Spring Security基础配置详解
    本文详细介绍了Spring Security的基础配置方法,包括如何搭建Maven多模块工程以及具体的安全配置步骤,帮助开发者更好地理解和应用这一强大的安全框架。 ... [详细]
  • Asynchronous JavaScript and XML (AJAX) 的流行很大程度上得益于 Google 在其产品如 Google Suggest 和 Google Maps 中的应用。本文将深入探讨 AJAX 在 .NET 环境下的工作原理及其实现方法。 ... [详细]
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社区 版权所有