kakaotalk-chat-analyzer 0.13.1 → 0.13.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/report-chart-util.d.ts +5 -0
- package/dist/src/report-chart-util.js +17 -0
- package/dist/src/report-chart-util.js.map +1 -0
- package/dist/src/report-charts.d.ts +8 -3
- package/dist/src/report-charts.js +136 -29
- package/dist/src/report-charts.js.map +1 -1
- package/dist/src/report-story.js +5 -2
- package/dist/src/report-story.js.map +1 -1
- package/dist/src/report-styles.d.ts +1 -1
- package/dist/src/report-styles.js +70 -2
- package/dist/src/report-styles.js.map +1 -1
- package/dist/src/report.js +19 -4
- package/dist/src/report.js.map +1 -1
- package/dist/src/version.d.ts +2 -2
- package/dist/src/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DailyCount, ReportTopic } from "./types.js";
|
|
2
|
+
/** 활동일 < 90일·활동 월 ≤ 2 — 월별 period 카드/차트는 기간 비교로 안내 */
|
|
3
|
+
export declare function isShortActivitySpan(daily: DailyCount[]): boolean;
|
|
4
|
+
export declare function topicsForDisplay(topics: ReportTopic[], daily: DailyCount[]): ReportTopic[];
|
|
5
|
+
export declare function topicsThemesOnly(topics: ReportTopic[]): ReportTopic[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** 활동일 < 90일·활동 월 ≤ 2 — 월별 period 카드/차트는 기간 비교로 안내 */
|
|
2
|
+
export function isShortActivitySpan(daily) {
|
|
3
|
+
const active = daily.filter((d) => d.count > 0);
|
|
4
|
+
if (active.length === 0 || active.length >= 90)
|
|
5
|
+
return false;
|
|
6
|
+
const months = new Set(active.map((d) => d.date.slice(0, 7)));
|
|
7
|
+
return months.size <= 2;
|
|
8
|
+
}
|
|
9
|
+
export function topicsForDisplay(topics, daily) {
|
|
10
|
+
if (!isShortActivitySpan(daily))
|
|
11
|
+
return topics;
|
|
12
|
+
return topics.filter((t) => t.kind === "theme");
|
|
13
|
+
}
|
|
14
|
+
export function topicsThemesOnly(topics) {
|
|
15
|
+
return topics.filter((t) => t.kind === "theme");
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=report-chart-util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report-chart-util.js","sourceRoot":"","sources":["../../src/report-chart-util.ts"],"names":[],"mappings":"AAEA,sDAAsD;AACtD,MAAM,UAAU,mBAAmB,CAAC,KAAmB;IACrD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAChD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,IAAI,EAAE;QAAE,OAAO,KAAK,CAAC;IAC7D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAqB,EAAE,KAAmB;IACzE,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAC/C,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -37,11 +37,16 @@ export interface ChartPayload {
|
|
|
37
37
|
}[];
|
|
38
38
|
burstDates: string[];
|
|
39
39
|
totalParticipants: number;
|
|
40
|
-
|
|
40
|
+
topicsThemes: {
|
|
41
41
|
title: string;
|
|
42
42
|
terms: string[];
|
|
43
43
|
messagePercent: number;
|
|
44
|
-
|
|
44
|
+
}[];
|
|
45
|
+
topicsPeriods: {
|
|
46
|
+
title: string;
|
|
47
|
+
terms: string[];
|
|
48
|
+
messagePercent: number;
|
|
49
|
+
periodLabel?: string;
|
|
45
50
|
}[];
|
|
46
51
|
interaction: {
|
|
47
52
|
aliases: string[];
|
|
@@ -53,4 +58,4 @@ export declare function serializeChartPayload(data: ReportData): string;
|
|
|
53
58
|
export declare function buildChartPayload(data: ReportData): ChartPayload;
|
|
54
59
|
export declare function serializeExplorerPayload(data: ReportData): string;
|
|
55
60
|
export declare function renderChartDeck(data: ReportData): string;
|
|
56
|
-
export declare const CHARTS_INIT_SCRIPT = "\n (function () {\n function run() {\n var dataEl = document.getElementById(\"kca-chart-data\");\n if (!dataEl) return;\n if (typeof echarts === \"undefined\") return;\n var data;\n try { data = JSON.parse(dataEl.textContent || \"{}\"); } catch (e) { return; }\n\n var dark = document.documentElement.getAttribute(\"data-theme\") === \"dark\" ||\n (!document.documentElement.getAttribute(\"data-theme\") &&\n window.matchMedia && window.matchMedia(\"(prefers-color-scheme: dark)\").matches);\n var text = dark ? \"#e9eef5\" : \"#141a1f\";\n var muted = dark ? \"#8b98a8\" : \"#5c6670\";\n var accent = dark ? \"#3ee8c5\" : \"#0f6b5c\";\n var accent2 = dark ? \"#818cf8\" : \"#4f46e5\";\n\n function baseOpt() {\n return {\n textStyle: { color: text, fontFamily: \"Pretendard, Apple SD Gothic Neo, sans-serif\" },\n tooltip: { trigger: \"axis\", backgroundColor: dark ? \"#1c2128\" : \"#fff\", borderColor: \"transparent\" },\n };\n }\n\n var charts = [];\n function resizeAll() {\n charts.forEach(function (c) {\n try { c.resize(); } catch (e) {}\n });\n }\n function layout(el) {\n var w = (el && el.clientWidth) || 400;\n if (w < 380) {\n return { w: w, left: 28, right: 8, top: 14, bottom: 44, fs: 9, rot: 40, leftCat: 56, bottomRot: 42 };\n }\n if (w < 640) {\n return { w: w, left: 40, right: 10, top: 18, bottom: 34, fs: 10, rot: 26, leftCat: 72, bottomRot: 32 };\n }\n return { w: w, left: 48, right: 14, top: 22, bottom: 28, fs: 11, rot: 0, leftCat: 96, bottomRot: 28 };\n }\n function init(id, opt) {\n var el = document.getElementById(id);\n if (!el) return null;\n try {\n var chart = echarts.init(el, null, { renderer: \"canvas\" });\n chart.setOption(opt);\n charts.push(chart);\n if (typeof ResizeObserver !== \"undefined\") {\n var ro = new ResizeObserver(function () {\n requestAnimationFrame(function () {\n try { chart.resize(); } catch (e) {}\n });\n });\n ro.observe(el);\n }\n return chart;\n } catch (err) {\n console.error(\"[kca-chart]\", id, err);\n el.setAttribute(\"data-chart-failed\", \"1\");\n el.innerHTML = '<p style=\"margin:0;padding:12px;font-size:12px;color:var(--muted);text-align:center\">\uCC28\uD2B8\uB97C \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC5B4\uC694. \uC0C8\uB85C\uACE0\uCE68\uD558\uAC70\uB098 \uB124\uD2B8\uC6CC\uD06C(CDN)\uB97C \uD655\uC778\uD574 \uC8FC\uC138\uC694.</p>';\n return null;\n }\n }\n var mqWide = window.matchMedia && window.matchMedia(\"(min-width: 900px)\");\n if (mqWide && mqWide.addEventListener) {\n mqWide.addEventListener(\"change\", function () { setTimeout(resizeAll, 80); });\n } else if (mqWide && mqWide.addListener) {\n mqWide.addListener(function () { setTimeout(resizeAll, 80); });\n }\n var themeObs = new MutationObserver(function () { setTimeout(resizeAll, 60); });\n themeObs.observe(document.documentElement, { attributes: true, attributeFilter: [\"data-theme\"] });\n\n function hourBarColor(h) {\n if (h <= 5) return dark ? \"#6366f1\" : \"#4f46e5\";\n if (h <= 11) return dark ? \"#3ee8c5\" : \"#0f6b5c\";\n if (h <= 17) return dark ? \"#fbbf24\" : \"#d97706\";\n return dark ? \"#3b82f6\" : \"#1d4ed8\";\n }\n if (data.hourly && document.getElementById(\"chart-hours\")) {\n var hoursEl = document.getElementById(\"chart-hours\");\n var hg = layout(hoursEl);\n init(\"chart-hours\", Object.assign(baseOpt(), {\n grid: { left: hg.left, right: hg.right, top: hg.top, bottom: hg.bottom },\n xAxis: { type: \"category\", data: data.hourly.map(function (_, h) { return h + \"\uC2DC\"; }), axisLabel: { color: muted, fontSize: hg.fs, rotate: hg.rot } },\n yAxis: { type: \"value\", axisLabel: { color: muted }, splitLine: { lineStyle: { color: dark ? \"rgba(255,255,255,0.06)\" : \"rgba(0,0,0,0.06)\" } } },\n series: [{\n type: \"bar\",\n data: data.hourly.map(function (v, h) {\n return { value: v, itemStyle: { color: hourBarColor(h), borderRadius: [4, 4, 0, 0] } };\n }),\n markArea: {\n silent: true,\n itemStyle: { color: dark ? \"rgba(99,102,241,0.12)\" : \"rgba(79,70,229,0.08)\" },\n data: [[{ xAxis: \"0\uC2DC\" }, { xAxis: \"5\uC2DC\" }], [{ xAxis: \"22\uC2DC\" }, { xAxis: \"23\uC2DC\" }]],\n },\n }],\n }));\n }\n\n if (data.weekdays && document.getElementById(\"chart-weekday\")) {\n var wdEl = document.getElementById(\"chart-weekday\");\n var wg = layout(wdEl);\n init(\"chart-weekday\", Object.assign(baseOpt(), {\n grid: { left: wg.leftCat, right: wg.right, top: wg.top, bottom: wg.bottom },\n xAxis: { type: \"value\", axisLabel: { color: muted, fontSize: wg.fs } },\n yAxis: { type: \"category\", data: data.weekdays.map(function (w) { return w.label; }), axisLabel: { color: muted, fontSize: wg.fs } },\n series: [{ type: \"bar\", data: data.weekdays.map(function (w) { return w.count; }), itemStyle: { color: accent, borderRadius: [0, 6, 6, 0] } }],\n }));\n }\n\n if (data.monthly && document.getElementById(\"chart-monthly\")) {\n var moEl = document.getElementById(\"chart-monthly\");\n var mg = layout(moEl);\n init(\"chart-monthly\", Object.assign(baseOpt(), {\n grid: { left: mg.left, right: mg.right, top: mg.top, bottom: mg.bottom },\n xAxis: { type: \"category\", data: data.monthly.map(function (m) { return m.label; }), axisLabel: { color: muted, fontSize: mg.fs, rotate: mg.bottomRot } },\n yAxis: { type: \"value\", axisLabel: { color: muted, fontSize: mg.fs }, splitLine: { lineStyle: { color: dark ? \"rgba(255,255,255,0.06)\" : \"rgba(0,0,0,0.06)\" } } },\n series: [{ type: \"line\", smooth: true, data: data.monthly.map(function (m) { return m.count; }), areaStyle: { opacity: 0.12 }, lineStyle: { width: 2, color: accent2 }, itemStyle: { color: accent2 } }],\n }));\n }\n\n if (data.daily && document.getElementById(\"chart-daily-heat\")) {\n var heatEl = document.getElementById(\"chart-daily-heat\");\n var dg = layout(heatEl);\n var heatMax = Math.max.apply(null, data.daily.map(function (d) { return d.count; }).concat([1]));\n var heat = data.daily.map(function (d) { return [d.date, d.count]; });\n var burstSet = {};\n (data.burstDates || []).forEach(function (d) { burstSet[d] = true; });\n var daySpan = data.daily.length;\n var useBarFallback = daySpan > 0 && daySpan < 90;\n if (useBarFallback) {\n var labels = data.daily.map(function (d) {\n var p = d.date.split(\"-\");\n return p.length === 3 ? Number(p[1]) + \"/\" + Number(p[2]) : d.date;\n });\n init(\"chart-daily-heat\", Object.assign(baseOpt(), {\n grid: { left: dg.left, right: dg.right, top: dg.top, bottom: Math.max(dg.bottom, 52), containLabel: true },\n tooltip: { trigger: \"axis\" },\n xAxis: { type: \"category\", data: labels, axisLabel: { color: muted, fontSize: dg.fs, rotate: labels.length > 20 ? 40 : 0, interval: labels.length > 40 ? Math.floor(labels.length / 20) : 0 } },\n yAxis: { type: \"value\", axisLabel: { color: muted }, splitLine: { lineStyle: { color: dark ? \"rgba(255,255,255,0.06)\" : \"rgba(0,0,0,0.06)\" } } },\n visualMap: { show: false, min: 0, max: heatMax, inRange: { color: dark ? [\"#161b22\", \"#0e4429\", \"#006d32\", \"#26a641\", \"#39d353\"] : [\"#ebedf0\", \"#9be9a8\", \"#40c463\", \"#30a14e\", \"#216e39\"] } },\n series: [{\n type: \"bar\",\n data: data.daily.map(function (d) { return d.count; }),\n itemStyle: { borderRadius: [3, 3, 0, 0], borderWidth: 0 },\n emphasis: { itemStyle: { shadowBlur: 10, shadowColor: dark ? \"rgba(62,232,197,0.45)\" : \"rgba(15,107,92,0.35)\" } },\n }],\n }));\n } else {\n var cellH = dg.w < 380 ? 12 : dg.w < 640 ? 14 : 16;\n var cellW = dg.w < 380 ? 12 : 14;\n init(\"chart-daily-heat\", Object.assign(baseOpt(), {\n tooltip: { position: \"top\" },\n visualMap: { min: 0, max: heatMax, calculable: true, orient: \"horizontal\", left: \"center\", bottom: 0, textStyle: { color: muted, fontSize: dg.fs }, itemWidth: dg.w < 380 ? 10 : 14, itemHeight: dg.w < 380 ? 60 : 80, inRange: { color: dark ? [\"#161b22\", \"#0e4429\", \"#006d32\", \"#26a641\", \"#39d353\"] : [\"#ebedf0\", \"#9be9a8\", \"#40c463\", \"#30a14e\", \"#216e39\"] } },\n calendar: { top: dg.w < 380 ? 28 : 36, left: dg.left, right: dg.right, cellSize: [cellW, cellH], range: data.daily.length ? [data.daily[0].date, data.daily[data.daily.length - 1].date] : undefined, itemStyle: { borderWidth: 0, borderColor: \"transparent\" }, dayLabel: { color: muted, fontSize: dg.fs }, monthLabel: { color: muted, fontSize: dg.fs } },\n series: [{ type: \"heatmap\", coordinateSystem: \"calendar\", data: heat, emphasis: { itemStyle: { shadowBlur: 8, shadowColor: dark ? \"rgba(62,232,197,0.5)\" : \"rgba(33,110,57,0.45)\" } } }],\n }));\n }\n }\n\n if (data.keywords && document.getElementById(\"chart-kw-bar\")) {\n var kwEl = document.getElementById(\"chart-kw-bar\");\n var kg = layout(kwEl);\n var topBar = data.keywords.slice(0, kg.w < 380 ? 24 : 80);\n var maxLabelLen = 0;\n topBar.forEach(function (k) { if (k.label.length > maxLabelLen) maxLabelLen = k.label.length; });\n var kwLeft = Math.max(kg.leftCat, Math.min(kg.w * 0.42, 24 + maxLabelLen * (kg.fs + 1)));\n init(\"chart-kw-bar\", Object.assign(baseOpt(), {\n grid: { left: kwLeft, right: kg.right, top: kg.top, bottom: kg.bottom, containLabel: true },\n xAxis: { type: \"value\", axisLabel: { color: muted, fontSize: kg.fs } },\n yAxis: { type: \"category\", data: topBar.map(function (k) { return k.label; }).reverse(), axisLabel: { color: text, fontSize: kg.fs, width: kwLeft - 12, overflow: \"truncate\" } },\n series: [{ type: \"bar\", data: topBar.map(function (k) { return k.count; }).reverse(), itemStyle: { color: accent2, borderRadius: [0, 4, 4, 0] }, label: { show: true, position: \"right\", color: muted, fontSize: kg.fs, formatter: function (p) { return p.value; } } }],\n }));\n }\n\n if (data.keywords && document.getElementById(\"chart-kw-cloud\")) {\n var cloudEl = document.getElementById(\"chart-kw-cloud\");\n var cg = layout(cloudEl);\n var cloud = data.keywords.slice(0, 100).map(function (k) {\n return { name: k.label, value: k.count };\n });\n var sizeLo = cg.w < 380 ? 10 : 12;\n var sizeHi = cg.w < 380 ? 34 : cg.w < 640 ? 46 : 56;\n init(\"chart-kw-cloud\", {\n textStyle: baseOpt().textStyle,\n tooltip: { show: true },\n series: [{\n type: \"wordCloud\",\n shape: \"circle\",\n gridSize: cg.w < 380 ? 8 : 6,\n sizeRange: [sizeLo, sizeHi],\n rotationRange: [-45, 45],\n textStyle: {\n fontFamily: \"Pretendard, Apple SD Gothic Neo, sans-serif\",\n color: function () {\n var palette = dark ? [\"#3ee8c5\", \"#818cf8\", \"#fbbf24\", \"#fb923c\", \"#f472b6\"] : [\"#0f6b5c\", \"#4f46e5\", \"#b8860b\", \"#c45c2a\", \"#be185d\"];\n return palette[Math.floor(Math.random() * palette.length)];\n },\n },\n data: cloud,\n }],\n });\n }\n\n if (data.participants && document.getElementById(\"chart-participants\")) {\n var pieEl = document.getElementById(\"chart-participants\");\n var pg = layout(pieEl);\n var topN = 10;\n var ranked = data.participants.slice().sort(function (a, b) { return b.messages - a.messages; });\n var topSlice = ranked.slice(0, topN);\n var otherSum = ranked.slice(topN).reduce(function (s, x) { return s + x.messages; }, 0);\n var pieData = topSlice.map(function (x) { return { name: x.alias, value: x.messages }; });\n if (otherSum > 0) pieData.push({ name: \"\uAE30\uD0C0\", value: otherSum });\n var pieR = pg.w < 380 ? [\"40%\", \"68%\"] : [\"38%\", \"66%\"];\n init(\"chart-participants\", Object.assign(baseOpt(), {\n tooltip: { trigger: \"item\", formatter: \"{b}: {c} ({d}%)\" },\n legend: { show: false },\n series: [{\n type: \"pie\",\n radius: pieR,\n center: [\"50%\", \"48%\"],\n avoidLabelOverlap: true,\n minShowLabelAngle: 10,\n data: pieData,\n label: {\n show: true,\n position: \"outside\",\n color: text,\n fontSize: pg.fs,\n formatter: function (params) {\n var n = params.name || \"\";\n return n.length > 8 ? n.slice(0, 7) + \"\u2026\" : n;\n },\n },\n labelLine: { show: true, length: 8, length2: 6, lineStyle: { color: muted } },\n itemStyle: { borderRadius: 4, borderWidth: 0 },\n }],\n }));\n }\n\n if (data.topics && data.topics.length && document.getElementById(\"chart-topics\")) {\n var topEl = document.getElementById(\"chart-topics\");\n var tg = layout(topEl);\n var topics = data.topics.slice(0, 8);\n init(\"chart-topics\", Object.assign(baseOpt(), {\n grid: { left: Math.max(tg.leftCat, tg.w < 380 ? 72 : 96), right: tg.right, top: tg.top, bottom: tg.bottom },\n xAxis: { type: \"value\", axisLabel: { color: muted, fontSize: tg.fs, formatter: \"{value}%\" } },\n yAxis: {\n type: \"category\",\n data: topics.map(function (t) { return t.title; }).reverse(),\n axisLabel: { color: text, fontSize: tg.fs },\n },\n series: [{\n type: \"bar\",\n data: topics.map(function (t) { return t.messagePercent; }).reverse(),\n itemStyle: {\n borderRadius: [0, 6, 6, 0],\n color: function (p) { return p.dataIndex % 2 === 0 ? accent : accent2; },\n },\n }],\n }));\n }\n\n if (data.domains && document.getElementById(\"chart-domains\")) {\n init(\"chart-domains\", Object.assign(baseOpt(), {\n tooltip: { trigger: \"item\" },\n series: [{\n type: \"treemap\",\n data: data.domains.map(function (d) { return { name: d.label, value: d.count }; }),\n label: { color: text, fontSize: 11 },\n itemStyle: { borderColor: dark ? \"#0d1117\" : \"#fff\", gapWidth: 2 },\n }],\n }));\n }\n\n if (data.interaction && data.interaction.aliases.length && document.getElementById(\"chart-dyad\")) {\n var ix = data.interaction;\n var heat = [];\n var maxV = 1;\n for (var ri = 0; ri < ix.matrix.length; ri += 1) {\n for (var ci = 0; ci < ix.matrix[ri].length; ci += 1) {\n var v = ix.matrix[ri][ci];\n if (v > maxV) maxV = v;\n if (v > 0) heat.push([ci, ri, v]);\n }\n }\n var dyEl = document.getElementById(\"chart-dyad\");\n var dg = layout(dyEl);\n init(\"chart-dyad\", Object.assign(baseOpt(), {\n tooltip: { position: \"top\" },\n grid: { left: Math.max(dg.leftCat, 72), right: dg.right, top: dg.top, bottom: 56 },\n xAxis: { type: \"category\", data: ix.aliases, axisLabel: { color: muted, fontSize: dg.fs, rotate: 32 }, splitArea: { show: true } },\n yAxis: { type: \"category\", data: ix.aliases, axisLabel: { color: muted, fontSize: dg.fs }, splitArea: { show: true } },\n visualMap: { min: 0, max: maxV, calculable: true, orient: \"horizontal\", left: \"center\", bottom: 4, inRange: { color: [dark ? \"#0d1117\" : \"#f0f4f8\", accent, accent2] } },\n series: [{ type: \"heatmap\", data: heat, emphasis: { itemStyle: { shadowBlur: 12, shadowColor: \"rgba(0,0,0,0.35)\" } } }],\n }));\n }\n requestAnimationFrame(resizeAll);\n setTimeout(resizeAll, 150);\n window.addEventListener(\"resize\", resizeAll);\n window.addEventListener(\"load\", resizeAll);\n }\n function whenVisible() {\n var anchor = document.getElementById(\"s-viz\") || document.querySelector(\".chart-box\");\n if (!anchor || typeof IntersectionObserver === \"undefined\") {\n run();\n return;\n }\n var started = false;\n var io = new IntersectionObserver(function (entries) {\n if (started) return;\n if (entries.some(function (e) { return e.isIntersecting; })) {\n started = true;\n io.disconnect();\n run();\n }\n }, { rootMargin: \"480px 0px\", threshold: 0.01 });\n io.observe(anchor);\n setTimeout(function () {\n if (started) return;\n var r = anchor.getBoundingClientRect();\n if (r.top < window.innerHeight + 320) {\n started = true;\n io.disconnect();\n run();\n }\n }, 200);\n }\n function bootCharts() {\n if (typeof echarts === \"undefined\") return false;\n whenVisible();\n return true;\n }\n if (!bootCharts()) {\n window.addEventListener(\"load\", function () {\n var tries = 0;\n (function wait() {\n if (bootCharts()) return;\n if (++tries > 120) {\n document.querySelectorAll(\".chart-box\").forEach(function (el) {\n if (!el.querySelector(\"canvas\")) {\n el.innerHTML = '<p style=\"margin:0;padding:12px;font-size:12px;color:var(--muted);text-align:center\">ECharts CDN\uC744 \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.</p>';\n }\n });\n return;\n }\n setTimeout(wait, 50);\n })();\n });\n }\n })();\n";
|
|
61
|
+
export declare const CHARTS_INIT_SCRIPT = "\n (function () {\n function run() {\n var dataEl = document.getElementById(\"kca-chart-data\");\n if (!dataEl) return;\n if (typeof echarts === \"undefined\") return;\n var data;\n try { data = JSON.parse(dataEl.textContent || \"{}\"); } catch (e) { return; }\n\n var dark = document.documentElement.getAttribute(\"data-theme\") === \"dark\" ||\n (!document.documentElement.getAttribute(\"data-theme\") &&\n window.matchMedia && window.matchMedia(\"(prefers-color-scheme: dark)\").matches);\n var text = dark ? \"#e9eef5\" : \"#141a1f\";\n var muted = dark ? \"#8b98a8\" : \"#5c6670\";\n var accent = dark ? \"#3ee8c5\" : \"#0f6b5c\";\n var accent2 = dark ? \"#818cf8\" : \"#4f46e5\";\n function cssVar(name, fallback) {\n try {\n var v = getComputedStyle(document.body).getPropertyValue(name).trim();\n return v || fallback;\n } catch (e) { return fallback; }\n }\n var heatLo = cssVar(\"--chart-heat-lo\", dark ? \"#1a2744\" : \"#d4e4f4\");\n var heatHi = cssVar(\"--chart-heat-hi\", dark ? \"#5ee8ff\" : \"#1e4fd6\");\n var wdColors = [\n cssVar(\"--chart-wd-0\", dark ? \"#818cf8\" : \"#4f46e5\"),\n cssVar(\"--chart-wd-1\", dark ? \"#3ee8c5\" : \"#0f6b5c\"),\n cssVar(\"--chart-wd-2\", dark ? \"#34d399\" : \"#059669\"),\n cssVar(\"--chart-wd-3\", dark ? \"#2dd4bf\" : \"#0d9488\"),\n cssVar(\"--chart-wd-4\", dark ? \"#38bdf8\" : \"#0284c7\"),\n cssVar(\"--chart-wd-5\", dark ? \"#fbbf24\" : \"#d97706\"),\n cssVar(\"--chart-wd-6\", dark ? \"#fb923c\" : \"#ea580c\"),\n ];\n\n function baseOpt() {\n return {\n textStyle: { color: text, fontFamily: \"Pretendard, Apple SD Gothic Neo, sans-serif\" },\n tooltip: { trigger: \"axis\", backgroundColor: dark ? \"#1c2128\" : \"#fff\", borderColor: \"transparent\" },\n };\n }\n\n var charts = [];\n function resizeAll() {\n charts.forEach(function (c) {\n try { c.resize(); } catch (e) {}\n });\n }\n function layout(el) {\n var w = (el && el.clientWidth) || 400;\n if (w < 380) {\n return { w: w, left: 28, right: 8, top: 14, bottom: 44, fs: 9, rot: 40, leftCat: 56, bottomRot: 42 };\n }\n if (w < 640) {\n return { w: w, left: 40, right: 10, top: 18, bottom: 34, fs: 10, rot: 26, leftCat: 72, bottomRot: 32 };\n }\n return { w: w, left: 48, right: 14, top: 22, bottom: 28, fs: 11, rot: 0, leftCat: 96, bottomRot: 28 };\n }\n function init(id, opt) {\n var el = document.getElementById(id);\n if (!el) return null;\n try {\n var chart = echarts.init(el, null, { renderer: \"canvas\" });\n chart.setOption(opt);\n charts.push(chart);\n if (typeof ResizeObserver !== \"undefined\") {\n var ro = new ResizeObserver(function () {\n requestAnimationFrame(function () {\n try { chart.resize(); } catch (e) {}\n });\n });\n ro.observe(el);\n }\n return chart;\n } catch (err) {\n console.error(\"[kca-chart]\", id, err);\n el.setAttribute(\"data-chart-failed\", \"1\");\n el.innerHTML = '<p style=\"margin:0;padding:12px;font-size:12px;color:var(--muted);text-align:center\">\uCC28\uD2B8\uB97C \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC5B4\uC694. \uC0C8\uB85C\uACE0\uCE68\uD558\uAC70\uB098 \uB124\uD2B8\uC6CC\uD06C(CDN)\uB97C \uD655\uC778\uD574 \uC8FC\uC138\uC694.</p>';\n return null;\n }\n }\n var mqWide = window.matchMedia && window.matchMedia(\"(min-width: 900px)\");\n if (mqWide && mqWide.addEventListener) {\n mqWide.addEventListener(\"change\", function () { setTimeout(resizeAll, 80); });\n } else if (mqWide && mqWide.addListener) {\n mqWide.addListener(function () { setTimeout(resizeAll, 80); });\n }\n var themeObs = new MutationObserver(function () { setTimeout(resizeAll, 60); });\n themeObs.observe(document.documentElement, { attributes: true, attributeFilter: [\"data-theme\"] });\n\n function hourBarColor(h) {\n if (h <= 5) return dark ? \"#6366f1\" : \"#4f46e5\";\n if (h <= 11) return dark ? \"#3ee8c5\" : \"#0f6b5c\";\n if (h <= 17) return dark ? \"#fbbf24\" : \"#d97706\";\n return dark ? \"#3b82f6\" : \"#1d4ed8\";\n }\n if (data.hourly && document.getElementById(\"chart-hours\")) {\n var hoursEl = document.getElementById(\"chart-hours\");\n var hg = layout(hoursEl);\n init(\"chart-hours\", Object.assign(baseOpt(), {\n grid: { left: hg.left, right: hg.right, top: hg.top, bottom: hg.bottom },\n xAxis: { type: \"category\", data: data.hourly.map(function (_, h) { return h + \"\uC2DC\"; }), axisLabel: { color: muted, fontSize: hg.fs, rotate: hg.rot } },\n yAxis: { type: \"value\", axisLabel: { color: muted }, splitLine: { lineStyle: { color: dark ? \"rgba(255,255,255,0.06)\" : \"rgba(0,0,0,0.06)\" } } },\n series: [{\n type: \"bar\",\n data: data.hourly.map(function (v, h) {\n return { value: v, itemStyle: { color: hourBarColor(h), borderRadius: [4, 4, 0, 0] } };\n }),\n markArea: {\n silent: true,\n itemStyle: { color: dark ? \"rgba(99,102,241,0.12)\" : \"rgba(79,70,229,0.08)\" },\n data: [[{ xAxis: \"0\uC2DC\" }, { xAxis: \"5\uC2DC\" }], [{ xAxis: \"22\uC2DC\" }, { xAxis: \"23\uC2DC\" }]],\n },\n }],\n }));\n }\n\n if (data.weekdays && document.getElementById(\"chart-weekday\")) {\n var wdEl = document.getElementById(\"chart-weekday\");\n var wg = layout(wdEl);\n var wdCounts = data.weekdays.map(function (w) { return w.count; });\n var wdMax = Math.max.apply(null, wdCounts.concat([1]));\n init(\"chart-weekday\", Object.assign(baseOpt(), {\n grid: { left: wg.leftCat, right: wg.right, top: wg.top, bottom: wg.bottom },\n xAxis: { type: \"value\", axisLabel: { color: muted, fontSize: wg.fs } },\n yAxis: { type: \"category\", data: data.weekdays.map(function (w) { return w.label; }), axisLabel: { color: muted, fontSize: wg.fs } },\n series: [{\n type: \"bar\",\n data: data.weekdays.map(function (w, i) {\n var c = wdColors[i % 7];\n return {\n value: w.count,\n itemStyle: {\n color: c,\n borderRadius: [0, 6, 6, 0],\n shadowBlur: w.count >= wdMax ? 10 : 0,\n shadowColor: w.count >= wdMax ? (dark ? \"rgba(62,232,197,0.45)\" : \"rgba(15,107,92,0.35)\") : \"transparent\",\n },\n };\n }),\n }],\n }));\n }\n\n if (data.monthly && document.getElementById(\"chart-monthly\")) {\n var moEl = document.getElementById(\"chart-monthly\");\n var mg = layout(moEl);\n init(\"chart-monthly\", Object.assign(baseOpt(), {\n grid: { left: mg.left, right: mg.right, top: mg.top, bottom: mg.bottom },\n xAxis: { type: \"category\", data: data.monthly.map(function (m) { return m.label; }), axisLabel: { color: muted, fontSize: mg.fs, rotate: mg.bottomRot } },\n yAxis: { type: \"value\", axisLabel: { color: muted, fontSize: mg.fs }, splitLine: { lineStyle: { color: dark ? \"rgba(255,255,255,0.06)\" : \"rgba(0,0,0,0.06)\" } } },\n series: [{ type: \"line\", smooth: true, data: data.monthly.map(function (m) { return m.count; }), areaStyle: { opacity: 0.12 }, lineStyle: { width: 2, color: accent2 }, itemStyle: { color: accent2 } }],\n }));\n }\n\n if (data.daily && document.getElementById(\"chart-daily-heat\")) {\n var heatEl = document.getElementById(\"chart-daily-heat\");\n var dg = layout(heatEl);\n var heatMax = Math.max.apply(null, data.daily.map(function (d) { return d.count; }).concat([1]));\n var heat = data.daily.map(function (d) { return [d.date, d.count]; });\n var burstSet = {};\n (data.burstDates || []).forEach(function (d) { burstSet[d] = true; });\n var daySpan = data.daily.length;\n var useBarFallback = daySpan > 0 && daySpan < 90;\n if (useBarFallback) {\n var labels = data.daily.map(function (d) {\n var p = d.date.split(\"-\");\n return p.length === 3 ? Number(p[1]) + \"/\" + Number(p[2]) : d.date;\n });\n init(\"chart-daily-heat\", Object.assign(baseOpt(), {\n grid: { left: dg.left, right: dg.right, top: dg.top, bottom: Math.max(dg.bottom, 52), containLabel: true },\n tooltip: { trigger: \"axis\" },\n xAxis: { type: \"category\", data: labels, axisLabel: { color: muted, fontSize: dg.fs, rotate: labels.length > 20 ? 40 : 0, interval: labels.length > 40 ? Math.floor(labels.length / 20) : 0 } },\n yAxis: { type: \"value\", axisLabel: { color: muted }, splitLine: { lineStyle: { color: dark ? \"rgba(255,255,255,0.06)\" : \"rgba(0,0,0,0.06)\" } } },\n visualMap: { show: false, min: 0, max: heatMax, inRange: { color: dark ? [\"#161b22\", \"#0e4429\", \"#006d32\", \"#26a641\", \"#39d353\"] : [\"#ebedf0\", \"#9be9a8\", \"#40c463\", \"#30a14e\", \"#216e39\"] } },\n series: [{\n type: \"bar\",\n data: data.daily.map(function (d) { return d.count; }),\n itemStyle: { borderRadius: [3, 3, 0, 0], borderWidth: 0 },\n emphasis: { itemStyle: { shadowBlur: 10, shadowColor: dark ? \"rgba(62,232,197,0.45)\" : \"rgba(15,107,92,0.35)\" } },\n }],\n }));\n } else {\n var cellH = dg.w < 380 ? 12 : dg.w < 640 ? 14 : 16;\n var cellW = dg.w < 380 ? 12 : 14;\n init(\"chart-daily-heat\", Object.assign(baseOpt(), {\n tooltip: { position: \"top\" },\n visualMap: { min: 0, max: heatMax, calculable: true, orient: \"horizontal\", left: \"center\", bottom: 0, textStyle: { color: muted, fontSize: dg.fs }, itemWidth: dg.w < 380 ? 10 : 14, itemHeight: dg.w < 380 ? 60 : 80, inRange: { color: dark ? [\"#161b22\", \"#0e4429\", \"#006d32\", \"#26a641\", \"#39d353\"] : [\"#ebedf0\", \"#9be9a8\", \"#40c463\", \"#30a14e\", \"#216e39\"] } },\n calendar: { top: dg.w < 380 ? 28 : 36, left: dg.left, right: dg.right, cellSize: [cellW, cellH], range: data.daily.length ? [data.daily[0].date, data.daily[data.daily.length - 1].date] : undefined, itemStyle: { borderWidth: 0, borderColor: \"transparent\" }, dayLabel: { color: muted, fontSize: dg.fs }, monthLabel: { color: muted, fontSize: dg.fs } },\n series: [{ type: \"heatmap\", coordinateSystem: \"calendar\", data: heat, emphasis: { itemStyle: { shadowBlur: 8, shadowColor: dark ? \"rgba(62,232,197,0.5)\" : \"rgba(33,110,57,0.45)\" } } }],\n }));\n }\n }\n\n if (data.keywords && document.getElementById(\"chart-kw-bar\")) {\n var kwEl = document.getElementById(\"chart-kw-bar\");\n var kg = layout(kwEl);\n var kwLimit = kg.w < 380 ? 20 : 30;\n var topBar = data.keywords.slice(0, kwLimit);\n var nKw = topBar.length;\n var padY = Math.min(48, 8 + nKw * 0.4);\n function kwBarColor(rankFromTop) {\n if (rankFromTop === 0) return dark ? \"#a78bfa\" : \"#6366f1\";\n if (rankFromTop === 1) return dark ? \"#818cf8\" : \"#4f46e5\";\n if (rankFromTop === 2) return dark ? \"#5b9bd5\" : \"#3b82f6\";\n return dark ? \"rgba(129,140,248,0.55)\" : \"rgba(79,70,229,0.45)\";\n }\n var kwSeries = topBar.map(function (k, i) {\n return {\n value: k.count,\n name: k.label,\n itemStyle: { color: kwBarColor(i), borderRadius: [0, 4, 4, 0] },\n };\n }).reverse();\n init(\"chart-kw-bar\", Object.assign(baseOpt(), {\n grid: { left: 8, right: kg.right, top: padY, bottom: padY, containLabel: false },\n xAxis: { type: \"value\", axisLabel: { color: muted, fontSize: kg.fs } },\n yAxis: {\n type: \"category\",\n data: topBar.map(function (k) { return k.label; }).reverse(),\n axisLabel: { show: false },\n axisTick: { show: false },\n axisLine: { show: false },\n },\n series: [{\n type: \"bar\",\n data: kwSeries,\n label: [\n {\n show: true,\n position: \"insideLeft\",\n color: text,\n fontSize: kg.fs,\n fontWeight: 600,\n formatter: \"{b}\",\n padding: [0, 0, 0, 6],\n },\n {\n show: true,\n position: \"right\",\n color: muted,\n fontSize: kg.fs,\n formatter: \"{c}\",\n },\n ],\n }],\n }));\n }\n\n if (data.keywords && document.getElementById(\"chart-kw-cloud\")) {\n var cloudEl = document.getElementById(\"chart-kw-cloud\");\n var cg = layout(cloudEl);\n var cloud = data.keywords.slice(0, 100).map(function (k) {\n return { name: k.label, value: k.count };\n });\n var sizeLo = cg.w < 380 ? 10 : 12;\n var sizeHi = cg.w < 380 ? 34 : cg.w < 640 ? 46 : 56;\n init(\"chart-kw-cloud\", {\n textStyle: baseOpt().textStyle,\n tooltip: { show: true },\n series: [{\n type: \"wordCloud\",\n shape: \"circle\",\n gridSize: cg.w < 380 ? 8 : 6,\n sizeRange: [sizeLo, sizeHi],\n rotationRange: [-45, 45],\n textStyle: {\n fontFamily: \"Pretendard, Apple SD Gothic Neo, sans-serif\",\n color: function () {\n var palette = dark ? [\"#3ee8c5\", \"#818cf8\", \"#fbbf24\", \"#fb923c\", \"#f472b6\"] : [\"#0f6b5c\", \"#4f46e5\", \"#b8860b\", \"#c45c2a\", \"#be185d\"];\n return palette[Math.floor(Math.random() * palette.length)];\n },\n },\n data: cloud,\n }],\n });\n }\n\n if (data.participants && document.getElementById(\"chart-participants\")) {\n var pieEl = document.getElementById(\"chart-participants\");\n var pg = layout(pieEl);\n var topN = 10;\n var ranked = data.participants.slice().sort(function (a, b) { return b.messages - a.messages; });\n var topSlice = ranked.slice(0, topN);\n var otherSum = ranked.slice(topN).reduce(function (s, x) { return s + x.messages; }, 0);\n var pieData = topSlice.map(function (x) { return { name: x.alias, value: x.messages }; });\n if (otherSum > 0) pieData.push({ name: \"\uAE30\uD0C0\", value: otherSum });\n var pieR = pg.w < 380 ? [\"40%\", \"68%\"] : [\"38%\", \"66%\"];\n init(\"chart-participants\", Object.assign(baseOpt(), {\n tooltip: { trigger: \"item\", formatter: \"{b}: {c} ({d}%)\" },\n legend: { show: false },\n series: [{\n type: \"pie\",\n radius: pieR,\n center: [\"50%\", \"48%\"],\n avoidLabelOverlap: true,\n minShowLabelAngle: 10,\n data: pieData,\n label: {\n show: true,\n position: \"outside\",\n color: text,\n fontSize: pg.fs,\n formatter: function (params) {\n var n = params.name || \"\";\n return n.length > 8 ? n.slice(0, 7) + \"\u2026\" : n;\n },\n },\n labelLine: { show: true, length: 8, length2: 6, lineStyle: { color: muted } },\n itemStyle: { borderRadius: 4, borderWidth: 0 },\n }],\n }));\n }\n\n if (data.topicsThemes && data.topicsThemes.length && document.getElementById(\"chart-topics\")) {\n var topEl = document.getElementById(\"chart-topics\");\n var tg = layout(topEl);\n var topics = data.topicsThemes.slice(0, 8);\n init(\"chart-topics\", Object.assign(baseOpt(), {\n grid: { left: Math.max(tg.leftCat, tg.w < 380 ? 72 : 96), right: tg.right, top: tg.top, bottom: tg.bottom },\n xAxis: { type: \"value\", axisLabel: { color: muted, fontSize: tg.fs, formatter: \"{value}%\" } },\n yAxis: {\n type: \"category\",\n data: topics.map(function (t) { return t.title; }).reverse(),\n axisLabel: { color: text, fontSize: tg.fs },\n },\n series: [{\n type: \"bar\",\n data: topics.map(function (t) { return t.messagePercent; }).reverse(),\n itemStyle: {\n borderRadius: [0, 6, 6, 0],\n color: function (p) { return p.dataIndex % 2 === 0 ? accent : accent2; },\n },\n }],\n }));\n }\n\n if (data.domains && document.getElementById(\"chart-domains\")) {\n init(\"chart-domains\", Object.assign(baseOpt(), {\n tooltip: { trigger: \"item\" },\n series: [{\n type: \"treemap\",\n data: data.domains.map(function (d) { return { name: d.label, value: d.count }; }),\n label: { color: text, fontSize: 11 },\n itemStyle: { borderColor: dark ? \"#0d1117\" : \"#fff\", gapWidth: 2 },\n }],\n }));\n }\n\n if (data.interaction && data.interaction.aliases.length && document.getElementById(\"chart-dyad\")) {\n var ix = data.interaction;\n var heat = [];\n var maxV = 1;\n for (var ri = 0; ri < ix.matrix.length; ri += 1) {\n for (var ci = 0; ci < ix.matrix[ri].length; ci += 1) {\n var v = ix.matrix[ri][ci];\n if (v > maxV) maxV = v;\n if (v > 0) heat.push({ value: [ci, ri, v], label: { show: v >= maxV * 0.15, formatter: String(v), color: text, fontSize: 9 } });\n }\n }\n var dyEl = document.getElementById(\"chart-dyad\");\n var dg = layout(dyEl);\n var splitFill = dark ? [\"rgba(255,255,255,0.03)\", \"rgba(255,255,255,0.06)\"] : [\"rgba(0,0,0,0.02)\", \"rgba(0,0,0,0.05)\"];\n init(\"chart-dyad\", Object.assign(baseOpt(), {\n tooltip: { position: \"top\", formatter: function (p) { var v = p.value[2]; return ix.aliases[p.value[1]] + \" \u2192 \" + ix.aliases[p.value[0]] + \": \" + v; } },\n grid: { left: Math.max(dg.leftCat, 72), right: dg.right, top: dg.top, bottom: 56 },\n xAxis: {\n type: \"category\",\n data: ix.aliases,\n axisLabel: { color: muted, fontSize: dg.fs, rotate: 32 },\n splitArea: { show: true, areaStyle: { color: splitFill } },\n },\n yAxis: {\n type: \"category\",\n data: ix.aliases,\n axisLabel: { color: muted, fontSize: dg.fs },\n splitArea: { show: true, areaStyle: { color: splitFill } },\n },\n visualMap: {\n min: 0,\n max: maxV,\n calculable: true,\n orient: \"horizontal\",\n left: \"center\",\n bottom: 4,\n inRange: { color: [heatLo, dark ? \"#2a9d8f\" : \"#7ecfc2\", dark ? \"#3ee8c5\" : \"#0f6b5c\", heatHi] },\n },\n series: [{\n type: \"heatmap\",\n data: heat,\n itemStyle: { borderWidth: 0 },\n emphasis: { itemStyle: { shadowBlur: 12, shadowColor: dark ? \"rgba(62,232,197,0.5)\" : \"rgba(15,107,92,0.35)\" } },\n }],\n }));\n }\n requestAnimationFrame(resizeAll);\n setTimeout(resizeAll, 150);\n window.addEventListener(\"resize\", resizeAll);\n window.addEventListener(\"load\", resizeAll);\n }\n function whenVisible() {\n var anchor = document.getElementById(\"s-viz\") || document.querySelector(\".chart-box\");\n if (!anchor || typeof IntersectionObserver === \"undefined\") {\n run();\n return;\n }\n var started = false;\n var io = new IntersectionObserver(function (entries) {\n if (started) return;\n if (entries.some(function (e) { return e.isIntersecting; })) {\n started = true;\n io.disconnect();\n run();\n }\n }, { rootMargin: \"480px 0px\", threshold: 0.01 });\n io.observe(anchor);\n setTimeout(function () {\n if (started) return;\n var r = anchor.getBoundingClientRect();\n if (r.top < window.innerHeight + 320) {\n started = true;\n io.disconnect();\n run();\n }\n }, 200);\n }\n function bootCharts() {\n if (typeof echarts === \"undefined\") return false;\n whenVisible();\n return true;\n }\n if (!bootCharts()) {\n window.addEventListener(\"load\", function () {\n var tries = 0;\n (function wait() {\n if (bootCharts()) return;\n if (++tries > 120) {\n document.querySelectorAll(\".chart-box\").forEach(function (el) {\n if (!el.querySelector(\"canvas\")) {\n el.innerHTML = '<p style=\"margin:0;padding:12px;font-size:12px;color:var(--muted);text-align:center\">ECharts CDN\uC744 \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.</p>';\n }\n });\n return;\n }\n setTimeout(wait, 50);\n })();\n });\n }\n })();\n";
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { isShortActivitySpan, topicsThemesOnly } from "./report-chart-util.js";
|
|
1
2
|
import { escapeHtml, formatNumber } from "./report-util.js";
|
|
3
|
+
const KW_BAR_CHART_LIMIT = 30;
|
|
2
4
|
/** @deprecated preconnect는 report-head.ts REPORT_HEAD_LINKS 사용 */
|
|
3
5
|
export const CHART_CDN_HEAD = ``;
|
|
4
6
|
/** body 끝: 차트 라이브러리 — defer 금지(인라인 init보다 반드시 먼저 실행) */
|
|
@@ -31,12 +33,20 @@ export function buildChartPayload(data) {
|
|
|
31
33
|
.map((c) => ({ date: c.date, count: c.count })),
|
|
32
34
|
burstDates: data.burstDays.map((b) => b.date),
|
|
33
35
|
totalParticipants: data.participants.length,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
terms: t.terms,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
topicsThemes: topicsThemesOnly(data.topics)
|
|
37
|
+
.slice(0, 8)
|
|
38
|
+
.map((t) => ({ title: t.title, terms: t.terms, messagePercent: t.messagePercent })),
|
|
39
|
+
topicsPeriods: isShortActivitySpan(data.daily)
|
|
40
|
+
? []
|
|
41
|
+
: data.topics
|
|
42
|
+
.filter((t) => t.kind === "period")
|
|
43
|
+
.slice(0, 4)
|
|
44
|
+
.map((t) => ({
|
|
45
|
+
title: t.title,
|
|
46
|
+
terms: t.terms,
|
|
47
|
+
messagePercent: t.messagePercent,
|
|
48
|
+
periodLabel: t.periodLabel,
|
|
49
|
+
})),
|
|
40
50
|
interaction: data.interaction
|
|
41
51
|
? {
|
|
42
52
|
aliases: data.interaction.aliases,
|
|
@@ -54,13 +64,13 @@ export function serializeExplorerPayload(data) {
|
|
|
54
64
|
}
|
|
55
65
|
export function renderChartDeck(data) {
|
|
56
66
|
const kw = data.keywords.length;
|
|
57
|
-
const
|
|
67
|
+
const themeCount = topicsThemesOnly(data.topics).length;
|
|
58
68
|
const showLegacyDaily = data.story.calendarWeeks.length === 0 && data.daily.length > 0;
|
|
59
|
-
const topicChart =
|
|
69
|
+
const topicChart = themeCount > 0
|
|
60
70
|
? `<article class="viz-card span-12">
|
|
61
|
-
<h3
|
|
62
|
-
<p class="viz-hint">막대 =
|
|
63
|
-
<div id="chart-topics" class="chart-box" role="img" aria-label="주제
|
|
71
|
+
<h3>대화 테마 · c-TF-IDF</h3>
|
|
72
|
+
<p class="viz-hint">막대 = <strong>의미 주제</strong> 신호 비중(근사 %). 월별 메시지량은 「기간 비교」·아래 주제 카드의 월별 화제를 보세요.</p>
|
|
73
|
+
<div id="chart-topics" class="chart-box" role="img" aria-label="주제 테마 차트"></div>
|
|
64
74
|
</article>`
|
|
65
75
|
: "";
|
|
66
76
|
return `<section id="s-viz" class="viz-hero anim-enter" style="--enter-delay:0.055s" aria-label="인터랙티브 차트">
|
|
@@ -92,8 +102,8 @@ export function renderChartDeck(data) {
|
|
|
92
102
|
<div id="chart-monthly" class="chart-box compact" role="img" aria-label="월별 차트"></div>
|
|
93
103
|
</article>
|
|
94
104
|
<article class="viz-card span-12">
|
|
95
|
-
<h3>키워드 상위 ${formatNumber(Math.min(kw,
|
|
96
|
-
<p class="viz-hint"
|
|
105
|
+
<h3>키워드 상위 ${formatNumber(Math.min(kw, KW_BAR_CHART_LIMIT))} · 메시지 등장 횟수</h3>
|
|
106
|
+
<p class="viz-hint">차트는 상위 ${KW_BAR_CHART_LIMIT}개(막대 안에 키워드 표시). 아래 표에서 전체 ${formatNumber(kw)}개를 볼 수 있어요.</p>
|
|
97
107
|
<div id="chart-kw-bar" class="chart-box tall" role="img" aria-label="키워드 막대 차트"></div>
|
|
98
108
|
${renderKeywordTable(data.keywords)}
|
|
99
109
|
</article>
|
|
@@ -145,6 +155,23 @@ export const CHARTS_INIT_SCRIPT = `
|
|
|
145
155
|
var muted = dark ? "#8b98a8" : "#5c6670";
|
|
146
156
|
var accent = dark ? "#3ee8c5" : "#0f6b5c";
|
|
147
157
|
var accent2 = dark ? "#818cf8" : "#4f46e5";
|
|
158
|
+
function cssVar(name, fallback) {
|
|
159
|
+
try {
|
|
160
|
+
var v = getComputedStyle(document.body).getPropertyValue(name).trim();
|
|
161
|
+
return v || fallback;
|
|
162
|
+
} catch (e) { return fallback; }
|
|
163
|
+
}
|
|
164
|
+
var heatLo = cssVar("--chart-heat-lo", dark ? "#1a2744" : "#d4e4f4");
|
|
165
|
+
var heatHi = cssVar("--chart-heat-hi", dark ? "#5ee8ff" : "#1e4fd6");
|
|
166
|
+
var wdColors = [
|
|
167
|
+
cssVar("--chart-wd-0", dark ? "#818cf8" : "#4f46e5"),
|
|
168
|
+
cssVar("--chart-wd-1", dark ? "#3ee8c5" : "#0f6b5c"),
|
|
169
|
+
cssVar("--chart-wd-2", dark ? "#34d399" : "#059669"),
|
|
170
|
+
cssVar("--chart-wd-3", dark ? "#2dd4bf" : "#0d9488"),
|
|
171
|
+
cssVar("--chart-wd-4", dark ? "#38bdf8" : "#0284c7"),
|
|
172
|
+
cssVar("--chart-wd-5", dark ? "#fbbf24" : "#d97706"),
|
|
173
|
+
cssVar("--chart-wd-6", dark ? "#fb923c" : "#ea580c"),
|
|
174
|
+
];
|
|
148
175
|
|
|
149
176
|
function baseOpt() {
|
|
150
177
|
return {
|
|
@@ -231,11 +258,27 @@ export const CHARTS_INIT_SCRIPT = `
|
|
|
231
258
|
if (data.weekdays && document.getElementById("chart-weekday")) {
|
|
232
259
|
var wdEl = document.getElementById("chart-weekday");
|
|
233
260
|
var wg = layout(wdEl);
|
|
261
|
+
var wdCounts = data.weekdays.map(function (w) { return w.count; });
|
|
262
|
+
var wdMax = Math.max.apply(null, wdCounts.concat([1]));
|
|
234
263
|
init("chart-weekday", Object.assign(baseOpt(), {
|
|
235
264
|
grid: { left: wg.leftCat, right: wg.right, top: wg.top, bottom: wg.bottom },
|
|
236
265
|
xAxis: { type: "value", axisLabel: { color: muted, fontSize: wg.fs } },
|
|
237
266
|
yAxis: { type: "category", data: data.weekdays.map(function (w) { return w.label; }), axisLabel: { color: muted, fontSize: wg.fs } },
|
|
238
|
-
series: [{
|
|
267
|
+
series: [{
|
|
268
|
+
type: "bar",
|
|
269
|
+
data: data.weekdays.map(function (w, i) {
|
|
270
|
+
var c = wdColors[i % 7];
|
|
271
|
+
return {
|
|
272
|
+
value: w.count,
|
|
273
|
+
itemStyle: {
|
|
274
|
+
color: c,
|
|
275
|
+
borderRadius: [0, 6, 6, 0],
|
|
276
|
+
shadowBlur: w.count >= wdMax ? 10 : 0,
|
|
277
|
+
shadowColor: w.count >= wdMax ? (dark ? "rgba(62,232,197,0.45)" : "rgba(15,107,92,0.35)") : "transparent",
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
}),
|
|
281
|
+
}],
|
|
239
282
|
}));
|
|
240
283
|
}
|
|
241
284
|
|
|
@@ -292,15 +335,55 @@ export const CHARTS_INIT_SCRIPT = `
|
|
|
292
335
|
if (data.keywords && document.getElementById("chart-kw-bar")) {
|
|
293
336
|
var kwEl = document.getElementById("chart-kw-bar");
|
|
294
337
|
var kg = layout(kwEl);
|
|
295
|
-
var
|
|
296
|
-
var
|
|
297
|
-
|
|
298
|
-
var
|
|
338
|
+
var kwLimit = kg.w < 380 ? 20 : 30;
|
|
339
|
+
var topBar = data.keywords.slice(0, kwLimit);
|
|
340
|
+
var nKw = topBar.length;
|
|
341
|
+
var padY = Math.min(48, 8 + nKw * 0.4);
|
|
342
|
+
function kwBarColor(rankFromTop) {
|
|
343
|
+
if (rankFromTop === 0) return dark ? "#a78bfa" : "#6366f1";
|
|
344
|
+
if (rankFromTop === 1) return dark ? "#818cf8" : "#4f46e5";
|
|
345
|
+
if (rankFromTop === 2) return dark ? "#5b9bd5" : "#3b82f6";
|
|
346
|
+
return dark ? "rgba(129,140,248,0.55)" : "rgba(79,70,229,0.45)";
|
|
347
|
+
}
|
|
348
|
+
var kwSeries = topBar.map(function (k, i) {
|
|
349
|
+
return {
|
|
350
|
+
value: k.count,
|
|
351
|
+
name: k.label,
|
|
352
|
+
itemStyle: { color: kwBarColor(i), borderRadius: [0, 4, 4, 0] },
|
|
353
|
+
};
|
|
354
|
+
}).reverse();
|
|
299
355
|
init("chart-kw-bar", Object.assign(baseOpt(), {
|
|
300
|
-
grid: { left:
|
|
356
|
+
grid: { left: 8, right: kg.right, top: padY, bottom: padY, containLabel: false },
|
|
301
357
|
xAxis: { type: "value", axisLabel: { color: muted, fontSize: kg.fs } },
|
|
302
|
-
yAxis: {
|
|
303
|
-
|
|
358
|
+
yAxis: {
|
|
359
|
+
type: "category",
|
|
360
|
+
data: topBar.map(function (k) { return k.label; }).reverse(),
|
|
361
|
+
axisLabel: { show: false },
|
|
362
|
+
axisTick: { show: false },
|
|
363
|
+
axisLine: { show: false },
|
|
364
|
+
},
|
|
365
|
+
series: [{
|
|
366
|
+
type: "bar",
|
|
367
|
+
data: kwSeries,
|
|
368
|
+
label: [
|
|
369
|
+
{
|
|
370
|
+
show: true,
|
|
371
|
+
position: "insideLeft",
|
|
372
|
+
color: text,
|
|
373
|
+
fontSize: kg.fs,
|
|
374
|
+
fontWeight: 600,
|
|
375
|
+
formatter: "{b}",
|
|
376
|
+
padding: [0, 0, 0, 6],
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
show: true,
|
|
380
|
+
position: "right",
|
|
381
|
+
color: muted,
|
|
382
|
+
fontSize: kg.fs,
|
|
383
|
+
formatter: "{c}",
|
|
384
|
+
},
|
|
385
|
+
],
|
|
386
|
+
}],
|
|
304
387
|
}));
|
|
305
388
|
}
|
|
306
389
|
|
|
@@ -369,10 +452,10 @@ export const CHARTS_INIT_SCRIPT = `
|
|
|
369
452
|
}));
|
|
370
453
|
}
|
|
371
454
|
|
|
372
|
-
if (data.
|
|
455
|
+
if (data.topicsThemes && data.topicsThemes.length && document.getElementById("chart-topics")) {
|
|
373
456
|
var topEl = document.getElementById("chart-topics");
|
|
374
457
|
var tg = layout(topEl);
|
|
375
|
-
var topics = data.
|
|
458
|
+
var topics = data.topicsThemes.slice(0, 8);
|
|
376
459
|
init("chart-topics", Object.assign(baseOpt(), {
|
|
377
460
|
grid: { left: Math.max(tg.leftCat, tg.w < 380 ? 72 : 96), right: tg.right, top: tg.top, bottom: tg.bottom },
|
|
378
461
|
xAxis: { type: "value", axisLabel: { color: muted, fontSize: tg.fs, formatter: "{value}%" } },
|
|
@@ -412,18 +495,42 @@ export const CHARTS_INIT_SCRIPT = `
|
|
|
412
495
|
for (var ci = 0; ci < ix.matrix[ri].length; ci += 1) {
|
|
413
496
|
var v = ix.matrix[ri][ci];
|
|
414
497
|
if (v > maxV) maxV = v;
|
|
415
|
-
if (v > 0) heat.push([ci, ri, v]);
|
|
498
|
+
if (v > 0) heat.push({ value: [ci, ri, v], label: { show: v >= maxV * 0.15, formatter: String(v), color: text, fontSize: 9 } });
|
|
416
499
|
}
|
|
417
500
|
}
|
|
418
501
|
var dyEl = document.getElementById("chart-dyad");
|
|
419
502
|
var dg = layout(dyEl);
|
|
503
|
+
var splitFill = dark ? ["rgba(255,255,255,0.03)", "rgba(255,255,255,0.06)"] : ["rgba(0,0,0,0.02)", "rgba(0,0,0,0.05)"];
|
|
420
504
|
init("chart-dyad", Object.assign(baseOpt(), {
|
|
421
|
-
tooltip: { position: "top" },
|
|
505
|
+
tooltip: { position: "top", formatter: function (p) { var v = p.value[2]; return ix.aliases[p.value[1]] + " → " + ix.aliases[p.value[0]] + ": " + v; } },
|
|
422
506
|
grid: { left: Math.max(dg.leftCat, 72), right: dg.right, top: dg.top, bottom: 56 },
|
|
423
|
-
xAxis: {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
507
|
+
xAxis: {
|
|
508
|
+
type: "category",
|
|
509
|
+
data: ix.aliases,
|
|
510
|
+
axisLabel: { color: muted, fontSize: dg.fs, rotate: 32 },
|
|
511
|
+
splitArea: { show: true, areaStyle: { color: splitFill } },
|
|
512
|
+
},
|
|
513
|
+
yAxis: {
|
|
514
|
+
type: "category",
|
|
515
|
+
data: ix.aliases,
|
|
516
|
+
axisLabel: { color: muted, fontSize: dg.fs },
|
|
517
|
+
splitArea: { show: true, areaStyle: { color: splitFill } },
|
|
518
|
+
},
|
|
519
|
+
visualMap: {
|
|
520
|
+
min: 0,
|
|
521
|
+
max: maxV,
|
|
522
|
+
calculable: true,
|
|
523
|
+
orient: "horizontal",
|
|
524
|
+
left: "center",
|
|
525
|
+
bottom: 4,
|
|
526
|
+
inRange: { color: [heatLo, dark ? "#2a9d8f" : "#7ecfc2", dark ? "#3ee8c5" : "#0f6b5c", heatHi] },
|
|
527
|
+
},
|
|
528
|
+
series: [{
|
|
529
|
+
type: "heatmap",
|
|
530
|
+
data: heat,
|
|
531
|
+
itemStyle: { borderWidth: 0 },
|
|
532
|
+
emphasis: { itemStyle: { shadowBlur: 12, shadowColor: dark ? "rgba(62,232,197,0.5)" : "rgba(15,107,92,0.35)" } },
|
|
533
|
+
}],
|
|
427
534
|
}));
|
|
428
535
|
}
|
|
429
536
|
requestAnimationFrame(resizeAll);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-charts.js","sourceRoot":"","sources":["../../src/report-charts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"report-charts.js","sourceRoot":"","sources":["../../src/report-charts.ts"],"names":[],"mappings":"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"}
|
package/dist/src/report-story.js
CHANGED
|
@@ -71,7 +71,8 @@ function renderGitHubCalendar(data) {
|
|
|
71
71
|
const summary = s.calendarTotalMessages > 0
|
|
72
72
|
? `<p class="gh-contrib-summary">이 기간 메시지 <strong>${formatNumber(s.calendarTotalMessages)}</strong>건<span class="gh-contrib-span">${escapeHtml(s.calendarSpanLabel)}</span></p>`
|
|
73
73
|
: `<p class="gh-contrib-summary">이 기간 활동 없음<span class="gh-contrib-span">${escapeHtml(s.calendarSpanLabel)}</span></p>`;
|
|
74
|
-
|
|
74
|
+
const compactClass = weekCount <= 14 ? " gh-contrib--compact" : "";
|
|
75
|
+
return `<div class="gh-contrib${compactClass}">
|
|
75
76
|
<div class="gh-cal-tooltip" data-gh-tip hidden><span data-gh-tip-text></span></div>
|
|
76
77
|
${summary}
|
|
77
78
|
<div class="gh-cal-scroll">
|
|
@@ -140,8 +141,10 @@ export function renderStorySections(data) {
|
|
|
140
141
|
</section>`);
|
|
141
142
|
}
|
|
142
143
|
if (s.calendarWeeks.length > 0) {
|
|
144
|
+
const calWeeks = s.calendarWeeks.length;
|
|
145
|
+
const calTitle = calWeeks <= 14 ? "활동 기간 그리드" : "연간 활동 그리드";
|
|
143
146
|
parts.push(`<section id="s-calendar" class="anim-enter" style="margin-bottom:14px;--enter-delay:0.05s">
|
|
144
|
-
<h2 style="margin:0 0 6px;font-size:20px;font-weight:800;letter-spacing:-0.02em"
|
|
147
|
+
<h2 style="margin:0 0 6px;font-size:20px;font-weight:800;letter-spacing:-0.02em">${calTitle}</h2>
|
|
145
148
|
<p class="chart-hint" style="margin-bottom:12px">GitHub 프로필 <strong>Contributions</strong>와 같은 레이아웃·색 단계예요. 셀에 마우스를 올리거나 탭하면 날짜와 건수가 표시됩니다.</p>
|
|
146
149
|
${renderGitHubCalendar(data)}
|
|
147
150
|
</section>`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report-story.js","sourceRoot":"","sources":["../../src/report-story.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEjF,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0ChC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAE3B,+EAA+E;AAE/E,SAAS,oBAAoB,CAAC,IAAgB;IAC5C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;IACrB,MAAM,SAAS,GAAG,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC;IACzC,IAAI,SAAS,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAE/B,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;QAC7D,MAAM,GAAG,GAAG,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;QAClE,OAAO,8BAA8B,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;IACjF,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,MAAM,SAAS,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC;SAC9C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,SAAS,CAAC;SAC/B,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,MAAM,KAAK,GAAG,CAAC,CAAC,aAAa;SAC1B,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;SACvB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACZ,OAAO,sFAAsF,CAAC;QAChG,CAAC;QACD,MAAM,KAAK,GACT,CAAC,CAAC,KAAK,GAAG,CAAC;YACT,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG;YAC7D,CAAC,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC;QAC9C,OAAO,yDAAyD,CAAC,CAAC,KAAK,gBAAgB,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,KAAK,iBAAiB,UAAU,CAAC,KAAK,CAAC,iBAAiB,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC;IACrN,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,MAAM,OAAO,GACX,CAAC,CAAC,qBAAqB,GAAG,CAAC;QACzB,CAAC,CAAC,kDAAkD,YAAY,CAAC,CAAC,CAAC,qBAAqB,CAAC,2CAA2C,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC,aAAa;QAChL,CAAC,CAAC,yEAAyE,UAAU,CAAC,CAAC,CAAC,iBAAiB,CAAC,aAAa,CAAC;IAE5H,OAAO;;
|
|
1
|
+
{"version":3,"file":"report-story.js","sourceRoot":"","sources":["../../src/report-story.ts"],"names":[],"mappings":"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"}
|