仪表盘其实也是环图的一种,但是比环图多的是一个指针,指针需要根据环图的进度调整位置,而这其中主要用到的就是canvas的旋转,但是注意的是canvas的旋转是以画布原点为旋转中心旋转的,因此,我们需要将旋转中心调整到我们需要的位置,再对画布进行旋转,要记得旋转完成之后,需要逆向旋转并平移复位,不然之后会错位的
有一点需要注意的是,如果其中有一段描边使用了ctx.setLineDash([])设置描边样式为虚线了,那么之后的所有描边都有可能会变成虚线,因此,在此后如果有实线的话需要通过ctx.setLineDash([1,0])的方法设置回来。 其中的两个参数分别是实线的像素长度,空位置的像素长度,比如[3,2]就是实线3像素,空2像素所以[1,0]就是实线1像素,空0像素也就是全都是实线
function DrawDoubleHalfCircle(data) { var canvas = document.querySelector('#cav6') var circlePoint = [canvas.clientWidth / 2, canvas.clientHeight / 2] var cav = canvas.getContext('2d') cav.clearRect(0, 0, canvas.clientWidth, canvas.clientHeight); var startAngle = Math.PI //圆圈中心文字 cav.textAlign = 'center' cav.textBaseline = 'middle' cav.font = '24px MeicrosoftYahei' cav.fillStyle = '#fff' cav.fillText('营销', circlePoint[0], circlePoint[1]) //文字外部圆环 var circleLine = cav.createLinearGradient(circlePoint[0], circlePoint[1] - 46, circlePoint[0], circlePoint[1] + 46); circleLine.addColorStop(0, "#FCECF4"); circleLine.addColorStop(0.4, '#0D135F'); circleLine.addColorStop(0.6, '#0D135F'); circleLine.addColorStop(1, '#FCECF4'); cav.beginPath() cav.lineWidth = 3 cav.arc(circlePoint[0], circlePoint[1], 46, 0, Math.PI * 2, true) cav.strokeStyle = circleLine cav.stroke() //文字外部圆环外部的圆圈 var circlePie = cav.createLinearGradient(circlePoint[0], circlePoint[1] - 67, circlePoint[0], circlePoint[1] + 67); circlePie.addColorStop(0, "rgba(255,255,255,0)"); circlePie.addColorStop(0.5, 'rgba(255,255,255,0.2)'); circlePie.addColorStop(1, 'rgba(255,255,255,0)'); cav.beginPath() cav.arc(circlePoint[0], circlePoint[1], 67, 0, Math.PI * 2, true) cav.fillStyle = circlePie cav.fill() //上半圆底纹 var topHalf = cav.createLinearGradient(circlePoint[0] - 94, circlePoint[1], circlePoint[0] + 94, circlePoint[1]); topHalf.addColorStop(0, "rgba(17, 6, 67,0)"); topHalf.addColorStop(1, 'rgba(17, 6, 67,1)'); cav.beginPath() cav.lineWidth = 16 cav.arc(circlePoint[0], circlePoint[1], 94, startAngle, Math.PI * 2, false) cav.strokeStyle = topHalf cav.setLineDash([1, 0]); cav.stroke() //下半圆底纹 cav.beginPath() cav.lineWidth = 16 cav.arc(circlePoint[0], circlePoint[1], 94, startAngle, 0, true) cav.strokeStyle = 'rgb(235, 73, 86)' cav.setLineDash([1, 5]); cav.stroke() //水平虚线及初始和饱和值 var lineDash1 = cav.createLinearGradient(0, circlePoint[1], circlePoint[0] - 48, circlePoint[1]); lineDash1.addColorStop(0, "rgba(255, 255, 255,0)"); lineDash1.addColorStop(1, 'rgba(255, 255, 255,1)'); cav.beginPath() cav.moveTo(0, circlePoint[1]) cav.lineTo(circlePoint[0] - 48, circlePoint[1]) cav.strokeStyle = lineDash1 cav.setLineDash([4, 2]) cav.lineWidth = 1 cav.stroke() var lineDash2 = cav.createLinearGradient(circlePoint[0] + 48, circlePoint[1], canvas.clientWidth, circlePoint[1]); lineDash2.addColorStop(0, "rgba(255, 255, 255,1)"); lineDash2.addColorStop(1, 'rgba(255, 255, 255,0)'); cav.beginPath() cav.moveTo(circlePoint[0] + 48, circlePoint[1]) cav.lineTo(canvas.clientWidth, circlePoint[1]) cav.strokeStyle = lineDash2 cav.setLineDash([4, 2]) cav.lineWidth = 1 cav.stroke() cav.textAlign = 'right' cav.textBaseline = 'middle' cav.font = '26px MeicrosoftYahei' cav.fillStyle = '#fff' cav.fillText('0', circlePoint[0] - 110, circlePoint[1]) cav.textAlign = 'start' cav.textBaseline = 'middle' cav.font = '26px MeicrosoftYahei' cav.fillStyle = '#fff' cav.fillText('100', circlePoint[0] + 110, circlePoint[1]) //上半圆数据显示 var PointAssemble = getPoint(startAngle, parseFloat(data[0]) * Math.PI + startAngle, 94, circlePoint[0], circlePoint[1]) var topHalfData = cav.createLinearGradient(circlePoint[0] - 94, circlePoint[1], PointAssemble.endPointX, PointAssemble.endPointY); topHalfData.addColorStop(0, "rgba(245, 75, 82,0)"); topHalfData.addColorStop(1, 'rgba(245, 75, 82,1)'); cav.beginPath() cav.lineWidth = 16 cav.arc(circlePoint[0], circlePoint[1], 94, startAngle, parseFloat(data[0]) * Math.PI + startAngle, false) cav.setLineDash([1, 0]); cav.strokeStyle = topHalfData cav.stroke() cav.drawImage(chartBall, PointAssemble.endPointX - chartBall.width / 2, PointAssemble.endPointY - chartBall .height / 2) //下半圆数据显示 var PointAssemble2 = getPoint(startAngle, startAngle - parseFloat(data[1]) * Math.PI, 94, circlePoint[0], circlePoint[1]) var bottomHalfData = cav.createLinearGradient(circlePoint[0] - 94, circlePoint[1], PointAssemble2.endPointX, PointAssemble2.endPointY); bottomHalfData.addColorStop(0, "rgba(255,255,255,0)"); bottomHalfData.addColorStop(1, 'rgba(255,255,255,1)'); cav.beginPath() cav.lineWidth = 16 cav.arc(circlePoint[0], circlePoint[1], 94, startAngle, startAngle - parseFloat(data[1]) * Math.PI, true) cav.setLineDash([1, 0]); cav.strokeStyle = bottomHalfData cav.stroke() //上半圆箭头指示 cav.translate(circlePoint[0], circlePoint[1]) cav.rotate(parseFloat(data[0]) * Math.PI) cav.drawImage(needle, -40 - needle.width, -needle.height / 2) cav.rotate(-parseFloat(data[0]) * Math.PI) cav.translate(-circlePoint[0], -circlePoint[1]) //下半圆箭头指示 cav.translate(circlePoint[0], circlePoint[1]) cav.rotate(-parseFloat(data[1]) * Math.PI) cav.drawImage(needle, -40 - needle.width, -needle.height / 2) cav.rotate(parseFloat(data[1]) * Math.PI) cav.translate(-circlePoint[0], -circlePoint[1]) //上半圆具体数据 //判断数据提示框的显示位置数据占比大于50%就靠右显示,否则靠左显示 if (parseFloat(data[0]) < 0.5) { cav.drawImage(activeBar, PointAssemble.endPointX - 22 * ((data[0] * 100).toFixed(1) + '%').length - 10, PointAssemble.endPointY - 35) } else { cav.drawImage(activeBar, PointAssemble.endPointX + 10, PointAssemble.endPointY - 35) } cav.textAlign = parseFloat(data[0]) < 0.5 ? 'right' : 'start' cav.textBaseline = 'bottom' cav.font = 'bold 36px Akrobat-Black' cav.fillStyle = '#fff' if (parseFloat(data[0]) < 0.5) { cav.fillText((data[0] * 100).toFixed(1) + '%', PointAssemble.endPointX - 10, PointAssemble.endPointY - 20) } else { cav.fillText((data[0] * 100).toFixed(1) + '%', PointAssemble.endPointX + 10, PointAssemble.endPointY - 20) } //下半圆具体数据 if (parseFloat(data[1]) < 0.5) { cav.drawImage(norBar, PointAssemble2.endPointX - 22 * ((data[1] * 100).toFixed(1) + '%').length - 10, PointAssemble2.endPointY + 45) } else { cav.drawImage(norBar, PointAssemble2.endPointX + 10, PointAssemble2.endPointY + 45) } cav.textAlign = parseFloat(data[1]) < 0.5 ? 'right' : 'start' cav.textBaseline = 'top' cav.font = 'bold 36px Akrobat-Black' cav.fillStyle = '#fff' if (parseFloat(data[1]) < 0.5) { cav.fillText((data[1] * 100).toFixed(1) + '%', PointAssemble2.endPointX - 10, PointAssemble2.endPointY + 25) } else { cav.fillText((data[1] * 100).toFixed(1) + '%', PointAssemble2.endPointX + 10, PointAssemble2.endPointY + 25) } }