canvas繪製環形進度條

最近公司讓作一個頁面,上面有幾個圖表,柱狀圖餅狀圖之類的,以前都是使用echarts插件來進行渲染的,但下面這個環形的進度條沒有找到太適合的插件,不知道echarts能不能修改爲這樣的。以前用canvas畫過滾動條,嘿嘿,那這個就用canvas畫布試試。



參考連接: canvas實現漸變色環形進度條                  git

這種圓環進度條是一個大圓環和一個小圓環,而後大圓環有底部背景圓環和上面可進行滾動的圓環,和上面的白色按鈕,小圓環又能夠分上下兩部分和最上面的指針,這樣咱們根據這些能夠一步一步的使用canvas來畫圖。github

<canvas id="canvas" width="300" height="300"></canvas>複製代碼

// 獲取canvas元素 let canvas = document.getElementById('canvas');
let ctx = canvas.getContext("2d");
let width = canvas.width; 
let height = canvas.height;複製代碼

1、先畫一個圓環canvas

使用canvas arc()方法   content.arc(x, y, radius, startAngle, endAngle, anticlockwise)bash


經過控制開始角(startAngle)和結束角(endAngle)就能夠畫任意的環形, 從0開始到 1 PI就是半圓,2PI就是整個圓。這樣咱們就很方便的畫出朝下的環形了,咱們能夠把開始角設爲 0.75PI 結束角設爲2.25PI,或者你也能夠如上圖同樣經過rotate()方法旋轉朝下,記得把圓心設爲中心點。echarts

draw(); 
// 繪製圓環
function draw() {
  let circleObj = {      
    ctx: ctx,      
    /*圓心*/      
    x: width / 2,      
    y: height / 2,      
    /*半徑*/      
    radius: width / 2 - 20, 
    //半徑比canvas寬的一半要小      
    /*環的寬度*/      
    lineWidth: 20    
  };    
  circleObj.color = '#ccc';    
  circleObj.startAngle = Math.PI * 0.75;    
  circleObj.endAngle = Math.PI * 2 + Math.PI * 0.25;    
  drawCircle(circleObj);  
}
function drawCircle(circleObj) {    
  let ctx = circleObj.ctx;    
  ctx.beginPath();    
  ctx.arc(circleObj.x, circleObj.y, circleObj.radius, circleObj.startAngle, circleObj.endAngle);   
  //設定曲線粗細度    
  ctx.lineWidth = circleObj.lineWidth;    
  //給曲線着色    
  ctx.strokeStyle = circleObj.color;    
  //鏈接處樣式    
  ctx.lineCap = 'round';    
  //給環着色    
  ctx.stroke();    
  ctx.closePath();  
}複製代碼


2、繪製圓環漸變色
函數

使用 canvas createLinearGradient(x1, y1, x2, x2) 方法給圓環添加漸變色 動畫

 x1,y1開始座標,x2,y2結束座標 
ui

和 gradient.addColorStop(stop,color);  配合使用spa

let grd = ctx.createLinearGradient(width / 2, 0, 0, height);
    grd.addColorStop(0, "#dd6200");
    grd.addColorStop(1, "#fff400");
    circleObj.color = grd;複製代碼

                            

3、繪製上層運動的圓環插件

經過定時器或者requestAnimationFrame對象來使圓環的結束角endAngle不停的自增來使圓環跑起來。

let defaultAngle = Math.PI * 0.75; 
animate();
// 逐幀動畫
function animate() {
  defaultAngle += 0.05;
  // 這個值能夠根據我的須要修改
  // 這個maxAngle 時上層圓環滾動的到最大的角度能夠傳入這個角度來控制滾動的百分比
  let maxAngle = Math.PI * 2 + Math.PI * 0.25;
  if (defaultAngle >= maxAngle ) {
    defaultAngle = maxAngle ;
    draw(); // 繪製圓環
    return
  }
  draw(); // 繪製圓環
  window.requestAnimationFrame(animate);
}
// 繪製圓環
function draw() {
  // 爲了不每次繪製的時候出現一些奇奇怪怪的問題,好比拖影之類的,每次繪製以前清空一次繪布
  ctx.clearRect(0, 0, width, height);
  let circleObj = {
    ctx: ctx,
    /*圓心*/ 
    x: width / 2,
    y: height / 2,
    /*半徑*/
    radius: width / 2 - 20,//半徑比canvas寬的一半要小
    /*環的寬度*/
    lineWidth: 20
  };
  // 繪製背景
  circleObj.color = '#eee';
  circleObj.startAngle = Math.PI * 0.75;
  circleObj.endAngle = Math.PI * 2 + Math.PI * 0.25;
  drawCircle(circleObj);
  // 繪製運動環
  circleObj.startAngle = Math.PI * 0.75;
  circleObj.endAngle = defaultAngle;
  // 背景漸變
  let grd = ctx.createLinearGradient(width / 2, 0, 0, height);
  grd.addColorStop(0, "#dd6200");
  grd.addColorStop(1, "#fff400");
  circleObj.color = grd;
  drawCircle(circleObj);
}
function drawCircle(circleObj) {
  let ctx = circleObj.ctx;
  ctx.beginPath();
  ctx.arc(circleObj.x, circleObj.y, circleObj.radius, circleObj.startAngle, circleObj.endAngle);
  //設定曲線粗細度
  ctx.lineWidth = circleObj.lineWidth;
  //給曲線着色
  ctx.strokeStyle = circleObj.color;
  //鏈接處樣式
  ctx.lineCap = 'round';
  //給環着色
  ctx.stroke();
  ctx.closePath();
}複製代碼


4、繪製運動圓環上的白色按鈕

上層圓環是根據角度增長來跟着運動的,那白色的圓點也來作同步運動呢,咱們已經知道圓環每次運動的角度數,那就跟着這個角度來同步就是。有兩種方法一種是經過  canvas rotate()方法以原點爲原點進行旋轉,圓環運動多少就旋轉多少,能夠達到同步。二是使用Math 三角函數的正弦/餘弦 和 半徑來計算出每次運動角度數對應的 座標 值,來更新白死圓點的位置。

這裏咱們使用第一種方法,經過rotate旋轉來同步,那麼白色圓點的位置就是到原點的位置也就是外環的半徑

注意:旋轉的中心是原點,你使用的x,y座標都是到原點的座標,不是到畫布 0, 0的座標。

// 繪製最上面的指針
  function circlingPointer(){
    let radius = height / 2 - 60;
    ctx.save(); //保存以前的狀態
    // 設置旋轉原點爲中心點
    ctx.translate(width / 2, height / 2);//原點移動到畫布中央
    ctx.rotate(defaultAngle);//根據角度改變來旋轉白色圓點
    // 白色圓點
    ctx.beginPath()
    ctx.arc(width / 2 - 20, 0, 8, 0, 2 * Math.PI, false)
    ctx.fillStyle="#fff"
    ctx.fill()
    ctx.closePath()
    ctx.restore();//回到未改變座標的狀態
  }
  // 和draw方法同樣放在animate就能夠複製代碼

5、繪製內環上的指針

經過畫線和畫圓兩種方法來畫一個指針, 用圓的開始角和結束角來調整圓的方向 


// 繪製最上面的指針  
function circlingPointer(){    
  let radius = height / 2 - 60;    
  ctx.save(); //保存以前的狀態    
  ctx.translate(width / 2, height / 2);
  //原點移動到畫布中央    
  ctx.rotate(defaultAngle);//根據角度改變來旋轉白色圓點
  // 經過lineTo()和arc方法繪製內環的指針    
  ctx.beginPath()    
  ctx.moveTo(radius, -10)    
  ctx.lineTo(radius + 30, 0)
  ctx.arc(radius, 0, 10, Math.PI * 0.5, Math.PI * 1.5, false)    
  ctx.lineTo(radius, 10)    
  ctx.fillStyle='#6de57a'    
  ctx.fill()
  ctx.closePath()    
  ctx.restore();//回到未改變座標的狀態  
}複製代碼

注意: 在手機上使用canvas時會出現畫布模糊的狀況,能夠把畫布的width和寬設置爲樣式的兩倍


如今整個大體的步驟就這些了,把這些步驟合在一塊兒就能實現上面的圓環進度條了

                

以下是整個代碼

<canvas id="canvas" width="300" height="300"></canvas>複製代碼

<script>
 // 獲取canvas元素
 let canvas = document.getElementById('canvas');
 let ctx = canvas.getContext("2d");
 let width = canvas.width;
 let height = canvas.height;

 // defaultAngle 設置可滾動圓環的起始角度,經過requestAnimationFrame函數一點一點的遞增來使圓環跑起來,
 // 也能夠使用setTimeout()
 // 與圓環的起始角度相同
 let defaultAngle = Math.PI * 0.75; 

 animate();
 // 逐幀動畫
 function animate() {
   defaultAngle += 0.05;
   // 這個值能夠根據我的須要修改
   // 這個maxAngle 時上層圓環滾動的到最大的角度能夠傳入這個角度來控制滾動的百分比
   let maxAngle = Math.PI * 2 + Math.PI * 0.25;
   if (defaultAngle >= maxAngle ) {
     defaultAngle = maxAngle ;
     draw(); // 繪製圓環
     circlingPointer() // 繪製最上面的指針
     return
   }
   draw(); // 繪製圓環
   circlingPointer() // 繪製最上面的指針
   window.requestAnimationFrame(animate);
 }  
  // 繪製圓環
  function draw() {
    // 爲了不每次繪製的時候出現一些奇奇怪怪的問題,好比拖影之類的,每次繪製以前清空一次繪布
    ctx.clearRect(0, 0, width, height);
    // 外環
    let circleObj = {
      ctx: ctx,
      /*圓心*/
      x: width / 2,
      y: height / 2,
      /*半徑*/
      radius: width / 2 - 20, //半徑比canvas寬的一半要小
      /*環的寬度*/
      lineWidth: 20
    };
    // 內環
    let smallCircle = {
      ctx: ctx,
      x: width / 2,
      y: height / 2,
      radius: width / 2 - 60,
      lineWidth: 6,
      color: '#eee',
      startAngle: 0,
      endAngle: Math.PI * 2
    };

    // 繪製內環背景
    drawCircle(smallCircle);
    // 繪製內環 根據defaultAngle的角度變化而滾動
    smallCircle.startAngle = Math.PI * 0.75;
    smallCircle.endAngle = defaultAngle;
    // 使用ctx.createLinearGradient來爲圓填充漸變色
    let smallGrd = ctx.createLinearGradient(width / 2, 0, 0, height);
    smallGrd.addColorStop(0, "#dd6200");
    smallGrd.addColorStop(1, "#fff400");
    smallCircle.color = smallGrd;
    drawCircle(smallCircle);
    // 繪製外環背景
    let bgrd = ctx.createLinearGradient(width / 2, 0, 0, height);
    bgrd.addColorStop(0, "#95ea5c");
    bgrd.addColorStop(1, "#f8d6c1");
    circleObj.color = bgrd;
    circleObj.startAngle = Math.PI * 0.75;
    circleObj.endAngle = Math.PI * 2 + Math.PI * 0.25;
    drawCircle(circleObj);
    // 繪製外環
    circleObj.startAngle = Math.PI * 0.75;
    circleObj.endAngle = defaultAngle;

    let grd = ctx.createLinearGradient(width / 2, 0, 0, height);
    grd.addColorStop(0, "#dd6200");
    grd.addColorStop(1, "#fff400");
    circleObj.color = grd;
    drawCircle(circleObj);
  }
  // 繪製最上面的指針
  function circlingPointer(){
    let radius = height / 2 - 60;
    ctx.save(); //保存以前的狀態 
    ctx.translate(width / 2, height / 2);//原點移動到畫布中央
    ctx.rotate(defaultAngle);//根據角度改變來旋轉白色圓點
    // 經過lineTo()和arc方法繪製內環的指針
    ctx.beginPath();
    ctx.moveTo(radius, -10);
    ctx.lineTo(radius + 30, 0);
    ctx.arc(radius, 0, 10, Math.PI * 0.5, Math.PI * 1.5, false);
    ctx.lineTo(radius, 10);
    ctx.fillStyle='#6de57a';
    ctx.fill();
    ctx.closePath();
    // 繪製內環指針上的圓點 
    ctx.beginPath();
    ctx.arc(radius, 0, 6, 0, Math.PI * 2, false);
    ctx.fillStyle='#fff';
    ctx.fill();
    ctx.closePath();

    // 繪製外環白色圓點
    ctx.beginPath();
    ctx.arc(width / 2 - 20, 0, 8, 0, 2 * Math.PI, false);
    ctx.fillStyle="#fff";
    ctx.fill();
    ctx.closePath();
    ctx.restore();//回到未改變座標的狀態
  }
  function drawCircle(circleObj) {
    let ctx = circleObj.ctx;
    ctx.beginPath();
    ctx.arc(circleObj.x, circleObj.y, circleObj.radius, circleObj.startAngle, circleObj.endAngle);
    //設定曲線粗細度
    ctx.lineWidth = circleObj.lineWidth;
    //給曲線着色
    ctx.strokeStyle = circleObj.color;
    //鏈接處樣式
    ctx.lineCap = 'round';
    //給環着色
    ctx.stroke();
    ctx.closePath();
  }

  // 另外一種使用三角函數進行旋轉 
 function circlingMotion(){
    let radius = width / 2 - 20;
    ctx.save();
    ctx.translate(0, 0);
    x = width / 2 + Math.cos(defaultAngle) * radius;//肯定座標(此處圓心便是原點)
    y = height / 2 + Math.sin(defaultAngle) * radius;//肯定座標(此處圓心便是原點)
    ctx.beginPath();
    ctx.arc(x, y, 8, 0, 2 * Math.PI, true);//繪畫作圓周運動的圓
    ctx.fillStyle="#fff";
    ctx.fill();
    ctx.closePath();
    ctx.restore();
  }
</script>複製代碼


參考連接: canvas實現漸變色環形進度條                  


參考了不少文章的內容才製做出這個環形進度條,若有哪裏不對或者錯誤的地方請多多指教 

相關文章
相關標籤/搜索