Skip to content

Commit

Permalink
perf: 优化节点宽度计算逻辑
Browse files Browse the repository at this point in the history
  • Loading branch information
fxzer committed Aug 24, 2024
1 parent fa0f5c7 commit 96e083e
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 45 deletions.
52 changes: 27 additions & 25 deletions src/utils/computeNodeSize.ts
Original file line number Diff line number Diff line change
@@ -1,66 +1,68 @@
// 计算节点大小
import { fittingString } from './fittingString'
import { fittingStringFn } from './fittingString'

// 将对象每个键值对 格式化为 字符串数组
function formatObj(obj: any) {
return Object.entries(obj).map((entriy) => {
const key = entriy[0]
const value = entriy[1]
if (typeof value === 'string')
return `${key}: "${value}"`
// boolean/number不加引号
return `${key}: ${value}`
// 将对象每个键值对格式化为字符串数组
function formatObj(obj: Record<string, any>): string[] {
return Object.entries(obj).map(([key, value]) => {
const formattedValue = typeof value === 'string' ? `"${value}"` : value
return `${key}: ${formattedValue}`
})
}

// 找到最长的字符串
function getLongestStr(strArr: string[]) {
return strArr.reduce((pre, cur) => {
return pre.length > cur.length ? pre : cur
})
function getLongestStr(strArr: string[]): string {
return strArr.reduce((pre, cur) => (pre.length > cur.length ? pre : cur), '')
}

// 获取节点宽度
// 获取文本宽度(缓存上下文以减少重复创建)
const getWidth = (() => {
const canvas = document.createElement('canvas')
const context = canvas.getContext('2d')
return (text, font = 'normal 12px Arial') => {
const cache = new Map<string, number>()

return (text: string, font: string = 'normal 12px Arial'): number => {
const cacheKey = `${font}:${text}`
if (cache.has(cacheKey)) return cache.get(cacheKey)!

context.font = font
const metrics = context.measureText(text)
return Math.ceil(metrics.width)
const width = Math.ceil(context.measureText(text).width)
cache.set(cacheKey, width)
return width
}
})()

const fittingString = fittingStringFn()

export function computeNodeSize(cfg: {
entries: Record<string, any>
keyName?: string
}): [number, number, string] {
const { entries, keyName = '' } = cfg
const hasKeyName = Boolean(keyName)

let width = 40
const maxWidth = 400
const lineHeight = 18
let width = 40
let height = lineHeight

if (hasKeyName) {
const keyNameStr
= getWidth(keyName) < maxWidth ? keyName : fittingString(keyName, maxWidth)
const keyNameStr = getWidth(keyName) <= maxWidth ? keyName : fittingString(keyName, maxWidth)
return [getWidth(keyNameStr), height, keyNameStr]
}

const entryKeys = Object.keys(entries)
const keyNum = entryKeys.length
height = keyNum * lineHeight

if (keyNum) {
if (keyNum > 0) {
const entriesArr = formatObj(entries)
const longestEntry = getLongestStr(entriesArr)
const widthest = getWidth(longestEntry)
width = widthest < maxWidth ? widthest : maxWidth
const entryWidth = getWidth(longestEntry)
width = entryWidth <= maxWidth ? entryWidth : maxWidth

const entriesStr = entriesArr
.map(item => fittingString(item.replace(/\n|\t/g, ''), maxWidth))
.join('\n')

return [width, height, entriesStr]
}

Expand Down
37 changes: 18 additions & 19 deletions src/utils/fittingString.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
// 节点文本溢出省略

// import G6 from '@antv/g6'

export function fittingString(str: string, maxWidth: number, fontSize: number = 12) {
// 节点文本溢出省略,利用闭包优化性能
export function fittingStringFn(fontSize: number = 12) {
const ellipsis = '...'
const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0]
let currentWidth = 0
let res = str
const pattern = /[\u4E00-\u9FA5]+/
str.split('').forEach((letter, i) => {
if (currentWidth > maxWidth - ellipsisLength)
return
if (pattern.test(letter))
currentWidth += fontSize
else
currentWidth += G6.Util.getLetterWidth(letter, fontSize)
return function (str: string, maxWidth: number) {
let currentWidth = 0
let res = str
const pattern = /[\u4E00-\u9FA5]+/
str.split('').forEach((letter, i) => {
if (currentWidth > maxWidth - ellipsisLength)
return
if (pattern.test(letter))
currentWidth += fontSize
else
currentWidth += G6.Util.getLetterWidth(letter, fontSize)

if (currentWidth > maxWidth - ellipsisLength)
res = `${str.substr(0, i)}${ellipsis}`
})
return res
if (currentWidth > maxWidth - ellipsisLength)
res = `${str.substring(0, i)}${ellipsis}`
})
return res
}
}
1 change: 0 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export * from './computeNodeSize'
export * from './dealDataToTree'
export * from './deepFormat'
export * from './fittingString'
export * from './registerNodes'
export * from './registerBehaviors'
Expand Down

0 comments on commit 96e083e

Please sign in to comment.