@tekkare/romulus 0.1.178 → 0.1.179
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/module.json +1 -1
- package/dist/runtime/components/ChartCard.vue +2 -2
- package/dist/runtime/components/SourceLine.vue +2 -2
- package/dist/runtime/components/ViewPill.vue +11 -1
- package/dist/runtime/composables/useRmExport.js +90 -11
- package/dist/runtime/utils/chart.d.ts +21 -1
- package/dist/runtime/utils/chart.js +19 -5
- package/dist/runtime/utils/export.d.ts +18 -0
- package/package.json +2 -1
package/dist/module.json
CHANGED
|
@@ -90,7 +90,7 @@ const emit = defineEmits<{
|
|
|
90
90
|
const WORDS = {
|
|
91
91
|
fr: {
|
|
92
92
|
source: 'Source :',
|
|
93
|
-
verified: '
|
|
93
|
+
verified: 'Dernière mise à jour le',
|
|
94
94
|
emptyTitle: 'Aucun résultat',
|
|
95
95
|
emptyText:
|
|
96
96
|
'Aucune ligne ne correspond aux filtres en cours. Élargissez votre période ou retirez une dimension.',
|
|
@@ -98,7 +98,7 @@ const WORDS = {
|
|
|
98
98
|
},
|
|
99
99
|
en: {
|
|
100
100
|
source: 'Source:',
|
|
101
|
-
verified: '
|
|
101
|
+
verified: 'Last updated',
|
|
102
102
|
emptyTitle: 'No results',
|
|
103
103
|
emptyText:
|
|
104
104
|
'No row matches the current filters. Widen your period or drop a dimension.',
|
|
@@ -31,8 +31,8 @@ const props = withDefaults(
|
|
|
31
31
|
|
|
32
32
|
/** Memes mots que le pied de RmChartCard. */
|
|
33
33
|
const WORDS = {
|
|
34
|
-
fr: { source: 'Source :', verified: '
|
|
35
|
-
en: { source: 'Source:', verified: '
|
|
34
|
+
fr: { source: 'Source :', verified: 'Dernière mise à jour le' },
|
|
35
|
+
en: { source: 'Source:', verified: 'Last updated' },
|
|
36
36
|
} as const
|
|
37
37
|
const t = computed(() => WORDS[props.lang])
|
|
38
38
|
|
|
@@ -82,6 +82,7 @@ const WORDS = {
|
|
|
82
82
|
favorites: 'Favoris',
|
|
83
83
|
actions: 'Actions',
|
|
84
84
|
unsaved: 'Modifications non enregistrées',
|
|
85
|
+
modified: 'modifiée',
|
|
85
86
|
applied: 'Vue appliquée',
|
|
86
87
|
save: 'Sauvegarder',
|
|
87
88
|
aria: 'Vue affichée',
|
|
@@ -92,6 +93,7 @@ const WORDS = {
|
|
|
92
93
|
favorites: 'Favorites',
|
|
93
94
|
actions: 'Actions',
|
|
94
95
|
unsaved: 'Unsaved changes',
|
|
96
|
+
modified: 'edited',
|
|
95
97
|
applied: 'View applied',
|
|
96
98
|
save: 'Save',
|
|
97
99
|
aria: 'Current view',
|
|
@@ -99,7 +101,15 @@ const WORDS = {
|
|
|
99
101
|
} as const
|
|
100
102
|
|
|
101
103
|
const t = computed(() => WORDS[props.lang])
|
|
102
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Le nom de la vue, suivi de son etat quand l'ecran ne lui correspond plus.
|
|
106
|
+
* La pastille coloree ne suffisait pas : on lisait « Vue : GLP-1 » sur un
|
|
107
|
+
* ecran qui ne montrait plus les produits de GLP-1.
|
|
108
|
+
*/
|
|
109
|
+
const label = computed(() => {
|
|
110
|
+
if (!props.viewName) return t.value.none
|
|
111
|
+
return props.dirty ? `${props.viewName} (${t.value.modified})` : props.viewName
|
|
112
|
+
})
|
|
103
113
|
|
|
104
114
|
const open = ref(false)
|
|
105
115
|
const root = ref<HTMLElement | null>(null)
|
|
@@ -88,6 +88,12 @@ function download(blob, fileName) {
|
|
|
88
88
|
setTimeout(() => URL.revokeObjectURL(url), 1e4);
|
|
89
89
|
return blob.size;
|
|
90
90
|
}
|
|
91
|
+
function titleGap(title) {
|
|
92
|
+
return title ? 22 : 0;
|
|
93
|
+
}
|
|
94
|
+
function drawableCharts(payload) {
|
|
95
|
+
return (payload.charts ?? []).map((chart) => ({ title: chart.title, svg: svgOf(chart.el) })).filter((chart) => !!chart.svg);
|
|
96
|
+
}
|
|
91
97
|
function svgOf(el) {
|
|
92
98
|
return el instanceof SVGSVGElement ? el : el.querySelector("svg");
|
|
93
99
|
}
|
|
@@ -106,6 +112,21 @@ function serialize(svg) {
|
|
|
106
112
|
if (!clone.getAttribute("viewBox")) clone.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
107
113
|
return { markup: new XMLSerializer().serializeToString(clone), width, height };
|
|
108
114
|
}
|
|
115
|
+
async function capture(el) {
|
|
116
|
+
try {
|
|
117
|
+
const { default: html2canvas } = await import("html2canvas-pro");
|
|
118
|
+
const canvas = await html2canvas(el, {
|
|
119
|
+
scale: 2,
|
|
120
|
+
backgroundColor: null,
|
|
121
|
+
logging: false,
|
|
122
|
+
useCORS: true
|
|
123
|
+
});
|
|
124
|
+
if (!canvas.width || !canvas.height) return null;
|
|
125
|
+
return { data: canvas.toDataURL("image/png"), width: canvas.width, height: canvas.height };
|
|
126
|
+
} catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
109
130
|
async function raster(markup, width, height, scale = 2) {
|
|
110
131
|
const image = new Image();
|
|
111
132
|
image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(markup)}`;
|
|
@@ -292,15 +313,15 @@ export function useRmExport() {
|
|
|
292
313
|
return { fileName, rows: rowCount, bytes: download(blob, fileName) };
|
|
293
314
|
}
|
|
294
315
|
async function toPng(config, payload, lang) {
|
|
295
|
-
const
|
|
296
|
-
if (!
|
|
316
|
+
const drawn = drawableCharts(payload);
|
|
317
|
+
if (!drawn.length) throw new Error(lang === "en" ? "No chart on this page" : "Aucun graphique sur cette page");
|
|
297
318
|
const scale = 2;
|
|
298
319
|
const pad = 24;
|
|
299
320
|
const sources = sourcesOf(config, payload);
|
|
300
321
|
const head = config.options.includes("logo") ? sources.length ? 88 : 72 : 0;
|
|
301
|
-
const parts =
|
|
322
|
+
const parts = drawn.map((chart) => ({ ...serialize(chart.svg), title: chart.title }));
|
|
302
323
|
const width = Math.max(...parts.map((part) => part.width)) + pad * 2;
|
|
303
|
-
const height = parts.reduce((total, part) => total + part.height + pad, pad) + head;
|
|
324
|
+
const height = parts.reduce((total, part) => total + part.height + pad + titleGap(part.title), pad) + head;
|
|
304
325
|
const canvas = document.createElement("canvas");
|
|
305
326
|
canvas.width = width * scale;
|
|
306
327
|
canvas.height = height * scale;
|
|
@@ -321,6 +342,12 @@ export function useRmExport() {
|
|
|
321
342
|
}
|
|
322
343
|
let y = head + pad;
|
|
323
344
|
for (const part of parts) {
|
|
345
|
+
if (part.title) {
|
|
346
|
+
context.fillStyle = "#1A1A2E";
|
|
347
|
+
context.font = "bold 14px Figtree, Helvetica, sans-serif";
|
|
348
|
+
context.fillText(part.title, pad, y + 12);
|
|
349
|
+
y += titleGap(part.title);
|
|
350
|
+
}
|
|
324
351
|
const raw = await raster(part.markup, part.width, part.height, scale);
|
|
325
352
|
context.drawImage(raw, pad, y, part.width, part.height);
|
|
326
353
|
y += part.height + pad;
|
|
@@ -332,19 +359,21 @@ export function useRmExport() {
|
|
|
332
359
|
return { fileName, rows: 0, bytes: download(blob, fileName) };
|
|
333
360
|
}
|
|
334
361
|
async function toSvg(config, payload, lang) {
|
|
335
|
-
const
|
|
336
|
-
if (!
|
|
362
|
+
const drawn = drawableCharts(payload);
|
|
363
|
+
if (!drawn.length) throw new Error(lang === "en" ? "No chart on this page" : "Aucun graphique sur cette page");
|
|
337
364
|
const pad = 24;
|
|
338
365
|
const sources = sourcesOf(config, payload);
|
|
339
366
|
const head = config.options.includes("logo") ? sources.length ? 88 : 72 : 0;
|
|
340
|
-
const parts =
|
|
367
|
+
const parts = drawn.map((chart) => ({ ...serialize(chart.svg), title: chart.title }));
|
|
341
368
|
const width = Math.max(...parts.map((part) => part.width)) + pad * 2;
|
|
342
|
-
const height = parts.reduce((total, part) => total + part.height + pad, pad) + head;
|
|
369
|
+
const height = parts.reduce((total, part) => total + part.height + pad + titleGap(part.title), pad) + head;
|
|
343
370
|
let y = head + pad;
|
|
344
371
|
const nested = parts.map((part) => {
|
|
372
|
+
const label = part.title ? `<text x="${pad}" y="${y + 12}" font-family="Figtree, Helvetica, sans-serif" font-size="14" font-weight="bold" fill="#1A1A2E">${escapeXml(part.title)}</text>` : "";
|
|
373
|
+
y += titleGap(part.title);
|
|
345
374
|
const markup2 = part.markup.replace(/^<svg /, `<svg x="${pad}" y="${y}" `);
|
|
346
375
|
y += part.height + pad;
|
|
347
|
-
return markup2;
|
|
376
|
+
return label + markup2;
|
|
348
377
|
}).join("\n");
|
|
349
378
|
const header = head ? `<text x="${pad}" y="32" font-family="Figtree, Helvetica, sans-serif" font-size="20" font-weight="bold" fill="#1A1A2E">${BRAND_TITLE}</text><text x="${pad}" y="52" font-family="Figtree, Helvetica, sans-serif" font-size="12" fill="#6C6C8A">${escapeXml(`${payload.title} \xB7 ${BRAND_LINE} \xB7 ${longDate(lang)}`)}</text>` + (sources.length ? `<text x="${pad}" y="68" font-family="Figtree, Helvetica, sans-serif" font-size="12" fill="#6C6C8A">${escapeXml(`Source${sources.length > 1 ? "s" : ""} : ${sources.map((source) => sourceLabel(source, lang)).join(" \xB7 ")}`)}</text>` : "") : "";
|
|
350
379
|
const markup = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><rect width="${width}" height="${height}" fill="#FFFFFF"/>${header}${nested}</svg>`;
|
|
@@ -541,8 +570,47 @@ export function useRmExport() {
|
|
|
541
570
|
);
|
|
542
571
|
y += cardHeight + 6;
|
|
543
572
|
}
|
|
573
|
+
const snapshots = (payload.nodes ?? []).filter((node) => {
|
|
574
|
+
if (node.kind === "chart") return false;
|
|
575
|
+
if (node.kind === "kpi") return config.sections.includes("kpi");
|
|
576
|
+
if (node.kind === "table") return config.sections.includes("table") || config.sections.includes("cards");
|
|
577
|
+
return config.sections.includes("cards");
|
|
578
|
+
});
|
|
579
|
+
const shots = [];
|
|
580
|
+
for (const node of snapshots) {
|
|
581
|
+
const shot = await capture(node.el);
|
|
582
|
+
if (shot) shots.push(shot);
|
|
583
|
+
}
|
|
584
|
+
const faithful = shots.length > 0;
|
|
585
|
+
if (faithful) {
|
|
586
|
+
sectionTitle(lang === "en" ? "Page" : "La page");
|
|
587
|
+
for (const shot of shots) {
|
|
588
|
+
let drawWidth = inner;
|
|
589
|
+
let drawHeight = shot.height / shot.width * drawWidth;
|
|
590
|
+
const maxHeight = bottom - margin;
|
|
591
|
+
if (drawHeight > maxHeight) {
|
|
592
|
+
drawHeight = maxHeight;
|
|
593
|
+
drawWidth = shot.width / shot.height * drawHeight;
|
|
594
|
+
}
|
|
595
|
+
if (y + drawHeight > bottom) {
|
|
596
|
+
doc.addPage();
|
|
597
|
+
y = margin;
|
|
598
|
+
}
|
|
599
|
+
doc.addImage(
|
|
600
|
+
shot.data,
|
|
601
|
+
"PNG",
|
|
602
|
+
margin + (inner - drawWidth) / 2,
|
|
603
|
+
y,
|
|
604
|
+
drawWidth,
|
|
605
|
+
drawHeight,
|
|
606
|
+
void 0,
|
|
607
|
+
"FAST"
|
|
608
|
+
);
|
|
609
|
+
y += drawHeight + 6;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
544
612
|
let rowCount = 0;
|
|
545
|
-
if (config.sections.includes("cards")) {
|
|
613
|
+
if (config.sections.includes("cards") && !faithful) {
|
|
546
614
|
const cards = cardsOf(payload, config, lang);
|
|
547
615
|
if (cards.length) {
|
|
548
616
|
if (y + 12 > bottom) {
|
|
@@ -754,7 +822,7 @@ export function useRmExport() {
|
|
|
754
822
|
y += 6;
|
|
755
823
|
}
|
|
756
824
|
}
|
|
757
|
-
if (config.sections.includes("table")) {
|
|
825
|
+
if (config.sections.includes("table") && !faithful) {
|
|
758
826
|
const MAX_COLUMNS = landscape ? 16 : 10;
|
|
759
827
|
payload.sheets.forEach((sheet) => {
|
|
760
828
|
const all = columnsOf(sheet, config.columns);
|
|
@@ -838,6 +906,10 @@ export function useRmExport() {
|
|
|
838
906
|
});
|
|
839
907
|
}
|
|
840
908
|
const pages = doc.getNumberOfPages();
|
|
909
|
+
const footList = sourcesOf(config, payload);
|
|
910
|
+
const footSources = footList.length ? printable(
|
|
911
|
+
`Source${footList.length > 1 ? "s" : ""} : ${footList.map((source) => sourceLabel(source, lang)).join(" \xB7 ")}`
|
|
912
|
+
) : "";
|
|
841
913
|
for (let page = 1; page <= pages; page += 1) {
|
|
842
914
|
doc.setPage(page);
|
|
843
915
|
const width = doc.internal.pageSize.getWidth();
|
|
@@ -854,6 +926,13 @@ export function useRmExport() {
|
|
|
854
926
|
)[0] ?? "";
|
|
855
927
|
doc.text(trail, margin, foot);
|
|
856
928
|
doc.text(`${page} / ${pages}`, width - margin, foot, { align: "right" });
|
|
929
|
+
if (footSources) {
|
|
930
|
+
doc.text(
|
|
931
|
+
doc.splitTextToSize(footSources, width - margin * 2)[0] ?? "",
|
|
932
|
+
margin,
|
|
933
|
+
foot - 8.5
|
|
934
|
+
);
|
|
935
|
+
}
|
|
857
936
|
}
|
|
858
937
|
const fileName = `${config.fileName}.pdf`;
|
|
859
938
|
const blob = doc.output("blob");
|
|
@@ -105,10 +105,14 @@ export declare function rmBaseOption(theme: RmChartTheme, decal?: boolean): {
|
|
|
105
105
|
};
|
|
106
106
|
borderColor: string;
|
|
107
107
|
borderWidth: number;
|
|
108
|
+
appendTo: string;
|
|
109
|
+
confine: boolean;
|
|
110
|
+
enterable: boolean;
|
|
111
|
+
extraCssText: string;
|
|
108
112
|
};
|
|
109
113
|
};
|
|
110
114
|
export declare const rmTooltipTrigger: (count: number) => "axis" | "item";
|
|
111
|
-
export declare function rmLegend(theme: RmChartTheme, count: number, position?: 'top' | 'bottom'): {
|
|
115
|
+
export declare function rmLegend(theme: RmChartTheme, count: number, position?: 'top' | 'bottom', names?: string[]): {
|
|
112
116
|
pageIconSize?: number | undefined;
|
|
113
117
|
pageIconColor?: string | undefined;
|
|
114
118
|
pageIconInactiveColor?: string | undefined;
|
|
@@ -207,6 +211,10 @@ export declare function rmBarVerticalOption(categories: (string | number)[], ser
|
|
|
207
211
|
};
|
|
208
212
|
borderColor: string;
|
|
209
213
|
borderWidth: number;
|
|
214
|
+
appendTo: string;
|
|
215
|
+
confine: boolean;
|
|
216
|
+
enterable: boolean;
|
|
217
|
+
extraCssText: string;
|
|
210
218
|
};
|
|
211
219
|
legend: {
|
|
212
220
|
pageIconSize?: number | undefined;
|
|
@@ -411,6 +419,10 @@ export declare function rmBarHorizontalOption(labels: string[], values: (number
|
|
|
411
419
|
};
|
|
412
420
|
borderColor: string;
|
|
413
421
|
borderWidth: number;
|
|
422
|
+
appendTo: string;
|
|
423
|
+
confine: boolean;
|
|
424
|
+
enterable: boolean;
|
|
425
|
+
extraCssText: string;
|
|
414
426
|
};
|
|
415
427
|
};
|
|
416
428
|
/** Line ou area chart. `step` produit la marche d'escalier des series de prix. */
|
|
@@ -472,6 +484,10 @@ export declare function rmLineOption(categories: (string | number)[], series: Rm
|
|
|
472
484
|
};
|
|
473
485
|
borderColor: string;
|
|
474
486
|
borderWidth: number;
|
|
487
|
+
appendTo: string;
|
|
488
|
+
confine: boolean;
|
|
489
|
+
enterable: boolean;
|
|
490
|
+
extraCssText: string;
|
|
475
491
|
};
|
|
476
492
|
legend: {
|
|
477
493
|
pageIconSize?: number | undefined;
|
|
@@ -729,6 +745,10 @@ export declare function rmDonutOption(data: {
|
|
|
729
745
|
};
|
|
730
746
|
borderColor: string;
|
|
731
747
|
borderWidth: number;
|
|
748
|
+
appendTo: string;
|
|
749
|
+
confine: boolean;
|
|
750
|
+
enterable: boolean;
|
|
751
|
+
extraCssText: string;
|
|
732
752
|
};
|
|
733
753
|
legend: {
|
|
734
754
|
pageIconSize?: number | undefined;
|
|
@@ -86,7 +86,17 @@ export function rmBaseOption(theme, decal = false) {
|
|
|
86
86
|
backgroundColor: theme.tooltipBg,
|
|
87
87
|
textStyle: { color: theme.tooltipText, fontFamily: FONT, fontSize: 12 },
|
|
88
88
|
borderColor: theme.tooltipBorder,
|
|
89
|
-
borderWidth: 1
|
|
89
|
+
borderWidth: 1,
|
|
90
|
+
// Posee par defaut DANS le conteneur du graphe, l'infobulle est rognee
|
|
91
|
+
// par la premiere carte a `overflow: hidden` des qu'elle en deborde :
|
|
92
|
+
// sur une colonne de quarante series il n'en reste qu'un morceau. Dans
|
|
93
|
+
// le body elle passe par-dessus la carte ; `confine` la garde ancree au
|
|
94
|
+
// cadre du graphe, et la hauteur plafonnee l'empeche de sortir de
|
|
95
|
+
// l'ecran (elle defile alors, d'ou `enterable`).
|
|
96
|
+
appendTo: "body",
|
|
97
|
+
confine: true,
|
|
98
|
+
enterable: true,
|
|
99
|
+
extraCssText: "max-height:70vh;overflow:auto;"
|
|
90
100
|
}
|
|
91
101
|
};
|
|
92
102
|
}
|
|
@@ -96,8 +106,12 @@ const LEGEND_MAX_INLINE = 6;
|
|
|
96
106
|
const LEGEND_NAME_MAX = 38;
|
|
97
107
|
const LEGEND_NAME_TAIL = 12;
|
|
98
108
|
const rmLegendName = (name) => name.length > LEGEND_NAME_MAX ? `${name.slice(0, LEGEND_NAME_MAX - LEGEND_NAME_TAIL - 1)}\u2026${name.slice(-LEGEND_NAME_TAIL)}` : name;
|
|
99
|
-
|
|
100
|
-
|
|
109
|
+
const LEGEND_ITEM_PAD = 32;
|
|
110
|
+
const LEGEND_CHAR_WIDTH = 6.2;
|
|
111
|
+
const LEGEND_WIDTH_BUDGET = 620;
|
|
112
|
+
const rmLegendWidth = (names) => names.reduce((total, name) => total + LEGEND_ITEM_PAD + rmLegendName(name).length * LEGEND_CHAR_WIDTH, 0);
|
|
113
|
+
export function rmLegend(theme, count, position = "bottom", names = []) {
|
|
114
|
+
const scroll = count > LEGEND_MAX_INLINE || rmLegendWidth(names) > LEGEND_WIDTH_BUDGET;
|
|
101
115
|
return {
|
|
102
116
|
...position === "bottom" ? { bottom: 0, left: "center" } : { top: 0 },
|
|
103
117
|
type: scroll ? "scroll" : "plain",
|
|
@@ -144,7 +158,7 @@ export function rmBarVerticalOption(categories, series, theme, palette, decal =
|
|
|
144
158
|
return {
|
|
145
159
|
...rmBaseOption(theme, decal),
|
|
146
160
|
tooltip: { ...rmBaseOption(theme, decal).tooltip, trigger: rmTooltipTrigger(series.length) },
|
|
147
|
-
legend: series.length > 1 ? rmLegend(theme, series.length) : void 0,
|
|
161
|
+
legend: series.length > 1 ? rmLegend(theme, series.length, "bottom", series.map((s) => String(s.name ?? ""))) : void 0,
|
|
148
162
|
// La legende passee sous le graphe prend sa place dans la gouttiere basse,
|
|
149
163
|
// sinon elle recouvre les libelles de l'axe des abscisses.
|
|
150
164
|
grid: { ...rmBaseOption(theme, decal).grid, bottom: series.length > 1 ? 56 : 36 },
|
|
@@ -229,7 +243,7 @@ export function rmLineOption(categories, series, theme, palette, options = {}) {
|
|
|
229
243
|
},
|
|
230
244
|
// Legende obligatoire en double axe : sans elle, rien ne dit quelle courbe
|
|
231
245
|
// se lit sur quel axe.
|
|
232
|
-
legend: series.length > 1 || dual ? rmLegend(theme, series.length, legendPosition) : void 0,
|
|
246
|
+
legend: series.length > 1 || dual ? rmLegend(theme, series.length, legendPosition, series.map((s) => String(s.name ?? ""))) : void 0,
|
|
233
247
|
grid: {
|
|
234
248
|
// Sans graduation a gauche, la gouttiere de 48 px ne sert plus qu'a
|
|
235
249
|
// laisser depasser la premiere pastille de valeur.
|
|
@@ -258,6 +258,15 @@ export interface RmExportPayload {
|
|
|
258
258
|
title?: string;
|
|
259
259
|
el: Element;
|
|
260
260
|
}[];
|
|
261
|
+
/**
|
|
262
|
+
* Cartes de l'ecran, a capturer telles quelles pour le rapport mis en page.
|
|
263
|
+
*
|
|
264
|
+
* Le rapport reconstruisait ses tableaux et ses fiches a partir de la
|
|
265
|
+
* donnee : il ne ressemblait plus a la page, colonnes et mises en forme
|
|
266
|
+
* comprises. Une page qui donne ses noeuds obtient une capture fidele ; les
|
|
267
|
+
* autres gardent le rendu reconstruit.
|
|
268
|
+
*/
|
|
269
|
+
nodes?: RmExportNode[];
|
|
261
270
|
/** URL a copier pour le format « Permalink ». */
|
|
262
271
|
permalink?: string;
|
|
263
272
|
/**
|
|
@@ -269,6 +278,15 @@ export interface RmExportPayload {
|
|
|
269
278
|
/** Plafond de lignes par onglet, pour ne pas geler l'onglet du navigateur. */
|
|
270
279
|
limit?: number;
|
|
271
280
|
}
|
|
281
|
+
/**
|
|
282
|
+
* Une carte de l'ecran, pour le rapport fidele. `kind` dit a quelle case du
|
|
283
|
+
* panneau elle repond (chiffres cles, graphique, tableau, fiche).
|
|
284
|
+
*/
|
|
285
|
+
export interface RmExportNode {
|
|
286
|
+
kind: 'kpi' | 'chart' | 'table' | 'card';
|
|
287
|
+
el: Element;
|
|
288
|
+
title?: string;
|
|
289
|
+
}
|
|
272
290
|
/** Extension de fichier par format. */
|
|
273
291
|
export declare const RM_EXPORT_EXTENSIONS: Record<string, string>;
|
|
274
292
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekkare/romulus",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.179",
|
|
4
4
|
"description": "Romulus Design System - Nuxt module by Tekkare",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"@nuxt/kit": "^3.16.0",
|
|
34
34
|
"@phosphor-icons/vue": "^2.2.1",
|
|
35
35
|
"echarts": "^5.6.0",
|
|
36
|
+
"html2canvas-pro": "^1.6.7",
|
|
36
37
|
"jspdf": "^4.2.0",
|
|
37
38
|
"jspdf-autotable": "^5.0.7",
|
|
38
39
|
"write-excel-file": "^1.4.30"
|