@tekkare/romulus 0.1.178 → 0.1.180
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 +120 -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,40 @@ 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 canvas;
|
|
126
|
+
} catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function slice(canvas, top, height) {
|
|
131
|
+
const part = document.createElement("canvas");
|
|
132
|
+
part.width = canvas.width;
|
|
133
|
+
part.height = Math.max(1, Math.round(height));
|
|
134
|
+
const context = part.getContext("2d");
|
|
135
|
+
if (!context) return canvas.toDataURL("image/png");
|
|
136
|
+
context.drawImage(
|
|
137
|
+
canvas,
|
|
138
|
+
0,
|
|
139
|
+
Math.round(top),
|
|
140
|
+
canvas.width,
|
|
141
|
+
part.height,
|
|
142
|
+
0,
|
|
143
|
+
0,
|
|
144
|
+
canvas.width,
|
|
145
|
+
part.height
|
|
146
|
+
);
|
|
147
|
+
return part.toDataURL("image/png");
|
|
148
|
+
}
|
|
109
149
|
async function raster(markup, width, height, scale = 2) {
|
|
110
150
|
const image = new Image();
|
|
111
151
|
image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(markup)}`;
|
|
@@ -292,15 +332,15 @@ export function useRmExport() {
|
|
|
292
332
|
return { fileName, rows: rowCount, bytes: download(blob, fileName) };
|
|
293
333
|
}
|
|
294
334
|
async function toPng(config, payload, lang) {
|
|
295
|
-
const
|
|
296
|
-
if (!
|
|
335
|
+
const drawn = drawableCharts(payload);
|
|
336
|
+
if (!drawn.length) throw new Error(lang === "en" ? "No chart on this page" : "Aucun graphique sur cette page");
|
|
297
337
|
const scale = 2;
|
|
298
338
|
const pad = 24;
|
|
299
339
|
const sources = sourcesOf(config, payload);
|
|
300
340
|
const head = config.options.includes("logo") ? sources.length ? 88 : 72 : 0;
|
|
301
|
-
const parts =
|
|
341
|
+
const parts = drawn.map((chart) => ({ ...serialize(chart.svg), title: chart.title }));
|
|
302
342
|
const width = Math.max(...parts.map((part) => part.width)) + pad * 2;
|
|
303
|
-
const height = parts.reduce((total, part) => total + part.height + pad, pad) + head;
|
|
343
|
+
const height = parts.reduce((total, part) => total + part.height + pad + titleGap(part.title), pad) + head;
|
|
304
344
|
const canvas = document.createElement("canvas");
|
|
305
345
|
canvas.width = width * scale;
|
|
306
346
|
canvas.height = height * scale;
|
|
@@ -321,6 +361,12 @@ export function useRmExport() {
|
|
|
321
361
|
}
|
|
322
362
|
let y = head + pad;
|
|
323
363
|
for (const part of parts) {
|
|
364
|
+
if (part.title) {
|
|
365
|
+
context.fillStyle = "#1A1A2E";
|
|
366
|
+
context.font = "bold 14px Figtree, Helvetica, sans-serif";
|
|
367
|
+
context.fillText(part.title, pad, y + 12);
|
|
368
|
+
y += titleGap(part.title);
|
|
369
|
+
}
|
|
324
370
|
const raw = await raster(part.markup, part.width, part.height, scale);
|
|
325
371
|
context.drawImage(raw, pad, y, part.width, part.height);
|
|
326
372
|
y += part.height + pad;
|
|
@@ -332,19 +378,21 @@ export function useRmExport() {
|
|
|
332
378
|
return { fileName, rows: 0, bytes: download(blob, fileName) };
|
|
333
379
|
}
|
|
334
380
|
async function toSvg(config, payload, lang) {
|
|
335
|
-
const
|
|
336
|
-
if (!
|
|
381
|
+
const drawn = drawableCharts(payload);
|
|
382
|
+
if (!drawn.length) throw new Error(lang === "en" ? "No chart on this page" : "Aucun graphique sur cette page");
|
|
337
383
|
const pad = 24;
|
|
338
384
|
const sources = sourcesOf(config, payload);
|
|
339
385
|
const head = config.options.includes("logo") ? sources.length ? 88 : 72 : 0;
|
|
340
|
-
const parts =
|
|
386
|
+
const parts = drawn.map((chart) => ({ ...serialize(chart.svg), title: chart.title }));
|
|
341
387
|
const width = Math.max(...parts.map((part) => part.width)) + pad * 2;
|
|
342
|
-
const height = parts.reduce((total, part) => total + part.height + pad, pad) + head;
|
|
388
|
+
const height = parts.reduce((total, part) => total + part.height + pad + titleGap(part.title), pad) + head;
|
|
343
389
|
let y = head + pad;
|
|
344
390
|
const nested = parts.map((part) => {
|
|
391
|
+
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>` : "";
|
|
392
|
+
y += titleGap(part.title);
|
|
345
393
|
const markup2 = part.markup.replace(/^<svg /, `<svg x="${pad}" y="${y}" `);
|
|
346
394
|
y += part.height + pad;
|
|
347
|
-
return markup2;
|
|
395
|
+
return label + markup2;
|
|
348
396
|
}).join("\n");
|
|
349
397
|
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
398
|
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 +589,58 @@ export function useRmExport() {
|
|
|
541
589
|
);
|
|
542
590
|
y += cardHeight + 6;
|
|
543
591
|
}
|
|
592
|
+
const snapshots = (payload.nodes ?? []).filter((node) => {
|
|
593
|
+
if (node.kind === "chart") return false;
|
|
594
|
+
if (node.kind === "kpi") return config.sections.includes("kpi");
|
|
595
|
+
if (node.kind === "table") return config.sections.includes("table") || config.sections.includes("cards");
|
|
596
|
+
return config.sections.includes("cards");
|
|
597
|
+
});
|
|
598
|
+
const shots = [];
|
|
599
|
+
for (const node of snapshots) {
|
|
600
|
+
const shot = await capture(node.el);
|
|
601
|
+
if (shot) shots.push(shot);
|
|
602
|
+
}
|
|
603
|
+
const faithful = shots.length > 0;
|
|
604
|
+
if (faithful) {
|
|
605
|
+
sectionTitle(lang === "en" ? "Page" : "La page");
|
|
606
|
+
for (const shot of shots) {
|
|
607
|
+
const drawWidth = inner;
|
|
608
|
+
const height = shot.height / shot.width * drawWidth;
|
|
609
|
+
const room = () => bottom - y;
|
|
610
|
+
if (height <= bottom - margin) {
|
|
611
|
+
if (height > room()) {
|
|
612
|
+
doc.addPage();
|
|
613
|
+
y = margin;
|
|
614
|
+
}
|
|
615
|
+
doc.addImage(shot.toDataURL("image/png"), "PNG", margin, y, drawWidth, height, void 0, "FAST");
|
|
616
|
+
y += height + 6;
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
let drawn = 0;
|
|
620
|
+
while (drawn < height - 0.5) {
|
|
621
|
+
if (room() < 20) {
|
|
622
|
+
doc.addPage();
|
|
623
|
+
y = margin;
|
|
624
|
+
}
|
|
625
|
+
const band = Math.min(room(), height - drawn);
|
|
626
|
+
doc.addImage(
|
|
627
|
+
slice(shot, drawn / height * shot.height, band / height * shot.height),
|
|
628
|
+
"PNG",
|
|
629
|
+
margin,
|
|
630
|
+
y,
|
|
631
|
+
drawWidth,
|
|
632
|
+
band,
|
|
633
|
+
void 0,
|
|
634
|
+
"FAST"
|
|
635
|
+
);
|
|
636
|
+
drawn += band;
|
|
637
|
+
y += band;
|
|
638
|
+
}
|
|
639
|
+
y += 6;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
544
642
|
let rowCount = 0;
|
|
545
|
-
if (config.sections.includes("cards")) {
|
|
643
|
+
if (config.sections.includes("cards") && !faithful) {
|
|
546
644
|
const cards = cardsOf(payload, config, lang);
|
|
547
645
|
if (cards.length) {
|
|
548
646
|
if (y + 12 > bottom) {
|
|
@@ -754,7 +852,7 @@ export function useRmExport() {
|
|
|
754
852
|
y += 6;
|
|
755
853
|
}
|
|
756
854
|
}
|
|
757
|
-
if (config.sections.includes("table")) {
|
|
855
|
+
if (config.sections.includes("table") && !faithful) {
|
|
758
856
|
const MAX_COLUMNS = landscape ? 16 : 10;
|
|
759
857
|
payload.sheets.forEach((sheet) => {
|
|
760
858
|
const all = columnsOf(sheet, config.columns);
|
|
@@ -838,6 +936,10 @@ export function useRmExport() {
|
|
|
838
936
|
});
|
|
839
937
|
}
|
|
840
938
|
const pages = doc.getNumberOfPages();
|
|
939
|
+
const footList = sourcesOf(config, payload);
|
|
940
|
+
const footSources = footList.length ? printable(
|
|
941
|
+
`Source${footList.length > 1 ? "s" : ""} : ${footList.map((source) => sourceLabel(source, lang)).join(" \xB7 ")}`
|
|
942
|
+
) : "";
|
|
841
943
|
for (let page = 1; page <= pages; page += 1) {
|
|
842
944
|
doc.setPage(page);
|
|
843
945
|
const width = doc.internal.pageSize.getWidth();
|
|
@@ -854,6 +956,13 @@ export function useRmExport() {
|
|
|
854
956
|
)[0] ?? "";
|
|
855
957
|
doc.text(trail, margin, foot);
|
|
856
958
|
doc.text(`${page} / ${pages}`, width - margin, foot, { align: "right" });
|
|
959
|
+
if (footSources) {
|
|
960
|
+
doc.text(
|
|
961
|
+
doc.splitTextToSize(footSources, width - margin * 2)[0] ?? "",
|
|
962
|
+
margin,
|
|
963
|
+
foot - 8.5
|
|
964
|
+
);
|
|
965
|
+
}
|
|
857
966
|
}
|
|
858
967
|
const fileName = `${config.fileName}.pdf`;
|
|
859
968
|
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.180",
|
|
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"
|