shared.ts 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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. export const frameEebounce = <T extends (...args: any) => any>(fn: T) => {
  125. let count = 0;
  126. return function (...args: Parameters<T>) {
  127. let current = ++count;
  128. requestAnimationFrame(() => {
  129. if (current === count) {
  130. fn.apply(null, args);
  131. }
  132. });
  133. };
  134. };
  135. /**
  136. * 获取数据变化
  137. * @param newIds
  138. * @param oldIds
  139. * @returns
  140. */
  141. export const getChangePart = <T>(newIds: T[], oldIds: T[] = []) => {
  142. const addPort = newIds.filter((newId) => !oldIds.includes(newId));
  143. const delPort = oldIds.filter((oldId) => !newIds.includes(oldId));
  144. const holdPort = oldIds.filter((oldId) => newIds.includes(oldId));
  145. return { addPort, delPort, holdPort };
  146. };
  147. export const flatPositions = (positions: Pos[]) =>
  148. positions.flatMap((p) => [p.x, p.y]);
  149. export const flatToPositions = (coords: number[]) => {
  150. const positions: Pos[] = [];
  151. for (let i = 0; i < coords.length; i += 2) {
  152. positions.push({
  153. x: coords[i],
  154. y: coords[i + 1],
  155. });
  156. }
  157. return positions;
  158. };
  159. export const onlyId = () => uuid();
  160. export const startAnimation = (update: () => void, dur = -1) => {
  161. let isStop = false;
  162. const animation = () => {
  163. requestAnimationFrame(() => {
  164. if (!isStop) {
  165. update();
  166. animation();
  167. }
  168. });
  169. };
  170. animation();
  171. let timeout: any;
  172. if (dur >= 0) {
  173. setTimeout(() => (isStop = true), dur);
  174. }
  175. return () => {
  176. clearTimeout(timeout);
  177. isStop = true;
  178. };
  179. };
  180. export const arrayInsert = <T>(
  181. array: T[],
  182. item: T,
  183. canInsert: (eItem: T, insertItem: T) => boolean
  184. ) => {
  185. let i = 0;
  186. for (i = 0; i < array.length; i++) {
  187. if (canInsert(array[i], item)) {
  188. break;
  189. }
  190. }
  191. array.splice(i, 0, item);
  192. return array;
  193. };
  194. export const asyncTimeout = (time: number) => {
  195. let timeout: any;
  196. let reject: any;
  197. const promise = new Promise<void>((resolve, r) => {
  198. timeout = setTimeout(resolve, time);
  199. reject = r;
  200. }) as Promise<void> & { stop: () => void };
  201. promise.stop = () => {
  202. clearTimeout(timeout);
  203. reject("取消");
  204. };
  205. return promise;
  206. };
  207. export const getResizeCorsur = (level = true, r = 0) => {
  208. r = rangMod(r, 360);
  209. if (level) {
  210. if ((r > 0 && r < 20) || (r > 160 && r <= 200)) {
  211. return "ew-resize";
  212. }
  213. if ((r >= 20 && r <= 70) || (r >= 200 && r <= 250)) {
  214. return "nwse-resize";
  215. } else if ((r > 70 && r < 110) || (r > 250 && r < 290)) {
  216. return "ns-resize";
  217. } else if ((r >= 110 && r <= 160) || (r >= 290 && r <= 340)) {
  218. return "nesw-resize";
  219. } else {
  220. return "ew-resize";
  221. }
  222. } else {
  223. if ((r > 0 && r < 20) || (r > 160 && r <= 200)) {
  224. return "ns-resize";
  225. }
  226. if ((r >= 20 && r <= 70) || (r >= 200 && r <= 250)) {
  227. return "nesw-resize";
  228. } else if ((r > 70 && r < 110) || (r > 250 && r < 290)) {
  229. return "ew-resize";
  230. } else if ((r >= 110 && r <= 160) || (r >= 290 && r <= 340)) {
  231. return "nwse-resize";
  232. } else {
  233. return "ns-resize";
  234. }
  235. }
  236. };
  237. export const diffArrayChange = <T extends Array<any>>(
  238. newItems: T,
  239. oldItems: T
  240. ) => {
  241. const addedItems = [] as unknown as T;
  242. const deletedItems = [] as unknown as T;
  243. for (const item of newItems) {
  244. if (!oldItems.includes(item)) {
  245. addedItems.push(item);
  246. }
  247. }
  248. for (const item of oldItems) {
  249. if (!newItems.includes(item)) {
  250. deletedItems.push(item);
  251. }
  252. }
  253. return {
  254. added: addedItems,
  255. deleted: deletedItems,
  256. };
  257. };
  258. const DMSRG =
  259. /(\d+(?:\.\d+)?)°(?:(\d+(?:\.\d+)?)['|′])?(?:(\d+(?:\.\d+)?)["|″])?$/;
  260. export const dmsCheck = (dms: string) => {
  261. const r = DMSRG.exec(dms);
  262. return r && Number(r[2] || 0) < 60 && (Number(r[3]) || 0) < 60;
  263. };
  264. // 度分秒转经纬度
  265. export const toDigital = (dms: string) => {
  266. const r = DMSRG.exec(dms);
  267. if (r) {
  268. return round(
  269. Number(r[1]) + Number(r[2] || 0) / 60 + (Number(r[3]) || 0) / 3600,
  270. 12
  271. );
  272. }
  273. };
  274. export const analysisGPS = (temp: string) => {
  275. const getGPS = (t: any[]) => {
  276. t = t.map((d) => (dmsCheck(d) ? toDigital(d) : Number(d)));
  277. if (t.length > 1 && t.every((v) => !Number.isNaN(v))) {
  278. return {
  279. x: t[0],
  280. y: t[1],
  281. } as Pos;
  282. }
  283. };
  284. function isValidWGS84(lon: number, lat: number) {
  285. const isValidLon = lon >= -180 && lon <= 180;
  286. const isValidLat = lat >= -90 && lat <= 90;
  287. return isValidLon && isValidLat;
  288. }
  289. const splitChars = [",", " ", ","];
  290. for (const splitChar of splitChars) {
  291. const gps = getGPS(temp.split(splitChar));
  292. if (gps && isValidWGS84(gps.x, gps.y)) {
  293. return gps;
  294. }
  295. }
  296. };
  297. export const tempStrFill = (tempStr: string, fill: Record<string, any>) => {
  298. const regex = /\{(.*?)\}/g;
  299. let str = "";
  300. let ndx = 0;
  301. let matches;
  302. while ((matches = regex.exec(tempStr)) !== null) {
  303. if (!(matches[1] in fill)) continue;
  304. str += tempStr.substring(ndx, matches.index) + fill[matches[1]];
  305. ndx = matches.index + matches[0].length;
  306. }
  307. str += tempStr.substring(ndx, tempStr.length);
  308. return str;
  309. };
  310. export const genBound = () => {
  311. let seted = false;
  312. let minX = Number.MAX_VALUE,
  313. minY = Number.MAX_VALUE,
  314. maxX = Number.MIN_VALUE,
  315. maxY = Number.MIN_VALUE;
  316. return {
  317. update(points: Pos | Pos[]) {
  318. console.log(points)
  319. points = Array.isArray(points) ? points : [points];
  320. points.forEach((pos) => {
  321. seted = true;
  322. minX = Math.min(pos.x, minX);
  323. minY = Math.min(pos.y, minY);
  324. maxX = Math.max(pos.x, maxX);
  325. maxY = Math.max(pos.y, maxY);
  326. });
  327. },
  328. get() {
  329. if (!seted) return null;
  330. return {
  331. x: minX,
  332. y: minY,
  333. width: maxX - minX,
  334. height: maxY - minY,
  335. maxX,
  336. maxY,
  337. center: {
  338. x: (minX + maxX) / 2,
  339. y: (minY + maxY) / 2,
  340. },
  341. };
  342. },
  343. };
  344. };
  345. export const validNum = (num: any) => typeof num === 'number' && !Number.isNaN(num)