index.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. <template>
  2. <div :class="classes" :style="{ height: Number(radius) * 2 + 'px', width: Number(radius) * 2 + 'px' }">
  3. <svg viewBox="0 0 100 100">
  4. <defs>
  5. <linearGradient :id="refRandomId" x1="100%" y1="0%" x2="0%" y2="0%">
  6. <stop v-for="(item, index) in stop" :key="index" :offset="item.key" :stop-color="item.value"></stop>
  7. </linearGradient>
  8. </defs>
  9. <path class="nut-circle-progress__path" :style="pathStyle" :d="path" fill="none" :stroke-width="strokeWidth">
  10. >
  11. </path>
  12. <path
  13. class="nut-circle-progress__hover"
  14. :style="hoverStyle"
  15. :d="path"
  16. fill="none"
  17. :stroke="hoverColor"
  18. :stroke-linecap="strokeLinecap"
  19. :stroke-width="strokeWidth"
  20. ></path>
  21. </svg>
  22. <div class="nut-circle-progress__text">
  23. <slot></slot>
  24. <div v-if="!slotDefault">{{ progress }}%</div>
  25. </div>
  26. </div>
  27. </template>
  28. <script lang="ts">
  29. import { computed, useSlots } from 'vue';
  30. import { createComponent } from '@/packages/utils/create';
  31. import { isObject } from '@/packages/utils/util';
  32. const { componentName, create } = createComponent('circle-progress');
  33. import type { PropType } from 'vue';
  34. export interface stopArr {
  35. key: string;
  36. value: string;
  37. }
  38. export default create({
  39. props: {
  40. progress: {
  41. type: [Number, String],
  42. required: true
  43. },
  44. strokeWidth: {
  45. type: [Number, String],
  46. default: 5
  47. },
  48. radius: {
  49. type: [Number, String],
  50. default: 50
  51. },
  52. strokeLinecap: {
  53. type: String as PropType<CanvasLineCap>,
  54. default: 'round'
  55. },
  56. color: {
  57. type: [String, Object],
  58. default: ''
  59. },
  60. pathColor: {
  61. type: String,
  62. default: ''
  63. },
  64. clockwise: {
  65. type: Boolean,
  66. default: true
  67. }
  68. },
  69. setup(props) {
  70. const slotDefault = !!useSlots().default;
  71. const refRandomId = Math.random().toString(36).slice(-8);
  72. const classes = computed(() => {
  73. const prefixCls = componentName;
  74. return {
  75. [prefixCls]: true
  76. };
  77. });
  78. const path = computed(() => {
  79. const isWise = props.clockwise ? 1 : 0;
  80. return `M 50 50 m 0 -45 a 45 45 0 1 ${isWise} 0 90 a 45 45 0 1, ${isWise} 0 -90`;
  81. });
  82. const hoverColor = computed(() => {
  83. return isObject(props.color) ? `url(#${refRandomId})` : props.color;
  84. });
  85. const hoverStyle = computed(() => {
  86. let perimeter = 283;
  87. let offset = (perimeter * Number(props.progress)) / 100;
  88. return {
  89. stroke: isObject(props.color) ? `url(#${refRandomId})` : props.color,
  90. strokeDasharray: `${offset}px ${perimeter}px`
  91. };
  92. });
  93. const pathStyle = computed(() => {
  94. return {
  95. stroke: props.pathColor
  96. };
  97. });
  98. const stop = computed(() => {
  99. if (!isObject(props.color)) {
  100. return;
  101. }
  102. let color = props.color;
  103. const colorArr = Object.keys(color).sort((a, b) => parseFloat(a) - parseFloat(b));
  104. let stopArr: stopArr[] = [];
  105. colorArr.map((item) => {
  106. let obj = {
  107. key: '',
  108. value: ''
  109. };
  110. obj.key = item;
  111. obj.value = color[item];
  112. stopArr.push(obj);
  113. });
  114. return stopArr;
  115. });
  116. return {
  117. classes,
  118. hoverStyle,
  119. pathStyle,
  120. path,
  121. hoverColor,
  122. stop,
  123. slotDefault,
  124. refRandomId
  125. };
  126. }
  127. });
  128. </script>