resource.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import { reactive } from "vue";
  2. import { Pos, Size } from "./math";
  3. let imageCache: Record<string, Promise<HTMLImageElement>>;
  4. let imageCache1: Record<string, HTMLImageElement>;
  5. export let imageInfo: Record<string, Record<'width' | 'height', number>> = reactive({})
  6. export let getImage = (url: string): Promise<HTMLImageElement> => {
  7. imageCache = {};
  8. imageCache1 = {};
  9. getImage = (url: string) => {
  10. if (url in imageCache) {
  11. if (imageCache1[url]?.width === 0 || imageCache1[url]?.height === 0) {
  12. delete imageCache1[url]
  13. delete imageCache[url];
  14. delete imageInfo[url]
  15. } else {
  16. return imageCache[url];
  17. }
  18. }
  19. return (imageCache[url] = new Promise((resolve, reject) => {
  20. const image = new Image();
  21. image.crossOrigin = "anonymous";
  22. image.onload = () => {
  23. resolve(image);
  24. imageInfo[url] = {
  25. width: image.width,
  26. height: image.height
  27. }
  28. imageCache1[url] = image
  29. };
  30. image.onerror = (e) => {
  31. console.error(e)
  32. reject(e);
  33. };
  34. image.src = url;
  35. }));
  36. };
  37. return getImage(url);
  38. };
  39. export const isSvgString = (str: string) => {
  40. // 检查字符串是否以 <svg> 标签开头
  41. const svgRegex = /^<svg[^>]*>.*<\/svg>$/is;
  42. return svgRegex.test(str);
  43. }
  44. let svgContentCache: Record<string, Promise<string>>;
  45. export let getSvgContent = (url: string): Promise<string> => {
  46. svgContentCache = {};
  47. getSvgContent = async (url: string) => {
  48. if (isSvgString(url)) {
  49. return url;
  50. }
  51. if (url in svgContentCache) {
  52. return svgContentCache[url];
  53. } else {
  54. const res = await fetch(url);
  55. return (svgContentCache[url] = res.text());
  56. }
  57. };
  58. return getSvgContent(url);
  59. };
  60. export type SVGPath = {
  61. fill?: string;
  62. stroke?: string;
  63. strokeWidth?: number;
  64. data: string;
  65. };
  66. export type SVGParseResult = Size & Pos & {
  67. paths: SVGPath[];
  68. };
  69. let svgParseCache: Record<string, SVGParseResult>;
  70. let helpDOM: HTMLDivElement;
  71. export let parseSvgContent = (svgContent: string): SVGParseResult => {
  72. svgParseCache = {};
  73. helpDOM = document.createElement("div");
  74. helpDOM.style.position = "absolute";
  75. helpDOM.style.left = "-99999px";
  76. helpDOM.style.top = "-99999px";
  77. parseSvgContent = (svgContent: string) => {
  78. if (svgContent in svgParseCache) return svgParseCache[svgContent];
  79. helpDOM.innerHTML = svgContent;
  80. document.body.appendChild(helpDOM);
  81. let right = 0;
  82. let bottom = 0;
  83. let x = Number.MAX_VALUE;
  84. let y = Number.MAX_VALUE;
  85. const svgPaths = Array.from(helpDOM.querySelectorAll("path"));
  86. const paths = svgPaths.map((path) => {
  87. const box = path.getBBox();
  88. x = Math.min(box.x, x);
  89. y = Math.min(box.y, y);
  90. right = Math.max(right, box.x + box.width);
  91. bottom = Math.max(bottom, box.y + box.height);
  92. const fill = path.getAttribute("fill")!;
  93. const data = path.getAttribute("d")!;
  94. const stroke = path.getAttribute("stroke")!;
  95. const strokeWidth = path.getAttribute("stroke-width")!;
  96. return {
  97. fill,
  98. data,
  99. stroke,
  100. strokeWidth: (strokeWidth && Number(strokeWidth)) || 1,
  101. };
  102. });
  103. helpDOM.innerHTML = "";
  104. document.body.removeChild(helpDOM);
  105. return (svgParseCache[svgContent] = { paths, width: right - x, height: bottom - y, x, y });
  106. };
  107. return parseSvgContent(svgContent);
  108. };