Example of implementing circular progress bar in Vue

Example of implementing circular progress bar in Vue

Data display has always been a demand that all walks of life enjoy. Specifically in the front-end development industry, it is a variety of charts and tables that display data, which is extremely annoying (too complicated)!
A few days ago, I just made graphical data display effects such as line charts, bar charts, and pie charts. Today, I encountered a display effect similar to a circular progress bar. I deal with data and interfaces every day. I have done a lot of projects, but I am still a rookie. It’s all tears!
To put it bluntly, I am not familiar with canvas and CSS3, so I found a ready-made wheel:

<template>
 <div class="content" ref="box">
 <svg style="transform: rotate(-90deg)" :width="width" :height="width" xmlns="http://www.w3.org/2000/svg">
  <circle :r="(width-radius)/2"
  :cy="width/2"
  :cx="width/2"
  :stroke-width="radius"
  :stroke="backgroundColor"
  fill="none"
  />
  <circle ref="$bar"
  :r="(width-radius)/2"
  :cy="width/2"
  :cx="width/2"
  :stroke="barColor"
  :stroke-width="radius"
  :stroke-linecap="isRound ? 'round' : 'square'"
  :stroke-dasharray="(width-radius)*3.14"
  :stroke-dashoffset="isAnimation ? (width-radius) * 3.14 : (width - radius) * 3.14 * (100 - progress) / 100"
  fill="none"
  />
 </svg>
 <div class="center_text" :style="{color, fontSize}">
  <p v-if="!$slots.default" class="title">{{progress}}%</p>
  <slot></slot>
 </div>
 </div>
</template>

<script>
export default {
 props: {
 radius:
  type: [Number, String],
  default: 20
 }, // Progress bar thickness progress: {
  type: [Number, String],
  default: 20
 }, // Progress bar percentage barColor: {
  type: String,
  default: "#1890ff"
 }, // Progress bar color backgroundColor: {
  type: String,
  default: "rgba(0,0,0,0.3)"
 }, // Background color isAnimation: {
  // Is it an animation effect type: Boolean,
  default: true
 },
 isRound: {
  // Is it a circular brush type: Boolean,
  default: true
 },
 id: {
  // Component id, used when multiple components coexist type: [String, Number],
  default: 1
 },
 duration: {
  // The entire animation duration type: [String, Number],
  default: 1000
 },
 delay:
  // How long to delay execution type: [String, Number],
  default: 200
 },
 timeFunction: {
  // Animation easing function type: String,
  default: "cubic-bezier(0.99, 0.01, 0.22, 0.94)"
 },
 circleWidth: {
  //Ring width type: Number,
  default: 100,
 },
 color:
  //Text color type: String,
  default: '#000'
 },
 fontSize: {
  //Text size type: String,
  default: '18px'
 }
 },
 data() {
 return {
  width: this.circleWidth,
  idStr: `circle_progress_keyframes_${this.id}`
 };
 },
 beforeDestroy() {
 // Clear the style tag of the old component document.getElementById(this.idStr) &&
 document.getElementById(this.idStr).remove();
 window.addEventListener(() => {});
 },
 mounted() {
 let self = this;
 this.setCircleWidth();
 this.setAnimation();
 // window.onresize cannot be used here
 window.addEventListener(
  "resize",
  debounce(function() {
  self.setCircleWidth();
  self.setAnimation(self);
  }, 300)
 );
 },
 methods: {
 setCircleWidth() {
  let box = this.$refs.box;
  let width = box.clientWidth;
  let height = box.clientHeight;
  let cW = width > height ? height : width;
  this.width = cW;
 },
 setAnimation() {
  let self = this;
  if (self.isAnimation) {
  // Repeat the definition if (document.getElementById(self.idStr)) {
   console.warn("vue-circle-progress should not have same id style");
   document.getElementById(self.idStr).remove();
  }
  // Generate animation style file let style = document.createElement("style");
  style.id = self.idStr;
  style.type = "text/css";
  style.innerHTML = `
  @keyframes circle_progress_keyframes_name_${self.id} {
  from {stroke-dashoffset: ${(self.width - self.radius) * 3.14}px;}
  to {stroke-dashoffset: ${((self.width - self.radius) *
  3.14 *
  (100 - self.progress)) /
  100}px;}}
  .circle_progress_bar${
  self.id
  } {animation: circle_progress_keyframes_name_${self.id} ${
   self.duration
  }ms ${self.delay}ms ${self.timeFunction} forwards;}`;
  // Add a new style file document.getElementsByTagName("head")[0].appendChild(style);
  // Add animation class to svg element
  self.$refs.$bar.classList.add(`circle_progress_bar${self.id}`);
  }
 }
 }
};
</script>
<style scoped>
.content {height:100%;display:flex;justify-content:center;align-items:center;}
.center_text {position:absolute;}
</style>

Directions:

<CircleProgress :id="'circle1'" :circleWidth="40" :radius="7" :progress="30" :isAnimation="true" :backgroundColor="'#E9E9E9'" :barColor="'#FF4F4F'" />
<CircleProgress :id="'circle2'" :circleWidth="40" :radius="7" :progress="50" :isAnimation="true" :backgroundColor="'#E9E9E9'" :barColor="'#FF902A'" />
<CircleProgress :id="'circle3'" :circleWidth="40" :radius="7" :progress="89" :isAnimation="true" :backgroundColor="'#E9E9E9'" :barColor="'#FFDB4F'" />
<CircleProgress :id="'circle4'" :circleWidth="40" :radius="7" :progress="25" :isAnimation="true" :backgroundColor="'#E9E9E9'" :barColor="'#B8D87E'" />

Please note that if you use more than two such circular progress bars on your page at the same time, you need to set a different ID for each circular progress bar, otherwise, the data finally displayed by all the circles will be the data of the last circle.

There is an anti-shake function in the code, here is the function:

function debounce(func, wait, immediate) {
 let timeout, args, context, timestamp, result

 const later = function () {
 // According to the last trigger time interval const last = +new Date() - timestamp

 // The last time the wrapped function was called, the time interval last is less than the set time interval wait
 if (last < wait && last > 0) {
  timeout = setTimeout(later, wait - last)
 } else {
  timeout = null
  // If set to immediate===true, there is no need to call it here because the start boundary has already been called if (!immediate) {
  result = func.apply(context, args)
  if (!timeout) context = args = null
  }
 }
 }

This article refers to a circular progress bar plugin vue-circleprogressbar on npm. The reason why this plugin is not directly installed and used in the project is that this plugin does not quite meet our development needs. For example, this plugin cannot set the width of the circle, the color of the text, or the size of the text. For another example, this plugin relies on lodash only for anti-shake (the size of this lodash is still very large).

As for the use of this component in react, it can be used with a slight modification according to the react lifecycle, the syntax of react hooks, or the syntax of dva mode. It is very simple and I will not elaborate on it.

Author: Xiaohuai

Source: http://tnnyang.cnblogs.com

The above is the details of the example of Vue implementing a circular progress bar. For more information about Vue implementing a circular progress bar, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Vue implements dynamic circular percentage progress bar
  • Using vue+ElementUI+echarts front-end and back-end interaction to realize dynamic donut chart in Springboot project (recommended)
  • Springboot uses vue+echarts front-end and back-end interaction to realize dynamic donut chart
  • Implementation of the function of the vue circular percentage progress bar component
  • Vue dynamically draws the effect of three-quarters donut chart
  • Example code of using echarts to make a donut chart in vue
  • Vue uses canvas to draw a circle

<<:  4 Ways to Quickly Teach Yourself Linux Commands

>>:  Simple Mysql backup BAT script sharing under Windows

Recommend

Summary of methods to clear cache in Linux system

1) Introduction to cache mechanism In the Linux s...

A few things about favicon.ico (it’s best to put it in the root directory)

Open any web page: for example, http://www.baidu....

Manjaro installation CUDA implementation tutorial analysis

At the end of last year, I replaced the opensuse ...

Tips for organizing strings in Linux

In Linux operations, we often replace and count s...

Summary of MySQL lock knowledge points

The concept of lock ①. Lock, in real life, is a t...

ElementUI implements the el-form form reset function button

Table of contents Business scenario: Effect demon...

MySQL cross-database transaction XA operation example

This article uses an example to describe the MySQ...

How to solve the timeout during pip operation in Linux

How to solve the timeout problem when pip is used...

Linux disk management LVM usage

1. Introduction to LVM When we manage Linux disks...

Discussion on more reasonable creation rules for MySQL string indexes

Preface Regarding the use of MySQL indexes, we ha...

Detailed explanation of the underlying encapsulation of Java connection to MySQL

This article shares the Java connection MySQL und...