zmiany1
This commit is contained in:
File diff suppressed because it is too large
Load Diff
416
static/css/style_old.css
Normal file
416
static/css/style_old.css
Normal file
@@ -0,0 +1,416 @@
|
||||
/* --- Rozmiary i kursory --- */
|
||||
.large-checkbox {
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
}
|
||||
|
||||
.clickable-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* --- Kolory tła (nadpisane klasy Bootstrapa) --- */
|
||||
.bg-success {
|
||||
background-color: #1e7e34 !important;
|
||||
}
|
||||
|
||||
.btn-outline-light:hover {
|
||||
background-color: #ffc107 !important;
|
||||
color: #000 !important;
|
||||
border-color: #ffc107 !important;
|
||||
}
|
||||
|
||||
.progress-dark {
|
||||
background-color: #212529 !important;
|
||||
border-radius: 20px !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
border-radius: 0 !important;
|
||||
transition: width 0.4s ease, background-color 0.4s ease;
|
||||
}
|
||||
|
||||
.progress-bar:first-child {
|
||||
border-top-left-radius: 20px !important;
|
||||
border-bottom-left-radius: 20px !important;
|
||||
}
|
||||
|
||||
.progress-bar:last-child {
|
||||
border-top-right-radius: 20px !important;
|
||||
border-bottom-right-radius: 20px !important;
|
||||
}
|
||||
|
||||
|
||||
/* rodzic już ma position-relative */
|
||||
.progress-label {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: none;
|
||||
/* klikalne przyciski obok paska nie ucierpią */
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.progress-thin {
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.item-not-checked {
|
||||
background-color: #2c2f33 !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
/* --- Styl przycisku wyboru pliku --- */
|
||||
input[type="file"]::file-selector-button {
|
||||
background-color: #225d36;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 0.5em 1em;
|
||||
border-radius: 4px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
/* --- Ciemniejsze alerty Bootstrapa --- */
|
||||
.alert-success {
|
||||
background-color: #225d36 !important;
|
||||
color: #eaffea !important;
|
||||
border-color: #174428 !important;
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
background-color: #7a1f23 !important;
|
||||
color: #ffeaea !important;
|
||||
border-color: #531417 !important;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
background-color: #1d3a4d !important;
|
||||
color: #eaf6ff !important;
|
||||
border-color: #152837 !important;
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
background-color: #665c1e !important;
|
||||
color: #fffbe5 !important;
|
||||
border-color: #4d4415 !important;
|
||||
}
|
||||
|
||||
/* Badge - kolory pasujące do ciemnych alertów */
|
||||
.badge.bg-success,
|
||||
.badge.text-bg-success {
|
||||
background-color: #225d36 !important;
|
||||
color: #eaffea !important;
|
||||
}
|
||||
|
||||
.badge.bg-danger,
|
||||
.badge.text-bg-danger {
|
||||
background-color: #7a1f23 !important;
|
||||
color: #ffeaea !important;
|
||||
}
|
||||
|
||||
.badge.bg-info,
|
||||
.badge.text-bg-info {
|
||||
background-color: #1d3a4d !important;
|
||||
color: #eaf6ff !important;
|
||||
}
|
||||
|
||||
.badge.bg-warning,
|
||||
.badge.text-bg-warning {
|
||||
background-color: #665c1e !important;
|
||||
color: #fffbe5 !important;
|
||||
}
|
||||
|
||||
.badge.bg-secondary,
|
||||
.badge.text-bg-secondary {
|
||||
background-color: #343a40 !important;
|
||||
color: #e2e3e5 !important;
|
||||
}
|
||||
|
||||
.badge.bg-primary,
|
||||
.badge.text-bg-primary {
|
||||
background-color: #184076 !important;
|
||||
color: #e6f0ff !important;
|
||||
}
|
||||
|
||||
.badge.bg-light,
|
||||
.badge.text-bg-light {
|
||||
background-color: #444950 !important;
|
||||
color: #f8f9fa !important;
|
||||
}
|
||||
|
||||
.badge.bg-dark,
|
||||
.badge.text-bg-dark {
|
||||
background-color: #181a1b !important;
|
||||
color: #f8f9fa !important;
|
||||
}
|
||||
|
||||
/* --- Styl dla własnych checkboxów --- */
|
||||
input[type="checkbox"].large-checkbox {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
input[type="checkbox"].large-checkbox::before {
|
||||
content: '✗';
|
||||
color: #dc3545;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
line-height: 1;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
|
||||
input[type="checkbox"].large-checkbox:checked::before {
|
||||
content: '✓';
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
input[type="checkbox"].large-checkbox:disabled::before {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
input[type="checkbox"].large-checkbox:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
#tempToggle {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
input.form-control {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.info-bar-fixed {
|
||||
width: 100%;
|
||||
color: #f8f9fa;
|
||||
background-color: #212529;
|
||||
border-radius: 12px 12px 0 0;
|
||||
text-align: center;
|
||||
padding: 10px 10px;
|
||||
font-size: 0.95rem;
|
||||
box-sizing: border-box;
|
||||
margin-top: 2rem;
|
||||
box-shadow: 0 -1px 4px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.info-bar-fixed {
|
||||
position: static;
|
||||
font-size: 0.85rem;
|
||||
padding: 8px 4px;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.table-responsive table {
|
||||
min-width: 1000px;
|
||||
}
|
||||
|
||||
.bg-dark .form-control::placeholder {
|
||||
color: #ccc !important;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.toast-body {
|
||||
color: #ffffff !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
.toast {
|
||||
animation: fadeInUp 0.5s ease;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
#mass-add-list li.active {
|
||||
background: #198754 !important;
|
||||
color: #fff !important;
|
||||
border: 1px solid #000000 !important;
|
||||
}
|
||||
|
||||
#mass-add-list li {
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.quantity-input {
|
||||
width: 60px;
|
||||
background: #343a40;
|
||||
color: #fff;
|
||||
border: 1px solid #495057;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.quantity-controls {
|
||||
min-width: 120px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.list-group-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#empty-placeholder {
|
||||
font-style: italic;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#items li.hide-purchased {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.list-group-item:first-child,
|
||||
.list-group-item:last-child {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.fade-out {
|
||||
opacity: 0;
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
|
||||
@media (pointer: fine) {
|
||||
.only-mobile {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.ts-dropdown .active {
|
||||
background-color: #495057 !important;
|
||||
}
|
||||
|
||||
.pagination-dark .page-link {
|
||||
color: #fff;
|
||||
background-color: #212529;
|
||||
border: 1px solid #495057;
|
||||
}
|
||||
|
||||
.pagination-dark .page-link:hover {
|
||||
background-color: #343a40;
|
||||
border-color: #6c757d;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.pagination-dark .page-item.active .page-link {
|
||||
background-color: #0d6efd;
|
||||
border-color: #0d6efd;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.pagination-dark .page-item.disabled .page-link {
|
||||
background-color: #2b3035;
|
||||
border-color: #495057;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.tom-dark .ts-control {
|
||||
background-color: #212529 !important;
|
||||
color: #fff !important;
|
||||
border: 1px solid #495057 !important;
|
||||
border-radius: 0.375rem;
|
||||
min-height: 38px;
|
||||
padding: 0.25rem 0.5rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tom-dark .ts-control .item {
|
||||
background-color: #343a40 !important;
|
||||
color: #fff !important;
|
||||
border-radius: 0.25rem;
|
||||
padding: 2px 8px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.ts-dropdown {
|
||||
background-color: #212529 !important;
|
||||
color: #fff !important;
|
||||
border: 1px solid #495057;
|
||||
border-radius: 0.375rem;
|
||||
z-index: 9999 !important;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.ts-dropdown .active {
|
||||
background-color: #495057 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
td select.tom-dark {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.table-dark.table-striped tbody tr:nth-of-type(odd) {
|
||||
background-color: rgba(255, 255, 255, 0.025);
|
||||
}
|
||||
|
||||
.table-dark tbody tr:hover {
|
||||
background-color: rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
.table-dark thead th {
|
||||
background-color: #1c1f22;
|
||||
color: #e1e1e1;
|
||||
font-weight: 500;
|
||||
border-bottom: 1px solid #3a3f44;
|
||||
}
|
||||
|
||||
.table-dark td,
|
||||
.table-dark th {
|
||||
padding: 0.6rem 0.75rem;
|
||||
vertical-align: middle;
|
||||
border-top: 1px solid #3a3f44;
|
||||
}
|
||||
|
||||
.card .table {
|
||||
border-radius: 0 !important;
|
||||
overflow: hidden;
|
||||
margin-bottom: 0;
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Znajdź przyciski
|
||||
const toggleMonthlySplit = document.getElementById('toggleMonthlySplit');
|
||||
const toggleDailySplit = document.getElementById('toggleDailySplit');
|
||||
const toggleCategorySplit = document.getElementById('toggleCategorySplit');
|
||||
|
||||
// Funkcja ustawiająca aktywność przycisków podziału czasu
|
||||
function setActiveTimeSplit(active) {
|
||||
if (active === 'monthly') {
|
||||
toggleMonthlySplit.classList.add('btn-primary');
|
||||
toggleMonthlySplit.classList.remove('btn-outline-light');
|
||||
toggleMonthlySplit.setAttribute('aria-pressed', 'true');
|
||||
|
||||
toggleDailySplit.classList.remove('btn-primary');
|
||||
toggleDailySplit.classList.add('btn-outline-light');
|
||||
toggleDailySplit.setAttribute('aria-pressed', 'false');
|
||||
} else if (active === 'daily') {
|
||||
toggleDailySplit.classList.add('btn-primary');
|
||||
toggleDailySplit.classList.remove('btn-outline-light');
|
||||
toggleDailySplit.setAttribute('aria-pressed', 'true');
|
||||
|
||||
toggleMonthlySplit.classList.remove('btn-primary');
|
||||
toggleMonthlySplit.classList.add('btn-outline-light');
|
||||
toggleMonthlySplit.setAttribute('aria-pressed', 'false');
|
||||
}
|
||||
}
|
||||
|
||||
// Obsługa kliknięć przycisków czasu
|
||||
toggleMonthlySplit.addEventListener('click', function() {
|
||||
setActiveTimeSplit('monthly');
|
||||
loadExpenses('monthly');
|
||||
});
|
||||
|
||||
toggleDailySplit.addEventListener('click', function() {
|
||||
setActiveTimeSplit('daily');
|
||||
loadExpenses('daily');
|
||||
});
|
||||
|
||||
// Obsługa kliknięcia przycisku podziału kategorii
|
||||
toggleCategorySplit.addEventListener('click', function() {
|
||||
const isActive = this.classList.contains('btn-primary');
|
||||
if (isActive) {
|
||||
this.classList.remove('btn-primary');
|
||||
this.classList.add('btn-outline-light');
|
||||
this.setAttribute('aria-pressed', 'false');
|
||||
loadExpenses(); // wyłącz podział kategorii
|
||||
} else {
|
||||
this.classList.add('btn-primary');
|
||||
this.classList.remove('btn-outline-light');
|
||||
this.setAttribute('aria-pressed', 'true');
|
||||
loadExpenses({ bycategory: true }); // włącz podział kategorii
|
||||
}
|
||||
});
|
||||
|
||||
// Inicjalizacja - domyślnie ustaw podział dzienny
|
||||
setActiveTimeSplit('daily');
|
||||
loadExpenses('daily');
|
||||
});
|
67
static/js/download_chart.js
Normal file
67
static/js/download_chart.js
Normal file
@@ -0,0 +1,67 @@
|
||||
// download_chart.js — eksport PNG z ciemnym tłem (tymczasowo), bez wielokrotnego bindowania
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const dlBtn = document.getElementById("downloadMainChartBtn");
|
||||
if (!dlBtn) return;
|
||||
|
||||
// helper: bezpieczna nazwa pliku
|
||||
const sanitize = (s) =>
|
||||
(s || "")
|
||||
.normalize("NFD").replace(/[\u0300-\u036f]/g, "")
|
||||
.replace(/[^a-zA-Z0-9-_]+/g, "_")
|
||||
.replace(/_+/g, "_").replace(/^_+|_+$/g, "");
|
||||
|
||||
// helper: eksport z tymczasowym tłem
|
||||
const exportChartPNG = (chart, bgColor = "#1e1e1e") => {
|
||||
const canvas = chart.canvas;
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
// 1) zapisz obraz
|
||||
const snapshot = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
|
||||
// 2) podłóż tło pod istniejący rysunek
|
||||
ctx.save();
|
||||
ctx.globalCompositeOperation = "destination-over";
|
||||
ctx.fillStyle = bgColor;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.restore();
|
||||
|
||||
// 3) wygeneruj PNG
|
||||
const dataUrl = chart.toBase64Image("image/png", 1.0);
|
||||
|
||||
// 4) przywróć pierwotny obraz (transparentny)
|
||||
ctx.putImageData(snapshot, 0, 0);
|
||||
|
||||
return dataUrl;
|
||||
};
|
||||
|
||||
// jednorazowe bindowanie click
|
||||
if (!dlBtn.dataset.bound) {
|
||||
dlBtn.addEventListener("click", () => {
|
||||
const chart = window.expensesChart || Chart.getChart(document.getElementById("expensesChart"));
|
||||
if (!chart) return;
|
||||
|
||||
// nazwa: zakres + timestamp
|
||||
const now = new Date();
|
||||
const pad = (n) => String(n).padStart(2, "0");
|
||||
const stamp = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}_${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
|
||||
const rangeLabel = document.getElementById("chartRangeLabel")?.textContent || "";
|
||||
const filename = `wydatki-${sanitize(rangeLabel)}-${stamp}.png`;
|
||||
|
||||
// (opcjonalnie) upewnij się, że layout jest świeży
|
||||
chart.resize();
|
||||
chart.update("none");
|
||||
|
||||
const a = document.createElement("a");
|
||||
a.href = exportChartPNG(chart, "#1e1e1e"); // tu ustawiasz kolor tła eksportu
|
||||
a.download = filename;
|
||||
a.click();
|
||||
});
|
||||
dlBtn.dataset.bound = "1";
|
||||
}
|
||||
|
||||
// aktywuj przycisk, gdy wykres istnieje
|
||||
const enableIfReady = () => { dlBtn.disabled = !window.expensesChart; };
|
||||
document.addEventListener("expensesChart:ready", enableIfReady);
|
||||
enableIfReady();
|
||||
});
|
@@ -89,7 +89,9 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
.then((data) => {
|
||||
if (!ctx) return;
|
||||
|
||||
if (expensesChart) expensesChart.destroy();
|
||||
if (expensesChart) { expensesChart.destroy(); window.expensesChart = null; }
|
||||
|
||||
//if (expensesChart) expensesChart.destroy();
|
||||
|
||||
const tooltipOptions = {
|
||||
mode: "index",
|
||||
@@ -105,6 +107,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
if (categorySplit) {
|
||||
// Stacked per-kategoria – backend zwraca datasets z labelami kategorii :contentReference[oaicite:6]{index=6}
|
||||
expensesChart = new Chart(ctx, {
|
||||
|
||||
type: "bar",
|
||||
data: { labels: data.labels || [], datasets: data.datasets || [] },
|
||||
options: {
|
||||
@@ -116,6 +119,7 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
} else {
|
||||
// Całościowo – backend zwraca labels + expenses (sumy) :contentReference[oaicite:7]{index=7}
|
||||
expensesChart = new Chart(ctx, {
|
||||
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: data.labels || [],
|
||||
@@ -132,6 +136,10 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
});
|
||||
}
|
||||
|
||||
// na potrzeby otwarciu w modalu
|
||||
window.expensesChart = expensesChart;
|
||||
document.dispatchEvent(new Event('expensesChart:ready'));
|
||||
|
||||
applyRangeLabel(range, startDate, endDate);
|
||||
})
|
||||
.catch((e) => console.error("Błąd pobierania danych:", e));
|
||||
|
118
static/js/modal_chart.js
Normal file
118
static/js/modal_chart.js
Normal file
@@ -0,0 +1,118 @@
|
||||
// modal_chart.js — final: kopiuje kolory z oryginałów, bez fallbacków i bez debugów
|
||||
|
||||
function openChartFullscreen(sourceChartIdOrKey, title) {
|
||||
const modalEl = document.getElementById("chartFullscreenModal");
|
||||
const canvas = document.getElementById("chartFullscreenCanvas");
|
||||
const titleEl = document.getElementById("chartModalTitle");
|
||||
if (titleEl) titleEl.textContent = title || "Wykres";
|
||||
|
||||
// Znajdź wykres źródłowy (po elemencie, id Chart.js lub globalu)
|
||||
const srcEl = document.getElementById(sourceChartIdOrKey);
|
||||
const srcChart =
|
||||
(srcEl && Chart.getChart(srcEl)) ||
|
||||
Chart.getChart(sourceChartIdOrKey) ||
|
||||
window[sourceChartIdOrKey] ||
|
||||
window.expensesChart ||
|
||||
null;
|
||||
|
||||
if (!srcChart) {
|
||||
bootstrap.Modal.getOrCreateInstance(modalEl).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// Skopiuj labels i datasets 1:1 (tylko bezpieczne klucze, żeby nie przenosić referencji Chart.js)
|
||||
const safeDataset = (d) => {
|
||||
const out = {
|
||||
// dane i opis
|
||||
label: d.label,
|
||||
data: Array.isArray(d.data) ? d.data.slice() : [],
|
||||
type: d.type,
|
||||
// kolory / styl — dokładnie z oryginału, jeśli były
|
||||
backgroundColor: d.backgroundColor,
|
||||
borderColor: d.borderColor,
|
||||
borderWidth: d.borderWidth,
|
||||
borderSkipped: d.borderSkipped,
|
||||
// stacking / kolejność
|
||||
stack: d.stack,
|
||||
order: d.order,
|
||||
// wszystko co może być ważne dla Twoich barów/konfiguracji
|
||||
parsing: d.parsing,
|
||||
indexAxis: d.indexAxis,
|
||||
};
|
||||
// usuń klucze undefined (Chart.js lubi czyste configi)
|
||||
Object.keys(out).forEach((k) => out[k] === undefined && delete out[k]);
|
||||
return out;
|
||||
};
|
||||
|
||||
const freshData = {
|
||||
labels: Array.isArray(srcChart.data?.labels) ? srcChart.data.labels.slice() : [],
|
||||
datasets: (srcChart.data?.datasets || []).map(safeDataset),
|
||||
};
|
||||
|
||||
// Typ wykresu z oryginału (np. "bar")
|
||||
const chartType = (srcChart.config && srcChart.config.type) || "bar";
|
||||
|
||||
// Minimalne, bezpieczne opcje: responsywność + stacking + orientacja
|
||||
const scx = srcChart.config?.options?.scales?.x || {};
|
||||
const scy = srcChart.config?.options?.scales?.y || {};
|
||||
|
||||
const freshOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
// jeżeli oryginał miał pion/poziom, zachowaj
|
||||
indexAxis: srcChart.config?.options?.indexAxis || "x",
|
||||
// nie kopiujemy całych pluginów (unikamy referencji) — domyślne legend/tooltip są OK
|
||||
plugins: {},
|
||||
scales: {
|
||||
x: { stacked: !!scx.stacked },
|
||||
y: { stacked: !!scy.stacked, beginAtZero: scy.beginAtZero !== false },
|
||||
},
|
||||
};
|
||||
|
||||
// Helper: zniszcz wykres na canvasie modala, jeśli istnieje
|
||||
const destroyOnCanvas = () => {
|
||||
if (canvas._chartInstance) {
|
||||
try { canvas._chartInstance.destroy(); } catch { }
|
||||
canvas._chartInstance = null;
|
||||
}
|
||||
const existing = Chart.getChart(canvas);
|
||||
if (existing) {
|
||||
try { existing.destroy(); } catch { }
|
||||
}
|
||||
};
|
||||
destroyOnCanvas();
|
||||
|
||||
// Po pokazaniu modala twórz wykres (gdy ma już wymiary)
|
||||
const onShown = () => {
|
||||
destroyOnCanvas();
|
||||
const ctx = canvas.getContext("2d");
|
||||
canvas._chartInstance = new Chart(ctx, {
|
||||
type: chartType,
|
||||
data: freshData,
|
||||
options: freshOptions,
|
||||
});
|
||||
// lekki nudge layoutu
|
||||
requestAnimationFrame(() => {
|
||||
canvas._chartInstance.resize();
|
||||
canvas._chartInstance.update();
|
||||
});
|
||||
};
|
||||
|
||||
const onHidden = () => { destroyOnCanvas(); };
|
||||
|
||||
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
|
||||
modalEl.addEventListener("shown.bs.modal", onShown, { once: true });
|
||||
modalEl.addEventListener("hidden.bs.modal", onHidden, { once: true });
|
||||
|
||||
modal.show();
|
||||
}
|
||||
|
||||
// Odblokuj ⛶ gdy bazowy wykres gotowy
|
||||
document.addEventListener("expensesChart:ready", () => {
|
||||
const b = document.getElementById("openFsBtn");
|
||||
if (b) b.disabled = false;
|
||||
});
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const b = document.getElementById("openFsBtn");
|
||||
if (b && window.expensesChart) b.disabled = false;
|
||||
});
|
Reference in New Issue
Block a user