From 75d9e11bab951755786f238d4055f1d99a0d4abf Mon Sep 17 00:00:00 2001 From: MaysWind Date: Wed, 25 Feb 2026 01:16:42 +0800 Subject: [PATCH] support exporting statistics & analysis result to mermaid --- src/core/file.ts | 1 + src/core/statistics.ts | 6 ++ src/locales/de.json | 2 + src/locales/en.json | 2 + src/locales/es.json | 2 + src/locales/fr.json | 2 + src/locales/it.json | 2 + src/locales/ja.json | 2 + src/locales/kn.json | 2 + src/locales/ko.json | 2 + src/locales/nl.json | 2 + src/locales/pt_BR.json | 2 + src/locales/ru.json | 2 + src/locales/sl.json | 2 + src/locales/ta.json | 2 + src/locales/th.json | 2 + src/locales/tr.json | 2 + src/locales/uk.json | 2 + src/locales/vi.json | 2 + src/locales/zh_Hans.json | 2 + src/locales/zh_Hant.json | 2 + .../insights/tabs/ExplorerChartTab.vue | 45 +++++++- .../desktop/statistics/TransactionPage.vue | 35 +++++- .../transaction/dialogs/ExportDialog.vue | 102 +++++++++++++++++- 24 files changed, 216 insertions(+), 11 deletions(-) diff --git a/src/core/file.ts b/src/core/file.ts index 848a7905..b0cdbff2 100644 --- a/src/core/file.ts +++ b/src/core/file.ts @@ -7,6 +7,7 @@ export class KnownFileType { public static readonly SSV = new KnownFileType('txt', 'text/plain'); public static readonly TXT = new KnownFileType('txt', 'text/plain'); public static readonly MARKDOWN = new KnownFileType('md', 'text/markdown'); + public static readonly MERMAID = new KnownFileType('mermaid', 'text/vnd.mermaid'); public static readonly JS = new KnownFileType('js', 'application/javascript'); public static readonly JPG = new KnownFileType('jpg', 'image/jpeg'); diff --git a/src/core/statistics.ts b/src/core/statistics.ts index 494375c0..ba0cb813 100644 --- a/src/core/statistics.ts +++ b/src/core/statistics.ts @@ -285,6 +285,12 @@ export class ChartDateAggregationType { } } +export enum ExportMermaidChartType { + PieChart = 'pieChart', + XYChartBar = 'xyChartBar', + XYChartLine = 'xyChartLine' +} + export const DEFAULT_CATEGORICAL_CHART_DATA_RANGE: DateRange = DateRange.ThisMonth; export const DEFAULT_TREND_CHART_DATA_RANGE: DateRange = DateRange.ThisYear; export const DEFAULT_ASSET_TRENDS_CHART_DATA_RANGE: DateRange = DateRange.ThisYear; diff --git a/src/locales/de.json b/src/locales/de.json index f8517c57..84260753 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown File", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Benutzerdaten löschen", "Clear All Transactions": "Clear All Transactions", "Clear All Data": "Clear All Data", diff --git a/src/locales/en.json b/src/locales/en.json index bf02ab32..2b63dcbd 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown File", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Clear User Data", "Clear All Transactions": "Clear All Transactions", "Clear All Data": "Clear All Data", diff --git a/src/locales/es.json b/src/locales/es.json index bf1d5614..3d237cb9 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Exportar a archivo TSV (Valores Separados por Tabulaciones)", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Archivo Markdown", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Borrar Datos de Usuario", "Clear All Transactions": "Eliminar Todas las Transacciones", "Clear All Data": "Eliminar Todos los Datos", diff --git a/src/locales/fr.json b/src/locales/fr.json index c901295f..4a094a20 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Exporter vers un fichier TSV (valeurs séparées par tabulations)", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Fichier Markdown", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Effacer les données utilisateur", "Clear All Transactions": "Effacer toutes les transactions", "Clear All Data": "Effacer toutes les données", diff --git a/src/locales/it.json b/src/locales/it.json index 757296ae..77fc3d50 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown File", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Cancella dati utente", "Clear All Transactions": "Clear All Transactions", "Clear All Data": "Clear All Data", diff --git a/src/locales/ja.json b/src/locales/ja.json index 1bfa525c..62f6f274 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown File", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "ユーザーデータをクリア", "Clear All Transactions": "Clear All Transactions", "Clear All Data": "Clear All Data", diff --git a/src/locales/kn.json b/src/locales/kn.json index e24438aa..95cd8c3d 100644 --- a/src/locales/kn.json +++ b/src/locales/kn.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "TSV (ಟ್ಯಾಬ್-ಪ್ರತ್ಯೇಕಿತ ಮೌಲ್ಯಗಳು) ಫೈಲ್‌ಗೆ ರಫ್ತು ಮಾಡಿ", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown ಫೈಲ್", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "ಬಳಕೆದಾರ ಡೇಟಾ ತೆರವುಗೊಳಿಸಿ", "Clear All Transactions": "ಎಲ್ಲಾ ವಹಿವಾಟುಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ", "Clear All Data": "ಎಲ್ಲಾ ಡೇಟಾವನ್ನು ತೆರವುಗೊಳಿಸಿ", diff --git a/src/locales/ko.json b/src/locales/ko.json index 7072720c..15b0b206 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "TSV (탭으로 구분된 값) 파일로 내보내기", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown 파일", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "사용자 데이터 지우기", "Clear All Transactions": "모든 거래 지우기", "Clear All Data": "모든 데이터 지우기", diff --git a/src/locales/nl.json b/src/locales/nl.json index 71dc59ba..9be5fe1b 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Exporteren naar TSV-bestand (tab-gescheiden waarden)", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown-bestand", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Gebruikersgegevens wissen", "Clear All Transactions": "Clear All Transactions", "Clear All Data": "Clear All Data", diff --git a/src/locales/pt_BR.json b/src/locales/pt_BR.json index 3ba9974b..ef3eed09 100644 --- a/src/locales/pt_BR.json +++ b/src/locales/pt_BR.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Arquivo Markdown", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Limpar Dados do Usuário", "Clear All Transactions": "Clear All Transactions", "Clear All Data": "Clear All Data", diff --git a/src/locales/ru.json b/src/locales/ru.json index 1413a3ca..c2dd5b66 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Экспорт в файл TSV (значения, разделенные табуляцией)", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Файл Markdown", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Очистить данные пользователя", "Clear All Transactions": "Отчистить все транзакции", "Clear All Data": "Отчистить все данные", diff --git a/src/locales/sl.json b/src/locales/sl.json index fcda8774..b6a81b51 100644 --- a/src/locales/sl.json +++ b/src/locales/sl.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Izvozi v TSV datoteko", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown datoteka", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Počisti uporabniške podatke", "Clear All Transactions": "Počisti vse transakcije", "Clear All Data": "Počisti vse podatke", diff --git a/src/locales/ta.json b/src/locales/ta.json index 0d2a784f..e4a8b24d 100644 --- a/src/locales/ta.json +++ b/src/locales/ta.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "TSV (தாவல்-தனிப்பட்ட மதிப்புகள்) கோப்பு‌க்கு ஏற்றுமதி செய்", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown கோப்பு", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "பயனர் தரவை அழி", "Clear All Transactions": "அனைத்தும் பரிவர்த்தனைகளை அழி", "Clear All Data": "அனைத்தும் தரவுவை அழி", diff --git a/src/locales/th.json b/src/locales/th.json index e0245371..ea953678 100644 --- a/src/locales/th.json +++ b/src/locales/th.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "ส่งออกเป็นไฟล์ TSV (คั่นด้วยแท็บ)", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "ไฟล์ Markdown", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "ลบข้อมูลผู้ใช้", "Clear All Transactions": "ลบรายการทั้งหมด", "Clear All Data": "ลบข้อมูลทั้งหมด", diff --git a/src/locales/tr.json b/src/locales/tr.json index 2939e213..78a577a8 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "TSV (Sekmeyle ayrılmış değerler) Dosyasına Dışa Aktar", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown Dosyası", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Kullanıcı Verilerini Temizle", "Clear All Transactions": "Tüm İşlemleri Temizle", "Clear All Data": "Tüm Verileri Temizle", diff --git a/src/locales/uk.json b/src/locales/uk.json index c1088bc9..a351dc2d 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown File", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Очистити дані користувача", "Clear All Transactions": "Clear All Transactions", "Clear All Data": "Clear All Data", diff --git a/src/locales/vi.json b/src/locales/vi.json index b58114bd..f03afa76 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "Export to TSV (Tab-separated values) File", "Export to SSV (Semicolon-separated values) File": "Export to SSV (Semicolon-separated values) File", "Markdown File": "Markdown File", + "Mermaid (Pie Chart)": "Mermaid (Pie Chart)", + "Mermaid (XY Chart)": "Mermaid (XY Chart)", "Clear User Data": "Xóa dữ liệu người dùng", "Clear All Transactions": "Clear All Transactions", "Clear All Data": "Clear All Data", diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index 238f5f88..49950936 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "导出到 TSV (制表符分隔的值) 文件", "Export to SSV (Semicolon-separated values) File": "导出到 SSV (分号分隔的值) 文件", "Markdown File": "Markdown 文件", + "Mermaid (Pie Chart)": "Mermaid (饼图)", + "Mermaid (XY Chart)": "Mermaid (XY图)", "Clear User Data": "清除用户数据", "Clear All Transactions": "清除所有交易", "Clear All Data": "清除所有数据", diff --git a/src/locales/zh_Hant.json b/src/locales/zh_Hant.json index db349356..6efd07dc 100644 --- a/src/locales/zh_Hant.json +++ b/src/locales/zh_Hant.json @@ -2300,6 +2300,8 @@ "Export to TSV (Tab-separated values) File": "匯出為 TSV (定位點分隔的值) 檔案", "Export to SSV (Semicolon-separated values) File": "匯出為 SSV (分號分隔的值) 檔案", "Markdown File": "Markdown 檔案", + "Mermaid (Pie Chart)": "Mermaid (圓餅圖)", + "Mermaid (XY Chart)": "Mermaid (XY圖)", "Clear User Data": "清除使用者資料", "Clear All Transactions": "清除所有交易", "Clear All Data": "清除所有資料", diff --git a/src/views/desktop/insights/tabs/ExplorerChartTab.vue b/src/views/desktop/insights/tabs/ExplorerChartTab.vue index 22258de4..0cd10a74 100644 --- a/src/views/desktop/insights/tabs/ExplorerChartTab.vue +++ b/src/views/desktop/insights/tabs/ExplorerChartTab.vue @@ -184,7 +184,7 @@ import { import { type NameValue, type TypeAndDisplayName } from '@/core/base.ts'; import { Month, WeekDay } from '@/core/datetime.ts'; -import { ChartSortingType } from '@/core/statistics.ts'; +import { ChartSortingType, ExportMermaidChartType } from '@/core/statistics.ts'; import { TransactionExplorerChartType, TransactionExplorerDataDimensionType, @@ -532,9 +532,14 @@ function onClickTrendChartItem(itemId: string, categoryIndex: number): void { } } -function buildExportResults(): { headers: string[], data: string[][] } | undefined { +function buildExportResults(): { headers: string[], data: string[][], supportedMermaidCharts?: ExportMermaidChartType[] } | undefined { if (currentExplorer.value.chartType === TransactionExplorerChartType.Pie.value || currentExplorer.value.chartType === TransactionExplorerChartType.Radar.value) { const valueMetric = TransactionExplorerValueMetric.valueOf(currentExplorer.value.valueMetric); + let supportedMermaidCharts: ExportMermaidChartType[] | undefined = undefined; + + if (currentExplorer.value.chartType === TransactionExplorerChartType.Pie.value) { + supportedMermaidCharts = [ ExportMermaidChartType.PieChart ]; + } return { headers: [ @@ -544,10 +549,42 @@ function buildExportResults(): { headers: string[], data: string[][] } | undefin data: categoryDimensionTransactionExplorerData.value.map(data => [ data.name, valueMetric?.isAmount ? formatAmountToWesternArabicNumeralsWithoutDigitGrouping(data.totalAmount) : data.totalAmount.toString(10) - ]) + ]), + supportedMermaidCharts: supportedMermaidCharts }; } else if (TransactionExplorerChartType.valueOf(currentExplorer.value.chartType)?.seriesDimensionRequired && axisChartDisplayType.value) { - return axisChart.value?.exportData(); + const results = axisChart.value?.exportData(); + + if (!results) { + return undefined; + } + + let supportedMermaidCharts: ExportMermaidChartType[] | undefined = undefined; + + if (results.headers.length === 2 && + ( + currentExplorer.value.chartType === TransactionExplorerChartType.ColumnStacked.value || + currentExplorer.value.chartType === TransactionExplorerChartType.Column100PercentStacked.value || + currentExplorer.value.chartType === TransactionExplorerChartType.ColumnGrouped.value + ) + ) { + supportedMermaidCharts = [ ExportMermaidChartType.XYChartBar ]; + } else if (results.headers.length === 2 && + ( + currentExplorer.value.chartType === TransactionExplorerChartType.AreaStacked.value || + currentExplorer.value.chartType === TransactionExplorerChartType.Area100PercentStacked.value + ) + ) { + supportedMermaidCharts = [ ExportMermaidChartType.XYChartLine ]; + } else if (currentExplorer.value.chartType === TransactionExplorerChartType.LineGrouped.value) { + supportedMermaidCharts = [ ExportMermaidChartType.XYChartLine ]; + } + + return { + headers: results.headers, + data: results.data, + supportedMermaidCharts: supportedMermaidCharts + }; } else { return undefined; } diff --git a/src/views/desktop/statistics/TransactionPage.vue b/src/views/desktop/statistics/TransactionPage.vue index fa7dd46e..fca07766 100644 --- a/src/views/desktop/statistics/TransactionPage.vue +++ b/src/views/desktop/statistics/TransactionPage.vue @@ -528,9 +528,11 @@ import { ChartDataAggregationType, StatisticsAnalysisType, CategoricalChartType, + TrendChartType, ChartDataType, ChartSortingType, - ChartDateAggregationType + ChartDateAggregationType, + ExportMermaidChartType } from '@/core/statistics.ts'; import { @@ -1243,6 +1245,12 @@ function setKeywordFilter(keyword: string): void { function exportResults(): void { if (analysisType.value === StatisticsAnalysisType.CategoricalAnalysis && categoricalAnalysisData.value && categoricalAnalysisData.value.items) { + let supportedMermaidCharts: ExportMermaidChartType[] | undefined = undefined; + + if (query.value.categoricalChartType === CategoricalChartType.Pie.type) { + supportedMermaidCharts = [ ExportMermaidChartType.PieChart ]; + } + exportDialog.value?.open({ headers: [ tt('Name'), @@ -1255,19 +1263,38 @@ function exportResults(): void { item.name, formatAmountToWesternArabicNumeralsWithoutDigitGrouping(item.totalAmount), item.percent.toFixed(4) - ]) + ]), + supportedMermaidCharts: supportedMermaidCharts }); } else if (analysisType.value === StatisticsAnalysisType.TrendAnalysis && trendsAnalysisData.value && trendsAnalysisData.value.items && monthlyTrendsChart.value) { const exportData = monthlyTrendsChart.value.exportData(); + let supportedMermaidCharts: ExportMermaidChartType[] | undefined = undefined; + + if (exportData.headers.length === 2 && query.value.trendChartType === TrendChartType.Column.type) { + supportedMermaidCharts = [ ExportMermaidChartType.XYChartBar ]; + } else if (exportData.headers.length === 2 && query.value.trendChartType === TrendChartType.Area.type) { + supportedMermaidCharts = [ ExportMermaidChartType.XYChartLine ]; + } + exportDialog.value?.open({ headers: exportData.headers || [], - data: exportData.data || [] + data: exportData.data || [], + supportedMermaidCharts: supportedMermaidCharts }); } else if (analysisType.value === StatisticsAnalysisType.AssetTrends && assetTrendsData.value && assetTrendsData.value.items && dailyTrendsChart.value) { const exportData = dailyTrendsChart.value.exportData(); + let supportedMermaidCharts: ExportMermaidChartType[] | undefined = undefined; + + if (exportData.headers.length === 2 && query.value.assetTrendsChartType === TrendChartType.Column.type) { + supportedMermaidCharts = [ ExportMermaidChartType.XYChartBar ]; + } else if (exportData.headers.length === 2 && query.value.assetTrendsChartType === TrendChartType.Area.type) { + supportedMermaidCharts = [ ExportMermaidChartType.XYChartLine ]; + } + exportDialog.value?.open({ headers: exportData.headers || [], - data: exportData.data || [] + data: exportData.data || [], + supportedMermaidCharts: supportedMermaidCharts }); } } diff --git a/src/views/desktop/statistics/transaction/dialogs/ExportDialog.vue b/src/views/desktop/statistics/transaction/dialogs/ExportDialog.vue index 26eb4369..9c2c6d98 100644 --- a/src/views/desktop/statistics/transaction/dialogs/ExportDialog.vue +++ b/src/views/desktop/statistics/transaction/dialogs/ExportDialog.vue @@ -34,6 +34,21 @@ :append-icon="fileFormat === KnownFileType.MARKDOWN.extension ? mdiCheck : undefined" :title="tt('Markdown File')" @click="fileFormat = KnownFileType.MARKDOWN.extension"> + + + @@ -91,9 +106,13 @@ import { useI18n } from '@/locales/helpers.ts'; import { useUserStore } from '@/stores/user.ts'; +import { type PartialRecord, itemAndIndex } from '@/core/base.ts'; import { KnownFileType } from '@/core/file.ts'; -import { replaceAll } from '@/lib/common.ts'; +import { ExportMermaidChartType } from '@/core/statistics.ts'; + +import { replaceAll, arrayItemToObjectField } from '@/lib/common.ts'; import { copyTextToClipboard, startDownloadFile } from '@/lib/ui/common.ts'; +import logger from '@/lib/logger.ts'; import { extendMdiSemicolon @@ -104,6 +123,7 @@ import { mdiComma, mdiKeyboardTab, mdiLanguageMarkdownOutline, + mdiCodeTags, mdiMenuDown } from '@mdi/js'; @@ -120,6 +140,8 @@ const showState = ref(false); const headers = ref([]); const data = ref([]); const fileFormat = ref(KnownFileType.CSV.extension); +const supportedMermaidChartTypes = ref>({}); +const mermaidChartType = ref(undefined); const showRawData = ref(false); const fileName = computed(() => { @@ -185,16 +207,90 @@ const exportedData = computed(() => { ret += '\n'; ret += '| ' + row.map(item => replaceAll(item, '|', ' ')).join(' | ') + ' |'; } - } + } else if (fileFormat.value === KnownFileType.MERMAID.extension && mermaidChartType.value === ExportMermaidChartType.PieChart) { + ret += 'pie'; + for (const row of data.value) { + if (row.length > 0) { + const lengendName: string = replaceAll(row[0] as string, '"', '\\"'); + const value: string = row[1] ?? '0'; + + ret += `\n "${lengendName}" : ${value}`; + } + } + } else if (fileFormat.value === KnownFileType.MERMAID.extension && (mermaidChartType.value === ExportMermaidChartType.XYChartBar || mermaidChartType.value === ExportMermaidChartType.XYChartLine)) { + ret += 'xychart'; + const lengendNames: string[] = []; + const xAxisLabels: string[] = []; + const yAxisValues: Record = {}; + let minValue: number = 0; + let maxValue: number = 0; + + for (const [header, index] of itemAndIndex(headers.value)) { + if (index > 0) { + lengendNames.push(header); + } + } + + for (const row of data.value) { + for (const [item, index] of itemAndIndex(row)) { + if (index === 0) { + xAxisLabels.push(`"${replaceAll(item, '"', '\\"')}"`); + } else { + let values: string[] | undefined = yAxisValues[index - 1]; + + if (!values) { + values = []; + yAxisValues[index - 1] = values; + } + + try { + const value: number = parseFloat(item); + + if (value > maxValue) { + maxValue = value; + } else if (value < minValue) { + minValue = value; + } + } catch (ex) { + logger.warn('cannot parse value, original value is ' + item, ex); + } + + values.push(item); + } + } + } + + ret += `\n x-axis [${xAxisLabels.join(', ')}]`; + + if (minValue < 0 || maxValue > 0) { + ret += `\n y-axis ${minValue} --> ${maxValue}`; + } + + for (const [legendName, index] of itemAndIndex(lengendNames)) { + const values = yAxisValues[index]; + + if (values) { + ret += `\n %% ${legendName}`; + + if (mermaidChartType.value === ExportMermaidChartType.XYChartBar) { + ret += `\n bar [${values.join(', ')}]`; + } else if (mermaidChartType.value === ExportMermaidChartType.XYChartLine) { + ret += `\n line [${values.join(', ')}]`; + } + } + } + } return ret; }); -function open(options: { headers: string[], data: string[][] }): void { +function open(options: { headers: string[], data: string[][], supportedMermaidCharts?: ExportMermaidChartType[] }): void { headers.value = options.headers || []; data.value = options.data || []; fileFormat.value = KnownFileType.CSV.extension; + supportedMermaidChartTypes.value = arrayItemToObjectField(options.supportedMermaidCharts || [], true); + mermaidChartType.value = undefined; showRawData.value = false; showState.value = true; }