|
import { firaMono } from "src/constants/fonts"; |
|
import useConfig from "src/store/useConfig"; |
|
import useGraph from "src/store/useGraph"; |
|
|
|
type Text = string | [string, string][]; |
|
type Size = { width: number; height: number }; |
|
|
|
export const isContentImage = (value: Text) => { |
|
if (typeof value !== "string") return false; |
|
|
|
const isImageURL = /(https?:\/\/.*\.(?:png|jpg|gif))/i.test(value); |
|
const isBase64 = value.startsWith("data:image/") && value.includes("base64"); |
|
|
|
return isImageURL || isBase64; |
|
}; |
|
|
|
const calculateLines = (text: Text): string => { |
|
if (typeof text === "string") { |
|
return text; |
|
} else { |
|
return text.map(([k, v]) => `${k}: ${JSON.stringify(v).slice(0, 80)}`).join("\n"); |
|
} |
|
}; |
|
|
|
const calculateWidthAndHeight = (str: string, single = false) => { |
|
if (!str) return { width: 45, height: 45 }; |
|
|
|
const dummyElement = document.createElement("div"); |
|
|
|
dummyElement.style.whiteSpace = single ? "nowrap" : "pre-wrap"; |
|
dummyElement.innerHTML = str; |
|
dummyElement.style.fontSize = "12px"; |
|
dummyElement.style.width = "fit-content"; |
|
dummyElement.style.height = "fit-content"; |
|
dummyElement.style.padding = "10px"; |
|
dummyElement.style.fontWeight = "500"; |
|
dummyElement.style.overflowWrap = "break-word"; |
|
dummyElement.style.fontFamily = firaMono.style.fontFamily; |
|
document.body.appendChild(dummyElement); |
|
|
|
const clientRect = dummyElement.getBoundingClientRect(); |
|
const width = clientRect.width + 4; |
|
const height = clientRect.height; |
|
|
|
document.body.removeChild(dummyElement); |
|
|
|
return { width, height }; |
|
}; |
|
|
|
const sizeCache = new Map<Text, Size>(); |
|
|
|
|
|
setInterval(() => sizeCache.clear(), 120_000); |
|
|
|
export const calculateNodeSize = (text: Text, isParent = false) => { |
|
const { foldNodes } = useGraph.getState(); |
|
const { imagePreviewEnabled } = useConfig.getState(); |
|
const isImage = isContentImage(text) && imagePreviewEnabled; |
|
|
|
const cacheKey = [text, isParent, foldNodes].toString(); |
|
|
|
|
|
if (sizeCache.has(cacheKey)) { |
|
const size = sizeCache.get(cacheKey); |
|
|
|
if (size) return size; |
|
} |
|
|
|
const lines = calculateLines(text); |
|
const sizes = calculateWidthAndHeight(lines, typeof text === "string"); |
|
|
|
if (isImage) { |
|
sizes.width = 80; |
|
sizes.height = 80; |
|
} |
|
|
|
if (foldNodes) sizes.width = 300; |
|
if (isParent && foldNodes) sizes.width = 170; |
|
if (isParent) sizes.width += 100; |
|
if (sizes.width > 700) sizes.width = 700; |
|
|
|
sizeCache.set(cacheKey, sizes); |
|
return sizes; |
|
}; |
|
|