Rings.weapp.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. import { Canvas } from "@tarojs/components";
  2. import Taro from "@tarojs/taro";
  3. import { useDidShow, useReady } from "@tarojs/taro";
  4. import { useEffect, useRef, useState } from "react";
  5. import { useSelector } from "react-redux";
  6. export type RingCommon = {
  7. useCase: string;
  8. status: string;
  9. isFast?: boolean;
  10. radius: number;
  11. lineWidth: number;
  12. }
  13. export type CurrentDot = {
  14. color: string;
  15. lineWidth: number;
  16. borderColor: string;
  17. timestamp?:number;
  18. }
  19. export type RealRing = {
  20. color: string;
  21. startArc: number;
  22. durationArc: number;
  23. }
  24. export type TargetRing = {
  25. color: string;
  26. startArc: number;
  27. durationArc: number;
  28. }
  29. export type BgRing = {
  30. color: string;
  31. }
  32. export default function Rings(props: {
  33. common: RingCommon;
  34. currentDot?: CurrentDot;
  35. realRing?: RealRing;
  36. targetRing?: TargetRing;
  37. breathAnimation?:boolean;
  38. bgRing: BgRing;
  39. canvasId?: string;
  40. ctx?:any;
  41. setCtx?:any;
  42. canvas?:any;
  43. setCanvas?:any;
  44. dotList?:Array<CurrentDot>;
  45. stageList?:Array<RealRing>;
  46. }) {
  47. const r = props.common.radius
  48. const strokeWidth = props.common.lineWidth;
  49. // const color = props.color || 'orange'
  50. const canvasRef = useRef(null);
  51. const canvasId = props.canvasId ? 'canvas_' + props.canvasId : 'progress-canvas';
  52. const dpr = Taro.getSystemInfoSync().pixelRatio; // 获取设备的像素比
  53. const radius = r; // 圆形进度条的半径
  54. const lineWidth = strokeWidth; // 圆形进度条的线宽
  55. const time = useSelector((state: any) => state.time);
  56. const user = useSelector((state: any) => state.user);
  57. useEffect(()=>{
  58. // drawCircle()
  59. },[])
  60. useReady(() => {
  61. drawCircle()
  62. })
  63. useEffect(() => {
  64. if (props.ctx){
  65. drawContent(props.ctx)
  66. }
  67. else {
  68. drawCircle()
  69. }
  70. }, [time.status,time.scenario,user.isLogin,props.targetRing, props.currentDot,props.realRing,props.currentDot?.color,props.canvasId]);
  71. useEffect(()=>{
  72. // if (props.breathAnimation){
  73. // animation()
  74. // }
  75. // else {
  76. // global.breathAlpha = 1
  77. // animation()
  78. // }
  79. },[props.breathAnimation])
  80. function animation(){
  81. const duration = 1000; // 动画执行时间(毫秒)
  82. let animationId: number | null = null;
  83. let startTime: number | null = null;
  84. const animate = (timestamp: number) => {
  85. if (!startTime) {
  86. startTime = timestamp;
  87. }
  88. const elapsed = timestamp - startTime;
  89. const progress = elapsed / duration; // 动画进度(0 到 1)
  90. global.breathAlpha = progress
  91. if (elapsed < duration) {
  92. animationId = requestAnimationFrame(animate);
  93. } else {
  94. // 动画完成后重新开始
  95. startTime = null;
  96. animationId = requestAnimationFrame(animate);
  97. }
  98. }
  99. animationId = requestAnimationFrame(animate);
  100. }
  101. function drawCircle() {
  102. const query = Taro.createSelectorQuery();
  103. query.select(`.${canvasId}`).fields({ node: true, size: true });
  104. query.exec((res) => {
  105. if (props.canvasId=='hello'){
  106. debugger
  107. }
  108. if (res[0] == null) {
  109. drawCircle()
  110. return;
  111. }
  112. const _canvas = res[0].node;
  113. _canvas.width = res[0].width * dpr;
  114. _canvas.height = res[0].height * dpr;
  115. const ctx = _canvas.getContext('2d');
  116. if (props.setCtx){
  117. props.setCtx(ctx)
  118. props.setCanvas(_canvas)
  119. drawContent(ctx)
  120. }
  121. else {
  122. drawContent(ctx)
  123. }
  124. // setCanvas(_canvas)
  125. // setContext(ctx)
  126. // const ctx = Taro.createCanvasContext(canvasId);
  127. // drawContent(ctx)
  128. });
  129. }
  130. function calculateCoordinates(x, y, r, angle) {
  131. const radians = angle * Math.PI / 180; // 将角度转换为弧度
  132. const xPrime = x + r * Math.cos(radians);
  133. const yPrime = y + r * Math.sin(radians);
  134. return { x: xPrime, y: yPrime };
  135. }
  136. function drawContent(ctx){
  137. if (props.canvas){
  138. props.canvas.width = ((radius * 2 + lineWidth)+6) * dpr;
  139. props.canvas.height = ((radius * 2 + lineWidth)+6) * dpr;
  140. }
  141. const center = radius + lineWidth / 2+3; // 圆心坐标
  142. ctx.clearRect(0, 0, radius * 2, radius * 2); // 清除画布
  143. // 设置画布尺寸
  144. ctx.scale(dpr, dpr);
  145. // 绘制背景圆
  146. ctx.beginPath();
  147. ctx.arc(center, center, radius, 0, 2 * Math.PI);
  148. ctx.lineWidth = lineWidth;
  149. ctx.strokeStyle = props.bgRing.color;
  150. ctx.lineCap = 'round'; // 设置为圆角
  151. ctx.stroke();
  152. // 绘制target进度环
  153. if (props.targetRing) {
  154. ctx.beginPath();
  155. ctx.arc(center, center, radius, props.targetRing!.startArc,
  156. props.targetRing!.startArc + props.targetRing!.durationArc);
  157. ctx.lineWidth = lineWidth;
  158. ctx.strokeStyle = props.targetRing!.color;
  159. ctx.lineCap = 'round'; // 设置为圆角
  160. ctx.stroke();
  161. }
  162. //绘制real进度环
  163. if (props.realRing) {
  164. if (props.realRing.durationArc <0.01) props.realRing.durationArc=0.01;
  165. ctx.beginPath();
  166. ctx.arc(center, center, radius, props.realRing!.startArc,
  167. props.realRing!.startArc + props.realRing!.durationArc);
  168. ctx.lineWidth = lineWidth;
  169. ctx.strokeStyle = props.realRing!.color;
  170. ctx.lineCap = 'round'; // 设置为圆角
  171. ctx.stroke();
  172. }
  173. if (props.stageList){
  174. props.stageList.map(item=>{
  175. if (item.durationArc <0.01) item.durationArc=0.01;
  176. ctx.beginPath();
  177. ctx.arc(center, center, radius, item.startArc,
  178. item.startArc + item.durationArc);
  179. ctx.lineWidth = lineWidth;
  180. ctx.strokeStyle = item.color;
  181. ctx.lineCap = 'round'; // 设置为圆角
  182. ctx.stroke();
  183. })
  184. }
  185. //绘制current_dot点
  186. if (props.currentDot) {
  187. var time = new Date();
  188. var seconds = time.getHours() * 3600 + time.getMinutes() * 60 + time.getSeconds();
  189. var arc = seconds / 86400 * 2 * Math.PI - Math.PI / 2.0;
  190. const radians = arc;//angle * Math.PI / 180; // 将角度转换为弧度
  191. const xPrime = center + r * Math.cos(radians);
  192. const yPrime = center + r * Math.sin(radians);
  193. ctx.beginPath();
  194. var dotLineWidth = 2
  195. if (lineWidth==28){
  196. dotLineWidth = 4
  197. }
  198. ctx.arc(xPrime, yPrime, lineWidth/2.0+dotLineWidth/2.0, 0, 2 * Math.PI);
  199. ctx.lineWidth = dotLineWidth;
  200. ctx.strokeStyle = '#1C1C1C';
  201. ctx.lineCap = 'round'; // 设置为圆角
  202. ctx.stroke();
  203. // ctx.beginPath();
  204. // ctx.arc(center, center, radius, arc,
  205. // arc + 0.001);
  206. // ctx.lineWidth = lineWidth+6;
  207. // ctx.strokeStyle = props.currentDot!.borderColor;
  208. // ctx.lineCap = 'round'; // 设置为圆角
  209. // ctx.stroke();
  210. // ctx.save()
  211. // ctx.beginPath();
  212. // ctx.arc(center, center, radius, arc,
  213. // arc + 0.001);
  214. // ctx.lineWidth = lineWidth;
  215. // ctx.strokeStyle = props.currentDot!.color;
  216. // ctx.lineCap = 'round'; // 设置为圆角
  217. // ctx.stroke();
  218. // ctx.restore()
  219. }
  220. if (props.dotList){
  221. props.dotList.map(item=>{
  222. var time = item.timestamp?new Date(item.timestamp):new Date();
  223. var seconds = time.getHours() * 3600 + time.getMinutes() * 60 + time.getSeconds();
  224. var arc = seconds / 86400 * 2 * Math.PI - Math.PI / 2.0;
  225. ctx.beginPath();
  226. ctx.arc(center, center, radius, arc,
  227. arc + 0.001);
  228. ctx.lineWidth = lineWidth+6;
  229. ctx.strokeStyle = item.borderColor;
  230. ctx.lineCap = 'round'; // 设置为圆角
  231. ctx.stroke();
  232. ctx.save()
  233. ctx.beginPath();
  234. ctx.arc(center, center, radius, arc,
  235. arc + 0.001);
  236. ctx.lineWidth = lineWidth;
  237. ctx.strokeStyle = item.color;
  238. ctx.lineCap = 'round'; // 设置为圆角
  239. // ctx.globalAlpha = global.breathAlpha
  240. ctx.stroke();
  241. ctx.restore()
  242. })
  243. }
  244. }
  245. return <Canvas canvasId={canvasId} id={canvasId} className={canvasId} type="2d" style={{ width: (radius * 2 + lineWidth)+6, height: (radius * 2 + lineWidth)+6, zIndex: 0 }} ref={canvasRef} />
  246. }
  247. // export default function Rings(props: {
  248. // common: RingCommon; currentDot?: CurrentDot;
  249. // realRing?: RealRing; targetRing?: TargetRing; bgRing: BgRing; canvasId?: string;test?:boolean
  250. // }) {
  251. // const r = props.common.radius
  252. // const strokeWidth = props.common.lineWidth;
  253. // // const color = props.color || 'orange'
  254. // const canvasRef = useRef(null);
  255. // const canvasId = props.canvasId ? 'canvas_' + props.canvasId : 'progress-canvas';
  256. // const dpr = Taro.getSystemInfoSync().pixelRatio; // 获取设备的像素比
  257. // const radius = r; // 圆形进度条的半径
  258. // const lineWidth = strokeWidth; // 圆形进度条的线宽
  259. // useDidShow(() => {
  260. // // drawCircle()
  261. // })
  262. // useReady(() => {
  263. // drawCircle()
  264. // })
  265. // function drawCircle() {
  266. // const query = Taro.createSelectorQuery();
  267. // query.select(`.${canvasId}`).fields({ node: true, size: true });
  268. // query.exec((res) => {
  269. // if (res[0] == null) return;
  270. // const _canvas = res[0].node;
  271. // _canvas.width = res[0].width * dpr;
  272. // _canvas.height = res[0].height * dpr;
  273. // const ctx = _canvas.getContext('2d');
  274. // // const ctx = Taro.createCanvasContext(canvasId);
  275. // const center = radius + lineWidth / 2; // 圆心坐标
  276. // ctx.clearRect(0, 0, radius * 2, radius * 2); // 清除画布
  277. // // 设置画布尺寸
  278. // ctx.scale(dpr, dpr);
  279. // // 绘制背景圆
  280. // ctx.beginPath();
  281. // ctx.arc(center, center, radius, 0, 2 * Math.PI);
  282. // ctx.lineWidth = lineWidth;
  283. // ctx.strokeStyle = props.bgRing.color;
  284. // ctx.lineCap = 'round'; // 设置为圆角
  285. // ctx.stroke();
  286. // // 绘制target进度环
  287. // if (props.common.useCase == 'ChooseScenario' || (props.common.useCase == 'Clock' && props.targetRing)) {
  288. // ctx.beginPath();
  289. // ctx.arc(center, center, radius, props.targetRing!.startArc,
  290. // props.targetRing!.startArc + props.targetRing!.durationArc);
  291. // ctx.lineWidth = lineWidth;
  292. // ctx.strokeStyle = props.targetRing!.color;
  293. // ctx.lineCap = 'round'; // 设置为圆角
  294. // ctx.stroke();
  295. // }
  296. // //绘制real进度环
  297. // if (props.common.status != 'WAIT_FOR_START' && props.realRing) {
  298. // ctx.beginPath();
  299. // ctx.arc(center, center, radius, props.realRing!.startArc,
  300. // props.realRing!.startArc + props.realRing!.durationArc);
  301. // ctx.lineWidth = lineWidth;
  302. // ctx.strokeStyle = props.realRing!.color;
  303. // ctx.lineCap = 'round'; // 设置为圆角
  304. // ctx.stroke();
  305. // }
  306. // //绘制current_dot点
  307. // if (props.common.useCase == 'Clock') {
  308. // var time = new Date();
  309. // var seconds = time.getHours() * 3600 + time.getMinutes() * 60 + time.getSeconds();
  310. // var arc = seconds / 86400 * 2 * Math.PI - Math.PI / 2.0;
  311. // ctx.beginPath();
  312. // ctx.arc(center, center, radius, arc,
  313. // arc + 0.001);
  314. // ctx.lineWidth = lineWidth;
  315. // ctx.strokeStyle = props.currentDot!.borderColor;
  316. // ctx.lineCap = 'round'; // 设置为圆角
  317. // ctx.stroke();
  318. // ctx.beginPath();
  319. // ctx.arc(center, center, radius, arc,
  320. // arc + 0.001);
  321. // ctx.lineWidth = lineWidth - 2;
  322. // ctx.strokeStyle = props.currentDot!.color;
  323. // ctx.lineCap = 'round'; // 设置为圆角
  324. // ctx.stroke();
  325. // }
  326. // // ctx.draw();
  327. // });
  328. // }
  329. // useEffect(() => {
  330. // drawCircle()
  331. // }, [props.targetRing, props.currentDot]);
  332. // return <Canvas canvasId={canvasId} id={canvasId} className={canvasId} type="2d" style={{ width: (radius * 2 + lineWidth), height: (radius * 2 + lineWidth), zIndex: 0 }} ref={canvasRef} />
  333. // }