128 lines
3.6 KiB
TypeScript
128 lines
3.6 KiB
TypeScript
![]() |
import MersenneTwister from "./mersenneTwister"
|
|||
|
import { ThemeConfig } from "../theme"
|
|||
|
import { richTextSupportStyleList } from "../constants/constant"
|
|||
|
import merge from 'deepmerge'
|
|||
|
|
|||
|
// 判断一个颜色是否是白色
|
|||
|
export const isWhite = (color: string): boolean => {
|
|||
|
color = String(color).replaceAll(/\s+/g, '')
|
|||
|
return (
|
|||
|
['#fff', '#ffffff', '#FFF', '#FFFFFF', 'rgb(255,255,255)'].includes(
|
|||
|
color
|
|||
|
) || /rgba\(255,255,255,[^)]+\)/.test(color)
|
|||
|
)
|
|||
|
}
|
|||
|
|
|||
|
// 判断一个颜色是否是透明
|
|||
|
export const isTransparent = (color: string): boolean => {
|
|||
|
color = String(color).replaceAll(/\s+/g, '')
|
|||
|
return (
|
|||
|
['', 'transparent'].includes(color) || /rgba\(\d+,\d+,\d+,0\)/.test(color)
|
|||
|
)
|
|||
|
}
|
|||
|
|
|||
|
// 从当前主题里获取一个非透明非白色的颜色
|
|||
|
export const getVisibleColorFromTheme = (themeConfig: ThemeConfig): string | undefined => {
|
|||
|
const { lineColor, root, second, node } = themeConfig
|
|||
|
const list = [
|
|||
|
lineColor,
|
|||
|
root.fillColor,
|
|||
|
root.color,
|
|||
|
second.fillColor,
|
|||
|
second.color,
|
|||
|
node.fillColor,
|
|||
|
node.color,
|
|||
|
root.borderColor,
|
|||
|
second.borderColor,
|
|||
|
node.borderColor
|
|||
|
]
|
|||
|
for (let i = 0; i < list.length; i++) {
|
|||
|
const color = list[i]
|
|||
|
if (!isTransparent(color) && !isWhite(color)) {
|
|||
|
return color
|
|||
|
}
|
|||
|
}
|
|||
|
return undefined
|
|||
|
}
|
|||
|
|
|||
|
// 根据内容生成颜色
|
|||
|
export const generateColorByContent = (str: string): string => {
|
|||
|
let hash = 0
|
|||
|
for (let i = 0; i < str.length; i++) {
|
|||
|
hash = str.charCodeAt(i) + ((hash << 5) - hash)
|
|||
|
}
|
|||
|
// 这里使用伪随机数的原因是因为
|
|||
|
// 1. 如果字符串的内容差不多,根据hash生产的颜色就比较相近,不好区分,比如v1.1 v1.2,所以需要加入随机数来使得颜色能够区分开
|
|||
|
// 2. 普通的随机数每次数值不一样,就会导致每次新增标签原来的标签颜色就会发生改变,所以加入了这个方法,使得内容不变随机数也不变
|
|||
|
const rng = new MersenneTwister(hash)
|
|||
|
const h = rng.genrand_int32() % 360
|
|||
|
return 'hsla(' + h + ', 50%, 50%, 1)'
|
|||
|
}
|
|||
|
|
|||
|
interface IconItem {
|
|||
|
type: string
|
|||
|
list: Array<{
|
|||
|
name: string
|
|||
|
icon: string
|
|||
|
}>
|
|||
|
}
|
|||
|
|
|||
|
export const mergerIconList = (list: IconItem[]): IconItem[] => {
|
|||
|
return list.reduce((result: IconItem[], item) => {
|
|||
|
const existingItem = result.find(x => x.type === item.type)
|
|||
|
if (existingItem) {
|
|||
|
item.list.forEach(newObj => {
|
|||
|
const existingObj = existingItem.list.find(x => x.name === newObj.name)
|
|||
|
if (existingObj) {
|
|||
|
existingObj.icon = newObj.icon
|
|||
|
} else {
|
|||
|
existingItem.list.push(newObj)
|
|||
|
}
|
|||
|
})
|
|||
|
} else {
|
|||
|
result.push({ ...item })
|
|||
|
}
|
|||
|
return result
|
|||
|
}, [])
|
|||
|
}
|
|||
|
|
|||
|
// 合并主题配置
|
|||
|
export const mergeTheme = <T extends object>(dest: T, source: T): T => {
|
|||
|
return merge(dest, source, {
|
|||
|
arrayMerge: (_destinationArray: any[], sourceArray: any[]) => sourceArray
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
interface NodeStyle {
|
|||
|
merge: (prop: string) => string | number
|
|||
|
}
|
|||
|
|
|||
|
interface Node {
|
|||
|
style: NodeStyle
|
|||
|
}
|
|||
|
|
|||
|
// 获取节点实例的文本样式数据
|
|||
|
export const getNodeRichTextStyles = (node: Node): Record<string, string> => {
|
|||
|
const res: Record<string, string> = {}
|
|||
|
richTextSupportStyleList.forEach(prop => {
|
|||
|
let value = node.style.merge(prop)
|
|||
|
if (prop === 'fontSize') {
|
|||
|
value = value + 'px'
|
|||
|
}
|
|||
|
res[prop] = String(value)
|
|||
|
})
|
|||
|
return res
|
|||
|
}
|
|||
|
|
|||
|
export interface FontOptions {
|
|||
|
italic?: boolean;
|
|||
|
bold?: boolean;
|
|||
|
fontSize: number;
|
|||
|
fontFamily: string;
|
|||
|
}
|
|||
|
|
|||
|
// 拼接font字符串
|
|||
|
export const joinFontStr = ({ italic, bold, fontSize, fontFamily }: FontOptions): string => {
|
|||
|
return `${italic ? 'italic ' : ''} ${bold ? 'bold ' : ''
|
|||
|
} ${fontSize}px ${fontFamily} `
|
|||
|
}
|