如图所示:
画布组件:dashboard.vue
<template> <div> <canvas ref="canvas" v-if="change" id="canvas" width="600" height="400" style="width: 300px;height: 200px;"></canvas> </div> </template> <script> export default { data() { return { change: true, text:['信用极差','信用较差','信用良好','信用极好'] }; }, props: ['score'], methods: { canvasScore(id, getScore) { const vm = this; if(this.common.basics.isNull(getScore)){ getScore = 999 } let fillText=vm.text[Math.floor(getScore/250)]; if(this.common.basics.isNull(fillText)){ fillText = vm.text[3]; } new init(this.$refs.canvas, { teamNum: 20, radius: 10 / 2, fullMarks:1000, grade:getScore, color:'#44AAC9', fillColor:'#ffffff', function:function(ctx,options){ ctx.font = '500 72px microsoft yahei'; ctx.textAlign = 'center'; ctx.fillStyle = '#ffffff'; ctx.fillText(options.grade, options.circle_x, options.circle_y-20); ctx.font = '500 40px microsoft yahei'; ctx.textAlign = 'center'; ctx.fillStyle = '#ffffff'; ctx.fillText(fillText, options.circle_x, options.circle_y+45); } }) } }, mounted() { this.canvasScore('canvas', this.score); }, watch: { 'score'() { this.change = false; this.$nextTick(() => { this.change = true; this.$nextTick(() => { this.canvasScore('canvas', this.score); }); }); } } }; /** * @desc:canvas绘画芝麻分仪表盘 * @param:canvas canvas自身 * @param:options options配置 * @param:options-width canvas宽度 * @param:options-height canvas高度 * @param:options-teamNum 小圆的个数 * @param:options-radius 小圆的直径 * @param:options-designChartWidth //设计图宽度 默认750 * @param:options-fillColor //小圆达到指标后的填充颜色 * @param:options-color //小圆的默认颜色 * @param:options-fontSzie //字体大小 * @param:options-fontColor //字体颜色 * @param:options-fullMarks//总分数 * @param:options-grade//目标分数 * @param:options-function//其他操作 函数 接受ctx-canvas 2d options-配置 */ function init(canvas, options) { if (!options) { options = {}; } var cxt = canvas.getContext('2d'); var clientWidth = document.documentElement.clientWidth;//根据设计图中的canvas画布的占比进行设置 options.width = 371;//canvas的宽 options.height = 270;//canvas的高 var canvasWidth = Math.floor(clientWidth * options.width / (options.designChartWidth ? options.designChartWidth : 750)); var canvasHeight = Math.floor(clientWidth * options.height / (options.designChartWidth ? options.designChartWidth : 750)); canvas.setAttribute('width', canvasWidth*this.getDevicePixelRatio()); canvas.setAttribute('height', canvasHeight*this.getDevicePixelRatio()); canvas.style.width = canvasWidth+'px'; canvas.style.height = canvasHeight+'px'; options.radius = options.radius || 50 / 10;//小圆的直径 options.radius = options.radius*this.getDevicePixelRatio() options.team_num = options.teamNum || 10;//小圆的个数 options.circle_r = canvas.getAttribute('width') / 2 - options.radius; // 半径 options.circle_x = 0 + options.circle_r + options.radius; // 圆心坐标x options.circle_y = 0 + options.circle_r + options.radius;//圆心坐标y this.loadTeams(cxt, options); } init.prototype = { loadTeams(cxt, options) {//加载布局模拟图 this.font(cxt, options); this.seating(cxt, options); }, font(cxt, options) {//加载图中文案 if(options.function){ options.function(cxt, options); } }, seating(cxt, options) { //分配小圆座次 var angle = 230 / options.teamNum; //角度 var a = options.fullMarks/options.teamNum;//计算每个小圆代表的值 var team_x = 0, team_y = 0; var team_r = options.radius; // options.team_num < 20 ? 10 : Math.sqrt(options.circle_r * options.circle_r * 2 * (1 - Math.cos(changeRadian(angle)))) / 2; //余弦定理 计算小圆的最大半径 BC2=AB2+AC2-2×AB×AC×cosα 如果小圆数目小于20个,半径最大30(上限) for (var i = 0; i < options.teamNum; i++) { team_x = options.circle_x + Math.sin(this.changeRadian((i * angle) + 250.9)) * options.circle_r; //角度转弧度 team_y = options.circle_y - Math.cos(this.changeRadian((i * angle) + 250.9)) * options.circle_r; cxt.beginPath(); cxt.arc(team_x, team_y, team_r, 0, 2 * Math.PI); if((i+1)*a<=options.grade)cxt.fillStyle = options.fillColor ? options.fillColor : 'red'; else cxt.fillStyle = options.color ? options.color : '#333333'; cxt.fill(); } }, changeRadian(angle) { //角度转换为弧度 return Math.PI / 180 * angle; }, getDevicePixelRatio (){//避免手机端失帧 return window.devicePixelRatio || 1; } } </script> <style scoped> </style>
父组件引用画布组件
<dashboard class="sizeQuery" :score="this.scoreVal"></dashboard>
scoreVal为分数值,从后台获取可得,从而传给画布组件。
此文为原创,不可转发。