亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > HTML > 正文

canvas實現有遞增動畫的環形進度條的實現方法

2024-08-26 00:21:32
字體:
來源:轉載
供稿:網友

老規矩,直接看圖!

效果如下:

canvas,遞增動畫,環形進度條

高清大圖!

canvas,遞增動畫,環形進度條

 碼農多年,老眼昏花,動圖看不清?!那就看靜態截圖?。?!

不同分值效果如下:

canvas,遞增動畫,環形進度條canvas,遞增動畫,環形進度條canvas,遞增動畫,環形進度條canvas,遞增動畫,環形進度條canvas,遞增動畫,環形進度條

 看完了賣家秀,我們來看產品的制作過程吧!

canvas繪制圓環1、vue中,<template lang="pug">里的代碼如下:

canvas,遞增動畫,環形進度條

canvas#baseCanvas是底部的灰色圓環

canvas#myCanvas是上邊的彩色圓環

需要用css樣式幫助我們把彩色圓環蓋到灰色圓環上邊。

2、css樣式:

canvas,遞增動畫,環形進度條

canvas,遞增動畫,環形進度條

canvas,遞增動畫,環形進度條

 3、js-canvas的樣式繪制代碼

這段代碼也很簡單,看canvas的api即可

3-1、vue組件中,script標簽頂部定義需要用的變量

canvas,遞增動畫,環形進度條

3-2、vue的methos對象中,定義方法三個:

drawBaseCanvas:用來繪制底部灰色圓環。由于灰色圓環沒有動畫效果,所以一開始就繪制一個完整的灰色圓環即可。drawClrCanvas:用來繪制上邊的彩色圓環。clearCanvas:用來清空畫布。這是彩色圓環動畫需要。因為我們圓環動畫效果的核心就是,每隔一段時間就把彩色圓環清空一下,然后把結束角度值增大、重畫,這樣連續起來就是動畫。

以下是三個方法的代碼:

canvas,遞增動畫,環形進度條

canvas,遞增動畫,環形進度條

canvas,遞增動畫,環形進度條

上邊三個方法里邊的代碼,幾乎都是對canvas API的應用,看教程即可。

只有draoClrCanvas方法中,canvas圓形的繪制時,arc的參數里關于開始值、結束值的設置。

開始值決定了圓環的起始繪制位置,結束值決定了結束的位置(我好像說了一句廢話,但是冥思苦想后的思想描述文字,不想刪掉哈哈哈)

這個結束值的計算,對于我來說還是比較麻煩的。

count變量為什么要這么計算,我也忘了我是怎么鼓搗出來的了。

this.grade是100以內的正整數,表示分值。被定義在data中,默認是0分。

canvas,遞增動畫,環形進度條

所以一開始彩色圓環就看不見,因為起始點和結束點都是0點。

如果更改grade的值,從0-100,canvas彩色圓環的值也就會更改。

這樣,只要我們逐漸修改grade的值,重新繪制,彩色圓環就會逐漸遞增,實現動畫效果。

圓環動畫效果

由于我這里需求特殊,需要用戶每次翻到canvas所在swiper時,才會觸發動畫(后來更麻煩一點需要柱狀圖和canvas部分有個入場效果后,動畫才開始。效果就是上圖中最長的那張gif動畫那樣)。

所以我得借助swiper才能實現。在swiper切換的回調函數中,從0開始不停遞增grade分數,并重新觸發彩色圓環的繪制,進而實現動畫效果。

vue中我用的swiper是'vue-awesome-swiper'。她的用法我在其他文章中寫過步驟。

swiper在vue-data中的配置里,有一個on對象。在on對象中的slideChange函數,就是每次翻頁swiper時會觸發的回調函數。

canvas,遞增動畫,環形進度條

這里我說一下幾個比較特殊的點:

(1)vm:是我早就在vue的script中存儲的變量,初始化為null,然后在mounted中,將其賦值為vue實例對象。

初始化數據、繪制灰色圓環

canvas,遞增動畫,環形進度條

通過這種方法,我在vue實例對象 - data - swiper - 回調函數中去拿vue實例對象 - data中的grade和gradeTarget屬性值,并對其進行修改。

ps:我也不知道這么做是不是很傻的一種做法,當時做到這里時是我遇到的一個難題,不知道怎么在swiper的on回調中獲取vue實例。于是就有了這么曲線救國的方法。如果看官有更好的解決方案,希望可以給我提供一個新的思路,感激不盡哦親

(2)(this.activeIndex == 2 && vm.isStar) || (this.activeIndex == 1 && !vm.isStar)

這里是因為業務,才這么判斷,可以忽略。

this在swiperChange函數中指向swiper對象。this.activeIndex是swiper實例的屬性,用官方的話說“返回當前活動塊(激活塊)的索引。”可以理解他指的是當前翻到的是哪一頁,就是當前你所看的swiper-slide的下標。

我因為用戶的身份,會判斷性的決定當前canvas所在swiper前一頁是否展示。 如果不展示就根本不會繪制前一頁,那么相應的當前頁的swiper的下標就會變成(index-1)。

總而言之,當滿足條件、用戶翻到canvas所在swiper頁面后,我就要觸發if里邊的圓環繪制邏輯。否則就走到else里初始化數據頁面的狀態、清除定時器暫停動畫、并把彩色圓環清空

(3)vm.aniShow

在我上篇《純css繪制柱狀圖》里邊說了,柱狀圖的動畫要跟canvas的動畫一起說。因為他們的動畫實現需要配合swiper的切換。說的就是這里的代碼:

vue - data - aniShow屬性變為true時,div.row就會添加ani這個class類名:

canvas,遞增動畫,環形進度條

同樣,aniShow為true,progress的高度就會附上自己的目標值,也就是這個progress的實際高度經過百分制轉化后被賦予給了style屬性的height。

此時,因為progress的transition監聽了height變化,就開始有了高度漸增的柱狀圖遞增動畫了。

canvas,遞增動畫,環形進度條

而ani類名下,progress的transition-delay實現了其高度錯開遞增效果。

canvas,遞增動畫,環形進度條

可能只看文字描述很晦澀,再看一眼效果:

canvas,遞增動畫,環形進度條

 (4)彩色圓環繪制代碼部分

canvas,遞增動畫,環形進度條

gradeTarget是實際分值,是最終要繪制到的結果。

grade從0開始,自增到gradeTarget的大小。

這里我沒有直接++vm.grade,我也不知道自己當時咋想的。

if判斷,如果grade遞增到了目標值gradeTarget或者大于目標值,就停止遞增,并讓grade=gradeTarget。屬于臨界值的判斷。在運動功能中,又算碰撞檢測。

反之,不到目標的話,就清除上一次繪制的canvas畫布,在grade遞增變化后重新繪制新的彩色圓環。

(5)所有這些放到setTimeout中,暫停500毫秒再執行,是為了等柱圖和環圖入場后,在開始繪制圓環的遞增效果。

其實上邊代碼都是很簡單的邏輯處理,看官們讀一遍代碼應該就差不離了。

新想法:

這個效果是我很久以前做的,今天在整理制作方法的時候,我想到自己代碼的一種優化方案:

其實沒必要在定時器里重新調用彩色圓環繪制方法。我們直接改的是this.grade屬性,監聽這個屬性的改變就好了其實。這樣此屬性在定時器中被修改,圓環方法就會自動執行。

這還是一個想法,還需要我的實踐。

中間文字的遞增效果:

因為grade是每次遞增的分數,所以利用vue的雙向數據綁定,直接把grade當作分數值綁定到對應dom視圖處即可。

最后,圓環和上邊柱狀圖的動畫結合,就是animation控制一下動畫延遲即可。很簡單的。

index.vue源碼:

(注,源碼稍作整理,單獨提取。為了完整性也為了保護其他業務代碼,部分變量名做了修改,可能會和之前截圖中略微不同)

<template lang='pug'>  .indexs#Indexs.app-bg    transition(name="fade")      swiper#swiperBox(:options="swiperOption" ref="mySwiper")        swiper-slide.swiper-slide1          .container          .up        swiper-slide.swiper-slide2(v-if="isShow")          .my-shark          .up        swiper-slide.swiper-slide3          .container            .data-cont              .data.data01                .data01-charts                  .row(v-for='item,index in Data' :key="index" :class='aniShow ? "ani":""')                    .data-txt {{item.grade > 0 ? item.grade : '無數據'}}                    .progress(:class='item.grade == 0 ? "nodata" : ""' :style="'height: ' + (aniShow ? (item.grade >= 100 ? (100 * 1.5) / 100 : item.grade == 0 ? 0.04 : item.grade * 1.5 / 100) : 0) +'rem'")                      span.pg-data                    .week {{item.week}}              .data.data02                .data02-charts                  .canvas-box                    //- baseCanvas                    canvas#baseCanvas.my-canvas(ref="baseCanvas" width="174" height="174")                    //- canvas                    canvas#myCanvas.my-canvas.clr-canvas(ref="myCanvas" width="174" height="174")                    .canvas-data #[span.num {{grade}}]分                  </template><script>var vm = null,  timer1 = null,  /* canvas基礎值 */  c = null, //document.getElementById("myCanvas");  ctx = null, //canvas-2d畫布  x = 161 / 2 + 1, //圓心坐標  r = (161 - 10) / 2; //半徑大小/* swiper組件 */import { swiper, swiperSlide } from "vue-awesome-swiper";import { getData } from "../io/getData";export default {  name: "Indexs",  components: {    swiper,    swiperSlide  },  data() {    return {      grade: 0, //圓環圖分數      gradeTarget: 78.54, //實際得分數,可ajax請求數據后修改      isShow: true,//是否展示第二頁swiper      aniShow: false,//是否開啟柱圖動畫      Data:[{          week: "第一周",          grade: 0        },        {          week: "第二周",          grade: 30        },        {          week: "第三周",          grade: 99.99        },        {          week: "第四周",          grade: 76.98        },        {          week: "第五周",          grade: 100        }],            swiperOption: {        //swiper參數        notNextTick: true,        direction: "vertical",        grabCursor: true,        setWrapperSize: true,        autoHeight: true,        slidesPerView: 1,        mousewheel: false,        mousewheelControl: false,        height: window.innerHeight, // 高度設置,占滿設備高度        resistanceRatio: 0,        observeParents: true,        initialSlide: 2 - 1, //設置初始化時,swiper的默認展示頁面,從零開始        on: {          slideChange() {            if (              (this.activeIndex == 2 && vm.isShow) ||              (this.activeIndex == 1 && !vm.isShow)            ) {              console.log(this.activeIndex, vm.isShow, "繪制動畫");              setTimeout(function() {                // 配合展示柱狀圖動畫                vm.aniShow = true;                // 定時器不斷觸發繪制彩色圓環,實現圓環動畫效果                timer1 = setInterval(function() {                  // 中間分數文案更改                  var num = vm.grade;                  num++;                  if (num >= vm.gradeTarget) {                    vm.grade = vm.gradeTarget;                    clearInterval(timer1);                  } else {                    vm.grade = num;                  }                  vm.clearCanvas();                  vm.drawClrCanvas();                }, 1000 / 60);              }, 500);            } else {              // 翻頁后,初始化數據頁面的狀態、清除定時器暫停動畫、并把彩色圓環清空              console.log("其他頁");              clearInterval(timer1);              vm.grade = 0;              vm.aniShow = false;              vm.clearCanvas();            }          }        }      }    };  },  computed: {},  mounted() {    // 初始化數據、繪制灰色圓環    vm = this;    c = this.$refs.myCanvas;    ctx = c.getContext("2d");    this.drawBaseCanvas();  },  methods: {    drawBaseCanvas() {      // canvas繪制      /* 基礎值 */      var c = this.$refs.baseCanvas, //document.getElementById("myCanvas");        // debugger;        ctx = c.getContext("2d"),        o = x,        randius = r;      /* 默認灰色圓圈 */      ctx.strokeStyle = "#eee";      ctx.lineWidth = 10;      ctx.beginPath();      ctx.arc(o, o, randius, 0, 2 * Math.PI);      ctx.stroke();    },    clearCanvas() {      // 清除畫布      ctx.clearRect(0, 0, 200, 200);    },    drawClrCanvas() {      var gradient = ctx.createLinearGradient(75, 50, 5, 90);      gradient.addColorStop("0", "#C88EFF");      gradient.addColorStop("1.0", "#7E5CFF");      ctx.strokeStyle = gradient; // 用漸變進行填充      ctx.lineWidth = 10;      ctx.lineCap = "round";      ctx.shadowColor = "rgba(191,142,255, 0.36)";      ctx.shadowBlur = 8;      ctx.shadowOffsetY = 8;      ctx.beginPath();      var count = this.grade / (100 / 2) + 1;      ctx.arc(x, x, r, Math.PI, Math.PI * count, false);      ctx.stroke();    }  }};</script><style lang='scss'>// 柱圖.row {  position: relative;  z-index: 1;  width: 0.61rem;  margin-bottom: -0.28 - 0.08 - 0.38rem;  text-align: center;}.data-txt {  font-size: 0.2rem;  line-height: 0.2rem;  margin-bottom: 0.09rem;}.progress {  height: 0rem;  transition: height 0.5s ease-in-out;}.ani {  @for $i from 1 to 6 {    &:nth-of-type(#{$i}) {      .progress {        transition-delay: #{$i * 0.15}s;      }    }  }  // &:nth-of-type(1) {  //   .progress {  //     transition-delay: .4s;  //   }  // }  // &:nth-of-type(2) {  //   .progress {  //     transition-delay: .8s;  //   }  // }  // &:nth-of-type(3) {  //   .progress {  //     transition-delay: 1s;  //   }  // }  // &:nth-of-type(4) {  //   .progress {  //     transition-delay: 1.4s;  //   }  // }  // &:nth-of-type(5) {  //   .progress {  //     transition-delay: 1.8s;  //   }  // }}.pg-data {  display: block;  width: 0.12rem;  height: 100%;  margin: 0 auto;  background: linear-gradient(0deg, #c88eff 0%, #7e5cff 100%);  box-shadow: 0 -0.04rem 0.14rem 0 rgba(129, 93, 255, 0.4);  border-radius: 0.05rem 0.05rem 0 0;}// 0分展示規則.nodata {  .pg-data {    border-radius: 0;    background: #e7e7e7;    box-shadow: none;  }}.week {  font-size: 0.2rem;  line-height: 0.2rem;  margin-top: 0.08rem;  color: #666;}// 環圖 - data02數據部分.data02-charts {  margin-top: 0.32rem;  height: 1.61rem;}.canvas-box {  position: relative;  float: left;  width: 1.61rem;  height: 1.61rem;  margin-left: 0.92rem;}.my-canvas {  width: 1.61rem;  height: 1.61rem;}.clr-canvas {  position: absolute;  top: 0;  left: 0;}.canvas-data {  position: absolute;  top: 0.56rem;  left: 0;  right: 0;  margin: auto;  margin-left: -0.1rem;  text-align: center;  font-size: 0.24rem;  .num {    font-size: 0.32rem;    font-weight: 600;  }}</style>

 以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到HTML教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
136fldh精品导航福利| 揄拍成人国产精品视频| 日本19禁啪啪免费观看www| 日韩有码在线观看| 97精品国产aⅴ7777| 国产日韩在线播放| 亚洲精品久久久久久久久久久久| 亚州国产精品久久久| 国产专区精品视频| 久久久成人精品| 夜夜嗨av一区二区三区四区| 欧美做爰性生交视频| 91精品国产高清久久久久久91| 欧美电影免费观看高清完整| 欧美性猛交xxxx久久久| 国语自产精品视频在线看抢先版图片| 中文字幕一区二区三区电影| 欧美激情亚洲一区| 亚洲欧美另类自拍| 亚洲天堂精品在线| 国产欧美精品一区二区| 在线看国产精品| 亚洲第一男人天堂| 欧美日韩不卡合集视频| 中日韩午夜理伦电影免费| 亚洲韩国青草视频| 亚洲自拍偷拍网址| 欧美视频在线视频| 国产在线精品一区免费香蕉| 国产精品欧美亚洲777777| 欧美精品videos性欧美| 久久黄色av网站| 最好看的2019年中文视频| 国产欧美日韩免费| 国产成人精品久久二区二区| 午夜精品一区二区三区在线播放| 久久亚洲一区二区三区四区五区高| 国产欧美精品va在线观看| 亚洲精品丝袜日韩| 韩国精品久久久999| 久久久久久久影院| 欧美性xxxx极品高清hd直播| 成人av资源在线播放| 亚洲欧美变态国产另类| 中文字幕亚洲一区在线观看| 91久久久国产精品| 欧美电影免费观看网站| 久久五月天色综合| 久久精品久久久久电影| 国产精自产拍久久久久久| 久久免费少妇高潮久久精品99| 国产91精品最新在线播放| 日韩女优人人人人射在线视频| 久久久国产成人精品| 国产精品美乳一区二区免费| 亚洲免费一在线| 欧美丰满少妇xxxxx| 国产欧美日韩中文| 日韩av在线电影网| 91精品国产综合久久香蕉最新版| 中文字幕不卡在线视频极品| 亚洲free性xxxx护士hd| 国产精品中文字幕在线观看| 欧美久久久精品| 69视频在线免费观看| 欧美激情一二区| 欧美极品少妇xxxxⅹ免费视频| 国产成人91久久精品| 欧美国产精品人人做人人爱| 午夜精品一区二区三区在线视频| 欧美激情精品久久久久久免费印度| 91亚洲国产精品| 久久精品一本久久99精品| 日本免费一区二区三区视频观看| 国产一区二区久久精品| 91精品国产综合久久男男| 久久精品男人天堂| 国产欧美精品在线播放| 亚洲日韩第一页| 成人女保姆的销魂服务| 欧美日韩国产精品一区| 欧美午夜精品久久久久久人妖| 一区二区国产精品视频| 亚洲精品美女视频| 日韩在线视频中文字幕| 丝袜情趣国产精品| 国产精品igao视频| 这里只有精品视频| 97久久久久久| 欧美成人免费网| 国产精品久久久久久一区二区| 色无极影院亚洲| 成人福利网站在线观看11| 亚洲国产免费av| 国产区亚洲区欧美区| 久久影视电视剧免费网站清宫辞电视| 日韩在线国产精品| 日韩在线一区二区三区免费视频| 国产又爽又黄的激情精品视频| 中文字幕日韩在线观看| 高清一区二区三区日本久| 亚洲成色www8888| 日韩美女av在线免费观看| 欧洲成人免费视频| 国产精品视频中文字幕91| 2023亚洲男人天堂| 亚洲激情小视频| 国产视频自拍一区| 欧美超级乱淫片喷水| 大伊人狠狠躁夜夜躁av一区| 国产欧美韩国高清| 中文字幕国产精品久久| 久久精品电影网| 亚洲福利视频网| 日韩精品中文字幕在线观看| 人人澡人人澡人人看欧美| 日韩免费不卡av| 欧美裸体视频网站| 中文字幕视频在线免费欧美日韩综合在线看| 亚洲精品国产成人| 欧美高清在线观看| 国产精国产精品| 亚洲人成网在线播放| 一本色道久久综合狠狠躁篇怎么玩| 亚洲一区二区日本| 九九热最新视频//这里只有精品| 91精品在线播放| 亚洲欧美在线一区二区| 欧美日韩黄色大片| 亚洲mm色国产网站| 亚洲片国产一区一级在线观看| 欧美日韩在线视频首页| 亚洲一区二区中文| 北条麻妃在线一区二区| 精品久久久久久久久久久久久久| 亚洲第一页自拍| 狠狠躁夜夜躁人人爽天天天天97| 色与欲影视天天看综合网| 日韩精品免费电影| 色偷偷偷亚洲综合网另类| 国产精品亚洲一区二区三区| 国产精品国产三级国产aⅴ9色| 91精品国产高清自在线| 日韩av电影国产| 日韩av免费在线| 欧美一级大胆视频| 久久久噜噜噜久噜久久| 国产精品女人久久久久久| 国产精品视频久久久久| 欧美日韩在线视频一区二区| 亚洲国产日韩欧美在线99| 亚洲精品一区av在线播放| 69**夜色精品国产69乱| 成人av资源在线播放| 国产一区二区久久精品| 欧美激情一区二区三区高清视频| 成人国产亚洲精品a区天堂华泰| 国产精品一区=区| 性金发美女69hd大尺寸| 日韩精品视频观看| 日韩国产精品亚洲а∨天堂免| 一区二区三区视频观看| 精品二区三区线观看| 日韩精品中文字|