import { Pos } from "@/utils/math.ts"; import { v4 as uuid } from "uuid"; /** * 四舍五入 * @param num * @param b 保留位数 * @returns */ export const round = (num: number, b: number = 2) => { const scale = Math.pow(10, b); return Math.round(num * scale) / scale; }; /** * 范围取余 * @param num * @param mod */ export const rangMod = (num: number, mod: number) => ((num % mod) + mod) % mod; /** * 有偏差的indexOf * @param arr * @param warp * @param val * @returns */ export const warpIndexOf = (arr: number[], warp: number, val: number) => arr.findIndex((num) => val >= num - warp && val <= num + warp); /** * 多个函数合并成一个函数 * @param fns * @returns */ export const mergeFuns = (...fns: (() => void)[] | (() => void)[][]) => { return () => { fns.forEach((fn) => { if (Array.isArray(fn)) { fn.forEach((f) => f()); } else { fn(); } }); }; }; export const copy = (data: T): T => JSON.parse(JSON.stringify(data)); /** * 获取数据类型 * @param value * @returns */ export const toRawType = (value: unknown): string => Object.prototype.toString.call(value).slice(8, -1); // 是否修改 const _inRevise = (raw1: any, raw2: any, readly: Set<[any, any]>): boolean => { if (raw1 === raw2) return false; const rawType1 = toRawType(raw1); const rawType2 = toRawType(raw2); if (rawType1 !== rawType2) { return true; } else if ( rawType1 === "String" || rawType1 === "Number" || rawType1 === "Boolean" ) { if (rawType1 === "Number" && isNaN(raw1) && isNaN(raw2)) { return false; } else { return raw1 !== raw2; } } const rawsArray = Array.from(readly.values()); for (const raws of rawsArray) { if (raws.includes(raw1) && raws.includes(raw2)) { return false; } } readly.add([raw1, raw2]); if (rawType1 === "Array") { return ( raw1.length !== raw2.length || raw1.some((item1: any, i: number) => _inRevise(item1, raw2[i], readly)) ); } else if (rawType1 === "Object") { const rawKeys1 = Object.keys(raw1).sort(); const rawKeys2 = Object.keys(raw2).sort(); return ( _inRevise(rawKeys1, rawKeys2, readly) || rawKeys1.some((key) => _inRevise(raw1[key], raw2[key], readly)) ); } else if (rawType1 === "Map") { const rawKeys1 = Array.from(raw1.keys()).sort(); const rawKeys2 = Array.from(raw2.keys()).sort(); return ( _inRevise(rawKeys1, rawKeys2, readly) || rawKeys1.some((key) => _inRevise(raw1.get(key), raw2.get(key), readly)) ); } else if (rawType1 === "Set") { return inRevise(Array.from(raw1.values()), Array.from(raw2.values())); } else { return raw1 !== raw2; } }; /** * 查看数据是否被修改 * @param raw1 * @param raw2 * @returns */ export const inRevise = (raw1: any, raw2: any) => _inRevise(raw1, raw2, new Set()); // 防抖 export const debounce = any>( fn: T, delay: number = 160 ) => { let timeout: any; return function (...args: Parameters) { clearTimeout(timeout); timeout = setTimeout(() => { fn.apply(null, args); }, delay); }; }; /** * 获取数据变化 * @param newIds * @param oldIds * @returns */ export const getChangePart = (newIds: T[], oldIds: T[] = []) => { const addPort = newIds.filter((newId) => !oldIds.includes(newId)); const delPort = oldIds.filter((oldId) => !newIds.includes(oldId)); const holdPort = oldIds.filter((oldId) => newIds.includes(oldId)); return { addPort, delPort, holdPort }; }; export const flatPositions = (positions: Pos[]) => positions.flatMap((p) => [p.x, p.y]); export const flatToPositions = (coords: number[]) => { const positions: Pos[] = []; for (let i = 0; i < coords.length; i += 2) { positions.push({ x: coords[i], y: coords[i + 1], }); } return positions; }; export const onlyId = () => uuid(); export const startAnimation = (update: () => void, dur = -1) => { let isStop = false; const animation = () => { requestAnimationFrame(() => { if (!isStop) { update(); animation(); } }); }; animation(); let timeout: any; if (dur >= 0) { setTimeout(() => (isStop = true), dur); } return () => { clearTimeout(timeout); isStop = true; }; }; export const arrayInsert = ( array: T[], item: T, canInsert: (eItem: T, insertItem: T) => boolean ) => { let i = 0; for (i = 0; i < array.length; i++) { if (canInsert(array[i], item)) { break; } } array.splice(i, 0, item); return array; }; export const asyncTimeout = (time: number) => { let timeout: any; let reject: any const promise = new Promise((resolve, r) => { timeout = setTimeout(resolve, time); reject = r }) as Promise & { stop: () => void }; promise.stop = () => { clearTimeout(timeout); reject('取消') }; return promise; };