| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- // 票 15 取证:主画板候选(Desktop-6 总体概览)与全稿对比 —— 画板底色、面板填充、标题/正文文字色
- import { readFileSync } from 'node:fs'
- const dir = '.scratch/lanhu-cockpit-asset-replacement/research/raw-v2'
- const hex = (c) => `#${[c.r, c.g, c.b].map((v) => Math.round(v * 255).toString(16).padStart(2, '0')).join('')}`
- const alpha = (c) => (c.a === undefined || c.a > 0.999 ? '' : `@${c.a.toFixed(2)}`)
- function load(n) {
- return JSON.parse(readFileSync(`${dir}/desktop-${String(n).padStart(2, '0')}.json`, 'utf8')).artboard
- }
- // 1. 画板根节点自身的填充(= 页面底色)
- for (const n of [2, 3, 4, 5, 6, 7, 8, 9, 10]) {
- const ab = load(n)
- const rootFills = (ab.style?.fills || []).filter((f) => f.type === 'color').map((f) => hex(f.color) + alpha(f.color))
- const big = []
- ;(function walk(node) {
- const w = node.frame?.width ?? 0
- const h = node.frame?.height ?? 0
- if (w >= 200 && h >= 100) {
- for (const f of node.style?.fills || []) {
- if (f.type === 'color') big.push({ n: node.name, w: Math.round(w), h: Math.round(h), c: hex(f.color) + alpha(f.color) })
- }
- }
- for (const c of node.layers || []) walk(c)
- })(ab)
- console.log(`\n=== ${ab.name} ${ab.frame.width}x${ab.frame.height}`)
- console.log(` 根填充: ${rootFills.join(', ') || '(无)'}`)
- console.log(` 大色块(≥200x100) 前 14: ${big.slice(0, 14).map((b) => `${b.n} ${b.w}x${b.h} ${b.c}`).join(' | ')}`)
- }
- // 2. 文字层级:按字号聚合文字颜色(看设计稿的文字色阶)
- const bySize = new Map()
- for (const n of [2, 3, 4, 5, 6, 7, 8, 9, 10]) {
- const ab = load(n)
- ;(function walk(node) {
- if (node.type === 'textLayer' && node.text?.style?.font?.size) {
- const size = node.text.style.font.size
- const c = node.text.style.color
- if (c) {
- const key = `${size}px ${hex(c)}${alpha(c)}`
- const cur = bySize.get(key) || { count: 0, sample: '' }
- cur.count += 1
- if (!cur.sample) cur.sample = String(node.text.style.content || '').slice(0, 12)
- bySize.set(key, cur)
- }
- }
- for (const ch of node.layers || []) walk(ch)
- })(ab)
- }
- console.log('\n=== 文字:字号×颜色 Top 30')
- console.log(
- [...bySize.entries()]
- .sort((a, b) => b[1].count - a[1].count)
- .slice(0, 30)
- .map(([k, v]) => `${k} ×${v.count} 例:${v.sample}`)
- .join('\n'),
- )
- // 3. 面板标题候选:文字内容含「总览/概览/预警/监测」的节点,取其字号与颜色
- console.log('\n=== 标题类文字样本(内容含 总览|概览|预警|监测|档案)')
- const seen = new Set()
- for (const n of [6, 2, 5]) {
- const ab = load(n)
- ;(function walk(node) {
- if (node.type === 'textLayer' && node.text?.style?.content) {
- const t = String(node.text.style.content)
- if (/总览|概览|预警|监测|档案|信息|分析/.test(t) && !seen.has(`${ab.name}:${t}`)) {
- seen.add(`${ab.name}:${t}`)
- const f = node.text.style.font
- const c = node.text.style.color
- console.log(` [${ab.name}] "${t}" ${f.name} ${f.size}px w${f.fontWeight} ${c ? hex(c) + alpha(c) : '-'} frame=${Math.round(node.frame.width)}x${Math.round(node.frame.height)}`)
- }
- }
- for (const ch of node.layers || []) walk(ch)
- })(ab)
- }
|