roundTurntable.vue 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <template>
  2. <div ref="turntable" class="turntable">
  3. <div class="myTurntable" :style="{transform: rotateAngle, transition: rotateTransition}">
  4. <canvas id="canvas" ref="canvas">
  5. 当前浏览器版本过低,请使用其他浏览器尝试
  6. </canvas>
  7. <div class="prize-container">
  8. <div v-for="(item, index) in prizeData" :key="index" class="item" :style="getRotateAngle(index)">
  9. <slot name="item" :item="item"></slot>
  10. </div>
  11. </div>
  12. </div>
  13. </div>
  14. </template>
  15. <script>
  16. export default {
  17. name: 'RoundTurntable',
  18. props: {
  19. prizeData: {
  20. required: true,
  21. type: Array
  22. },
  23. rotateCircle: {
  24. default: 6,
  25. type: Number
  26. },
  27. turntableStyleOption: {
  28. type: Object,
  29. default: () => {
  30. return {
  31. // 背景色
  32. prizeBgColors: ['#ffdfd4', '#fffdfe', '#ffdfd4', '#fffdfe', '#ffdfd4', '#fffdfe', '#ffdfd4', '#fffdfe'],
  33. // 转盘的外边框颜色
  34. borderColor: '#f9dc84'
  35. };
  36. }
  37. },
  38. duringTime: {
  39. type: Number,
  40. default: 4.5
  41. }
  42. },
  43. data() {
  44. return {
  45. // 开始转动的角度
  46. startRotateDegree: 0,
  47. rotateAngle: 0,
  48. rotateTransition: ''
  49. };
  50. },
  51. mounted() {
  52. this.init();
  53. },
  54. methods: {
  55. // 根据index计算每一格要旋转的角度的样式
  56. getRotateAngle(index) {
  57. const angle = 360 / this.prizeData.length * index + (180 / this.prizeData.length);
  58. return {
  59. transform: `rotate(${angle}deg)`
  60. };
  61. },
  62. // 初始化圆形转盘canvas
  63. init() {
  64. // 各种数据
  65. const data = this.turntableStyleOption;
  66. const prizeNum = this.prizeData.length;
  67. const { prizeBgColors, borderColor } = data;
  68. // 开始绘画
  69. const canvas = this.$refs.canvas;
  70. const ctx = canvas.getContext('2d');
  71. const canvasW = this.$refs.canvas.width = this.$refs.turntable.clientWidth; // 画板的高度
  72. const canvasH = this.$refs.canvas.height = this.$refs.turntable.clientHeight; // 画板的宽度
  73. // translate方法重新映射画布上的 (0,0) 位置
  74. ctx.translate(0, canvasH);
  75. // rotate方法旋转当前的绘图,因为文字适合当前扇形中心线垂直的!
  76. ctx.rotate(-90 * Math.PI / 180);
  77. // 圆环的外圆的半径
  78. const outRadius = canvasW / 2;
  79. // 圆环的内圆的半径
  80. const innerRadius = 0;
  81. const baseAngle = Math.PI * 2 / prizeNum; // 计算每个奖项所占角度数
  82. ctx.clearRect(0, 0, canvasW, canvasH); // 去掉背景默认的黑色
  83. ctx.strokeStyle = borderColor; // 设置画图线的颜色
  84. for (let index = 0; index < prizeNum; index++) {
  85. const angle = index * baseAngle;
  86. ctx.fillStyle = prizeBgColors[index]; // 设置每个扇形区域的颜色
  87. ctx.beginPath(); // 开始绘制
  88. // 标准圆弧:arc(x,y,radius,startAngle,endAngle,anticlockwise)
  89. ctx.arc(canvasW * 0.5, canvasH * 0.5, outRadius, angle, angle + baseAngle, false);
  90. ctx.arc(canvasW * 0.5, canvasH * 0.5, innerRadius, angle + baseAngle, angle, true);
  91. ctx.stroke();// 开始链线
  92. ctx.fill(); // 填充颜色
  93. ctx.save(); // 保存当前环境的状态
  94. }
  95. },
  96. // 转动起来
  97. rotate(index) {
  98. // 运转时长
  99. const duringTime = this.duringTime;
  100. const rotateAngle = this.startRotateDegree + this.rotateCircle * 360 + 360 - (180 / this.prizeData.length + 360 / this.prizeData.length * index) - this.startRotateDegree % 360 - 13;
  101. this.startRotateDegree = rotateAngle;
  102. this.rotateAngle = `rotate(${rotateAngle}deg)`;
  103. this.rotateTransition = `transform ${duringTime}s cubic-bezier(0.250, 0.460, 0.455, 0.995)`;
  104. setTimeout(() => {
  105. this.$emit('endRotation');
  106. }, duringTime * 1000 + 500);
  107. }
  108. }
  109. };
  110. </script>
  111. <style scoped lang="scss">
  112. .turntable {
  113. /*background-color: red;*/
  114. position: absolute;
  115. left: 0;
  116. top: 0;
  117. text-align: center;
  118. transform: translateZ(0);
  119. .myTurntable {
  120. position: absolute;
  121. left: 0;
  122. top: 0;
  123. width: 100%;
  124. height: 100%;
  125. }
  126. .prize-container {
  127. position: absolute;
  128. left: 25%;
  129. top: 0;
  130. width: 50%;
  131. height: 50%;
  132. .item {
  133. /*background: pink;*/
  134. position: absolute;
  135. left: 0;
  136. top: 0;
  137. width: 100%;
  138. height: 100%;
  139. transform-origin: center bottom;
  140. }
  141. }
  142. }
  143. </style>