柱图
canvas画图最主要的就是把一张图分成各个部分,然后一块一块的去进行绘制,比如柱图,在绘制的过程中就可以分成x轴,x轴的label,y轴,y轴的label,平行于x轴的分割线,以及每个柱体等等和一些细节。
柱图的x轴就是等分嘛,有几个数据就等分成几块,y轴就是先得出数据的最大值,然后看你想把这最大值均分成几份嘛,比如把1200分成4份,那y轴就是被均分成四份,每个刻度就是300
还是要强调一点,以为上面这个图片中的柱图用的是svg,所以一定要先加载图片,等图片加载完了之后再调用绘制函数
js
function DrawRect(dataArr1, dataArr2, nameArr, index) {
var canvas = document.querySelector('#cav5')
var cav = canvas.getContext('2d');
cav.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight);
var width = canvas.clientWidth
var height = canvas.clientHeight
var zeroPoint = [width * 0.1, height * 0.9] //柱图图表零点坐标
var Yheight = height * 0.5 //图表高度
var Xwidth = width * 0.8 //图表宽度
var Ypoint = [zeroPoint[0], zeroPoint[1] - Yheight] //Y轴顶点坐标
var Xpoint = [zeroPoint[0] + Xwidth, zeroPoint[1]] //X轴右端坐标
var Xpatition = Xwidth * 0.95 / nameArr.length //第一个柱图的横坐标
var namePoint = [Xpatition / 2 + zeroPoint[0], zeroPoint[1] + 15] //X轴第一个label的坐标
//数据处理获取两个数组中的最大值
var max = dataArr1[0]
for (let i = 0; i < dataArr1.length; i++) {
if (max <= dataArr1[i]) {
max = dataArr1[i]
}
}
for (let i = 0; i < dataArr2.length; i++) {
if (max <= dataArr2[i]) {
max = dataArr2[i]
}
}
var Ypatition = Yheight * 0.95 / 5 //Y轴分隔距离
var dataPoint = [zeroPoint[0] - 15, zeroPoint[1] - Ypatition / 2] //Y轴label的坐标
var YdataLabel = [] //Y轴label数组
var dataLabel = max / 5 //Y轴分割的倍数
for (let i = 0; i < 5; i++) {
YdataLabel.push(dataLabel)
dataLabel += max / 5
}
var barWidth = 10 //柱体宽度
var linePoint = [] //柱图连线的端点坐标数组
var tipsPoint = [] //提示框的坐标数组
//Y轴
cav.beginPath()
cav.moveTo(zeroPoint[0], zeroPoint[1])
cav.lineTo(Ypoint[0], Ypoint[1])
cav.strokeStyle = 'red'
cav.closePath()
cav.stroke()
//X轴
cav.beginPath()
cav.moveTo(zeroPoint[0], zeroPoint[1])
cav.lineTo(Xpoint[0], Xpoint[1])
cav.strokeStyle = 'red'
cav.closePath()
cav.stroke()
//Y轴端点箭头
cav.beginPath()
cav.moveTo(Ypoint[0], Ypoint[1])
cav.lineTo(Ypoint[0] - 3, Ypoint[1] + 3)
cav.strokeStyle = 'red'
cav.stroke()
cav.save()
cav.restore()
cav.lineTo(Ypoint[0] + 3, Ypoint[1] + 3)
cav.strokeStyle = 'red'
cav.stroke()
cav.closePath()
cav.fillStyle = 'red'
cav.fill()
//X轴端点箭头
cav.beginPath()
cav.moveTo(Xpoint[0], Xpoint[1])
cav.lineTo(Xpoint[0] - 3, Xpoint[1] - 3)
cav.strokeStyle = 'red'
cav.stroke()
cav.save()
cav.restore()
cav.lineTo(Xpoint[0] - 3, Xpoint[1] + 3)
cav.strokeStyle = 'red'
cav.stroke()
cav.closePath()
cav.fillStyle = 'red'
cav.fill()
//Y轴文字及分割线
for (let i = 0; i < YdataLabel.length; i++) {
cav.textAlign = 'end'
cav.textBaseline = 'middle'
cav.font = '14px'
cav.fillStyle = 'red'
cav.fillText(parseInt(YdataLabel[i]) + '', dataPoint[0], dataPoint[1])
cav.beginPath()
cav.moveTo(zeroPoint[0], dataPoint[1])
cav.lineTo(Xpoint[0], dataPoint[1])
cav.strokeStyle = 'red'
cav.closePath()
cav.stroke()
dataPoint[1] -= Ypatition
}
//高亮框
var lightHeightColor = cav.createLinearGradient(Xpatition * index + zeroPoint[0] + 15, zeroPoint[1] - Yheight,
Xpatition * (index + 1) + zeroPoint[0] - 15, zeroPoint[1]);
lightHeightColor.addColorStop(0, "rgba(53,103,235,1)");
lightHeightColor.addColorStop(1, 'rgba(53,103,235,0.3)');
cav.beginPath()
cav.rect(Xpatition * (index) + zeroPoint[0], zeroPoint[1] - Yheight, Xpatition, Yheight)
cav.fillStyle = lightHeightColor
cav.fill()
for (let i = 0; i < nameArr.length; i++) {
//文字
cav.textAlign = 'center'
cav.textBaseline = 'top'
cav.font = '14px'
cav.fillStyle = 'red'
cav.fillText(nameArr[i], namePoint[0], namePoint[1])
//柱图
var barHeight1 = dataArr1[i] / max * 0.95 * Yheight - Ypatition / 2
var barHeight2 = dataArr2[i] / max * 0.95 * Yheight - Ypatition / 2
cav.drawImage(img, namePoint[0] - barWidth, zeroPoint[1] - barHeight1, barWidth, barHeight1)
cav.drawImage(img3, namePoint[0] - barWidth, zeroPoint[1] - barHeight1 - img3.height / 2, barWidth, img3
.height)
cav.drawImage(img2, namePoint[0], zeroPoint[1] - barHeight2, barWidth, barHeight2)
cav.drawImage(img4, namePoint[0], zeroPoint[1] - barHeight2 - img4.height / 2, barWidth, img4.height)
linePoint.push({
startX: namePoint[0] - barWidth / 2,
startY: zeroPoint[1] - barHeight1,
endX: namePoint[0] + barWidth / 2,
endY: zeroPoint[1] - barHeight2
})
namePoint[0] += Xpatition
}
//连线
cav.beginPath()
cav.setLineDash([2]);
cav.strokeStyle = "#fff"
cav.moveTo(linePoint[index].startX, linePoint[index].startY)
cav.lineTo(linePoint[index].endX, linePoint[index].endY)
cav.closePath()
cav.stroke()
//连线端点圆点
cav.beginPath()
cav.arc(linePoint[index].startX, linePoint[index].startY, 2, 0, Math.PI * 2, false)
cav.fillStyle = '#fff'
cav.closePath()
cav.fill()
cav.beginPath()
cav.arc(linePoint[index].endX, linePoint[index].endY, 2, 0, Math.PI * 2, false)
cav.fillStyle = '#fff'
cav.closePath()
cav.fill()
//文字框
if (dataArr1[index] > dataArr2[index]) {
if(index==dataArr2.length-1) {
tipsPoint[0] = linePoint[index].startX-tipsImg.width
}else {
tipsPoint[0] = linePoint[index].startX
}
tipsPoint[1] = linePoint[index].startY - tipsImg.height
} else {
if(index==dataArr2.length-1) {
tipsPoint[0] = linePoint[index].endX-tipsImg.width
}else {
tipsPoint[0] = linePoint[index].endX
}
tipsPoint[1] = linePoint[index].endY - tipsImg.height
}
cav.drawImage(tipsImg, tipsPoint[0], tipsPoint[1])
cav.textAlign = 'start'
cav.textBaseline = 'middle'
cav.font = '14px'
cav.fillStyle = 'red'
cav.fillText('独立用户', tipsPoint[0] + 10, tipsPoint[1] + tipsImg.height / 3)
cav.textAlign = 'right'
cav.textBaseline = 'middle'
cav.font = '14px'
cav.fillStyle = '#fff'
cav.fillText(dataArr1[index], tipsPoint[0] + tipsImg.width - 12, tipsPoint[1] + tipsImg.height / 3)
cav.textAlign = 'start'
cav.textBaseline = 'middle'
cav.font = '14px'
cav.fillStyle = 'red'
cav.fillText('浏览量', tipsPoint[0] + 10, tipsPoint[1] + tipsImg.height - 15)
cav.textAlign = 'right'
cav.textBaseline = 'middle'
cav.font = '14px'
cav.fillStyle = '#fff'
cav.fillText(dataArr2[index], tipsPoint[0] + tipsImg.width - 12, tipsPoint[1] + tipsImg.height - 15)
}