UNPKG

14.3 kBHTMLView Raw
1<!doctype html>
2<html lang="en">
3 <head>
4 <meta charset="UTF-8" />
5 <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7 <title></title>
8 </head>
9
10 <style>
11 body {
12 overflow-wrap: break-word;
13 font-size: 18px;
14 }
15 h3 {
16 font-family:
17 system-ui,
18 -apple-system,
19 BlinkMacSystemFont,
20 'Segoe UI',
21 Roboto,
22 Oxygen,
23 Ubuntu,
24 Cantarell,
25 'Open Sans',
26 'Helvetica Neue',
27 sans-serif;
28 font-weight: normal;
29 }
30 </style>
31
32 <body></body>
33 <script type="module">
34 import {
35 createSignal,
36 createResource,
37 onMount,
38 createEffect,
39 } from 'https://esm.sh/solid-js';
40 import html from 'https://esm.sh/solid-js/html';
41 import prettyBytes from 'https://esm.sh/pretty-bytes';
42 import { UnicodeRange } from 'https://esm.sh/@japont/unicode-range@1.0.0';
43 /** 延迟获取 Echarts*/
44 const getECharts = () =>
45 import('https://esm.sh/echarts@5.3.3/dist/echarts.esm.min.js');
46 const getFontData = (nameTable) =>
47 Object.fromEntries(
48 Object.entries(nameTable).map(([key, val]) => {
49 return [key, typeof val === 'string' ? val : val.en];
50 }),
51 );
52 const range = [
53 ['基本汉字', 0x4e00, 0x9fa5],
54 ['基本汉字补充', 0x9fa6, 0x9fff],
55 ['扩展A', 0x3400, 0x4dbf],
56 ['扩展B', 0x20000, 0x2a6df],
57 ['扩展C', 0x2a700, 0x2b738],
58 ['扩展D', 0x2b740, 0x2b81d],
59 ['扩展E', 0x2b820, 0x2cea1],
60 ['扩展F', 0x2ceb0, 0x2ebe0],
61 ['扩展G', 0x30000, 0x3134a],
62 ['康熙部首', 0x2f00, 0x2fd5],
63 ['部首扩展', 0x2e80, 0x2ef3],
64 ['兼容汉字', 0xf900, 0xfad9],
65 ['兼容扩展', 0x2f800, 0x2fa1d],
66 ['PUA(GBK)部件', 0xe815, 0xe86f],
67 ['部件扩展', 0xe400, 0xe5e8],
68 ['PUA增补', 0xe600, 0xe6cf],
69 ['汉字笔画', 0x31c0, 0x31e3],
70 ['汉字结构', 0x2ff0, 0x2ffb],
71 ['汉语注音', 0x3105, 0x312f],
72 ['注音扩展', 0x31a0, 0x31ba],
73 ['〇', 0x3007, 0x3007],
74 ];
75
76 const RangeAnalyze = (data) => {
77 const total = data.reduce((col, cur) => {
78 if (cur.chars.startsWith('U+')) {
79 return (
80 col +
81 String.fromCodePoint(
82 ...UnicodeRange.parse(cur.chars.split(',')),
83 )
84 );
85 }
86 return col + cur.chars;
87 }, '');
88 const result = range.map(([name, min, max]) => {
89 let exist = '';
90 let voids = '';
91 for (let i = min; i <= max; i++) {
92 const char = String.fromCodePoint(i);
93 const isExist = total.includes(char);
94 if (isExist) {
95 exist += char;
96 } else {
97 voids += char;
98 }
99 }
100 return [name, exist, voids];
101 });
102 return html`
103 <table style="width:80%;margin:auto;padding:1rem">
104 <thead>
105 <tr>
106 <th>位置</th>
107 <th>存在</th>
108 <th>不存在</th>
109 <th>覆盖率</th>
110 </tr>
111 </thead>
112 ${result.map(([name, exist, voids]) => {
113 const coverage =
114 (exist.length * 100) /
115 (exist.length + voids.length);
116 return html`
117 <tr>
118 <td>${name}</td>
119 <td>${exist.length}</td>
120 <td>${voids.length}</td>
121 <td>${coverage.toFixed(2)}%</td>
122 </tr>
123 `;
124 })}
125 </table>
126 `;
127 };
128
129 const TimeAnalyze = (record, message) => {
130 record.pop(); // 最后一个记录是没有用的
131 const total = record.reduce(
132 (col, cur) => col + cur.end - cur.start,
133 0,
134 );
135 let chartDom;
136 // console.log(record, total);
137
138 onMount(() => {
139 // 问就是渲染代价太大,等 1000ms 让浏览器冷静一下
140 setTimeout(async () => {
141 const echarts = await getECharts();
142 let myChart = echarts.init(chartDom);
143 let option = {
144 tooltip: {
145 trigger: 'axis',
146 axisPointer: {
147 type: 'shadow',
148 },
149 },
150 title: {
151 text: '打包时间分布图',
152 subtext: `时间为 ms; 总时间 ${total} ms;\n${message.fontFamily}`,
153 },
154 legend: {
155 top: '15%',
156 },
157 grid: {
158 left: '10%',
159 right: '10%',
160 bottom: '30%',
161 top: '30%',
162 },
163 xAxis: {
164 type: 'value',
165 },
166 yAxis: {
167 type: 'category',
168 data: ['时间轴'],
169 },
170 series: record.map((i) => {
171 return {
172 name: i.name,
173 type: 'bar',
174 stack: 'total',
175 label: {
176 show: true,
177 },
178 emphasis: {
179 focus: 'series',
180 },
181 data: [
182 parseFloat((i.end - i.start).toFixed(1)),
183 ],
184 };
185 }),
186 };
187
188 option && myChart.setOption(option);
189 }, 1500);
190 });
191 return html`<div
192 ref=${function (dom) {
193 chartDom = dom;
194 }}
195 style="width: 600px;height:400px;margin:auto"
196 ></div>`;
197 };
198 const DataAnalyze = (data, message) => {
199 const total = data.reduce((col, cur) => col + cur.size, 0);
200 // console.log(data, total);
201 let chartDom;
202 onMount(() => {
203 // 问就是渲染代价太大,等 1000ms 让浏览器冷静一下
204 setTimeout(async () => {
205 const echarts = await getECharts();
206 let myChart = echarts.init(chartDom);
207 let option = {
208 tooltip: {
209 trigger: 'item',
210 formatter(data) {
211 return (
212 `第 ${data.dataIndex + 1} 分包\n` +
213 data.data.name +
214 '\n' +
215 prettyBytes(data.data.value)
216 );
217 },
218 },
219
220 title: {
221 text: message.fontFamily,
222 subtext: `总共 ${
223 data.length
224 } 分包; 总大小 ${prettyBytes(
225 total,
226 )} 点击跳转查看;`,
227 left: 'center',
228 },
229 series: [
230 {
231 name: '分包信息',
232 type: 'pie',
233 radius: ['40%', '70%'],
234 avoidLabelOverlap: false,
235 itemStyle: {
236 borderRadius: 10,
237 borderColor: '#fff',
238 borderWidth: 2,
239 },
240
241 emphasis: {
242 label: {
243 show: true,
244 fontSize: '18',
245 fontWeight: 'bold',
246 },
247 },
248 labelLine: {
249 show: true,
250 },
251 label: {
252 show: true,
253 minMargin: 5,
254 edgeDistance: 10,
255 lineHeight: 15,
256 formatter(data) {
257 return (
258 (
259 (data.data.value * 100) /
260 total
261 ).toFixed(2) + '%'
262 );
263 },
264 },
265 data: data.map((i) => ({
266 value: i.size,
267 name: i.name.slice(0, 7),
268 hash: i.name,
269 })),
270 },
271 ],
272 };
273
274 option && myChart.setOption(option);
275 myChart.on('click', (data) => {
276 document
277 .getElementById(data.data.hash)
278 .scrollIntoView();
279 });
280 }, 300);
281 });
282 return html`<div
283 ref=${function (dom) {
284 chartDom = dom;
285 }}
286 style="width: 600px;height:600px;margin:auto"
287 ></div>`;
288 };
289 const CharList = (data) => {
290 return data.map((i) => {
291 const chars = i.chars.startsWith('U+')
292 ? String.fromCodePoint(
293 ...UnicodeRange.parse(i.chars.split(',')),
294 )
295 : i.chars;
296 return html`<div>
297 <h3 id="${i.name}">
298 分片名称 ${i.name} | 分片大小 ${prettyBytes(i.size)}
299 </h3>
300 <p>${chars}</p>
301 </div>`;
302 });
303 };
304 const BaseMessage = (message) => {
305 return html`
306 <table style="margin:auto">
307 ${Object.entries(message).map((i) => {
308 return html`
309 <tr>
310 <td>${i[0].en}</td>
311 <td>${i[1].en}</td>
312 </tr>
313 `;
314 })}
315 </table>
316 `;
317 };
318 const App = () => {
319 const [data] = createResource(() =>
320 fetch('./reporter.json')
321 .then((res) => res.json())
322 .then((res) => {
323 res.message =
324 res.message.windows || res.message.macintosh;
325 return res;
326 }),
327 );
328 createEffect(() => {
329 if (data()) {
330 console.log(data().message);
331 document.body.style.fontFamily = `"${
332 getFontData(data().message).fontFamily ||
333 getFontData(data().message).preferredFamily
334 }"`;
335
336 document.querySelector('title').textContent = getFontData(
337 data().message,
338 ).fontFamily;
339 const link = document.createElement('link');
340 link.rel = 'stylesheet';
341 link.href =
342 './' + (data().config.cssFileName || 'result') + '.css';
343 document.head.appendChild(link);
344 }
345 });
346 const content = () =>
347 html` <div>
348 ${RangeAnalyze(
349 data().data,
350 getFontData(data().message),
351 )}
352 ${DataAnalyze(data().data, getFontData(data().message))}
353 ${TimeAnalyze(
354 data().record,
355 getFontData(data().message),
356 )}
357 ${BaseMessage(getFontData(data().message))}
358 </div>
359 ${CharList(data().data)}`;
360 return html`<div>
361 ${() => (data.loading ? `<div>加载中</div>` : content())}
362 </div>`;
363 };
364
365 import { render } from 'https://esm.sh/solid-js/web';
366 render(App, document.body);
367 </script>
368</html>