uniapp中用canvas绘制简单柱形图,小容量,不用插件
效果图
完整代码
<template>
<view>
<!-- 学习数据 -->
<!-- 头部选项卡 -->
<view class="navTab">
<view :class="listIndex==i?'activite':''" @click="gopage(i)" v-for="(item,i) in navList" :key="i">{{item}}</view>
</view>
<!-- 不同的图表 -->
<view id="mycan">
<canvas style="height: 250px;" canvas-id="DataCanvas" class='canvasII'></canvas>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: '学习数据',
canvasList: [
{date:"9-12",num:0},
{date:"9-13",num:24},
{date:"9-14",num:100},
{date:"9-15",num:45},
{date:"9-16",num:15},
{date:"9-17",num:54},
{date:"9-18",num:10}
],
width:300,
height:200,
canPersent: [] ,//百分比数组
listIndex:0,
navList:["最近七天","最近七个月"],
}
},
onLoad() {
this.showChart()
},
methods: {
gopage(i){
this.listIndex = i
if(i == 0){
this.canvasList = [
{date:"9-12",num:0},
{date:"9-13",num:24},
{date:"9-14",num:100},
{date:"9-15",num:45},
{date:"9-16",num:15},
{date:"9-17",num:54},
{date:"9-18",num:10}], //测试数据
this.showChart()
}else if( i == 1){
this.canvasList = [
{date:"3月",num:0},
{date:"4月",num:234},
{date:"5月",num:120},
{date:"6月",num:145},
{date:"7月",num:15},
{date:"8月",num:543},
{date:"9月",num:10}], //测试数据
this.showChart()
}
},
// 坐标图
showChart() {
const ctx = uni.createCanvasContext("DataCanvas")
ctx.lineWidth = 1;
// 横坐标
ctx.beginPath(); //新建一条path
ctx.setStrokeStyle('#c6c6c6')
ctx.moveTo(20, this.height); //把画笔移动到指定的坐标
ctx.lineTo(this.width, this.height); //绘制一条从当前位置到指定坐标(200, 50)的直线.
ctx.closePath(); //闭合路径。会拉一条从当前点到path起始点的直线。如果当前点与起始点重合,则什么都不做
ctx.stroke(); //绘制路径。
// 纵坐标
ctx.beginPath();
ctx.moveTo(20, 0);
ctx.lineTo(20, this.height);
ctx.closePath();
ctx.stroke();
var max = 0 //最大值
// 找到最大的数
for (var i = 0; i < this.canvasList.length; i++) {
if(this.canvasList[i].num >= max){
max = this.canvasList[i].num
}
}
console.log("max---->",max);
// 计算百分比: 以数组中最大的为100%,来计算其他的百分比
for (var i = 0; i < this.canvasList.length; i++) {
this.canPersent[i] = (this.canvasList[i].num / max) * (this.height-40) // -10 ,防止太高溢出头
}
console.log(this.canPersent);
// 柱状图之间的间隔
// 绘制7个粗线条 (300-20)/7 = 40,所以 i 每次要加上40 20为左右间隔
var gap = (this.width - 10*2) / this.canPersent.length
console.log("--gap----->",gap);
for (var i = 0; i < this.canPersent.length; i++) {
// 横坐标的数据
ctx.fillText(this.canvasList[i].date, 30 + gap * i, 220);
// 柱状图上的数据
ctx.fillText(this.canvasList[i].num, 33 + gap * i, this.height - this.canPersent[i] - 15);
if(this.canPersent[i] == 0){
i++
ctx.fillText(this.canvasList[i].date, 30 + gap * i, 220);
ctx.fillText(this.canvasList[i].num, 33 + gap * i, this.height - this.canPersent[i] - 15);
}
ctx.beginPath();
ctx.setStrokeStyle('#F36521') //设置柱状图颜色
ctx.moveTo(40 + gap*i, this.height - this.canPersent[i] - 6);
ctx.lineTo(40 + gap*i, this.height - 6);
ctx.lineWidth = 10;
ctx.lineCap = "round"; //设置线条样式
ctx.stroke();
}
ctx.draw()
},
}
}
</script>
<style>
#mycan {
margin: 20px;
}
.navTab{
display: flex;
justify-content: space-evenly;
margin: 3px 0;
}
.activite{
color: #fc722d;
padding: 3px 0;
border-bottom: 3px #fc722d solid;
}
</style>
- 其实还可以更完美一点,y轴的数据也可以添加上。
知识点
其实,整个代码就涉及到了一个知识点,只要会画线条就可以了。
坐标轴
和平常的坐标不一样啊,y轴是朝下的。
如何画线条
ctx.beginPath(); //新建一条path
ctx.moveTo(50, 50); //把画笔移动到指定的坐标
ctx.lineTo(200, 50); //绘制一条从当前位置到指定坐标(200, 50)的直线.
ctx.closePath();//闭合路径。会拉一条从当前点到path起始点的直线。如果当前点与起始点重合,则什么都不做
ctx.stroke(); //绘制路径。
ctx.setStrokeStyle('#c6c6c6')//设置线条颜色
ctx.lineWidth = 10;//设置线条宽度
效果图
ctx.moveTo(x1, y1); 起始坐标
ctx.lineTo(x2, y2); 终点坐标
- 会画线条之后,就可以for一下,计算好间隔等等,就可以初步绘制柱形图了
如何绘制文本
ctx.fillText("这是文字", x, y);
同理,绘制折线图
等我有空再画
[参考文档:https://www.runoob.com/w3cnote/html5-canvas-intro.html]