index.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. import { Base64 } from "js-base64";
  2. export const getRealativeMosePosition = (
  3. dom: HTMLElement,
  4. mousePosition: number[]
  5. ) => {
  6. const rect = dom.getBoundingClientRect();
  7. return [mousePosition[0] - rect.left, mousePosition[1] - rect.top];
  8. };
  9. // 节流
  10. export const throttle = <T extends (...args: any) => any>(
  11. fn: T,
  12. delay: number = 160
  13. ) => {
  14. let previous = 0;
  15. return function <This>(this: This, ...args: Parameters<T>) {
  16. const now = Date.now();
  17. if (now - previous >= delay) {
  18. fn.apply(this, args);
  19. previous = now;
  20. }
  21. };
  22. };
  23. // 防抖
  24. export const debounce = <T extends (...args: any) => any>(
  25. fn: T,
  26. delay: number = 160
  27. ) => {
  28. let timeout: any;
  29. return function <This>(this: This, ...args: Parameters<T>) {
  30. clearTimeout(timeout);
  31. timeout = setTimeout(() => {
  32. fn.apply(this, args);
  33. }, delay);
  34. };
  35. };
  36. export const loadImage = (src: string): Promise<HTMLImageElement> => {
  37. const img = new Image();
  38. img.src = src;
  39. img.crossOrigin = "anonymous";
  40. return new Promise<HTMLImageElement>((resolve) => {
  41. img.onload = () => resolve(img);
  42. });
  43. };
  44. export const mergeFuns = (...fns: (() => void)[]) => {
  45. return () => {
  46. fns.forEach((fn) => fn());
  47. };
  48. };
  49. // 四舍五入保留指定位数
  50. export const round = (num: number, index: number = 2) => {
  51. const s = Math.pow(10, index);
  52. return Math.round(num * s) / s;
  53. };
  54. export const numberSplice = (val: number) => {
  55. const integer = Math.floor(val);
  56. const decimal = val - integer;
  57. return [integer, decimal];
  58. };
  59. //经纬度转度°分′秒″
  60. export const toDegrees = (val: number, retain = 2) => {
  61. let temps = numberSplice(val);
  62. const d = temps[0];
  63. temps = numberSplice(temps[1] * 60);
  64. const m = temps[0];
  65. const s = round(temps[1] * 60, retain);
  66. return `${d}°${m}′${s.toFixed(2)}″`;
  67. };
  68. export const copyText = async (
  69. text: string,
  70. fallback?: boolean
  71. ): Promise<void> => {
  72. if (navigator.clipboard && !fallback) {
  73. let permiss: any;
  74. try {
  75. permiss = await navigator.permissions.query({
  76. name: "geolocation",
  77. });
  78. permiss.state === "denied";
  79. } catch (e) {
  80. console.error(e);
  81. }
  82. if (permiss && permiss.state === "denied") {
  83. console.error(permiss);
  84. throw new Error("请授予写入粘贴板权限!");
  85. } else {
  86. try {
  87. await navigator.clipboard.writeText(text);
  88. } catch (e) {
  89. console.error("不支持navigator.clipboard.writeText 开启回退");
  90. return await copyText(text, true);
  91. }
  92. }
  93. } else {
  94. const textarea = document.createElement("textarea");
  95. document.body.appendChild(textarea);
  96. // 隐藏此输入框
  97. textarea.style.position = "fixed";
  98. textarea.style.clip = "rect(0 0 0 0)";
  99. textarea.style.top = "10px";
  100. // 赋值
  101. textarea.value = text;
  102. // 选中
  103. textarea.select();
  104. // 复制
  105. document.execCommand("copy", true);
  106. // 移除输入框
  107. document.body.removeChild(textarea);
  108. }
  109. };
  110. function randomWord(randomFlag: boolean, min: number, max?: number) {
  111. let str = "";
  112. let range = min;
  113. const arr = [
  114. "0",
  115. "1",
  116. "2",
  117. "3",
  118. "4",
  119. "5",
  120. "6",
  121. "7",
  122. "8",
  123. "9",
  124. "a",
  125. "b",
  126. "c",
  127. "d",
  128. "e",
  129. "f",
  130. "g",
  131. "h",
  132. "i",
  133. "j",
  134. "k",
  135. "l",
  136. "m",
  137. "n",
  138. "o",
  139. "p",
  140. "q",
  141. "r",
  142. "s",
  143. "t",
  144. "u",
  145. "v",
  146. "w",
  147. "x",
  148. "y",
  149. "z",
  150. "A",
  151. "B",
  152. "C",
  153. "D",
  154. "E",
  155. "F",
  156. "G",
  157. "H",
  158. "I",
  159. "J",
  160. "K",
  161. "L",
  162. "M",
  163. "N",
  164. "O",
  165. "P",
  166. "Q",
  167. "R",
  168. "S",
  169. "T",
  170. "U",
  171. "V",
  172. "W",
  173. "X",
  174. "Y",
  175. "Z",
  176. ];
  177. // 随机产生
  178. if (randomFlag && max) {
  179. range = Math.round(Math.random() * (max - min)) + min;
  180. }
  181. for (let i = 0; i < range; i++) {
  182. const pos = Math.round(Math.random() * (arr.length - 1));
  183. str += arr[pos];
  184. }
  185. return str;
  186. }
  187. export function encodePwd(str: string) {
  188. str = Base64.encode(str);
  189. const NUM = 2;
  190. const front = randomWord(false, 8);
  191. const middle = randomWord(false, 8);
  192. const end = randomWord(false, 8);
  193. const str1 = str.substring(0, NUM);
  194. const str2 = str.substring(NUM);
  195. return front + str2 + middle + str1 + end;
  196. }
  197. const place = /(?:\/:([^/]*))/g;
  198. // 生成/:id 类真实url
  199. export const gendUrl = (tempUrl: string, params: { [key: string]: any }) => {
  200. let url = "";
  201. let preIndex = 0;
  202. let m;
  203. while ((m = place.exec(tempUrl))) {
  204. url += tempUrl.substring(preIndex, m.index + 1) + (params[m[1]] || "null");
  205. preIndex = m.index + m[0].length;
  206. }
  207. url += tempUrl.substr(preIndex);
  208. return url;
  209. };
  210. export const dateFormat = (date: Date, fmt: string) => {
  211. var o: any = {
  212. "M+": date.getMonth() + 1, //月份
  213. "d+": date.getDate(), //日
  214. "h+": date.getHours(), //小时
  215. "m+": date.getMinutes(), //分
  216. "s+": date.getSeconds(), //秒
  217. "q+": Math.floor((date.getMonth() + 3) / 3), //季度
  218. S: date.getMilliseconds(), //毫秒
  219. };
  220. if (/(y+)/.test(fmt)) {
  221. fmt = fmt.replace(
  222. RegExp.$1,
  223. (date.getFullYear() + "").substr(4 - RegExp.$1.length)
  224. );
  225. }
  226. for (var k in o) {
  227. if (new RegExp("(" + k + ")").test(fmt)) {
  228. fmt = fmt.replace(
  229. RegExp.$1,
  230. RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
  231. );
  232. }
  233. }
  234. return fmt;
  235. };
  236. let canvas: HTMLCanvasElement;
  237. let ctx: CanvasRenderingContext2D;
  238. export const getTextBound = (
  239. text: string,
  240. font: string,
  241. padding: number[] = [0, 0],
  242. margin: number[] = [0, 0]
  243. ) => {
  244. if (!canvas) {
  245. canvas = document.createElement("canvas");
  246. ctx = canvas.getContext("2d")!;
  247. }
  248. ctx.font = font;
  249. const textMetrics = ctx.measureText(text);
  250. const width = textMetrics.width + (padding[1] + margin[1]) * 2;
  251. const fontHeight =
  252. textMetrics.fontBoundingBoxAscent + textMetrics.fontBoundingBoxDescent;
  253. console.log(fontHeight);
  254. const height = fontHeight + (padding[0] + margin[0]) * 2;
  255. return { width, height };
  256. };
  257. export * from "./tree";