@massimo-cassandro/minimo 1.31.0 → 1.31.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.
@@ -1,5 +1,5 @@
1
1
  import { parseStdAxisOpts } from './helpers/parse-std-axis-opts.js';
2
- import { parseContainer } from './helpers/chart-utils.js';
2
+ import { parseContainer, waitForContainerSize } from './helpers/chart-utils.js';
3
3
  import { cartesianAxis } from './helpers/cartesian-axis.js';
4
4
  import { legenda } from './helpers/legenda.js';
5
5
 
@@ -149,7 +149,7 @@ const default_params = {
149
149
  Null per nessuna eleborazione.
150
150
  La funzione di default assume che il valore sia di tipo numerico
151
151
  */
152
- labelYFormatter: etiValue => Math.ceil(etiValue / 1e3)
152
+ labelYFormatter: etiValue => (Math.ceil(etiValue / 1e3) || 0) // `|| 0` normalizza -0 (altrimenti mostrato come "-0")
153
153
  .toLocaleString('it-IT', {
154
154
  minimumFractionDigits: 0,
155
155
  maximumFractionDigits: 0
@@ -185,13 +185,15 @@ export async function bars(params) {
185
185
  }
186
186
 
187
187
  // container
188
- [, params.width, params.height] = parseContainer({ container: params.container, width: params.width, height: params.height });
188
+ let containerElement;
189
+ [containerElement, params.width, params.height] = parseContainer({ container: params.container, width: params.width, height: params.height });
189
190
 
190
-
191
- if(!params.width || !params.height) {
191
+ if(!containerElement && (!params.width || !params.height)) {
192
192
  throw `width e/o height mancanti: width: ${params.width}, height: ${params.height}`;
193
193
  }
194
194
 
195
+ ({ width: params.width, height: params.height } = await waitForContainerSize(containerElement, { width: params.width, height: params.height }, params.debug));
196
+
195
197
  // =>> legenda
196
198
  // costruzione delle opzioni per la legenda
197
199
  const legenda_params = {
@@ -1,7 +1,7 @@
1
1
  // mostra un triangolo rettangolo disposto orizzontalmente che mostra
2
2
  // la porzione di raggiungimento di un obiettivo
3
3
 
4
- import { parseContainer, getElementFromContainer } from './helpers/chart-utils.js';
4
+ import { parseContainer, getElementFromContainer, waitForContainerSize } from './helpers/chart-utils.js';
5
5
  import { createTextEl } from './helpers/create-text-element.js';
6
6
 
7
7
  export async function goal({
@@ -158,11 +158,12 @@ export async function goal({
158
158
  // calcolo width
159
159
  [, width] = parseContainer({ container: container, width: width, height: height });
160
160
 
161
-
162
- if(!width || !height) {
161
+ if(!container && (!width || !height)) {
163
162
  throw `width e/o height mancanti: width: ${width}, height: ${height} (chartHeight: ${chartHeight})`;
164
163
  }
165
164
 
165
+ ({ width, height } = await waitForContainerSize(container, { width, height }, debug));
166
+
166
167
  // larghezza iniziale grafico
167
168
  // al netto del padding orizzontale pari a 1/2 cursore, in modo che sia visibile interamente
168
169
  // quando posizionato agli estremi (anche in presenta di etichetta laterale, nel caso quest'ultima sia più alta del grafico)
@@ -2,7 +2,7 @@
2
2
  // categorie sull'asse verticale (a sinistra), valori sull'asse orizzontale (in basso)
3
3
 
4
4
  import { parseStdAxisOpts } from './helpers/parse-std-axis-opts.js';
5
- import { parseContainer } from './helpers/chart-utils.js';
5
+ import { parseContainer, waitForContainerSize } from './helpers/chart-utils.js';
6
6
  import { cartesianAxis } from './helpers/cartesian-axis.js';
7
7
  import { legenda } from './helpers/legenda.js';
8
8
 
@@ -150,7 +150,7 @@ const default_params = {
150
150
  Null per nessuna eleborazione.
151
151
  La funzione di default assume che il valore sia di tipo numerico
152
152
  */
153
- labelYFormatter: etiValue => Math.ceil(etiValue / 1e3)
153
+ labelYFormatter: etiValue => (Math.ceil(etiValue / 1e3) || 0) // `|| 0` normalizza -0 (altrimenti mostrato come "-0")
154
154
  .toLocaleString('it-IT', {
155
155
  minimumFractionDigits: 0,
156
156
  maximumFractionDigits: 0
@@ -186,13 +186,15 @@ export async function hbars(params) {
186
186
  }
187
187
 
188
188
  // container
189
- [, params.width, params.height] = parseContainer({ container: params.container, width: params.width, height: params.height });
189
+ let containerElement;
190
+ [containerElement, params.width, params.height] = parseContainer({ container: params.container, width: params.width, height: params.height });
190
191
 
191
-
192
- if(!params.width || !params.height) {
192
+ if(!containerElement && (!params.width || !params.height)) {
193
193
  throw `width e/o height mancanti: width: ${params.width}, height: ${params.height}`;
194
194
  }
195
195
 
196
+ ({ width: params.width, height: params.height } = await waitForContainerSize(containerElement, { width: params.width, height: params.height }, params.debug));
197
+
196
198
  // =>> legenda
197
199
  // costruzione delle opzioni per la legenda
198
200
  const legenda_params = {
@@ -375,6 +375,15 @@ async function cartesianAxisHorizontal(chartInstance, {
375
375
  chart_area.bottom + ticksLength + 2 // 2 è un distanziatore tra l'etichetta e la linea
376
376
  );
377
377
 
378
+ // eventuale correzione ultima etichetta (evita che esca dal margine destro dell'svg)
379
+ if(stepIdx === stepY_count) {
380
+ const labelX2 = labelEl.bbox().x2;
381
+
382
+ if(labelX2 > width - padding) {
383
+ labelEl.dx(-(labelX2 - width + padding/2));
384
+ }
385
+ }
386
+
378
387
  // =>> griglia verticale (ortogonale all'asse valori)
379
388
  // viene omessa solo la linea che coincide con l'asse categorie (la linea dello zero)
380
389
  if(showYgrid && Math.abs(x - zero_x) > 0.01) {
@@ -155,3 +155,50 @@ export function parseContainer({ container = null, width = null, height = null }
155
155
 
156
156
  return [containerElement, width, height];
157
157
  }
158
+
159
+ /**
160
+ * Attende che il container abbia dimensioni valide, utile quando è temporaneamente
161
+ * nascosto (es. `display: none` dentro un tab o un pannello non ancora attivo) al
162
+ * momento della creazione del grafico. Se `width`/`height` sono già entrambe valide
163
+ * risolve immediatamente, altrimenti osserva il container con un `ResizeObserver` ed
164
+ * attende che torni visibile. Non ha timeout: se il container non torna mai visibile
165
+ * la promise resta in sospeso.
166
+ * @param {Element|null} containerElement - L'elemento container (può essere null).
167
+ * @param {Object} size - Dimensioni già note.
168
+ * @param {number|null} size.width - Larghezza già nota (se valida, non si attende il container).
169
+ * @param {number|null} size.height - Altezza già nota (se valida, non si attende il container).
170
+ * @param {boolean} [debug=false] - Se true, logga in console quando l'attesa ha inizio. (default: false)
171
+ * @returns {Promise<{width: number, height: number}>} Le dimensioni effettive una volta disponibili.
172
+ */
173
+ export function waitForContainerSize(containerElement, { width = null, height = null } = {}, debug = false) {
174
+ if (width && height) {
175
+ return Promise.resolve({ width, height });
176
+ }
177
+
178
+ if (!containerElement) {
179
+ return Promise.resolve({ width, height });
180
+ }
181
+
182
+ return new Promise(resolve => {
183
+
184
+ if (debug) {
185
+ // eslint-disable-next-line no-console
186
+ console.warn('MinimoCharts → in attesa che il container ottenga dimensioni valide (es. tab/pannello nascosto)', containerElement);
187
+ }
188
+
189
+ const observer = new ResizeObserver(entries => {
190
+ for (const entry of entries) {
191
+ const observedWidth = width || entry.contentRect.width;
192
+ const observedHeight = height || entry.contentRect.height;
193
+
194
+ if (observedWidth && observedHeight) {
195
+ observer.disconnect();
196
+ resolve({ width: observedWidth, height: observedHeight });
197
+ return;
198
+ }
199
+ }
200
+ });
201
+
202
+ observer.observe(containerElement);
203
+ });
204
+ }
@@ -1,5 +1,5 @@
1
1
  import { parseStdAxisOpts } from './helpers/parse-std-axis-opts.js';
2
- import { parseContainer } from './helpers/chart-utils.js';
2
+ import { parseContainer, waitForContainerSize } from './helpers/chart-utils.js';
3
3
  import { cartesianAxis } from './helpers/cartesian-axis.js';
4
4
  import { legenda } from './helpers/legenda.js';
5
5
 
@@ -165,7 +165,7 @@ const default_params = {
165
165
  Null per nessuna eleborazione.
166
166
  La funzione di default assume che il valore sia di tipo numerico
167
167
  */
168
- labelYFormatter: etiValue => Math.ceil(etiValue / 1e3)
168
+ labelYFormatter: etiValue => (Math.ceil(etiValue / 1e3) || 0) // `|| 0` normalizza -0 (altrimenti mostrato come "-0")
169
169
  .toLocaleString('it-IT', {
170
170
  minimumFractionDigits: 0,
171
171
  maximumFractionDigits: 0
@@ -196,12 +196,15 @@ export async function lines(params) {
196
196
 
197
197
 
198
198
  // container
199
- [, params.width, params.height] = parseContainer({ container: params.container, width: params.width, height: params.height });
199
+ let containerElement;
200
+ [containerElement, params.width, params.height] = parseContainer({ container: params.container, width: params.width, height: params.height });
200
201
 
201
- if(!params.width || !params.height) {
202
+ if(!containerElement && (!params.width || !params.height)) {
202
203
  throw `width e/o height mancanti: width: ${params.width}, height: ${params.height}`;
203
204
  }
204
205
 
206
+ ({ width: params.width, height: params.height } = await waitForContainerSize(containerElement, { width: params.width, height: params.height }, params.debug));
207
+
205
208
  // =>> ricalcolo data_lines_attrs (utilizzato anche per le linee della legenda)
206
209
  const default_line_width = params.data_lines_attrs['stroke-width']?? 1;
207
210
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massimo-cassandro/minimo",
3
- "version": "1.31.0",
3
+ "version": "1.31.2",
4
4
  "description": "Light css framework & utilities",
5
5
  "type": "module",
6
6
  "main": "./index.js",