麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > 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教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 深夜免费福利视频 | 成人性视频免费网站下载软件 | 欧美成人精品一区二区 | 欧美视频在线一区二区三区 | 久久国产免费视频 | 4p一女两男做爰在线观看 | 成人福利在线看 | 一级黄色片在线看 | 亚洲黑人在线观看 | 一区二区久久久久草草 | 久久蜜臀一区二区三区av | 亚洲第一色片 | 国产精品久久久久久一区二区三区 | 久久国产不卡 | 特级a欧美做爰片毛片 | 羞羞网站在线观看入口免费 | 国产亚洲精品综合一区91 | 毛片免费视频观看 | 久久国产综合精品 | 亚洲综合网站 | 91福利免费观看 | 久国久产久精永久网页 | 91精品国产免费久久 | 国产羞羞视频在线观看 | 国产精选久久久 | 久久久久久久一区 | 亚洲片在线 | 一区二区久久精品66国产精品 | 极品美女一级毛片 | 久久精品一区二区三区国产主播 | 妇女毛片| 国产精品久久久久久久久粉嫩 | 精品99在线视频 | 久久久久久亚洲国产精品 | 日本在线视 | 国产一级淫片免费看 | 在线播放免费av | 伦一区二区三区中文字幕v亚洲 | 999精品国产| 12av电影 | 久久亚洲线观看视频 |