在微信小程序里面用canvas画区间图
需求:需要展示日、周、月、年的区间图
解决方案
我发现用chart.js或者echarts都不能满足需求,所以决定用d3试一下,结果发现小程序不支持d3,所以决定用原生画一个
以下是效果图
wxml
<view style="height:500px">
<canvas id="firstCanvas" type="2d"></canvas>
</view>
wxss
#firstCanvas{
width: 300px;
height: 185px;
border: 1px solid #ddd;
display: block;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
js
import {recordPaint} from '../../utils/canvas'
Page({
data: {
path: ''
},
onLoad(option) {
this.setcanvas('#firstCanvas')
},
setcanvas(text){
const query = wx.createSelectorQuery()
query.select(text)
.fields({ node: true, size: true })
.exec((res) => {
console.log(res)
const canvas = res[0].node
const datas = [[0,0],[97,81],[0,0],[96,85],[0,0],[0,0],[0,0],[0,0],[95,94],[0,0],[97,96],[0,0],[0,0],[0,0],[96,94],[96,95],[94,93],[0,0],[0,0],[0,0],[0,0],[71,70],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]]
const color = ['rgba(90,200,250,0.5)','#5AC8FA']
const xdata = [1,2,3,4,5,6,7,8,9,10,11,12,13]
const stepSize = 10
const max = 100
const min = 70
const datas1 = []
recordPaint(canvas,datas,datas1,color,xdata,stepSize,max,min)
})
}
})
canvas.js
export function recordPaint(elem, datas,datas1,color,xdata,stepSize,max,min) {
//1.创建画布对象
var context = elem.getContext('2d');
// 设置canvas的真实宽高
elem.width = 2 * elem._width; // 想当于 2 * 375 = 750
elem.height = 2 * elem._height;
//2、获取画布的宽度和高度
const WIDTH = elem.width;
const HEIGHT = elem.height;
//定义坐标轴相对于画布的内边距
var padding = 10;//初始化内边距
var paddingLeft = 40;// 至少大于绘制文字的宽度
var paddingBottom = 30;// 至少大于绘制文字的高度
// 4、定义绘制坐标轴的关键点的坐标值
var axisY = { // y轴的起点坐标值
x: paddingLeft,
y: paddingBottom
};
var origin = { // 原点坐标值(x轴与y轴交叉点)
x: paddingLeft,
y: HEIGHT - paddingBottom
};
var axisX = { // X轴的起点坐标值
x: WIDTH - padding-5,
y: HEIGHT - paddingBottom
};
context.strokeStyle = '#BDC2CE'
context.fillStyle = '#BDC2CE'
//存储x轴的值
var pointsX = [];
//绘制坐标轴的刻度
//x轴的月份
var month = {
x: paddingLeft,
y: HEIGHT - paddingBottom + 5
};
let z = (axisX.x - origin.x) / xdata.length/2 // 格子的中间值
for (var i = 0; i < xdata.length; i++) {
context.textBaseline = "top";
context.font = "20pt Calibri"
context.fillText(xdata[i], month.x+z, month.y); // 设置x轴值
pointsX.push(month.x + z);
month.x += (axisX.x - origin.x) / xdata.length;
}
//绘制y轴值
var moneyY = (origin.y - axisY.y) / ((max-min) / stepSize)
var money = {
x: axisX.x + 20,
y: axisY.y + moneyY-4,
jin: max
}
//遍历y轴值
for (var i = 0; i <= (max-min) / stepSize; i++) {
context.fillText(money.jin,0, money.y-moneyY); // 设置y轴值
money.y += moneyY;
money.jin -= stepSize;
}
//绘制水平方向的网格线
let n = (max-min) / stepSize
for(let y=origin.y;y>moneyY;y-=moneyY){
//开启路径
if(n > 1){
drawDashLine(context,origin.x + 5,y-moneyY, axisX.x,y-moneyY)
}else{
context.beginPath()
context.fillStyle = color[0]
context.moveTo(origin.x,y-moneyY)
context.lineTo(axisX.x,y-moneyY)
context.stroke()
}
// context.font = "20pt Calibri"
// context.fillText(money.jin,0, money.y-moneyY); // 设置y轴值
// money.y += moneyY;
// money.jin -= stepSize;
n--
}
//绘制垂直方向的网格线
let space1 = (axisX.x - origin.x) / xdata.length
for(let x=origin.x;x<axisX.x+space1;x+=space1){
//开启路径
context.beginPath()
context.lineWidth = 1
if(max == 350){
context.moveTo(x,axisY.y-10)
context.lineTo(x,origin.y)
}else{
context.moveTo(x,axisY.y)
context.lineTo(x,origin.y)
}
context.stroke()
}
//绘制坐标轴
context.beginPath()
context.moveTo(axisY.x, axisY.y)
context.lineTo(origin.x, origin.y)
context.lineTo(axisX.x, axisX.y)
context.stroke();
//绘制折线
var width=12;//设定每个柱子的宽度
for (let i = 0; i < datas.length; i++) {
context.beginPath();
context.fillStyle = color[0]
//x轴的坐标
let pointX = pointsX[i];
if (datas[i][0]!=0 && datas[i][1]!=0){
//y轴的坐标
let pointY = origin.y - (origin.y - (axisY.y)) * datas[i][0] / max;
let pointY1 = origin.y - (origin.y - (axisY.y)) * datas[i][1] / max;
if (i === 0) {
// context.textBaseline = "";
context.textAlign = "left"
context.moveTo(pointX, pointY);
} else {
context.textBaseline = "bottom";
context.textAlign = "center"
context.lineTo(pointX, pointY);
}
var height = pointY-pointY1
//绘制
context.fillRect(pointX-6,pointY, width, -height);//绘制一个柱状
}
}
for (let i = 0; i < datas1.length; i++) {
context.beginPath();
context.fillStyle = color[2]
//x轴的坐标
let pointX = pointsX[i];
if (datas1[i][0]!=0 && datas1[i][1]!=0){
//y轴的坐标
let pointY = origin.y - (origin.y - (axisY.y)) * datas1[i][0] / max;
let pointY1 = origin.y - (origin.y - (axisY.y)) * datas1[i][1] / max;
if (i === 0) {
// context.textBaseline = "";
context.textAlign = "left"
context.moveTo(pointX, pointY);
} else {
context.textBaseline = "bottom";
context.textAlign = "center"
context.lineTo(pointX, pointY);
}
var height = pointY-pointY1
//绘制
context.fillRect(pointX-6,pointY, width, -height);//绘制一个柱状
}
}
context.stroke();
//绘制小圆点
for(let i = 0; i < datas.length; i++){
//x轴的坐标
let pointX = pointsX[i];
//y轴的坐标
if(datas[i][0]!=0 && datas[i][1]!=0){
let pointY = origin.y - (origin.y - (axisY.y)) * datas[i][0] / max;
let pointY1 = origin.y - (origin.y - (axisY.y)) * datas[i][1] / max;
context.fillStyle = color[1]
context.beginPath();
context.arc(pointX,pointY1,6,0,2*Math.PI);
context.arc(pointX,pointY,6,0,2*Math.PI);
context.fill();
}
}
for(let i = 0; i < datas1.length; i++){
//x轴的坐标
let pointX = pointsX[i];
//y轴的坐标
if(datas1[i][0]!=0 && datas1[i][1]!=0){
let pointY = origin.y - (origin.y - (axisY.y)) * datas1[i][0] / max;
let pointY1 = origin.y - (origin.y - (axisY.y)) * datas1[i][1] / max;
context.fillStyle = color[3]
context.beginPath();
context.arc(pointX,pointY1,6,0,2*Math.PI);
context.arc(pointX,pointY,6,0,2*Math.PI);
context.fill();
}
}
}
function drawDashLine(context, x1, y1, x2, y2, dashLength) { //绘制虚线
dashLength = dashLength === undefined ? 5 : dashLength
var deltaX = x2 - x1;
var deltaY = y2 - y1;
var numDashes = Math.floor(
Math.sqrt(deltaX * deltaX + deltaY * deltaY) / dashLength
)
for(var i = 0; i < numDashes; i++) {
context[ i % 2 === 0 ? 'moveTo' : 'lineTo']
(x1 + (deltaX / numDashes) * i, y1 + (deltaY / numDashes) * i);
}
context.fillStyle = "#BDC2CE";
context.stroke();
}
还有一个用d3画的区间图,有需要的去我博客取http://t.csdn.cn/0m7mJ