shared.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import { Pos } from "@/utils/math.ts";
  2. import { v4 as uuid } from "uuid";
  3. /**
  4. * 四舍五入
  5. * @param num
  6. * @param b 保留位数
  7. * @returns
  8. */
  9. export const round = (num: number, b: number = 2) => {
  10. const scale = Math.pow(10, b);
  11. return Math.round(num * scale) / scale;
  12. };
  13. /**
  14. * 范围取余
  15. * @param num
  16. * @param mod
  17. */
  18. export const rangMod = (num: number, mod: number) => ((num % mod) + mod) % mod;
  19. /**
  20. * 有偏差的indexOf
  21. * @param arr
  22. * @param warp
  23. * @param val
  24. * @returns
  25. */
  26. export const warpIndexOf = (arr: number[], warp: number, val: number) =>
  27. arr.findIndex((num) => val >= num - warp && val <= num + warp);
  28. /**
  29. * 多个函数合并成一个函数
  30. * @param fns
  31. * @returns
  32. */
  33. export const mergeFuns = (...fns: (() => void)[] | (() => void)[][]) => {
  34. return () => {
  35. fns.forEach((fn) => {
  36. if (Array.isArray(fn)) {
  37. fn.forEach((f) => f());
  38. } else {
  39. fn();
  40. }
  41. });
  42. };
  43. };
  44. export const copy = <T>(data: T): T => JSON.parse(JSON.stringify(data));
  45. /**
  46. * 获取数据类型
  47. * @param value
  48. * @returns
  49. */
  50. export const toRawType = (value: unknown): string =>
  51. Object.prototype.toString.call(value).slice(8, -1);
  52. // 是否修改
  53. const _inRevise = (raw1: any, raw2: any, readly: Set<[any, any]>): boolean => {
  54. if (raw1 === raw2) return false;
  55. const rawType1 = toRawType(raw1);
  56. const rawType2 = toRawType(raw2);
  57. if (rawType1 !== rawType2) {
  58. return true;
  59. } else if (
  60. rawType1 === "String" ||
  61. rawType1 === "Number" ||
  62. rawType1 === "Boolean"
  63. ) {
  64. if (rawType1 === "Number" && isNaN(raw1) && isNaN(raw2)) {
  65. return false;
  66. } else {
  67. return raw1 !== raw2;
  68. }
  69. }
  70. const rawsArray = Array.from(readly.values());
  71. for (const raws of rawsArray) {
  72. if (raws.includes(raw1) && raws.includes(raw2)) {
  73. return false;
  74. }
  75. }
  76. readly.add([raw1, raw2]);
  77. if (rawType1 === "Array") {
  78. return (
  79. raw1.length !== raw2.length ||
  80. raw1.some((item1: any, i: number) => _inRevise(item1, raw2[i], readly))
  81. );
  82. } else if (rawType1 === "Object") {
  83. const rawKeys1 = Object.keys(raw1).sort();
  84. const rawKeys2 = Object.keys(raw2).sort();
  85. return (
  86. _inRevise(rawKeys1, rawKeys2, readly) ||
  87. rawKeys1.some((key) => _inRevise(raw1[key], raw2[key], readly))
  88. );
  89. } else if (rawType1 === "Map") {
  90. const rawKeys1 = Array.from(raw1.keys()).sort();
  91. const rawKeys2 = Array.from(raw2.keys()).sort();
  92. return (
  93. _inRevise(rawKeys1, rawKeys2, readly) ||
  94. rawKeys1.some((key) => _inRevise(raw1.get(key), raw2.get(key), readly))
  95. );
  96. } else if (rawType1 === "Set") {
  97. return inRevise(Array.from(raw1.values()), Array.from(raw2.values()));
  98. } else {
  99. return raw1 !== raw2;
  100. }
  101. };
  102. /**
  103. * 查看数据是否被修改
  104. * @param raw1
  105. * @param raw2
  106. * @returns
  107. */
  108. export const inRevise = (raw1: any, raw2: any) =>
  109. _inRevise(raw1, raw2, new Set());
  110. // 防抖
  111. export const debounce = <T extends (...args: any) => any>(
  112. fn: T,
  113. delay: number = 160
  114. ) => {
  115. let timeout: any;
  116. return function (...args: Parameters<T>) {
  117. clearTimeout(timeout);
  118. timeout = setTimeout(() => {
  119. fn.apply(null, args);
  120. }, delay);
  121. };
  122. };
  123. /**
  124. * 获取数据变化
  125. * @param newIds
  126. * @param oldIds
  127. * @returns
  128. */
  129. export const getChangePart = <T>(newIds: T[], oldIds: T[] = []) => {
  130. const addPort = newIds.filter((newId) => !oldIds.includes(newId));
  131. const delPort = oldIds.filter((oldId) => !newIds.includes(oldId));
  132. const holdPort = oldIds.filter((oldId) => newIds.includes(oldId));
  133. return { addPort, delPort, holdPort };
  134. };
  135. export const flatPositions = (positions: Pos[]) =>
  136. positions.flatMap((p) => [p.x, p.y]);
  137. export const flatToPositions = (coords: number[]) => {
  138. const positions: Pos[] = [];
  139. for (let i = 0; i < coords.length; i += 2) {
  140. positions.push({
  141. x: coords[i],
  142. y: coords[i + 1],
  143. });
  144. }
  145. return positions;
  146. };
  147. export const onlyId = () => uuid();
  148. export const startAnimation = (update: () => void, dur = -1) => {
  149. let isStop = false;
  150. const animation = () => {
  151. requestAnimationFrame(() => {
  152. if (!isStop) {
  153. update();
  154. animation();
  155. }
  156. });
  157. };
  158. animation();
  159. let timeout: any;
  160. if (dur >= 0) {
  161. setTimeout(() => (isStop = true), dur);
  162. }
  163. return () => {
  164. clearTimeout(timeout);
  165. isStop = true;
  166. };
  167. };
  168. export const arrayInsert = <T>(
  169. array: T[],
  170. item: T,
  171. canInsert: (eItem: T, insertItem: T) => boolean
  172. ) => {
  173. let i = 0;
  174. for (i = 0; i < array.length; i++) {
  175. if (canInsert(array[i], item)) {
  176. break;
  177. }
  178. }
  179. array.splice(i, 0, item);
  180. return array;
  181. };
  182. export const asyncTimeout = (time: number) => {
  183. let timeout: any;
  184. let reject: any
  185. const promise = new Promise<void>((resolve, r) => {
  186. timeout = setTimeout(resolve, time);
  187. reject = r
  188. }) as Promise<void> & { stop: () => void };
  189. promise.stop = () => {
  190. clearTimeout(timeout);
  191. reject('取消')
  192. };
  193. return promise;
  194. };