@acorex/charts 20.1.4 → 20.1.6

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.
@@ -200,7 +200,7 @@ class AXLineChartComponent extends NXComponent {
200
200
  return;
201
201
  const containerElement = this.chartContainerEl().nativeElement;
202
202
  const allSeriesData = this._fullNormalizedData;
203
- this.d3.select(containerElement).selectAll('*').remove();
203
+ this.d3.select(containerElement).select('svg').remove();
204
204
  if (allSeriesData.length === 0 || allSeriesData.every((series) => !series.data || series.data.length === 0)) {
205
205
  this.showNoDataMessage(containerElement);
206
206
  return;
@@ -243,7 +243,7 @@ class AXLineChartComponent extends NXComponent {
243
243
  this._tooltipVisible.set(false);
244
244
  }
245
245
  setupDimensions(containerElement, options) {
246
- this.calculateMargins(options);
246
+ this.calculateMargins(options, containerElement.clientWidth);
247
247
  const containerWidth = containerElement.clientWidth;
248
248
  const containerHeight = containerElement.clientHeight;
249
249
  const minDim = Math.min(200, containerWidth, containerHeight);
@@ -276,13 +276,36 @@ class AXLineChartComponent extends NXComponent {
276
276
  this.svg = svg;
277
277
  this.chart = this.svg.append('g').attr('transform', `translate(${this.margin.left},${this.margin.top})`);
278
278
  }
279
- calculateMargins(options) {
279
+ calculateMargins(options, containerWidth) {
280
280
  this.margin = {
281
281
  top: options.margins?.top ?? 20,
282
282
  right: options.margins?.right ?? 25,
283
283
  bottom: options.margins?.bottom ?? 40,
284
284
  left: options.margins?.left ?? 50,
285
285
  };
286
+ const allDataPoints = this._fullNormalizedData.flatMap((series) => series.data);
287
+ if (allDataPoints.length > 0) {
288
+ const allNumericX = allDataPoints.every((d) => typeof d.x === 'number');
289
+ if (!allNumericX) {
290
+ const visibleSeries = this._fullNormalizedData.filter((s) => !this.hiddenSeries.has(s.id || s.label || `series-${s.originalIndex}`));
291
+ const allXValues = new Set(visibleSeries.flatMap((series) => series.data.map((d) => String(d.x))));
292
+ const labelCount = allXValues.size;
293
+ if (labelCount > 0 && containerWidth > 0) {
294
+ const workingWidth = containerWidth - this.margin.left - this.margin.right;
295
+ if (workingWidth > 0) {
296
+ const availableWidthPerLabel = workingWidth / labelCount;
297
+ const labels = Array.from(allXValues);
298
+ const longestLabel = labels.reduce((a, b) => (a.length > b.length ? a : b), '');
299
+ const estimatedFontSize = Math.max(11, Math.min(15, Math.round(workingWidth / 45)));
300
+ const estimatedLongestLabelWidth = longestLabel.length * estimatedFontSize * 0.6;
301
+ if (estimatedLongestLabelWidth > availableWidthPerLabel) {
302
+ const requiredExtraMargin = estimatedLongestLabelWidth * Math.sin(Math.PI / 4) + 10;
303
+ this.margin.bottom += Math.min(60, requiredExtraMargin);
304
+ }
305
+ }
306
+ }
307
+ }
308
+ }
286
309
  if (options.xAxisLabel) {
287
310
  const xLabelLength = options.xAxisLabel.length;
288
311
  const extraBottomMargin = Math.min(20, Math.max(10, xLabelLength * 0.8));
@@ -312,7 +335,6 @@ class AXLineChartComponent extends NXComponent {
312
335
  allDataPoints.push({ x: 0, y: 0 }); // Default fallback to prevent crash with empty domain
313
336
  }
314
337
  const allNumericX = allDataPoints.every((d) => typeof d.x === 'number');
315
- const allDates = !allNumericX && allDataPoints.every((d) => !isNaN(new Date(d.x).getTime()));
316
338
  if (allNumericX) {
317
339
  const xMin = this.d3.min(allDataPoints, (d) => d.x) ?? 0;
318
340
  const xMax = this.d3.max(allDataPoints, (d) => d.x) ?? 0;
@@ -326,20 +348,6 @@ class AXLineChartComponent extends NXComponent {
326
348
  this.xScale = this.d3.scaleLinear().domain([xMin, xMax]).range([0, this.width]);
327
349
  }
328
350
  }
329
- else if (allDates) {
330
- const xMin = this.d3.min(allDataPoints, (d) => new Date(d.x)) ?? new Date();
331
- const xMax = this.d3.max(allDataPoints, (d) => new Date(d.x)) ?? new Date();
332
- if (xMin.getTime() === xMax.getTime()) {
333
- const oneDayMs = 86400000;
334
- this.xScale = this.d3
335
- .scaleTime()
336
- .domain([new Date(xMin.getTime() - oneDayMs), new Date(xMax.getTime() + oneDayMs)])
337
- .range([0, this.width]);
338
- }
339
- else {
340
- this.xScale = this.d3.scaleTime().domain([xMin, xMax]).range([0, this.width]);
341
- }
342
- }
343
351
  else {
344
352
  this.xScale = this.d3
345
353
  .scaleBand()
@@ -382,13 +390,27 @@ class AXLineChartComponent extends NXComponent {
382
390
  .attr('stroke-dasharray', '2,2')
383
391
  .attr('stroke-opacity', '0.5');
384
392
  const dynamicXAxisTickFontSize = Math.max(11, Math.min(15, Math.round(this.width / 45)));
385
- this.xAxis.selectAll('text').attr('style', `
386
- font-size: ${dynamicXAxisTickFontSize}px;
387
- font-weight: 400;
388
- fill: rgba(var(--ax-comp-line-chart-labels-color), 0.7);
389
- `);
393
+ const xAxisTicks = this.xAxis
394
+ .selectAll('text')
395
+ .style('font-size', `${dynamicXAxisTickFontSize}px`)
396
+ .style('font-weight', '400')
397
+ .style('fill', 'rgba(var(--ax-comp-line-chart-labels-color), 0.7)');
398
+ // Automatically rotate labels if they are likely to overlap
399
+ if (isBandScale && this.xScale.domain().length > 0) {
400
+ const step = this.xScale.step();
401
+ const longestLabel = this.xScale.domain().reduce((a, b) => (a.length > b.length ? a : b), '');
402
+ // Using 0.6 as a better estimate for char width-to-height ratio
403
+ const estimatedLongestLabelWidth = longestLabel.length * dynamicXAxisTickFontSize * 0.6;
404
+ if (estimatedLongestLabelWidth > step) {
405
+ xAxisTicks
406
+ .attr('transform', 'rotate(-45)')
407
+ .style('text-anchor', 'end')
408
+ .attr('dx', '-0.8em')
409
+ .attr('dy', '0.15em');
410
+ }
411
+ }
390
412
  if (options.xAxisLabel) {
391
- const labelY = this.height + this.margin.bottom * 0.8;
413
+ const labelY = this.height + this.margin.bottom * 0.7;
392
414
  axesGroup
393
415
  .append('text')
394
416
  .attr('class', 'ax-line-chart-axis-label ax-x-axis-label')
@@ -496,7 +518,7 @@ class AXLineChartComponent extends NXComponent {
496
518
  return this.xScale(String(d.x)) + this.xScale.bandwidth() / 2;
497
519
  }
498
520
  else {
499
- return this.xScale(typeof d.x === 'number' ? d.x : new Date(d.x));
521
+ return this.xScale(d.x);
500
522
  }
501
523
  };
502
524
  const lineGenerator = this.d3
@@ -797,7 +819,7 @@ class AXLineChartComponent extends NXComponent {
797
819
  x = this.xScale(String(dataPoint.x)) + this.xScale.bandwidth() / 2;
798
820
  }
799
821
  else {
800
- x = this.xScale(typeof dataPoint.x === 'number' ? dataPoint.x : new Date(dataPoint.x));
822
+ x = this.xScale(dataPoint.x);
801
823
  }
802
824
  const y = this.yScale(dataPoint.y);
803
825
  let crosshairGroup = this.chart.select('.ax-line-chart-crosshair');