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

首頁 > 開發 > HTML5 > 正文

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

2024-09-05 07:19:33
字體:
來源:轉載
供稿:網友

老規矩,直接看圖!

效果如下:

高清大圖!

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

不同分值效果如下:

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

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

canvas#baseCanvas是底部的灰色圓環

canvas#myCanvas是上邊的彩色圓環

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

2、css樣式:

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

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

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

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

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

以下是三個方法的代碼:

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

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

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

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

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

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

所以一開始彩色圓環就看不見,因為起始點和結束點都是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時會觸發的回調函數。

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

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

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

通過這種方法,我在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類名:

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

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

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

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

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

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>

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

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久久有精品国产| 亚洲一区www| 国产欧美婷婷中文| 日韩在线观看免费全| 午夜免费久久久久| 亚洲成人激情小说| 中文字幕欧美国内| 欧美性猛xxx| 国产精品私拍pans大尺度在线| 国产性猛交xxxx免费看久久| 久久精品亚洲热| 欧美精品videos性欧美| 久久这里只有精品99| 日韩精品在线观看一区| 亚洲专区中文字幕| 国产精品h片在线播放| 国产欧美日韩丝袜精品一区| 亚洲加勒比久久88色综合| 久久视频在线观看免费| 久久久免费精品| 国产视频999| 国产主播欧美精品| 欧美精品免费看| 国产精品网站入口| 国内精品免费午夜毛片| 亚洲久久久久久久久久| 精品久久久久久亚洲国产300| 97超级碰碰碰久久久| 91日韩在线视频| 国产一区红桃视频| 午夜免费日韩视频| 亚洲一区中文字幕| 久热爱精品视频线路一| 色哟哟亚洲精品一区二区| 久久国产精品久久国产精品| zzjj国产精品一区二区| 欧美日韩亚洲91| 国产精品女主播视频| 亚洲人成网站777色婷婷| 欧美日韩国产成人高清视频| …久久精品99久久香蕉国产| 久久精品一区中文字幕| 国产精欧美一区二区三区| 亚洲国产美女久久久久| 久久久久久久影视| 欧美在线视频播放| 永久免费看mv网站入口亚洲| 色综合久久88色综合天天看泰| 精品视频久久久久久久| 中文字幕亚洲综合| 日韩激情在线视频| 91精品国产99| 欧美成人精品在线观看| 欧美色视频日本版| 96精品久久久久中文字幕| 日韩精品欧美国产精品忘忧草| 2020欧美日韩在线视频| 成人精品网站在线观看| 久久中国妇女中文字幕| 91欧美日韩一区| 国产精品久久婷婷六月丁香| 午夜精品视频在线| 91在线|亚洲| 欧美福利视频在线观看| 国产成人一区二区三区小说| 日韩精品视频在线免费观看| 欧美片一区二区三区| 成人欧美在线视频| 欧美电影免费观看网站| 色噜噜狠狠色综合网图区| 色综合久久久888| 精品亚洲va在线va天堂资源站| 中文字幕日韩综合av| 亚洲人精品午夜在线观看| 亚洲人在线视频| 成人精品久久av网站| 亚洲女人天堂成人av在线| 国自产精品手机在线观看视频| 亚洲情综合五月天| 热久久这里只有| 国产性色av一区二区| 国产精品久久av| 欧美中文在线免费| 久久777国产线看观看精品| 国色天香2019中文字幕在线观看| 欧美三级欧美成人高清www| 欧美激情免费观看| 国产精品久久久久久久久借妻| 国精产品一区一区三区有限在线| 亚洲国产三级网| 日韩美女中文字幕| 国产精品久久久久91| 国产精品视频网| 黑人极品videos精品欧美裸| 国产精品第三页| 97精品国产91久久久久久| 在线日韩欧美视频| 国模极品一区二区三区| 成人激情免费在线| 亚洲精品中文字幕av| 亚洲精品丝袜日韩| 国产精品久久久久久久久久免费| 亚洲综合中文字幕68页| 亚洲qvod图片区电影| 欧美性猛xxx| 国产91精品不卡视频| 日韩电影免费在线观看| 日本中文字幕成人| 国产精品99久久99久久久二8| 亚洲夜晚福利在线观看| 日本精品久久中文字幕佐佐木| 97国产精品人人爽人人做| 久久综合伊人77777尤物| 精品日韩视频在线观看| 91亚洲国产成人精品性色| 91精品视频一区| 成人免费视频网址| 最新的欧美黄色| 欧美中文字幕在线视频| 精品美女永久免费视频| 亚洲视频在线播放| 国产精品天天狠天天看| 欧美日本黄视频| 久久久久久国产精品久久| 性夜试看影院91社区| 国产精品一区二区三区久久| 亚洲在线视频福利| 亚洲精品综合久久中文字幕| 欧美性猛交xxxx乱大交蜜桃| 5278欧美一区二区三区| 亚洲国产精品福利| 国产精品白丝av嫩草影院| 91精品国产自产91精品| 这里只有精品丝袜| 亚洲精品国产拍免费91在线| 国产精品极品美女粉嫩高清在线| 久久中文字幕视频| 精品动漫一区二区三区| 欧美精品久久久久久久久久| 性欧美xxxx交| 精品欧美激情精品一区| 欧美性少妇18aaaa视频| 91av在线看| 国产精品你懂得| 欧美激情va永久在线播放| 欧美日韩免费看| 97视频在线观看视频免费视频| 国产精品极品在线| 亚洲第一男人天堂| 久久久久久尹人网香蕉| 日韩美女在线看| 91高清免费在线观看| 色偷偷av一区二区三区乱| 日本久久久久亚洲中字幕| 欧美大成色www永久网站婷| 国产精品成人在线| 久久人人爽人人爽爽久久| 欧美大片大片在线播放| 精品久久久久久久久中文字幕| 国产成人福利网站| x99av成人免费| 欧美最猛性xxxxx(亚洲精品)| 国产精品美女在线观看| 欧美黑人视频一区|