UNPKG

@chinese-fonts/yozai

Version:
369 lines (357 loc) 14.3 kB
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title></title> </head> <style> body { overflow-wrap: break-word; font-size: 18px; } h3 { font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; font-weight: normal; } </style> <body></body> <script type="module"> import { createSignal, createResource, onMount, createEffect, } from 'https://esm.sh/solid-js'; import html from 'https://esm.sh/solid-js/html'; import prettyBytes from 'https://esm.sh/pretty-bytes'; import { UnicodeRange } from 'https://esm.sh/@japont/unicode-range@1.0.0'; /** 延迟获取 Echarts*/ const getECharts = () => import('https://esm.sh/echarts@5.3.3/dist/echarts.esm.min.js'); const getFontData = (nameTable) => Object.fromEntries( Object.entries(nameTable).map(([key, val]) => { return [key, typeof val === 'string' ? val : val.en]; }), ); const range = [ ['基本汉字', 0x4e00, 0x9fa5], ['基本汉字补充', 0x9fa6, 0x9fff], ['扩展A', 0x3400, 0x4dbf], ['扩展B', 0x20000, 0x2a6df], ['扩展C', 0x2a700, 0x2b738], ['扩展D', 0x2b740, 0x2b81d], ['扩展E', 0x2b820, 0x2cea1], ['扩展F', 0x2ceb0, 0x2ebe0], ['扩展G', 0x30000, 0x3134a], ['康熙部首', 0x2f00, 0x2fd5], ['部首扩展', 0x2e80, 0x2ef3], ['兼容汉字', 0xf900, 0xfad9], ['兼容扩展', 0x2f800, 0x2fa1d], ['PUA(GBK)部件', 0xe815, 0xe86f], ['部件扩展', 0xe400, 0xe5e8], ['PUA增补', 0xe600, 0xe6cf], ['汉字笔画', 0x31c0, 0x31e3], ['汉字结构', 0x2ff0, 0x2ffb], ['汉语注音', 0x3105, 0x312f], ['注音扩展', 0x31a0, 0x31ba], ['〇', 0x3007, 0x3007], ]; const RangeAnalyze = (data) => { const total = data.reduce((col, cur) => { if (cur.chars.startsWith('U+')) { return ( col + String.fromCodePoint( ...UnicodeRange.parse(cur.chars.split(',')), ) ); } return col + cur.chars; }, ''); const result = range.map(([name, min, max]) => { let exist = ''; let voids = ''; for (let i = min; i <= max; i++) { const char = String.fromCodePoint(i); const isExist = total.includes(char); if (isExist) { exist += char; } else { voids += char; } } return [name, exist, voids]; }); return html` <table style="width:80%;margin:auto;padding:1rem"> <thead> <tr> <th>位置</th> <th>存在</th> <th>不存在</th> <th>覆盖率</th> </tr> </thead> ${result.map(([name, exist, voids]) => { const coverage = (exist.length * 100) / (exist.length + voids.length); return html` <tr> <td>${name}</td> <td>${exist.length}</td> <td>${voids.length}</td> <td>${coverage.toFixed(2)}%</td> </tr> `; })} </table> `; }; const TimeAnalyze = (record, message) => { record.pop(); // 最后一个记录是没有用的 const total = record.reduce( (col, cur) => col + cur.end - cur.start, 0, ); let chartDom; // console.log(record, total); onMount(() => { // 问就是渲染代价太大,等 1000ms 让浏览器冷静一下 setTimeout(async () => { const echarts = await getECharts(); let myChart = echarts.init(chartDom); let option = { tooltip: { trigger: 'axis', axisPointer: { type: 'shadow', }, }, title: { text: '打包时间分布图', subtext: `时间为 ms; 总时间 ${total} ms;\n${message.fontFamily}`, }, legend: { top: '15%', }, grid: { left: '10%', right: '10%', bottom: '30%', top: '30%', }, xAxis: { type: 'value', }, yAxis: { type: 'category', data: ['时间轴'], }, series: record.map((i) => { return { name: i.name, type: 'bar', stack: 'total', label: { show: true, }, emphasis: { focus: 'series', }, data: [ parseFloat((i.end - i.start).toFixed(1)), ], }; }), }; option && myChart.setOption(option); }, 1500); }); return html`<div ref=${function (dom) { chartDom = dom; }} style="width: 600px;height:400px;margin:auto" ></div>`; }; const DataAnalyze = (data, message) => { const total = data.reduce((col, cur) => col + cur.size, 0); // console.log(data, total); let chartDom; onMount(() => { // 问就是渲染代价太大,等 1000ms 让浏览器冷静一下 setTimeout(async () => { const echarts = await getECharts(); let myChart = echarts.init(chartDom); let option = { tooltip: { trigger: 'item', formatter(data) { return ( `第 ${data.dataIndex + 1} 分包\n` + data.data.name + '\n' + prettyBytes(data.data.value) ); }, }, title: { text: message.fontFamily, subtext: `总共 ${ data.length } 分包; 总大小 ${prettyBytes( total, )} 点击跳转查看;`, left: 'center', }, series: [ { name: '分包信息', type: 'pie', radius: ['40%', '70%'], avoidLabelOverlap: false, itemStyle: { borderRadius: 10, borderColor: '#fff', borderWidth: 2, }, emphasis: { label: { show: true, fontSize: '18', fontWeight: 'bold', }, }, labelLine: { show: true, }, label: { show: true, minMargin: 5, edgeDistance: 10, lineHeight: 15, formatter(data) { return ( ( (data.data.value * 100) / total ).toFixed(2) + '%' ); }, }, data: data.map((i) => ({ value: i.size, name: i.name.slice(0, 7), hash: i.name, })), }, ], }; option && myChart.setOption(option); myChart.on('click', (data) => { document .getElementById(data.data.hash) .scrollIntoView(); }); }, 300); }); return html`<div ref=${function (dom) { chartDom = dom; }} style="width: 600px;height:600px;margin:auto" ></div>`; }; const CharList = (data) => { return data.map((i) => { const chars = i.chars.startsWith('U+') ? String.fromCodePoint( ...UnicodeRange.parse(i.chars.split(',')), ) : i.chars; return html`<div> <h3 id="${i.name}"> 分片名称 ${i.name} | 分片大小 ${prettyBytes(i.size)} </h3> <p>${chars}</p> </div>`; }); }; const BaseMessage = (message) => { return html` <table style="margin:auto"> ${Object.entries(message).map((i) => { return html` <tr> <td>${i[0].en}</td> <td>${i[1].en}</td> </tr> `; })} </table> `; }; const App = () => { const [data] = createResource(() => fetch('./reporter.json') .then((res) => res.json()) .then((res) => { res.message = res.message.windows || res.message.macintosh; return res; }), ); createEffect(() => { if (data()) { console.log(data().message); document.body.style.fontFamily = `"${ getFontData(data().message).fontFamily || getFontData(data().message).preferredFamily }"`; document.querySelector('title').textContent = getFontData( data().message, ).fontFamily; const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = './' + (data().config.cssFileName || 'result') + '.css'; document.head.appendChild(link); } }); const content = () => html` <div> ${RangeAnalyze( data().data, getFontData(data().message), )} ${DataAnalyze(data().data, getFontData(data().message))} ${TimeAnalyze( data().record, getFontData(data().message), )} ${BaseMessage(getFontData(data().message))} </div> ${CharList(data().data)}`; return html`<div> ${() => (data.loading ? `<div>加载中</div>` : content())} </div>`; }; import { render } from 'https://esm.sh/solid-js/web'; render(App, document.body); </script> </html>