@malinconico/nmcharts 2.4.0 → 2.5.0

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/nmcharts.d.ts CHANGED
@@ -39,8 +39,8 @@ interface NMChartsOptions {
39
39
  interface NMChartsInstance {
40
40
  render(): void;
41
41
  exportPNG(filename?: string): void;
42
- /** Export chart as SVG file (raster image embedded in SVG wrapper) */
43
- exportSVG(filename?: string): void;
42
+ /** Export chart as SVG file (requires nmcharts-extras.js) */
43
+ exportSVG?(filename?: string): void;
44
44
  setDarkMode(enabled: boolean): void;
45
45
  updateSeries(series: NMChartsSeries[]): void;
46
46
  destroy(): void;
@@ -79,6 +79,8 @@ interface NMCategoryOptions {
79
79
  gridColor?: string;
80
80
  gridDashed?: boolean;
81
81
  colors?: string[];
82
+ zoomPan?: boolean;
83
+ annotations?: NMAnnotation[];
82
84
  barWidth?: number;
83
85
  barGap?: number;
84
86
  groupPadding?: number;
@@ -314,6 +316,69 @@ interface NMLinkInstance {
314
316
  destroy(): void;
315
317
  }
316
318
 
319
+ interface NMBookingTimelineOptions {
320
+ title?: string;
321
+ month?: number;
322
+ year?: number;
323
+ properties?: Array<{
324
+ name: string;
325
+ location?: string;
326
+ rating?: number;
327
+ avatar?: string;
328
+ color?: string;
329
+ }>;
330
+ bookings?: Array<{
331
+ property: number;
332
+ guest?: string;
333
+ checkIn: string;
334
+ checkOut: string;
335
+ status?: 'confirmed' | 'pending' | 'checked-in' | 'checked-out' | 'cancelled' | 'blocked';
336
+ price?: string;
337
+ platform?: 'airbnb' | 'booking' | 'direct' | string;
338
+ color?: string;
339
+ guestAvatar?: string;
340
+ nights?: number;
341
+ }>;
342
+ cellWidth?: number;
343
+ rowHeight?: number;
344
+ avatarSize?: number;
345
+ statusColors?: Record<string, string>;
346
+ onBookingClick?: (booking: any) => void;
347
+ }
348
+
349
+ interface NMBookingTimelineInstance {
350
+ destroy(): void;
351
+ }
352
+
353
+ interface NMAnnotation {
354
+ type: 'line' | 'band' | 'vline' | 'marker';
355
+ value?: number;
356
+ from?: number;
357
+ to?: number;
358
+ category?: string | number;
359
+ color?: string;
360
+ label?: string;
361
+ labelColor?: string;
362
+ labelAlign?: string;
363
+ lineWidth?: number;
364
+ dash?: number[];
365
+ radius?: number;
366
+ }
367
+
368
+ interface NMDiagnosticResult {
369
+ nmchartsLoaded: boolean;
370
+ version: string;
371
+ debug: boolean;
372
+ cspFallback: boolean;
373
+ stylesInjected: boolean;
374
+ nmchartsStyleTag: boolean;
375
+ dpr: number;
376
+ roundRectNative: boolean;
377
+ container: any;
378
+ cssVars?: any;
379
+ chartMethods: string[];
380
+ }
381
+
317
382
  // --- Theme definitions ---
318
383
 
319
384
  interface NMChartsThemes {
@@ -348,7 +413,11 @@ interface NMChartsStatic {
348
413
  boxplot(selector: string | HTMLElement, options: NMBoxplotOptions): NMCategoryInstance;
349
414
  sparkline(selector: string | HTMLElement, data: number[], options?: NMSparklineOptions): NMSparklineInstance;
350
415
  link(charts: NMCategoryInstance[], options?: NMLinkOptions): NMLinkInstance;
416
+ bookingTimeline(selector: string | HTMLElement, options: NMBookingTimelineOptions): NMBookingTimelineInstance;
351
417
  lttb(data: any[], threshold: number): any[];
418
+ diagnose(selector?: string | HTMLElement): NMDiagnosticResult;
419
+ debug: boolean;
420
+ _cspNonce: string;
352
421
  themes: NMChartsThemes;
353
422
  }
354
423
 
@@ -364,6 +433,10 @@ export {
364
433
  NMBulletOptions, NMTimelineOptions, NMWaterfallOptions,
365
434
  NMTreemapOptions, NMFunnelOptions, NMPolarOptions,
366
435
  NMScatterOptions, NMSankeyOptions, NMBoxplotOptions,
436
+ NMSparklineOptions, NMSparklineInstance,
437
+ NMLinkOptions, NMLinkInstance,
438
+ NMBookingTimelineOptions, NMBookingTimelineInstance,
439
+ NMAnnotation, NMDiagnosticResult,
367
440
  NMChartsThemes
368
441
  };
369
442
  export default NMCharts;
package/nmcharts.js CHANGED
@@ -177,7 +177,10 @@
177
177
  e = !0;
178
178
  _styleEl = document.createElement("style");
179
179
  _styleEl.setAttribute("data-nmcharts", "");
180
- ((_styleEl.textContent = i), document.head.appendChild(_styleEl));
180
+ var _nonce = (t.NMCharts && t.NMCharts._cspNonce) || "";
181
+ if (_nonce) _styleEl.setAttribute("nonce", _nonce);
182
+ _styleEl.textContent = i;
183
+ try { document.head.appendChild(_styleEl); } catch(ex) { console.warn("[NMCharts] CSP blocked style injection:", ex.message); }
181
184
  }
182
185
  _instanceCount++;
183
186
  })(),
@@ -186,9 +189,12 @@
186
189
  !this.el)
187
190
  )
188
191
  throw new Error("NMCharts: container not found");
192
+ if (t.NMCharts && t.NMCharts.debug) console.log("[NMCharts:create] Creating time-series chart", { container: this.el.id || this.el.tagName, width: this.el.getBoundingClientRect().width, series: (n.series||[]).length, title: n.title || '' });
189
193
  ((this.opts = n),
190
194
  (this.bands = n.bands || []),
191
- (this.forecastFrom = n.forecastFrom || null));
195
+ (this.forecastFrom = n.forecastFrom || null),
196
+ (this._externalListeners = []),
197
+ (this._destroyed = !1));
192
198
  var a = n.toolbar || {};
193
199
  ((this.series = (n.series || []).map(function (t) {
194
200
  return {
@@ -230,14 +236,15 @@
230
236
  }
231
237
  ((v.prototype._buildDOM = function (t, e) {
232
238
  var i = p("div", "mc-root", this.el);
239
+ i.style.maxWidth = "100%"; i.style.overflow = "hidden"; i.style.boxSizing = "border-box";
233
240
  this._root = i;
234
241
  var n = p("div", "mc-header", i);
235
242
  p("div", "", n).style.width = "120px";
236
243
  var a = p("div", "mc-titles", n);
237
244
  ((p("div", "mc-title", a).textContent = t.title || ""),
238
- (p("div", "mc-subtitle", a).innerHTML =
245
+ (p("div", "mc-subtitle", a).textContent =
239
246
  t.subtitle ||
240
- "Drag to zoom &middot; Shift+drag to pan &middot; Scroll to zoom &middot; Double-click to reset"));
247
+ "Drag to zoom \u00B7 Shift+drag to pan \u00B7 Scroll to zoom \u00B7 Double-click to reset"));
241
248
  var o = p("div", "mc-toolbar", n),
242
249
  r = this;
243
250
  if (!1 !== e.dark) {
@@ -317,6 +324,20 @@
317
324
  var t = window.devicePixelRatio || 1,
318
325
  e = this._wrap.getBoundingClientRect().width,
319
326
  i = Math.round(0.42 * e);
327
+ if (e <= 0) {
328
+ var self = this;
329
+ if (!this._sizeRetry) this._sizeRetry = 0;
330
+ if (this._sizeRetry < 20) {
331
+ this._sizeRetry++;
332
+ if (window.NMCharts && window.NMCharts.debug) console.log("[NMCharts:create] Width=0, retrying (" + this._sizeRetry + "/20)");
333
+ this._sizeTimer = setTimeout(function () { self._initSize(); if (self.W > 0) { if (window.NMCharts && window.NMCharts.debug) console.log("[NMCharts:create] Container now visible, width=" + self.W); self._entryProgress = 0; self._startEntryAnim(); } }, 66);
334
+ } else {
335
+ if (window.NMCharts && window.NMCharts.debug) console.warn("[NMCharts:create] WARNING: Container still 0px after 20 retries", { el: this.el.id || this.el.tagName, display: getComputedStyle(this.el).display });
336
+ }
337
+ return;
338
+ }
339
+ this._sizeRetry = 0;
340
+ if (window.NMCharts && window.NMCharts.debug && !this._sizeLogged) { this._sizeLogged = true; console.log("[NMCharts:create] Size OK", { width: e, height: i, dpr: t }); }
320
341
  ((this.canvas.width = e * t),
321
342
  (this.canvas.height = i * t),
322
343
  (this.canvas.style.height = i + "px"),
@@ -336,7 +357,7 @@
336
357
  }),
337
358
  (v.prototype._buildLegend = function () {
338
359
  var t = this;
339
- ((this._legendEl.innerHTML = ""),
360
+ ((this._legendEl.textContent = ""),
340
361
  this.series.forEach(function (e) {
341
362
  var i = p(
342
363
  "div",
@@ -355,12 +376,12 @@
355
376
  e.color +
356
377
  ";height:0;margin-top:1px"
357
378
  : "background:" + e.color;
358
- ((i.innerHTML =
359
- '<div class="mc-legend-swatch" style="' +
360
- n +
361
- '"></div><span>' +
362
- e.name +
363
- "</span>"),
379
+ (i.textContent = "",
380
+ (function() {
381
+ var sw = document.createElement("div"); sw.className = "mc-legend-swatch"; sw.style.cssText = n;
382
+ var sp = document.createElement("span"); sp.textContent = e.name;
383
+ i.appendChild(sw); i.appendChild(sp);
384
+ })(),
364
385
  i.addEventListener("click", function () {
365
386
  ((e.visible = !e.visible),
366
387
  i.classList.toggle("disabled", !e.visible),
@@ -1024,42 +1045,31 @@
1024
1045
  (v.prototype._showTooltip = function (t, e) {
1025
1046
  if (e < 0) this._hideTooltip();
1026
1047
  else {
1027
- var i = "",
1028
- o = null;
1029
- if (
1030
- (this.series.forEach(function (t) {
1031
- !t.visible ||
1032
- e >= t.data.length ||
1033
- (o || (o = t.data[e][0]),
1034
- (i +=
1035
- '<div class="mc-tooltip-row"><div class="mc-tooltip-dot" style="background:' +
1036
- t.color +
1037
- '"></div><span>' +
1038
- t.name +
1039
- '</span><span class="mc-tooltip-val">' +
1040
- l(t.data[e][1]) +
1041
- "</span></div>"));
1042
- }),
1043
- o)
1044
- ) {
1045
- ((i =
1046
- '<div class="mc-tooltip-date">' +
1047
- (function (t) {
1048
- var e = new Date(t);
1049
- return (
1050
- a[e.getUTCDay()] +
1051
- ", " +
1052
- n[e.getUTCMonth()] +
1053
- " " +
1054
- e.getUTCDate() +
1055
- ", " +
1056
- e.getUTCFullYear()
1057
- );
1058
- })(o) +
1059
- "</div>" +
1060
- i),
1061
- (this._tooltipEl.innerHTML = i),
1062
- this._tooltipEl.classList.add("visible"));
1048
+ var o = null;
1049
+ var entries = [];
1050
+ this.series.forEach(function (t) {
1051
+ if (!t.visible || e >= t.data.length) return;
1052
+ if (!o) o = t.data[e][0];
1053
+ entries.push({ color: t.color, name: t.name, value: l(t.data[e][1]) });
1054
+ });
1055
+ if (o) {
1056
+ // Build tooltip with safe DOM methods (no innerHTML)
1057
+ this._tooltipEl.textContent = "";
1058
+ var dateDiv = document.createElement("div"); dateDiv.className = "mc-tooltip-date";
1059
+ dateDiv.textContent = (function (t) {
1060
+ var e = new Date(t);
1061
+ return a[e.getUTCDay()] + ", " + n[e.getUTCMonth()] + " " + e.getUTCDate() + ", " + e.getUTCFullYear();
1062
+ })(o);
1063
+ this._tooltipEl.appendChild(dateDiv);
1064
+ entries.forEach(function (entry) {
1065
+ var row = document.createElement("div"); row.className = "mc-tooltip-row";
1066
+ var dot = document.createElement("div"); dot.className = "mc-tooltip-dot"; dot.style.background = entry.color;
1067
+ var nm = document.createElement("span"); nm.textContent = entry.name;
1068
+ var val = document.createElement("span"); val.className = "mc-tooltip-val"; val.textContent = entry.value;
1069
+ row.appendChild(dot); row.appendChild(nm); row.appendChild(val);
1070
+ this._tooltipEl.appendChild(row);
1071
+ }.bind(this));
1072
+ this._tooltipEl.classList.add("visible");
1063
1073
  var s = this._tooltipEl.offsetWidth,
1064
1074
  c = this._tooltipEl.offsetHeight,
1065
1075
  d = t.x + 16,
@@ -1116,6 +1126,7 @@
1116
1126
  if (this._rafId) { cancelAnimationFrame(this._rafId); this._rafId = null; }
1117
1127
  // Clear resize debounce timer
1118
1128
  if (this._resizeTimer) { clearTimeout(this._resizeTimer); this._resizeTimer = null; }
1129
+ if (this._sizeTimer) { clearTimeout(this._sizeTimer); this._sizeTimer = null; }
1119
1130
  // Remove all external listeners (window/document)
1120
1131
  if (this._externalListeners) {
1121
1132
  for (var i = 0; i < this._externalListeners.length; i++) {
@@ -1128,13 +1139,9 @@
1128
1139
  if (this._root && this._root.parentNode) {
1129
1140
  this._root.parentNode.removeChild(this._root);
1130
1141
  }
1131
- // Decrement instance count; remove global CSS when last instance is destroyed
1142
+ // Decrement instance count (keep styles category charts may depend on them)
1132
1143
  _instanceCount--;
1133
- if (_instanceCount <= 0 && _styleEl && _styleEl.parentNode) {
1134
- _styleEl.parentNode.removeChild(_styleEl);
1135
- _styleEl = null;
1136
- e = !1;
1137
- _instanceCount = 0;
1144
+ if (_instanceCount < 0) _instanceCount = 0;
1138
1145
  }
1139
1146
  // Null out references to aid GC
1140
1147
  this.canvas = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malinconico/nmcharts",
3
- "version": "2.4.0",
3
+ "version": "2.5.0",
4
4
  "description": "NM Charts — Zero-dependency Canvas charting library with 23 chart types",
5
5
  "type": "module",
6
6
  "main": "nmcharts.js",