環圖
canvas製作圓形所用的方法是
ctx.arc(x,y,r,0,Math,PI*2,false)
其中的6個參數分別是圓心橫座標,圓心縱座標,半徑,起始角度,結束角度,false順勢針/true逆時針
而圓環也是用的這個方法,只不過是ctx.fill()填充,替換成了ctx.stroke()描邊,利用描邊我們就可以繪製出任何大小及弧度的圓環了,通過ctx.linewidth可以設置描邊的粗細,也就是圓環的寬窄。
上圖中其實是個統計用的圖表,展示的是四個數據在這個圓環中的佔比情況。由於canvas採用的是幀繪製,所以在有輪流高亮的情況下,就是定時的清除畫布然後重繪,清除畫布的方法是
ctx.clearRect(起始x,起始y,結束x,結束y)
圖一
圖一JS
function gague(arr, index) {
var canvas = document.querySelector('#cav')
var cav = canvas.getContext('2d');
cav.clearRect(0, 0, 300, 300);
var wholeCircle = Math.PI * 2
var wholeAngle = wholeCircle * 3 / 4 //圓環的全部角度是3/4個圓
var sum = eval(arr.join('+')) //對傳入數據的處理求和
var startAngle = wholeCircle * 3 / 8 + wholeCircle / 200 //設置圓環的初始角度
var endAngle = startAngle + wholeAngle * (arr[0] / sum) - wholeCircle / 100 //根據數據佔比設置第一個弧長的結束角度
//繪製起始的小分割圓弧
cav.beginPath()
cav.lineWidth = 40
cav.strokeStyle = 'rgb(56,64,129)';
cav.arc(150, 150, 90, startAngle - wholeCircle / 200, startAngle, false)
cav.stroke()
for (let i = 0; i < arr.length; i++) {
//getPoint是自定義的一個方法,通過傳入圓弧的起始角度,結束角度,半徑和圓心的橫縱座標來獲得圓弧的起始和結束點座標,返回的是一個對象集合
var PointAssemble = getPoint(startAngle, endAngle, 110, 150, 150)
//cav.createLinearGradient()是canvas設置漸變色的方法,這是徑向漸變傳入的參數是漸變起始點橫縱座標和結束點橫縱座標
var normalColor = cav.createLinearGradient(PointAssemble.startPointX, PointAssemble.startPointY, PointAssemble
.endPointX, PointAssemble.endPointY);
normalColor.addColorStop(0, "rgba(68,102,244,0.2)");
normalColor.addColorStop(1, 'rgba(68,102,244,0.4)');
var highlightColor = cav.createLinearGradient(PointAssemble.startPointX, PointAssemble.startPointY,
PointAssemble.endPointX, PointAssemble.endPointY);
highlightColor.addColorStop(0, "rgba(56,64,129,0.2)");
highlightColor.addColorStop(1, 'rgba(255,15,110,0.6)');
//開始繪製圓弧
cav.beginPath()
cav.lineWidth = 40
cav.strokeStyle = index == i ? highlightColor : normalColor;
cav.arc(150, 150, 90, startAngle, endAngle, false)
cav.stroke()
//繪製每個圓弧之間的分割圓弧
cav.beginPath()
cav.lineWidth = 40
cav.strokeStyle = index == i ? 'rgb(255,15,110)' : 'rgb(68,102,244)';
cav.arc(150, 150, 90, endAngle, endAngle + wholeCircle / 100, false)
cav.stroke()
startAngle = startAngle + wholeAngle * (arr[i] / sum)
endAngle = startAngle + wholeAngle * (arr[i + 1] / sum) - wholeCircle / 100
}
}
圖二
上圖的高亮處小圓點是個圖片,要注意的是,如果canvas中出現圖片,要先獲取圖片,等圖片加載完畢之後再調用canvas的繪圖方法
var img = new Image()
img.src='圖片路徑'
img.onload =()=>{
//這裏調用你的繪圖函數
}
圖二JS
function halfCircle(arr, index) {
var canvas = document.querySelector('#cav4')
var cav = canvas.getContext('2d');
cav.clearRect(0, 0, 300, 300);
//跟上面的環圖一樣,首先先設置的是初始值,比如第一個環的起始和結束角度以及整個圓弧的角度
var wholeCircle = Math.PI * 2
var wholeAngle = wholeCircle / 2
var sum = eval(arr.join('+'))
var startAngle = wholeCircle / 2
var endAngle = startAngle + wholeAngle * (arr[0] / sum)
for (let i = 0; i < arr.length; i++) {
//這裏依然需要獲取到每一個圓弧的起始和結束座標點用來定位圖片的繪製位置
var PointAssemble = getPoint(startAngle, endAngle, 90, 150, 150)
var normalColor = cav.createLinearGradient(PointAssemble.startPointX, PointAssemble.startPointY, PointAssemble
.endPointX, PointAssemble.endPointY);
normalColor.addColorStop(0, "rgba(9, 9, 24,0)");
normalColor.addColorStop(1, 'rgba(42, 81, 248,1)');
var highlightColor = cav.createLinearGradient(PointAssemble.startPointX, PointAssemble.startPointY,
PointAssemble.endPointX, PointAssemble.endPointY);
highlightColor.addColorStop(0, "rgba(29, 11, 35,0)");
highlightColor.addColorStop(1, 'rgba(228, 90, 147,1)');
cav.beginPath()
cav.lineWidth = 10
cav.strokeStyle = index == i ? highlightColor : normalColor;
cav.lineCap = 'round'
cav.arc(150, 150, 90, startAngle, endAngle, false)
cav.stroke()
if (i == index) {
cav.drawImage(imgYuan, PointAssemble.endPointX - imgYuan.width / 2, PointAssemble.endPointY - imgYuan
.height / 2)
}
startAngle = startAngle + wholeAngle * (arr[i] / sum)
endAngle = startAngle + wholeAngle * (arr[i + 1] / sum)
}
}
值得注意的一點是,當你的圓環半徑確定的時候,不管你的圓環寬度有多寬,圓環的半徑始終是從圓心到二分之一圓環寬度的距離,而不是從圓心到圓環外邊或者到圓環內邊的距離,所以你的圓環越寬,他的實際面積會越大
自定義獲取座標點函數
function getPoint(startAngle, endAngle, r, circleX, circleY) {
var startPointX, startPointY, endPointX, endPointY
if (startAngle < Math.PI) {
startPointX = circleX - Math.sin(startAngle - Math.PI / 2) * r
startPointY = circleY + Math.cos(startAngle - Math.PI / 2) * r
} else if (startAngle < Math.PI * 3 / 2) {
startPointX = circleX - Math.cos(startAngle - Math.PI) * r
startPointY = circleY - Math.sin(startAngle - Math.PI) * r
} else if (startAngle < Math.PI * 2) {
startPointX = circleX + Math.sin(startAngle - Math.PI * 3 / 2) * r
startPointY = circleY - Math.cos(startAngle - Math.PI * 3 / 2) * r
} else {
startPointX = circleX + Math.cos(startAngle - Math.PI * 2) * r
startPointY = circleY + Math.sin(startAngle - Math.PI * 2) * r
}
if (endAngle < Math.PI) {
endPointX = circleX - Math.sin(endAngle - Math.PI / 2) * r
endPointY = circleY + Math.cos(endAngle - Math.PI / 2) * r
} else if (endAngle < Math.PI * 3 / 2) {
endPointX = circleX - Math.cos(endAngle - Math.PI) * r
endPointY = circleY - Math.sin(endAngle - Math.PI) * r
} else if (endAngle < Math.PI * 2) {
endPointX = circleX + Math.sin(endAngle - Math.PI * 3 / 2) * r
endPointY = circleY - Math.cos(endAngle - Math.PI * 3 / 2) * r
} else {
endPointX = circleX + Math.cos(endAngle - Math.PI * 2) * r
endPointY = circleY + Math.sin(endAngle - Math.PI * 2) * r
}
return {
startPointX,
startPointY,
endPointX,
endPointY
}
}