@acorex/charts 22.3.20 → 22.3.22
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/fesm2022/acorex-charts-bar-chart.mjs +66 -26
- package/fesm2022/acorex-charts-bar-chart.mjs.map +1 -1
- package/fesm2022/acorex-charts-line-chart.mjs +26 -0
- package/fesm2022/acorex-charts-line-chart.mjs.map +1 -1
- package/package.json +1 -1
- package/types/acorex-charts-bar-chart.d.ts +7 -0
- package/types/acorex-charts-line-chart.d.ts +2 -0
|
@@ -396,15 +396,7 @@ class AXBarChartComponent extends AXChartComponent {
|
|
|
396
396
|
.domain(data.map((d) => d.id))
|
|
397
397
|
.range([0, this.width])
|
|
398
398
|
.padding(padding);
|
|
399
|
-
|
|
400
|
-
// Support negative values by calculating min/max
|
|
401
|
-
const minValue = this.d3.min(data, (d) => d.value) || 0;
|
|
402
|
-
const maxValue = this.d3.max(data, (d) => d.value) || 0;
|
|
403
|
-
this.yScale = this.d3
|
|
404
|
-
.scaleLinear()
|
|
405
|
-
.domain([Math.min(0, minValue), Math.max(0, maxValue)])
|
|
406
|
-
.nice()
|
|
407
|
-
.range([this.height, 0]);
|
|
399
|
+
this.setupYScale(data.map((item) => item.value));
|
|
408
400
|
}
|
|
409
401
|
/**
|
|
410
402
|
* Creates x and y scales for clustered charts
|
|
@@ -433,13 +425,51 @@ class AXBarChartComponent extends AXChartComponent {
|
|
|
433
425
|
allVisibleValues.push(item.value);
|
|
434
426
|
});
|
|
435
427
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
428
|
+
this.setupYScale(allVisibleValues);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Whole-number spans of 0–8 stay on integer ticks.
|
|
432
|
+
* `.nice()` on 0–1 otherwise subdivides the axis into 0.1 steps.
|
|
433
|
+
*/
|
|
434
|
+
setupYScale(values) {
|
|
435
|
+
const finite = values.filter((value) => Number.isFinite(value));
|
|
436
|
+
const dataMin = finite.length > 0 ? (this.d3.min(finite) ?? 0) : 0;
|
|
437
|
+
const dataMax = finite.length > 0 ? (this.d3.max(finite) ?? 0) : 0;
|
|
438
|
+
const yMin = Math.min(0, dataMin);
|
|
439
|
+
const yMax = Math.max(0, dataMax);
|
|
440
|
+
const ySpan = yMax - yMin;
|
|
441
|
+
const integralDomain = finite.every((value) => Number.isInteger(value)) && Number.isInteger(yMin) && Number.isInteger(yMax);
|
|
442
|
+
if (integralDomain && ySpan <= 8) {
|
|
443
|
+
const upper = ySpan === 0 ? yMax + 1 : yMax;
|
|
444
|
+
this.yScale = this.d3.scaleLinear().domain([yMin, upper]).range([this.height, 0]);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
this.yScale = this.d3.scaleLinear().domain([yMin, yMax]).nice().range([this.height, 0]);
|
|
448
|
+
if (integralDomain) {
|
|
449
|
+
const [niceMin, niceMax] = this.yScale.domain();
|
|
450
|
+
const snappedMin = Math.floor(niceMin);
|
|
451
|
+
const snappedMax = Math.max(snappedMin + 1, Math.ceil(niceMax));
|
|
452
|
+
this.yScale.domain([snappedMin, snappedMax]);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
/** Integer ticks for a short whole-number domain so D3 does not subdivide 0–1 into decimals. */
|
|
456
|
+
resolveYAxisTickValues() {
|
|
457
|
+
const [min, max] = this.yScale.domain();
|
|
458
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
461
|
+
if (!Number.isInteger(min) || !Number.isInteger(max)) {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
const span = max - min;
|
|
465
|
+
if (span > 8) {
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
const ticks = [];
|
|
469
|
+
for (let value = min; value <= max; value += 1) {
|
|
470
|
+
ticks.push(value);
|
|
471
|
+
}
|
|
472
|
+
return ticks;
|
|
443
473
|
}
|
|
444
474
|
/**
|
|
445
475
|
* Creates x and y axes with grid lines
|
|
@@ -466,17 +496,22 @@ class AXBarChartComponent extends AXChartComponent {
|
|
|
466
496
|
}
|
|
467
497
|
createYAxis(axesGroup, options) {
|
|
468
498
|
// Create Y axis with smart number formatting
|
|
499
|
+
const yTickValues = this.resolveYAxisTickValues();
|
|
469
500
|
const yAxisGenerator = this.d3.axisLeft(this.yScale).tickFormat((value) => {
|
|
470
501
|
const numValue = typeof value === 'number' ? value : value.valueOf();
|
|
471
502
|
return formatLargeNumber(numValue);
|
|
472
503
|
});
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
if (maxValue > 1e6) {
|
|
476
|
-
yAxisGenerator.ticks(6); // Fewer ticks for large numbers
|
|
504
|
+
if (yTickValues) {
|
|
505
|
+
yAxisGenerator.tickValues(yTickValues);
|
|
477
506
|
}
|
|
478
|
-
else
|
|
479
|
-
|
|
507
|
+
else {
|
|
508
|
+
const maxValue = this.yScale.domain()[1];
|
|
509
|
+
if (maxValue > 1e6) {
|
|
510
|
+
yAxisGenerator.ticks(6);
|
|
511
|
+
}
|
|
512
|
+
else if (maxValue > 1e3) {
|
|
513
|
+
yAxisGenerator.ticks(8);
|
|
514
|
+
}
|
|
480
515
|
}
|
|
481
516
|
this.yAxis = axesGroup.append('g').attr('class', 'ax-bar-chart-axis-y').call(yAxisGenerator);
|
|
482
517
|
// Style the axis text
|
|
@@ -585,13 +620,18 @@ class AXBarChartComponent extends AXChartComponent {
|
|
|
585
620
|
return tickLabelText.length * this.DEFAULT_FONT_SIZE * this.FONT_WIDTH_MULTIPLIER + this.FONT_PADDING;
|
|
586
621
|
}
|
|
587
622
|
createGridLines() {
|
|
623
|
+
const yTickValues = this.resolveYAxisTickValues();
|
|
624
|
+
const gridAxis = this.d3
|
|
625
|
+
.axisLeft(this.yScale)
|
|
626
|
+
.tickSize(-this.width)
|
|
627
|
+
.tickFormat(() => '');
|
|
628
|
+
if (yTickValues) {
|
|
629
|
+
gridAxis.tickValues(yTickValues);
|
|
630
|
+
}
|
|
588
631
|
this.chart
|
|
589
632
|
.append('g')
|
|
590
633
|
.attr('class', 'ax-bar-chart-grid')
|
|
591
|
-
.call(
|
|
592
|
-
.axisLeft(this.yScale)
|
|
593
|
-
.tickSize(-this.width)
|
|
594
|
-
.tickFormat(() => ''))
|
|
634
|
+
.call(gridAxis)
|
|
595
635
|
.selectAll('line')
|
|
596
636
|
.style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))')
|
|
597
637
|
.style('stroke-opacity', 0.2);
|