axidio-styleguide-library1-v2 0.2.27 → 0.2.28

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.
@@ -8187,352 +8187,1553 @@ class HorizontalGroupedBarWithScrollZoomComponent extends ComponentUniqueId {
8187
8187
  get isAlertEnabled() {
8188
8188
  return this.chartConfiguration?.headerMenuOptions?.some((option) => option.id === 'editAlert');
8189
8189
  }
8190
+ // initializegroupChart() {
8191
+ // var self = this;
8192
+ // let data = [];
8193
+ // let metaData: any = null;
8194
+ // let keyList = null;
8195
+ // let lineData = null;
8196
+ // let colorMap = {};
8197
+ // var formatFromBackend;
8198
+ // var formatForHugeNumbers;
8199
+ // const isMobile = window.innerWidth < 576;
8200
+ // const isTablet = window.innerWidth >= 576 && window.innerWidth < 992;
8201
+ // const isDesktop = window.innerWidth >= 992;
8202
+ // let isria = this.customChartConfiguration.isRia
8203
+ // var x: any;
8204
+ // var alternate_text = false;
8205
+ // var short_tick_length = 4;
8206
+ // var long_tick_length = 16;
8207
+ // /**
8208
+ // * longer tick length needed for weekly charts
8209
+ // */
8210
+ // var short_tick_length_bg = 5;
8211
+ // var long_tick_length_bg = 30;
8212
+ // var leftAndRightSpaces = 50;
8213
+ // var rightSvgWidth = 60;
8214
+ // var tempScale;
8215
+ // for (var i in this.defaultConfiguration) {
8216
+ // this.chartConfiguration[i] = ChartHelper.getValueByConfigurationType(
8217
+ // i,
8218
+ // this.defaultConfiguration,
8219
+ // this.customChartConfiguration
8220
+ // );
8221
+ // }
8222
+ // data = this.chartData.data;
8223
+ // metaData = this.chartData.metaData;
8224
+ // lineData = this.chartData.lineData;
8225
+ // // if (lineData || this.chartData.targetLineData) {
8226
+ // // rightSvgWidth = 60;
8227
+ // // }
8228
+ // if (!metaData.colorAboveTarget) {
8229
+ // metaData['colorAboveTarget'] = metaData.colors;
8230
+ // }
8231
+ // colorMap = metaData.colors;
8232
+ // keyList = metaData.keyList;
8233
+ // var chartContainer = d3.select(this.containerElt.nativeElement);
8234
+ // var verticalstackedcontainer = d3.select(
8235
+ // this.groupcontainerElt.nativeElement
8236
+ // );
8237
+ // var margin = this.chartConfiguration.margin;
8238
+ // const { width, height } = this.calculateChartDimensions(
8239
+ // chartContainer,
8240
+ // verticalstackedcontainer,
8241
+ // margin,
8242
+ // self
8243
+ // );
8244
+ // /**
8245
+ // * for hiding header
8246
+ // * used by weekly charts
8247
+ // */
8248
+ // if (this.chartConfiguration.isHeaderVisible != undefined)
8249
+ // this.isHeaderVisible = this.chartConfiguration.isHeaderVisible;
8250
+ // /**
8251
+ // * for hiding legends
8252
+ // * used by weekly charts
8253
+ // */
8254
+ // if (this.chartConfiguration.legendVisible != undefined) {
8255
+ // this.legendVisible = this.chartConfiguration.legendVisible;
8256
+ // }
8257
+ // /**
8258
+ // * for removing background color so that it can take parents color
8259
+ // *
8260
+ // */
8261
+ // if (this.chartConfiguration.isTransparentBackground != undefined) {
8262
+ // this.isTransparentBackground =
8263
+ // this.chartConfiguration.isTransparentBackground;
8264
+ // }
8265
+ // /**
8266
+ // * format data values based on configuration received
8267
+ // */
8268
+ // if (this.chartConfiguration.textFormatter != undefined) {
8269
+ // formatFromBackend = ChartHelper.dataValueFormatter(
8270
+ // this.chartConfiguration.textFormatter
8271
+ // );
8272
+ // formatForHugeNumbers = ChartHelper.dataValueFormatter('.2s');
8273
+ // }
8274
+ // const {
8275
+ // outerContainer,
8276
+ // svgYAxisLeft,
8277
+ // svgYAxisRight,
8278
+ // innerContainer,
8279
+ // svg
8280
+ // } = this.createChartContainers(chartContainer, margin, height, rightSvgWidth, self, width);
8281
+ // var subgroups: any = keyList;
8282
+ // var groups = d3
8283
+ // .map(data, function (d) {
8284
+ // return d.name;
8285
+ // })
8286
+ // .keys();
8287
+ // /**
8288
+ // * x axis range made similar to line chart or vertical stack so that all the charts will get aligned with each other.
8289
+ // */
8290
+ // if (this.chartConfiguration.isMultiChartGridLine != undefined) {
8291
+ // x = d3
8292
+ // .scaleBand()
8293
+ // .rangeRound([width, 0])
8294
+ // .align(0.5)
8295
+ // .padding([0.5])
8296
+ // .domain(
8297
+ // data.map(function (d: any) {
8298
+ // return d.name.toLowerCase();
8299
+ // })
8300
+ // );
8301
+ // } else {
8302
+ // x = d3
8303
+ // .scaleBand()
8304
+ // .domain(groups)
8305
+ // .range([leftAndRightSpaces, width - rightSvgWidth - leftAndRightSpaces])
8306
+ // .padding([0.3]);
8307
+ // }
8308
+ // // x.bandwidth(96);
8309
+ // var xScaleFromOrigin = d3
8310
+ // .scaleBand()
8311
+ // .domain(groups)
8312
+ // .range([0, width - rightSvgWidth]);
8313
+ // // .padding([0.2]);
8314
+ // if (this.chartConfiguration.isMultiChartGridLine == undefined) {
8315
+ // /**
8316
+ // * normal ticks for all dashboard charts
8317
+ // */
8318
+ // svg
8319
+ // .append('g')
8320
+ // .attr('class', 'x1 axis1')
8321
+ // .attr('transform', 'translate(0,' + height + ')')
8322
+ // .call(d3.axisBottom(x))
8323
+ // .call((g) => g.select('.domain').remove());
8324
+ // svg.selectAll('g.x1.axis1 g.tick line').remove();
8325
+ // // Only move x-axis labels further down for grouped charts if there is no xLabel
8326
+ // if (subgroups.length > 1 && !metaData.xLabel) {
8327
+ // svg
8328
+ // .selectAll('g.x1.axis1 g.tick text')
8329
+ // .attr('class', 'lib-xaxis-labels-texts-drilldown')
8330
+ // .style('fill', 'var(--chart-text-color)')
8331
+ // .attr('y', 32); // Increase distance from bars (default is ~9)
8332
+ // } else {
8333
+ // svg
8334
+ // .selectAll('g.x1.axis1 g.tick text')
8335
+ // .attr('class', 'lib-xaxis-labels-texts-drilldown')
8336
+ // .style('fill', 'var(--chart-text-color)');
8337
+ // }
8338
+ // }
8339
+ // else {
8340
+ // /**
8341
+ // * bigger ticks for weekly charts and more space from x axis to labels
8342
+ // */
8343
+ // /**
8344
+ // * draw x axis
8345
+ // */
8346
+ // svg
8347
+ // .append('g')
8348
+ // .attr('class', 'x1 axis1')
8349
+ // .attr('transform', 'translate(0,' + height + ')')
8350
+ // .call(d3.axisBottom(x).tickSize(0))
8351
+ // .call((g) => g.select('.domain').attr('fill', 'none'));
8352
+ // /**
8353
+ // * tick line size in alternate fashion
8354
+ // */
8355
+ // svg.selectAll('g.x1.axis1 g.tick line').attr('y2', function () {
8356
+ // if (
8357
+ // alternate_text &&
8358
+ // self.chartConfiguration.isNoAlternateXaxisText == undefined
8359
+ // ) {
8360
+ // alternate_text = false;
8361
+ // return long_tick_length_bg - 7;
8362
+ // } else {
8363
+ // alternate_text = true;
8364
+ // return short_tick_length_bg - 4;
8365
+ // }
8366
+ // });
8367
+ // /**
8368
+ // * reset the flag so that values can be shown in same alternate fashion
8369
+ // */
8370
+ // alternate_text = false;
8371
+ // /**
8372
+ // * print x-axis label texts
8373
+ // * used by weekly charts
8374
+ // */
8375
+ // svg
8376
+ // .selectAll('g.x1.axis1 g.tick text')
8377
+ // .attr('class', 'lib-xaxis-labels-texts-weeklycharts')
8378
+ // .attr('y', function () {
8379
+ // // Minimize gap in maximized (fullscreen) view for weekly charts
8380
+ // if (self.chartConfiguration.isFullScreen) {
8381
+ // return short_tick_length_bg;
8382
+ // }
8383
+ // if (alternate_text) {
8384
+ // alternate_text = false;
8385
+ // return long_tick_length_bg;
8386
+ // } else {
8387
+ // alternate_text = true;
8388
+ // return short_tick_length_bg;
8389
+ // }
8390
+ // });
8391
+ // }
8392
+ // if (self.chartConfiguration.xLabelsOnSameLine) {
8393
+ // const xAxisLabels = svg
8394
+ // .selectAll('g.x1.axis1 g.tick text')
8395
+ // .attr('class', 'lib-xaxis-labels-texts-drilldown')
8396
+ // .style('font-size', this.isHeaderVisible ? '18px' : '14px')
8397
+ // .attr('text-anchor', 'middle')
8398
+ // .attr('y', function(d) {
8399
+ // // For grouped bar charts with many bars and xLabel present, only add 5 if the label is a date
8400
+ // if (subgroups.length > 1 && data.length > 8 && metaData.xLabel) {
8401
+ // const isDateLabel = /\d{2,4}[-\/]/.test(d);
8402
+ // if (self.chartConfiguration.isFullScreen) {
8403
+ // return isDateLabel ? short_tick_length_bg + 14 : short_tick_length_bg;
8404
+ // }
8405
+ // return isDateLabel ? short_tick_length_bg + 14 : short_tick_length_bg;
8406
+ // }
8407
+ // // For grouped bar charts with many bars and NO xLabel, add space as before, but reduce in fullscreen
8408
+ // if (subgroups.length > 1 && data.length > 8 && !metaData.xLabel) {
8409
+ // const chartHasExtraBottom = (self.chartConfiguration.margin && self.chartConfiguration.margin.bottom >= 40);
8410
+ // if (self.chartConfiguration.isFullScreen) {
8411
+ // // Reduce extra gap in maximized view
8412
+ // return short_tick_length_bg + 2;
8413
+ // }
8414
+ // return chartHasExtraBottom ? short_tick_length_bg : short_tick_length_bg + 10;
8415
+ // }
8416
+ // // Default/fallback logic for other cases
8417
+ // let baseY = self.isHeaderVisible ? short_tick_length_bg + 25 : short_tick_length_bg;
8418
+ // if (
8419
+ // subgroups.length > 1 &&
8420
+ // !metaData.xLabel &&
8421
+ // (/\d{2,4}[-\/]\d{2}[-\/]\d{2,4}/.test(d) || /\d{2,4}[-\/]\d{2,4}/.test(d))
8422
+ // ) {
8423
+ // baseY = self.isHeaderVisible ? short_tick_length_bg + 15 : short_tick_length_bg + 25;
8424
+ // }
8425
+ // if (/\d{2,4}[-\/]\d{2,4}/.test(d) && d.indexOf(' ') > -1) {
8426
+ // baseY += 4;
8427
+ // }
8428
+ // // In maximized view, reduce baseY slightly for grouped bars
8429
+ // if (self.chartConfiguration.isFullScreen && subgroups.length > 1) {
8430
+ // baseY = Math.max(short_tick_length_bg, baseY - 10);
8431
+ // }
8432
+ // return baseY;
8433
+ // })
8434
+ // .attr('x', function (d) {
8435
+ // if (self.chartData.data.length > 8 && !self.isZoomedOut) {
8436
+ // return 1; // Move first line text slightly to the left in zoom-in view for better alignment
8437
+ // }
8438
+ // return 0; // Default position
8439
+ // })
8440
+ // .text(function (d) {
8441
+ // var isValueToBeIgnored = false;
8442
+ // if (isMobile && !self.isHeaderVisible) {
8443
+ // let firstPart = d.split(/[\s\-]+/)[0];
8444
+ // return firstPart.substring(0, 3).toLowerCase();
8445
+ // }
8446
+ // (data as any[]).map((indiv: any) => {
8447
+ // if (
8448
+ // indiv.name &&
8449
+ // indiv.name.toLowerCase() == d.trim().toLowerCase() &&
8450
+ // indiv[metaData.keyList[0]] == -1
8451
+ // ) {
8452
+ // isValueToBeIgnored = true;
8453
+ // }
8454
+ // });
8455
+ // if (isValueToBeIgnored) {
8456
+ // return '';
8457
+ // }
8458
+ // // Always add space before and after hyphen for date range labels, even when header is visible and label is single line
8459
+ // // Apply for grouped bar charts and single bar charts, header visible, single line
8460
+ // const dateRangeRegex = /(\d{2,4}[-\/]\d{2}[-\/]\d{2,4})\s*-\s*(\d{2,4}[-\/]\d{2}[-\/]\d{2,4})/;
8461
+ // if (dateRangeRegex.test(d.trim())) {
8462
+ // return d.trim().replace(dateRangeRegex, (m, d1, d2) => `${d1} - ${d2}`);
8463
+ // }
8464
+ // // Split date and week labels into two lines in grouped bar zoom-in view (and minimized view)
8465
+ // const isDateLabel = /\d{2,4}[-\/]/.test(d);
8466
+ // const isWeekLabel = /week|wk|w\d+/i.test(d);
8467
+ // if (
8468
+ // subgroups.length > 1 && !self.isZoomedOut && data.length > 8 && d.indexOf(' ') > -1 && (isDateLabel || isWeekLabel)
8469
+ // ) {
8470
+ // var first = d.substring(0, d.indexOf(' '));
8471
+ // var second = d.substring(d.indexOf(' ') + 1).trim();
8472
+ // return first + '\n' + second;
8473
+ // }
8474
+ // // Also keep previous logic for minimized view
8475
+ // if (isDateLabel) {
8476
+ // if (!self.isHeaderVisible && data.length > 8 && d.indexOf(' ') > -1) {
8477
+ // var first = d.substring(0, d.indexOf(' '));
8478
+ // var second = d.substring(d.indexOf(' ') + 1).trim();
8479
+ // return first + '\n' + second;
8480
+ // } else {
8481
+ // return d;
8482
+ // }
8483
+ // }
8484
+ // if (d.trim().indexOf(' ') > -1) {
8485
+ // return d.trim().substring(0, d.indexOf(' ')).toLowerCase();
8486
+ // }
8487
+ // return d.toLowerCase();
8488
+ // // If label looks like a date (contains digits and - or /)
8489
+ // const isDateLabel2 = /\d{2,4}[-\/]/.test(d);
8490
+ // // Only split date/week labels if there are many grouped bars and header is not visible
8491
+ // if (isDateLabel) {
8492
+ // if (!self.isHeaderVisible && data.length > 8 && d.indexOf(' ') > -1) {
8493
+ // var first = d.substring(0, d.indexOf(' '));
8494
+ // var second = d.substring(d.indexOf(' ') + 1).trim();
8495
+ // return first + '\n' + second;
8496
+ // } else {
8497
+ // return d;
8498
+ // }
8499
+ // }
8500
+ // if (d.trim().indexOf(' ') > -1) {
8501
+ // return d.trim().substring(0, d.indexOf(' ')).toLowerCase();
8502
+ // }
8503
+ // return d.toLowerCase();
8504
+ // });
8505
+ // // Now apply writing-mode: sideways-lr for grouped charts with date labels in zoomed-out view and many bars
8506
+ // xAxisLabels.each(function(this: SVGTextElement, d: any) {
8507
+ // // Only apply writing-mode for exact date labels, not those containing 'week' or similar
8508
+ // const isDateLabel = /^(\d{2,4}[-\/])?\d{2,4}[-\/]\d{2,4}$/.test(d.trim());
8509
+ // const isWeekLabel = /week|wk|w\d+/i.test(d);
8510
+ // if (subgroups.length > 1 && self.isZoomedOut && data.length > 8 && isDateLabel && !isWeekLabel) {
8511
+ // d3.select(this).style('writing-mode', 'sideways-lr');
8512
+ // }
8513
+ // });
8514
+ // if (!isMobile) {
8515
+ // svg
8516
+ // .selectAll('g.x1.axis1 g.tick')
8517
+ // .filter(function (d) {
8518
+ // return !/\d{2,4}[-\/]/.test(d); // Only process non-date labels
8519
+ // })
8520
+ // .append('text')
8521
+ // .attr('class', 'lib-xaxis-labels-texts-drilldown')
8522
+ // .attr('y', long_tick_length_bg)
8523
+ // .attr('fill', 'var(--chart-text-color)')
8524
+ // .attr('x', function (d) {
8525
+ // if (self.chartData.data.length > 8 && !self.isZoomedOut) {
8526
+ // return 1; // Move text slightly to the left
8527
+ // }
8528
+ // return 0; // Default position
8529
+ // })
8530
+ // .text(function (d) {
8531
+ // if (d.trim().indexOf(' ') > -1) {
8532
+ // return d.trim().substring(d.indexOf(' '), d.length).toLowerCase();
8533
+ // }
8534
+ // return '';
8535
+ // });
8536
+ // }
8537
+ // }
8538
+ // if (isria && self.chartData.data.length > 8) {
8539
+ // svg
8540
+ // .selectAll('g.x1.axis1 g.tick text')
8541
+ // .classed('mobile-xaxis-override', true)
8542
+ // .text(function (d: string) {
8543
+ // return d.substring(0, 3);
8544
+ // })
8545
+ // .style('font-size', '12px')
8546
+ // .attr('y', 5)
8547
+ // .attr('x', 5)
8548
+ // .style('text-anchor', 'middle');
8549
+ // }
8550
+ // if (isMobile && !this.isHeaderVisible) {
8551
+ // svg
8552
+ // .selectAll('g.x1.axis1 g.tick text')
8553
+ // .classed('mobile-xaxis-override', true);
8554
+ // }
8555
+ // /**y scale for left y axis */
8556
+ // var y = d3.scaleLinear().rangeRound([height, 0]);
8557
+ // var maxValue = d3.max(data, (d) => d3.max(keyList, (key) => +d[key]));
8558
+ // if (maxValue == 0) {
8559
+ // if (this.chartData.targetLineData) {
8560
+ // maxValue = this.chartData.targetLineData.target + 20;
8561
+ // } else {
8562
+ // maxValue = 100;
8563
+ // }
8564
+ // }
8565
+ // if (this.chartConfiguration.customYscale) {
8566
+ // /**
8567
+ // * increase y-scale so that values wont cross or exceed out of range
8568
+ // * used in weekly charts
8569
+ // */
8570
+ // maxValue = maxValue * this.chartConfiguration.customYscale;
8571
+ // }
8572
+ // if (
8573
+ // this.chartData.targetLineData &&
8574
+ // maxValue < this.chartData.targetLineData.target
8575
+ // ) {
8576
+ // maxValue =
8577
+ // maxValue < 10 && this.chartData.targetLineData.target < 10
8578
+ // ? this.chartData.targetLineData.target + 3
8579
+ // : this.chartData.targetLineData.target + 20;
8580
+ // }
8581
+ // y.domain([0, maxValue]).nice();
8582
+ // let lineYscale;
8583
+ // if (lineData != null) {
8584
+ // let maxLineValue = d3.max(lineData, function (d) {
8585
+ // return +d.value;
8586
+ // });
8587
+ // maxLineValue = maxLineValue * this.chartConfiguration.customYscale;
8588
+ // let minLineValue = d3.min(lineData, function (d) {
8589
+ // return +d.value;
8590
+ // });
8591
+ // if (maxLineValue > 0) minLineValue = minLineValue - 3;
8592
+ // if (minLineValue > 0) {
8593
+ // minLineValue = 0;
8594
+ // }
8595
+ // lineYscale = d3
8596
+ // .scaleLinear()
8597
+ // .domain([minLineValue, maxLineValue])
8598
+ // .range([height, minLineValue]);
8599
+ // }
8600
+ // let yLineAxis;
8601
+ // if (lineYscale != null) {
8602
+ // yLineAxis = d3
8603
+ // .axisRight(lineYscale)
8604
+ // .ticks(self.chartConfiguration.numberOfYTicks)
8605
+ // .tickSize(0)
8606
+ // .tickFormat(self.chartConfiguration.yLineAxisLabelFomatter);
8607
+ // }
8608
+ // /**
8609
+ // * show x-axis grid between labels
8610
+ // * used by weekly charts
8611
+ // */
8612
+ // if (self.chartConfiguration.isXgridBetweenLabels) {
8613
+ // svg
8614
+ // .append('g')
8615
+ // .attr('class', 'grid')
8616
+ // .attr(
8617
+ // 'transform',
8618
+ // 'translate(' + x.bandwidth() / 2 + ',' + height + ')'
8619
+ // )
8620
+ // .call(d3.axisBottom(x).tickSize(-height).tickFormat(''))
8621
+ // .style('stroke-dasharray', '5 5')
8622
+ // .style('color', 'var(--chart-grid-color, #999999)') // Use CSS variable
8623
+ // .call((g) => g.select('.domain').remove());
8624
+ // }
8625
+ // if (this.chartConfiguration.yAxisGrid) {
8626
+ // svg
8627
+ // .append('g')
8628
+ // .call(
8629
+ // d3
8630
+ // .axisLeft(y)
8631
+ // .ticks(self.chartConfiguration.numberOfYTicks)
8632
+ // .tickSize(-width)
8633
+ // )
8634
+ // .style('color', 'var(--chart-axis-color, #B9B9B9)')
8635
+ // .style('opacity', '0.5')
8636
+ // .call((g) => {
8637
+ // g.select('.domain')
8638
+ // .remove()
8639
+ // .style('stroke', 'var(--chart-domain-color, #000000)'); // Add CSS variable for domain
8640
+ // });
8641
+ // } else {
8642
+ // svg
8643
+ // .append('g')
8644
+ // .call(d3.axisLeft(y).ticks(self.chartConfiguration.numberOfYTicks))
8645
+ // .style('color', 'var(--chart-axis-color, #B9B9B9)')
8646
+ // .style('opacity', '0.5')
8647
+ // .call((g) => {
8648
+ // g.select('.domain')
8649
+ // .style('stroke', 'var(--chart-domain-color, #000000)') // Add CSS variable for domain
8650
+ // .style('stroke-width', '1px'); // Ensure visibility
8651
+ // });
8652
+ // }
8653
+ // var xSubgroup = d3.scaleBand().domain(subgroups);
8654
+ // if (subgroups.length > 1 && !this.isZoomedOut) {
8655
+ // // For grouped bar charts in zoom-in view, use full x.bandwidth() for subgroups
8656
+ // xSubgroup.range([0, x.bandwidth()]);
8657
+ // } else if (subgroups.length === 1 && !this.isZoomedOut) {
8658
+ // // For single-bar (non-grouped) charts in zoom-in view, set bar width to 100 (increased from 80)
8659
+ // xSubgroup.range([0, 100]);
8660
+ // } else if (this.chartConfiguration.isMultiChartGridLine == undefined) {
8661
+ // xSubgroup.range([0, x.bandwidth()]);
8662
+ // } else {
8663
+ // // used to make grouped bars with lesser width as we are not using padding for width
8664
+ // xSubgroup.range([0, x.bandwidth()]);
8665
+ // }
8666
+ // // if (this.chartConfiguration.isDrilldownChart) {
8667
+ // // }
8668
+ // var color = d3
8669
+ // .scaleOrdinal()
8670
+ // .domain(subgroups)
8671
+ // .range(Object.values(metaData.colors));
8672
+ // // var colorAboveTarget = d3
8673
+ // // .scaleOrdinal()
8674
+ // // .domain(subgroups)
8675
+ // // .range(Object.values(metaData.colorAboveTarget));
8676
+ // var state = svg
8677
+ // .append('g')
8678
+ // .selectAll('.state')
8679
+ // .data(data)
8680
+ // .enter()
8681
+ // .append('g')
8682
+ // .attr('transform', function (d) {
8683
+ // return 'translate(' + x(d.name) + ',0)';
8684
+ // });
8685
+ // state
8686
+ // .selectAll('rect')
8687
+ // .data(function (d) {
8688
+ // let newList: any = [];
8689
+ // subgroups.map(function (key) {
8690
+ // // if (key !== "group") {
8691
+ // let obj: any = { key: key, value: d[key], name: d.name };
8692
+ // newList.push(obj);
8693
+ // // }
8694
+ // });
8695
+ // return newList;
8696
+ // })
8697
+ // .enter()
8698
+ // .append('rect')
8699
+ // .attr('class', 'bars')
8700
+ // .on('click', function (d) {
8701
+ // if (d.key != 'Target') {
8702
+ // if (
8703
+ // !metaData.barWithoutClick ||
8704
+ // !metaData.barWithoutClick.length ||
8705
+ // (!metaData.barWithoutClick.includes(d?.name) &&
8706
+ // !metaData.barWithoutClick.includes(d?.key))
8707
+ // )
8708
+ // // self.handleClick(d.data.name);
8709
+ // self.handleClick(d);
8710
+ // }
8711
+ // })
8712
+ // .attr('x', function (d) {
8713
+ // if (self.chartConfiguration.isDrilldownChart) {
8714
+ // data.map((indiv: any) => {
8715
+ // if (indiv.name == d.name) {
8716
+ // let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8717
+ // tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8718
+ // if (x.bandwidth() > 100) {
8719
+ // // Increase bar width a bit in zoom-in view
8720
+ // let reducedBarWidth = 60;
8721
+ // if (!self.isZoomedOut) {
8722
+ // reducedBarWidth = 30;
8723
+ // }
8724
+ // if (self.chartData.data.length == 1) {
8725
+ // if (Object.keys(self.chartData.data[0]).length == 2) {
8726
+ // tempScale.range([
8727
+ // 0 + (x.bandwidth() - reducedBarWidth) / 2,
8728
+ // x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8729
+ // ]);
8730
+ // } else
8731
+ // tempScale.range([
8732
+ // 0 + (x.bandwidth() - reducedBarWidth) / 2,
8733
+ // x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8734
+ // ]);
8735
+ // } else
8736
+ // tempScale.range([
8737
+ // 0 + (x.bandwidth() - reducedBarWidth) / 2,
8738
+ // x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8739
+ // ]);
8740
+ // }
8741
+ // }
8742
+ // });
8743
+ // return tempScale(d.key);
8744
+ // }
8745
+ // return xSubgroup(d.key);
8746
+ // })
8747
+ // .attr('y', function (d) {
8748
+ // if (d.value == -1) {
8749
+ // return y(0);
8750
+ // }
8751
+ // if (d.value >= 0) {
8752
+ // const barHeight = height - y(d.value);
8753
+ // const minHeight = self.chartConfiguration.defaultBarHeight || 2;
8754
+ // return barHeight < minHeight ? y(0) - minHeight : y(d.value);
8755
+ // }
8756
+ // return y(0);
8757
+ // })
8758
+ // .attr('width', function (d) {
8759
+ // // For grouped bar charts in zoom-in view, set bar width to 50 for maximum thickness
8760
+ // if (subgroups.length > 1 && !self.isZoomedOut) {
8761
+ // return 50;
8762
+ // }
8763
+ // // For single-bar (non-grouped) charts in zoom-in view, set bar width to 80
8764
+ // if (subgroups.length === 1 && !self.isZoomedOut) {
8765
+ // return 80;
8766
+ // }
8767
+ // let tempScale = d3.scaleBand().domain([]).range([0, 0]);
8768
+ // // Default logic for other chart types
8769
+ // if (self.chartConfiguration.isDrilldownChart) {
8770
+ // data.map((indiv: any) => {
8771
+ // if (indiv.name == d.name) {
8772
+ // let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8773
+ // tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8774
+ // if (x.bandwidth() > 100) {
8775
+ // // Increase bar width a bit in zoom-in view
8776
+ // let reducedBarWidth = 60;
8777
+ // if (!self.isZoomedOut) {
8778
+ // reducedBarWidth = 100;
8779
+ // }
8780
+ // if (self.chartData.data.length == 1) {
8781
+ // if (Object.keys(self.chartData.data[0]).length == 2) {
8782
+ // tempScale.range([
8783
+ // 0 + (x.bandwidth() - reducedBarWidth) / 2,
8784
+ // x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8785
+ // ]);
8786
+ // } else
8787
+ // tempScale.range([
8788
+ // 0 + (x.bandwidth() - reducedBarWidth) / 2,
8789
+ // x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8790
+ // ]);
8791
+ // } else
8792
+ // tempScale.range([
8793
+ // 0 + (x.bandwidth() - reducedBarWidth) / 2,
8794
+ // x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8795
+ // ]);
8796
+ // }
8797
+ // }
8798
+ // });
8799
+ // return self.isZoomedOut
8800
+ // ? tempScale.bandwidth()
8801
+ // : self.chartData.data.length && self.chartData.data.length > 8
8802
+ // ? tempScale.bandwidth()
8803
+ // : tempScale.bandwidth();
8804
+ // }
8805
+ // return self.isZoomedOut
8806
+ // ? tempScale.bandwidth()
8807
+ // : self.chartData.data.length && self.chartData.data.length > 8
8808
+ // ? tempScale.bandwidth()
8809
+ // : tempScale.bandwidth();
8810
+ // })
8811
+ // .attr('height', function (d) {
8812
+ // if (d.value == -1) {
8813
+ // return height - y(0);
8814
+ // }
8815
+ // if (d.value >= 0) {
8816
+ // const barHeight = height - y(d.value);
8817
+ // const minHeight = self.chartConfiguration.defaultBarHeight || 2;
8818
+ // return Math.max(barHeight, minHeight);
8819
+ // }
8820
+ // return height - y(0);
8821
+ // })
8822
+ // .style('cursor', function (d) {
8823
+ // if (metaData.hasDrillDown && !isria) return 'pointer';
8824
+ // else return 'default';
8825
+ // })
8826
+ // .attr('fill', function (d) {
8827
+ // if (
8828
+ // d.value &&
8829
+ // self.chartData.targetLineData &&
8830
+ // d.value >= parseFloat(self.chartData.targetLineData.target) &&
8831
+ // self.chartData.metaData.colorAboveTarget
8832
+ // ) {
8833
+ // const key = d.key.toLowerCase();
8834
+ // const colorAboveTarget = Object.keys(self.chartData.metaData.colorAboveTarget).find(
8835
+ // k => k.toLowerCase() === key
8836
+ // );
8837
+ // if (colorAboveTarget) {
8838
+ // return self.chartData.metaData.colorAboveTarget[colorAboveTarget];
8839
+ // }
8840
+ // }
8841
+ // return self.chartData.metaData.colors[d.key];
8842
+ // });
8843
+ // /**
8844
+ // * display angled texts on the bars
8845
+ // */
8846
+ // if (this.chartConfiguration.textsOnBar != undefined && !this.isZoomedOut) {
8847
+ // state
8848
+ // .selectAll('text')
8849
+ // .data(function (d) {
8850
+ // let newList: any = [];
8851
+ // subgroups.map(function (key) {
8852
+ // let obj: any = { key: key, value: d[key], name: d.name };
8853
+ // newList.push(obj);
8854
+ // });
8855
+ // return newList;
8856
+ // })
8857
+ // .enter()
8858
+ // .append('text')
8859
+ // .attr('fill', 'var(--chart-text-color)')
8860
+ // .attr('x', function (d) {
8861
+ // return 0;
8862
+ // })
8863
+ // .attr('y', function (d) {
8864
+ // return 0;
8865
+ // })
8866
+ // .attr('class', 'lib-data-labels-weeklycharts')
8867
+ // .text(function (d) {
8868
+ // return d.key && d.value
8869
+ // ? d.key.length > 20
8870
+ // ? d.key.substring(0, 17) + '...'
8871
+ // : d.key
8872
+ // : '';
8873
+ // })
8874
+ // .style('fill', function (d) {
8875
+ // return '#000';
8876
+ // })
8877
+ // .style('font-weight', 'bold')
8878
+ // .style('font-size', function (d) {
8879
+ // if (self.isZoomedOut) {
8880
+ // return '9px'; // 👈 Zoomed out mode
8881
+ // }
8882
+ // if (self.chartConfiguration.isDrilldownChart) {
8883
+ // if (window.innerWidth > 1900) {
8884
+ // return '18px';
8885
+ // } else if (window.innerWidth < 1400) {
8886
+ // return '10px';
8887
+ // } else {
8888
+ // return '14px';
8889
+ // }
8890
+ // } else {
8891
+ // return '14px';
8892
+ // }
8893
+ // })
8894
+ // .attr('transform', function (d) {
8895
+ // data.map((indiv: any) => {
8896
+ // if (indiv.name == d.name) {
8897
+ // let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8898
+ // var temp;
8899
+ // tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8900
+ // if (x.bandwidth() > 100) {
8901
+ // if (self.chartData.data.length == 1) {
8902
+ // if (Object.keys(self.chartData.data[0]).length == 2) {
8903
+ // tempScale.range([
8904
+ // 0 + (x.bandwidth() - 200) / 2,
8905
+ // x.bandwidth() - (x.bandwidth() - 200) / 2,
8906
+ // ]);
8907
+ // // .padding(0.05);
8908
+ // } else
8909
+ // tempScale.range([
8910
+ // 0 + (x.bandwidth() - 300) / 2,
8911
+ // x.bandwidth() - (x.bandwidth() - 300) / 2,
8912
+ // ]);
8913
+ // // .padding(0.05);
8914
+ // } else
8915
+ // tempScale.range([
8916
+ // 0 + (x.bandwidth() - 125) / 2,
8917
+ // x.bandwidth() - (x.bandwidth() - 125) / 2,
8918
+ // ]);
8919
+ // }
8920
+ // }
8921
+ // });
8922
+ // /**
8923
+ // * if set, then all texts ll be horizontal
8924
+ // */
8925
+ // if (self.chartConfiguration.textAlwaysHorizontal) {
8926
+ // return (
8927
+ // 'translate(' + xSubgroup(d.key) + ',' + (y(d.value) - 3) + ')'
8928
+ // );
8929
+ // }
8930
+ // /**
8931
+ // * rotate texts having more than one digits
8932
+ // */
8933
+ // // if (d.value > 9)
8934
+ // if (!isNaN(tempScale(d.key)))
8935
+ // return (
8936
+ // 'translate(' +
8937
+ // (tempScale(d.key) + tempScale.bandwidth() * 0.55) +
8938
+ // ',' +
8939
+ // (y(0) - 10) +
8940
+ // ') rotate(270)'
8941
+ // );
8942
+ // return 'translate(0,0)';
8943
+ // // else
8944
+ // // return (
8945
+ // // 'translate(' +
8946
+ // // (tempScale(d.key) + tempScale.bandwidth() / 2) +
8947
+ // // ',' +
8948
+ // // y(0) +
8949
+ // // ')'
8950
+ // // );
8951
+ // })
8952
+ // .on('click', function (d) {
8953
+ // if (
8954
+ // !metaData.barWithoutClick ||
8955
+ // !metaData.barWithoutClick.length ||
8956
+ // (!metaData.barWithoutClick.includes(d?.name) &&
8957
+ // !metaData.barWithoutClick.includes(d?.key))
8958
+ // )
8959
+ // self.handleClick(d);
8960
+ // });
8961
+ // if (!isria) {
8962
+ // state
8963
+ // .selectAll('.lib-data-labels-weeklycharts')
8964
+ // .on('mouseout', handleMouseOut)
8965
+ // .on('mouseover', handleMouseOver);
8966
+ // }
8967
+ // }
8968
+ // if (this.chartConfiguration.displayTitleOnTop || (
8969
+ // this.chartConfiguration.textsOnBar == undefined &&
8970
+ // this.chartConfiguration.displayTitleOnTop == undefined
8971
+ // )) {
8972
+ // if (!isria) {
8973
+ // state
8974
+ // .selectAll('rect')
8975
+ // .on('mouseout', handleMouseOut)
8976
+ // .on('mouseover', handleMouseOver);
8977
+ // }
8978
+ // }
8979
+ // function handleMouseOver(d, i) {
8980
+ // svg.selectAll('.lib-verticalstack-title-ontop').remove();
8981
+ // svg
8982
+ // .append('foreignObject')
8983
+ // .attr('x', function () {
8984
+ // // ...existing code for tempScale calculation...
8985
+ // var elementsCounter;
8986
+ // data.map((indiv: any) => {
8987
+ // if (indiv.name == d.name) {
8988
+ // let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8989
+ // elementsCounter = keys.length;
8990
+ // tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8991
+ // if (x.bandwidth() > 100) {
8992
+ // if (self.chartData.data.length == 1) {
8993
+ // if (Object.keys(self.chartData.data[0]).length == 2) {
8994
+ // tempScale.range([
8995
+ // 0 + (x.bandwidth() - 200) / 2,
8996
+ // x.bandwidth() - (x.bandwidth() - 200) / 2,
8997
+ // ]);
8998
+ // } else
8999
+ // tempScale.range([
9000
+ // 0 + (x.bandwidth() - 300) / 2,
9001
+ // x.bandwidth() - (x.bandwidth() - 300) / 2,
9002
+ // ]);
9003
+ // } else
9004
+ // tempScale.range([
9005
+ // 0 + (x.bandwidth() - 125) / 2,
9006
+ // x.bandwidth() - (x.bandwidth() - 125) / 2,
9007
+ // ]);
9008
+ // }
9009
+ // }
9010
+ // });
9011
+ // if (metaData.hasDrillDown) {
9012
+ // if (tempScale.bandwidth() + leftAndRightSpaces * 2 > 180) {
9013
+ // return (
9014
+ // x(d.name) + tempScale(d.key) + tempScale.bandwidth() / 2 - 90
9015
+ // );
9016
+ // }
9017
+ // return (
9018
+ // x(d.name) +
9019
+ // tempScale(d.key) -
9020
+ // (tempScale.bandwidth() + leftAndRightSpaces * 2) / 2 +
9021
+ // tempScale.bandwidth() / 2
9022
+ // );
9023
+ // } else return x(d.name) + tempScale(d.key) - (tempScale.bandwidth() + leftAndRightSpaces * 2) / 2 + tempScale.bandwidth() / 2;
9024
+ // })
9025
+ // .attr('class', 'lib-verticalstack-title-ontop')
9026
+ // .attr('y', function () {
9027
+ // return y(d.value) - 3 - 40 - 10;
9028
+ // })
9029
+ // .attr('dy', function () {
9030
+ // return d.class;
9031
+ // })
9032
+ // .attr('width', function () {
9033
+ // data.map((indiv: any) => {
9034
+ // if (indiv.name == d.name) {
9035
+ // let keys = Object.keys(indiv).filter((temp, i) => i != 0);
9036
+ // tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
9037
+ // if (x.bandwidth() > 100) {
9038
+ // if (self.chartData.data.length == 1) {
9039
+ // if (Object.keys(self.chartData.data[0]).length == 2) {
9040
+ // tempScale.range([
9041
+ // 0 + (x.bandwidth() - 200) / 2,
9042
+ // x.bandwidth() - (x.bandwidth() - 200) / 2,
9043
+ // ]);
9044
+ // } else
9045
+ // tempScale.range([
9046
+ // 0 + (x.bandwidth() - 300) / 2,
9047
+ // x.bandwidth() - (x.bandwidth() - 300) / 2,
9048
+ // ]);
9049
+ // } else
9050
+ // tempScale.range([
9051
+ // 0 + (x.bandwidth() - 125) / 2,
9052
+ // x.bandwidth() - (x.bandwidth() - 125) / 2,
9053
+ // ]);
9054
+ // }
9055
+ // }
9056
+ // });
9057
+ // if (metaData.hasDrillDown) {
9058
+ // if (tempScale.bandwidth() + leftAndRightSpaces * 2 > 180) {
9059
+ // return '180px';
9060
+ // }
9061
+ // return tempScale.bandwidth() + leftAndRightSpaces * 2;
9062
+ // } else return tempScale.bandwidth() + leftAndRightSpaces * 2;
9063
+ // })
9064
+ // .attr('height', 50)
9065
+ // .append('xhtml:div')
9066
+ // .attr('class', 'title')
9067
+ // .style('z-index', 99)
9068
+ // .html(function () {
9069
+ // let barLabel = d.key;
9070
+ // let dataType = metaData.dataType ? metaData.dataType : '';
9071
+ // let value = d.value;
9072
+ // let desiredText =
9073
+ // '<span class="title-bar-name">' + barLabel + '</span>';
9074
+ // desiredText +=
9075
+ // '<span class="title-bar-value"><span>' +
9076
+ // value +
9077
+ // '</span>' +
9078
+ // dataType +
9079
+ // '</span>';
9080
+ // return desiredText;
9081
+ // });
9082
+ // }
9083
+ // function handleMouseOut(d, i) {
9084
+ // svg.selectAll('.lib-verticalstack-title-ontop').remove();
9085
+ // }
9086
+ // svg
9087
+ // .append('g')
9088
+ // .attr('class', 'x2 axis2')
9089
+ // .attr('transform', 'translate(0,' + height + ')')
9090
+ // .style('color', 'var(--chart-axis-color, #000)') // Use CSS variable instead of hardcoded #000
9091
+ // .call(d3.axisBottom(xScaleFromOrigin).tickSize(0))
9092
+ // .call((g) => g.select('.domain').attr('fill', 'none'));
9093
+ // svg.selectAll('g.x2.axis2 g.tick text').style('display', 'none');
9094
+ // svg
9095
+ // .append('g')
9096
+ // .attr('class', 'lib-stacked-y-axis-text yaxis-dashed')
9097
+ // .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
9098
+ // .attr('transform', 'translate(0,0)')
9099
+ // .call(y)
9100
+ // .style('display', 'none');
9101
+ // svgYAxisLeft
9102
+ // .append('g')
9103
+ // .append('g')
9104
+ // .attr('class', 'lib-yaxis-labels-texts-drilldown yaxis-dashed')
9105
+ // .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
9106
+ // .attr('transform', 'translate(0,0)')
9107
+ // .call(
9108
+ // d3
9109
+ // .axisLeft(y)
9110
+ // .tickSize(0)
9111
+ // .ticks(self.chartConfiguration.numberOfYTicks)
9112
+ // .tickFormat(function (d) {
9113
+ // const formatted = self.chartConfiguration.yAxisLabelFomatter
9114
+ // ? self.chartConfiguration.yAxisLabelFomatter(d)
9115
+ // : d;
9116
+ // return formatted >= 1000 ? formatted / 1000 + 'k' : formatted;
9117
+ // })
9118
+ // )
9119
+ // .call((g) => {
9120
+ // // Style the domain line for theme support
9121
+ // g.select('.domain')
9122
+ // .style('stroke', 'var(--chart-domain-color, #000000)')
9123
+ // .style('stroke-width', '1px');
9124
+ // })
9125
+ // .selectAll('text')
9126
+ // .style('fill', 'var(--chart-text-color)');
9127
+ // svgYAxisRight
9128
+ // .append('g')
9129
+ // .attr('class', 'lib-yaxis-labels-texts-drilldown yaxis-dashed')
9130
+ // .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
9131
+ // .attr('transform', 'translate(0,0)')
9132
+ // .call(y)
9133
+ // .style('display', 'none');
9134
+ // /**
9135
+ // * hide x axis labels
9136
+ // * config is there for future use
9137
+ // * used by weekly charts
9138
+ // */
9139
+ // if (
9140
+ // this.chartConfiguration.isXaxisLabelHidden != undefined &&
9141
+ // this.chartConfiguration.isXaxisLabelHidden
9142
+ // ) {
9143
+ // d3.selectAll('g.lib-line-x-axis-text > g > text').attr(
9144
+ // 'class',
9145
+ // 'lib-display-hidden'
9146
+ // );
9147
+ // }
9148
+ // /**
9149
+ // * hide y axis labels
9150
+ // * used by weekly charts
9151
+ // */
9152
+ // if (
9153
+ // this.chartConfiguration.isYaxisLabelHidden != undefined &&
9154
+ // this.chartConfiguration.isYaxisLabelHidden
9155
+ // ) {
9156
+ // d3.selectAll('.yaxis-dashed > g > text').attr(
9157
+ // 'class',
9158
+ // 'lib-display-hidden'
9159
+ // );
9160
+ // }
9161
+ // /**
9162
+ // * hide y axis labels
9163
+ // * config is there for future use
9164
+ // */
9165
+ // if (
9166
+ // this.chartConfiguration.isYaxisHidden != undefined &&
9167
+ // this.chartConfiguration.isYaxisHidden
9168
+ // ) {
9169
+ // d3.selectAll('.yaxis-dashed').attr('class', 'lib-display-hidden');
9170
+ // }
9171
+ // /**
9172
+ // * dashed y axis
9173
+ // * used by weekly charts
9174
+ // */
9175
+ // if (
9176
+ // this.chartConfiguration.isYaxisDashed != undefined &&
9177
+ // this.chartConfiguration.isYaxisDashed
9178
+ // ) {
9179
+ // d3.selectAll('.yaxis-dashed')
9180
+ // .style('stroke-dasharray', '5 5')
9181
+ // .style('color', 'var(--chart-axis-color, #999999)'); // Use CSS variable
9182
+ // }
9183
+ // if (lineData != null) {
9184
+ // if (lineData && self.chartConfiguration.showLineChartAxis) {
9185
+ // svgYAxisRight
9186
+ // .append('g')
9187
+ // .attr('class', 'lib-stacked-y-axis-text1')
9188
+ // .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
9189
+ // .attr('transform', 'translate(' + 0 + ',0)')
9190
+ // .call(yLineAxis);
9191
+ // }
9192
+ // }
9193
+ // /**
9194
+ // * used to display y label
9195
+ // */
9196
+ // // if (this.isZoomedOut) {
9197
+ // // svg
9198
+ // // .selectAll('.lib-xaxis-labels-texts-drilldown')
9199
+ // // .attr('class', 'lib-display-hidden');
9200
+ // // }
9201
+ // if (this.isZoomedOut) {
9202
+ // svg
9203
+ // .selectAll('.lib-xaxis-labels-texts-drilldown')
9204
+ // .each((d, i, nodes) => {
9205
+ // const text = d3.select(nodes[i]);
9206
+ // const label = text.text();
9207
+ // if (label.indexOf('\n') > -1) {
9208
+ // const lines = label.split('\n');
9209
+ // text.text(null);
9210
+ // lines.forEach((line, idx) => {
9211
+ // text.append('tspan')
9212
+ // .text(line)
9213
+ // .attr('x', 0)
9214
+ // .attr('dy', idx === 0 ? '1em' : '1.1em');
9215
+ // });
9216
+ // } else {
9217
+ // const words = label.split(' ');
9218
+ // text.text(null);
9219
+ // words.forEach((word, index) => {
9220
+ // text.append('tspan').text(word);
9221
+ // });
9222
+ // }
9223
+ // })
9224
+ // .style('fill', 'var(--chart-text-color)')
9225
+ // .attr('transform', null);
9226
+ // svg
9227
+ // .select('.x-axis')
9228
+ // .attr('transform', `translate(0, ${height - margin.bottom + 10})`);
9229
+ // }
9230
+ // /**
9231
+ // * used to write y labels based on configuration
9232
+ // */
9233
+ // if (metaData.yLabel) {
9234
+ // const yPosition = isria ? 0 - margin.left / 2 - 30 : 0 - margin.left / 2 - 40;
9235
+ // svgYAxisLeft
9236
+ // .append('text')
9237
+ // .attr('class', 'lib-axis-group-label font-size-1')
9238
+ // .attr('style', self.chartConfiguration.yAxisCustomlabelStyles)
9239
+ // .attr('transform', 'rotate(-90)')
9240
+ // .attr('y', yPosition)
9241
+ // .attr('x', 0 - height / 2)
9242
+ // .attr('dy', '1em')
9243
+ // .style('text-anchor', 'middle')
9244
+ // .attr('fill', 'var(--chart-text-color)');
9245
+ // if (this.chartConfiguration.isMultiChartGridLine === undefined) {
9246
+ // svgYAxisLeft
9247
+ // .selectAll('.lib-axis-group-label')
9248
+ // .style('font-size', 'smaller')
9249
+ // .text(metaData.yLabel);
9250
+ // } else {
9251
+ // svg
9252
+ // .selectAll('.lib-axis-group-label')
9253
+ // .attr('class', 'lib-ylabel-weeklyCharts')
9254
+ // .text(metaData.yLabel.toLowerCase());
9255
+ // }
9256
+ // }
9257
+ // if (this.chartData.targetLineData) {
9258
+ // const yZero = y(this.chartData.targetLineData.target);
9259
+ // svg
9260
+ // .append('line')
9261
+ // .attr('x1', 0)
9262
+ // .attr('x2', width)
9263
+ // .attr('y1', yZero)
9264
+ // .attr('y2', yZero)
9265
+ // .style('stroke-dasharray', '5 5')
9266
+ // .style('stroke', this.chartData.targetLineData.color);
9267
+ // // svgYAxisRight
9268
+ // // .append('line')
9269
+ // // .attr('x1', 0)
9270
+ // // .attr('x2', rightSvgWidth)
9271
+ // // .attr('y1', yZero)
9272
+ // // .attr('y2', yZero)
9273
+ // // .style('stroke', this.chartData.targetLineData.color);
9274
+ // svgYAxisRight
9275
+ // .append('foreignObject')
9276
+ // .attr('transform', 'translate(' + 0 + ',' + (yZero - 30) + ')')
9277
+ // .attr('width', rightSvgWidth)
9278
+ // .attr('height', 50)
9279
+ // .append('xhtml:div')
9280
+ // .attr('class', 'target-display')
9281
+ // .style('color', 'var(--chart-text-color)')
9282
+ // .html(function () {
9283
+ // let dataTypeTemp = '';
9284
+ // let targetLineName = 'target';
9285
+ // if (metaData.dataType) {
9286
+ // dataTypeTemp = metaData.dataType;
9287
+ // }
9288
+ // if (
9289
+ // self.chartData.targetLineData &&
9290
+ // self.chartData.targetLineData.targetName
9291
+ // ) {
9292
+ // targetLineName = self.chartData.targetLineData.targetName;
9293
+ // }
9294
+ // return (
9295
+ // `<div>${targetLineName}</div>` +
9296
+ // '<div>' +
9297
+ // self.chartData.targetLineData.target +
9298
+ // '' +
9299
+ // dataTypeTemp +
9300
+ // '</div>'
9301
+ // );
9302
+ // });
9303
+ // }
9304
+ // if (this.chartConfiguration.isDrilldownChart) {
9305
+ // /**
9306
+ // * used by drilldown charts
9307
+ // */
9308
+ // // svg
9309
+ // // .selectAll('.lib-axis-group-label')
9310
+ // // .attr('class', 'lib-ylabel-drilldowncharts')
9311
+ // // .text(metaData.yLabel.toLowerCase());
9312
+ // svg.selectAll('g.x1.axis1 g.tick line').style('display', 'none');
9313
+ // }
9314
+ // if (metaData.xLabel) {
9315
+ // function isAcronym(label) {
9316
+ // return (
9317
+ // (label.length <= 4 && /^[A-Z]+$/.test(label)) ||
9318
+ // (label === label.toUpperCase() && /[A-Z]/.test(label))
9319
+ // );
9320
+ // }
9321
+ // const xLabelText = metaData.xLabel;
9322
+ // const isAcr = isAcronym(xLabelText.replace(/[^A-Za-z]/g, ''));
9323
+ // const xPosition = isria ? (height + margin.top + margin.bottom) : (height + margin.top + margin.bottom + 40);
9324
+ // svg
9325
+ // .append('text')
9326
+ // .attr('class', function () {
9327
+ // let baseClass = 'lib-axis-group-label font-size-1';
9328
+ // if (self.chartConfiguration.isDrilldownChart)
9329
+ // return baseClass + ' lib-xlabel-drilldowncharts';
9330
+ // if (self.chartConfiguration.isMultiChartGridLine != undefined)
9331
+ // return baseClass + ' lib-xlabel-weeklyCharts';
9332
+ // return baseClass + ' lib-axis-waterfall-label';
9333
+ // })
9334
+ // .attr('style', self.chartConfiguration.xAxisCustomlabelStyles)
9335
+ // .attr(
9336
+ // 'transform',
9337
+ // 'translate(' + width / 2 + ' ,' + xPosition + ')'
9338
+ // )
9339
+ // .style('text-anchor', 'middle')
9340
+ // .style('fill', 'var(--chart-text-color)')
9341
+ // .text(isAcr ? xLabelText.toUpperCase() : xLabelText.toLowerCase())
9342
+ // .style('text-transform', isAcr ? 'none' : 'capitalize');
9343
+ // }
9344
+ // if (metaData.lineyLabel) {
9345
+ // svgYAxisRight
9346
+ // .append('text')
9347
+ // .attr('class', 'lib-axis-group-label lib-line-axis')
9348
+ // .attr('fill', 'var(--chart-text-color)')
9349
+ // .attr('style', self.chartConfiguration.yAxisCustomlabelStyles)
9350
+ // .attr('transform', 'translate(0,0) rotate(90)')
9351
+ // .attr('y', 0 - 100)
9352
+ // .attr('x', 0 + 100)
9353
+ // .attr('dy', '5em')
9354
+ // .style('text-anchor', 'middle')
9355
+ // .style('font-size', 'smaller')
9356
+ // .text(metaData.lineyLabel);
9357
+ // }
9358
+ // if (lineData) {
9359
+ // svg
9360
+ // .append('path')
9361
+ // .datum(lineData)
9362
+ // .attr('fill', 'none')
9363
+ // .attr('stroke', self.chartConfiguration.lineGraphColor)
9364
+ // .attr('stroke-width', 1.5)
9365
+ // .attr(
9366
+ // 'd',
9367
+ // d3
9368
+ // .line()
9369
+ // .x(function (d) {
9370
+ // return x(d.name) + x.bandwidth() / 2;
9371
+ // })
9372
+ // .y(function (d) {
9373
+ // return lineYscale(d.value);
9374
+ // })
9375
+ // );
9376
+ // var dot = svg
9377
+ // .selectAll('myCircles')
9378
+ // .data(lineData)
9379
+ // .enter()
9380
+ // .append('g')
9381
+ // .on('click', function (d) {
9382
+ // if (
9383
+ // !metaData.barWithoutClick ||
9384
+ // !metaData.barWithoutClick.length ||
9385
+ // (!metaData.barWithoutClick.includes(d?.name) &&
9386
+ // !metaData.barWithoutClick.includes(d?.key))
9387
+ // )
9388
+ // self.handleClick(d);
9389
+ // });
9390
+ // dot
9391
+ // .append('circle')
9392
+ // .attr('fill', function (d) {
9393
+ // return self.chartConfiguration.lineGraphColor;
9394
+ // })
9395
+ // .attr('stroke', 'none')
9396
+ // .attr('cx', function (d) {
9397
+ // return x(d.name) + x.bandwidth() / 2;
9398
+ // })
9399
+ // .attr('cy', function (d) {
9400
+ // return lineYscale(d.value);
9401
+ // })
9402
+ // .style('cursor', () =>
9403
+ // self.chartData.metaData.hasDrillDown ? 'pointer' : 'default'
9404
+ // )
9405
+ // .attr('r', 3);
9406
+ // if (self.chartConfiguration.lineGraphColor) {
9407
+ // dot
9408
+ // .append('text')
9409
+ // .attr('class', 'dot')
9410
+ // .attr('fill', 'var(--chart-text-color)')
9411
+ // .attr('color', self.chartConfiguration.lineGraphColor)
9412
+ // .attr('style', 'font-size: ' + '.85em')
9413
+ // .attr('x', function (d, i) {
9414
+ // return x(d.name) + x.bandwidth() / 2;
9415
+ // })
9416
+ // .attr('y', function (d) {
9417
+ // return lineYscale(d.value);
9418
+ // })
9419
+ // .attr('dy', '-1em')
9420
+ // .text(function (d) {
9421
+ // return self.chartConfiguration.labelFormatter(d.value);
9422
+ // });
9423
+ // }
9424
+ // }
9425
+ // }
8190
9426
  initializegroupChart() {
8191
- var self = this;
9427
+ // ==================== VARIABLE DECLARATIONS ====================
9428
+ const self = this;
8192
9429
  let data = [];
8193
9430
  let metaData = null;
8194
9431
  let keyList = null;
8195
9432
  let lineData = null;
8196
9433
  let colorMap = {};
8197
- var formatFromBackend;
8198
- var formatForHugeNumbers;
9434
+ let formatFromBackend;
9435
+ let formatForHugeNumbers;
9436
+ // Device detection
8199
9437
  const isMobile = window.innerWidth < 576;
8200
9438
  const isTablet = window.innerWidth >= 576 && window.innerWidth < 992;
8201
9439
  const isDesktop = window.innerWidth >= 992;
8202
- let isria = this.customChartConfiguration.isRia;
8203
- var x;
8204
- var alternate_text = false;
8205
- var short_tick_length = 4;
8206
- var long_tick_length = 16;
8207
- /**
8208
- * longer tick length needed for weekly charts
8209
- */
8210
- var short_tick_length_bg = 5;
8211
- var long_tick_length_bg = 30;
8212
- var leftAndRightSpaces = 50;
8213
- var rightSvgWidth = 60;
8214
- var tempScale;
8215
- for (var i in this.defaultConfiguration) {
8216
- this.chartConfiguration[i] = ChartHelper.getValueByConfigurationType(i, this.defaultConfiguration, this.customChartConfiguration);
9440
+ const isria = this.customChartConfiguration.isRia;
9441
+ // Chart scale variables
9442
+ let x;
9443
+ let tempScale;
9444
+ // Tick length constants
9445
+ const SHORT_TICK_LENGTH = 4;
9446
+ const LONG_TICK_LENGTH = 16;
9447
+ const SHORT_TICK_LENGTH_BG = 5;
9448
+ const LONG_TICK_LENGTH_BG = 30;
9449
+ const LEFT_AND_RIGHT_SPACES = 50;
9450
+ const RIGHT_SVG_WIDTH = 60;
9451
+ // Flags
9452
+ let alternate_text = false;
9453
+ // ==================== CONFIGURATION SETUP ====================
9454
+ for (const key in this.defaultConfiguration) {
9455
+ this.chartConfiguration[key] = ChartHelper.getValueByConfigurationType(key, this.defaultConfiguration, this.customChartConfiguration);
8217
9456
  }
9457
+ // Extract chart data
8218
9458
  data = this.chartData.data;
8219
9459
  metaData = this.chartData.metaData;
8220
9460
  lineData = this.chartData.lineData;
8221
- // if (lineData || this.chartData.targetLineData) {
8222
- // rightSvgWidth = 60;
8223
- // }
9461
+ // Setup color mappings
8224
9462
  if (!metaData.colorAboveTarget) {
8225
9463
  metaData['colorAboveTarget'] = metaData.colors;
8226
9464
  }
8227
9465
  colorMap = metaData.colors;
8228
9466
  keyList = metaData.keyList;
8229
- var chartContainer = d3.select(this.containerElt.nativeElement);
8230
- var verticalstackedcontainer = d3.select(this.groupcontainerElt.nativeElement);
8231
- var margin = this.chartConfiguration.margin;
9467
+ // ==================== CONTAINER SETUP ====================
9468
+ const chartContainer = d3.select(this.containerElt.nativeElement);
9469
+ const verticalstackedcontainer = d3.select(this.groupcontainerElt.nativeElement);
9470
+ const margin = this.chartConfiguration.margin;
8232
9471
  const { width, height } = this.calculateChartDimensions(chartContainer, verticalstackedcontainer, margin, self);
8233
- /**
8234
- * for hiding header
8235
- * used by weekly charts
8236
- */
8237
- if (this.chartConfiguration.isHeaderVisible != undefined)
9472
+ // ==================== VISIBILITY CONFIGURATION ====================
9473
+ if (this.chartConfiguration.isHeaderVisible !== undefined) {
8238
9474
  this.isHeaderVisible = this.chartConfiguration.isHeaderVisible;
8239
- /**
8240
- * for hiding legends
8241
- * used by weekly charts
8242
- */
8243
- if (this.chartConfiguration.legendVisible != undefined) {
9475
+ }
9476
+ if (this.chartConfiguration.legendVisible !== undefined) {
8244
9477
  this.legendVisible = this.chartConfiguration.legendVisible;
8245
9478
  }
8246
- /**
8247
- * for removing background color so that it can take parents color
8248
- *
8249
- */
8250
- if (this.chartConfiguration.isTransparentBackground != undefined) {
8251
- this.isTransparentBackground =
8252
- this.chartConfiguration.isTransparentBackground;
9479
+ if (this.chartConfiguration.isTransparentBackground !== undefined) {
9480
+ this.isTransparentBackground = this.chartConfiguration.isTransparentBackground;
8253
9481
  }
8254
- /**
8255
- * format data values based on configuration received
8256
- */
8257
- if (this.chartConfiguration.textFormatter != undefined) {
9482
+ // ==================== DATA FORMATTING ====================
9483
+ if (this.chartConfiguration.textFormatter !== undefined) {
8258
9484
  formatFromBackend = ChartHelper.dataValueFormatter(this.chartConfiguration.textFormatter);
8259
9485
  formatForHugeNumbers = ChartHelper.dataValueFormatter('.2s');
8260
9486
  }
8261
- const { outerContainer, svgYAxisLeft, svgYAxisRight, innerContainer, svg } = this.createChartContainers(chartContainer, margin, height, rightSvgWidth, self, width);
8262
- var subgroups = keyList;
8263
- var groups = d3
8264
- .map(data, function (d) {
8265
- return d.name;
8266
- })
8267
- .keys();
8268
- /**
8269
- * x axis range made similar to line chart or vertical stack so that all the charts will get aligned with each other.
8270
- */
8271
- if (this.chartConfiguration.isMultiChartGridLine != undefined) {
8272
- x = d3
8273
- .scaleBand()
9487
+ // ==================== SVG CONTAINERS CREATION ====================
9488
+ const { outerContainer, svgYAxisLeft, svgYAxisRight, innerContainer, svg } = this.createChartContainers(chartContainer, margin, height, RIGHT_SVG_WIDTH, self, width);
9489
+ // ==================== SCALES SETUP ====================
9490
+ const subgroups = keyList;
9491
+ const groups = d3.map(data, (d) => d.name).keys();
9492
+ // X-axis scale configuration
9493
+ if (this.chartConfiguration.isMultiChartGridLine !== undefined) {
9494
+ x = d3.scaleBand()
8274
9495
  .rangeRound([width, 0])
8275
9496
  .align(0.5)
8276
9497
  .padding([0.5])
8277
- .domain(data.map(function (d) {
8278
- return d.name.toLowerCase();
8279
- }));
9498
+ .domain(data.map((d) => d.name.toLowerCase()));
8280
9499
  }
8281
9500
  else {
8282
- x = d3
8283
- .scaleBand()
9501
+ x = d3.scaleBand()
8284
9502
  .domain(groups)
8285
- .range([leftAndRightSpaces, width - rightSvgWidth - leftAndRightSpaces])
9503
+ .range([LEFT_AND_RIGHT_SPACES, width - RIGHT_SVG_WIDTH - LEFT_AND_RIGHT_SPACES])
8286
9504
  .padding([0.3]);
8287
9505
  }
8288
- // x.bandwidth(96);
8289
- var xScaleFromOrigin = d3
8290
- .scaleBand()
9506
+ const xScaleFromOrigin = d3.scaleBand()
8291
9507
  .domain(groups)
8292
- .range([0, width - rightSvgWidth]);
8293
- // .padding([0.2]);
8294
- if (this.chartConfiguration.isMultiChartGridLine == undefined) {
8295
- /**
8296
- * normal ticks for all dashboard charts
8297
- */
8298
- svg
8299
- .append('g')
9508
+ .range([0, width - RIGHT_SVG_WIDTH]);
9509
+ // ==================== X-AXIS RENDERING ====================
9510
+ this.renderXAxis(svg, x, height, metaData, subgroups, data, SHORT_TICK_LENGTH_BG, LONG_TICK_LENGTH_BG, self, isria, isMobile);
9511
+ // ==================== Y-AXIS SETUP ====================
9512
+ const y = d3.scaleLinear().rangeRound([height, 0]);
9513
+ let maxValue = this.calculateMaxValue(data, keyList);
9514
+ if (this.chartConfiguration.customYscale) {
9515
+ maxValue = maxValue * this.chartConfiguration.customYscale;
9516
+ }
9517
+ if (this.chartData.targetLineData && maxValue < this.chartData.targetLineData.target) {
9518
+ maxValue = maxValue < 10 && this.chartData.targetLineData.target < 10
9519
+ ? this.chartData.targetLineData.target + 3
9520
+ : this.chartData.targetLineData.target + 20;
9521
+ }
9522
+ y.domain([0, maxValue]).nice();
9523
+ // ==================== LINE CHART Y-SCALE ====================
9524
+ let lineYscale;
9525
+ let yLineAxis;
9526
+ if (lineData != null) {
9527
+ const result = this.setupLineYScale(lineData, height, self);
9528
+ lineYscale = result.lineYscale;
9529
+ yLineAxis = result.yLineAxis;
9530
+ }
9531
+ // ==================== GRID LINES ====================
9532
+ this.renderGridLines(svg, x, y, height, width, self);
9533
+ // ==================== BARS RENDERING ====================
9534
+ const xSubgroup = this.setupXSubgroupScale(subgroups, x, self);
9535
+ const color = d3.scaleOrdinal()
9536
+ .domain(subgroups)
9537
+ .range(Object.values(metaData.colors));
9538
+ this.renderBars(svg, data, subgroups, x, xSubgroup, y, height, color, metaData, self, LEFT_AND_RIGHT_SPACES, tempScale, isria);
9539
+ // ==================== BAR LABELS ====================
9540
+ if (this.chartConfiguration.textsOnBar !== undefined && !this.isZoomedOut) {
9541
+ this.renderBarLabels(svg, data, subgroups, x, xSubgroup, y, height, metaData, self, tempScale, isria);
9542
+ }
9543
+ // ==================== Y-AXIS RENDERING ====================
9544
+ this.renderYAxis(svg, svgYAxisLeft, svgYAxisRight, y, yLineAxis, lineData, self, isria, margin);
9545
+ // ==================== AXIS LABELS ====================
9546
+ this.renderAxisLabels(svg, svgYAxisLeft, svgYAxisRight, metaData, width, height, margin, self, isria, RIGHT_SVG_WIDTH);
9547
+ // ==================== TARGET LINE ====================
9548
+ if (this.chartData.targetLineData) {
9549
+ this.renderTargetLine(svg, svgYAxisRight, y, width, RIGHT_SVG_WIDTH, metaData, self);
9550
+ }
9551
+ // ==================== LINE CHART ====================
9552
+ if (lineData) {
9553
+ this.renderLineChart(svg, lineData, x, lineYscale, metaData, self);
9554
+ }
9555
+ // ==================== ZOOM HANDLING ====================
9556
+ if (this.isZoomedOut) {
9557
+ this.handleZoomOut(svg, height, margin);
9558
+ }
9559
+ }
9560
+ // ==================== HELPER METHODS ====================
9561
+ renderXAxis(svg, x, height, metaData, subgroups, data, shortTickLengthBg, longTickLengthBg, self, isria, isMobile) {
9562
+ let alternate_text = false;
9563
+ if (this.chartConfiguration.isMultiChartGridLine === undefined) {
9564
+ // Normal ticks for dashboard charts
9565
+ svg.append('g')
8300
9566
  .attr('class', 'x1 axis1')
8301
- .attr('transform', 'translate(0,' + height + ')')
9567
+ .attr('transform', `translate(0,${height})`)
8302
9568
  .call(d3.axisBottom(x))
8303
9569
  .call((g) => g.select('.domain').remove());
8304
9570
  svg.selectAll('g.x1.axis1 g.tick line').remove();
8305
- // Only move x-axis labels further down for grouped charts if there is no xLabel
8306
- if (subgroups.length > 1 && !metaData.xLabel) {
8307
- svg
8308
- .selectAll('g.x1.axis1 g.tick text')
8309
- .attr('class', 'lib-xaxis-labels-texts-drilldown')
8310
- .style('fill', 'var(--chart-text-color)')
8311
- .attr('y', 32); // Increase distance from bars (default is ~9)
8312
- }
8313
- else {
8314
- svg
8315
- .selectAll('g.x1.axis1 g.tick text')
8316
- .attr('class', 'lib-xaxis-labels-texts-drilldown')
8317
- .style('fill', 'var(--chart-text-color)');
8318
- }
9571
+ const yOffset = subgroups.length > 1 && !metaData.xLabel ? 32 : 0;
9572
+ svg.selectAll('g.x1.axis1 g.tick text')
9573
+ .attr('class', 'lib-xaxis-labels-texts-drilldown')
9574
+ .style('fill', 'var(--chart-text-color)')
9575
+ .attr('y', yOffset || null);
8319
9576
  }
8320
9577
  else {
8321
- /**
8322
- * bigger ticks for weekly charts and more space from x axis to labels
8323
- */
8324
- /**
8325
- * draw x axis
8326
- */
8327
- svg
8328
- .append('g')
9578
+ // Bigger ticks for weekly charts
9579
+ svg.append('g')
8329
9580
  .attr('class', 'x1 axis1')
8330
- .attr('transform', 'translate(0,' + height + ')')
9581
+ .attr('transform', `translate(0,${height})`)
8331
9582
  .call(d3.axisBottom(x).tickSize(0))
8332
9583
  .call((g) => g.select('.domain').attr('fill', 'none'));
8333
- /**
8334
- * tick line size in alternate fashion
8335
- */
9584
+ // Alternate tick line sizes
8336
9585
  svg.selectAll('g.x1.axis1 g.tick line').attr('y2', function () {
8337
- if (alternate_text &&
8338
- self.chartConfiguration.isNoAlternateXaxisText == undefined) {
9586
+ if (alternate_text && self.chartConfiguration.isNoAlternateXaxisText === undefined) {
8339
9587
  alternate_text = false;
8340
- return long_tick_length_bg - 7;
9588
+ return longTickLengthBg - 7;
8341
9589
  }
8342
9590
  else {
8343
9591
  alternate_text = true;
8344
- return short_tick_length_bg - 4;
9592
+ return shortTickLengthBg - 4;
8345
9593
  }
8346
9594
  });
8347
- /**
8348
- * reset the flag so that values can be shown in same alternate fashion
8349
- */
8350
9595
  alternate_text = false;
8351
- /**
8352
- * print x-axis label texts
8353
- * used by weekly charts
8354
- */
8355
- svg
8356
- .selectAll('g.x1.axis1 g.tick text')
9596
+ // X-axis label texts
9597
+ svg.selectAll('g.x1.axis1 g.tick text')
8357
9598
  .attr('class', 'lib-xaxis-labels-texts-weeklycharts')
8358
9599
  .attr('y', function () {
8359
- // Minimize gap in maximized (fullscreen) view for weekly charts
8360
9600
  if (self.chartConfiguration.isFullScreen) {
8361
- return short_tick_length_bg;
9601
+ return shortTickLengthBg;
8362
9602
  }
8363
9603
  if (alternate_text) {
8364
9604
  alternate_text = false;
8365
- return long_tick_length_bg;
9605
+ return longTickLengthBg;
8366
9606
  }
8367
9607
  else {
8368
9608
  alternate_text = true;
8369
- return short_tick_length_bg;
9609
+ return shortTickLengthBg;
8370
9610
  }
8371
9611
  });
8372
9612
  }
9613
+ // Apply labels on same line configuration
8373
9614
  if (self.chartConfiguration.xLabelsOnSameLine) {
8374
- const xAxisLabels = svg
8375
- .selectAll('g.x1.axis1 g.tick text')
8376
- .attr('class', 'lib-xaxis-labels-texts-drilldown')
8377
- .style('font-size', this.isHeaderVisible ? '18px' : '14px')
8378
- .attr('text-anchor', 'middle')
8379
- .attr('y', function (d) {
8380
- // For grouped bar charts with many bars and xLabel present, only add 5 if the label is a date
8381
- if (subgroups.length > 1 && data.length > 8 && metaData.xLabel) {
8382
- const isDateLabel = /\d{2,4}[-\/]/.test(d);
8383
- if (self.chartConfiguration.isFullScreen) {
8384
- return isDateLabel ? short_tick_length_bg + 14 : short_tick_length_bg;
8385
- }
8386
- return isDateLabel ? short_tick_length_bg + 14 : short_tick_length_bg;
8387
- }
8388
- // For grouped bar charts with many bars and NO xLabel, add space as before, but reduce in fullscreen
8389
- if (subgroups.length > 1 && data.length > 8 && !metaData.xLabel) {
8390
- const chartHasExtraBottom = (self.chartConfiguration.margin && self.chartConfiguration.margin.bottom >= 40);
8391
- if (self.chartConfiguration.isFullScreen) {
8392
- // Reduce extra gap in maximized view
8393
- return short_tick_length_bg + 2;
8394
- }
8395
- return chartHasExtraBottom ? short_tick_length_bg : short_tick_length_bg + 10;
8396
- }
8397
- // Default/fallback logic for other cases
8398
- let baseY = self.isHeaderVisible ? short_tick_length_bg + 25 : short_tick_length_bg;
8399
- if (subgroups.length > 1 &&
8400
- !metaData.xLabel &&
8401
- (/\d{2,4}[-\/]\d{2}[-\/]\d{2,4}/.test(d) || /\d{2,4}[-\/]\d{2,4}/.test(d))) {
8402
- baseY = self.isHeaderVisible ? short_tick_length_bg + 15 : short_tick_length_bg + 25;
8403
- }
8404
- if (/\d{2,4}[-\/]\d{2,4}/.test(d) && d.indexOf(' ') > -1) {
8405
- baseY += 4;
8406
- }
8407
- // In maximized view, reduce baseY slightly for grouped bars
8408
- if (self.chartConfiguration.isFullScreen && subgroups.length > 1) {
8409
- baseY = Math.max(short_tick_length_bg, baseY - 10);
8410
- }
8411
- return baseY;
8412
- })
8413
- .attr('x', function (d) {
8414
- if (self.chartData.data.length > 8 && !self.isZoomedOut) {
8415
- return 1; // Move first line text slightly to the left in zoom-in view for better alignment
8416
- }
8417
- return 0; // Default position
8418
- })
8419
- .text(function (d) {
8420
- var isValueToBeIgnored = false;
8421
- if (isMobile && !self.isHeaderVisible) {
8422
- let firstPart = d.split(/[\s\-]+/)[0];
8423
- return firstPart.substring(0, 3).toLowerCase();
8424
- }
8425
- data.map((indiv) => {
8426
- if (indiv.name &&
8427
- indiv.name.toLowerCase() == d.trim().toLowerCase() &&
8428
- indiv[metaData.keyList[0]] == -1) {
8429
- isValueToBeIgnored = true;
8430
- }
8431
- });
8432
- if (isValueToBeIgnored) {
8433
- return '';
8434
- }
8435
- // Always add space before and after hyphen for date range labels, even when header is visible and label is single line
8436
- // Apply for grouped bar charts and single bar charts, header visible, single line
8437
- const dateRangeRegex = /(\d{2,4}[-\/]\d{2}[-\/]\d{2,4})\s*-\s*(\d{2,4}[-\/]\d{2}[-\/]\d{2,4})/;
8438
- if (dateRangeRegex.test(d.trim())) {
8439
- return d.trim().replace(dateRangeRegex, (m, d1, d2) => `${d1} - ${d2}`);
8440
- }
8441
- // Split date and week labels into two lines in grouped bar zoom-in view (and minimized view)
8442
- const isDateLabel = /\d{2,4}[-\/]/.test(d);
8443
- const isWeekLabel = /week|wk|w\d+/i.test(d);
8444
- if (subgroups.length > 1 && !self.isZoomedOut && data.length > 8 && d.indexOf(' ') > -1 && (isDateLabel || isWeekLabel)) {
8445
- var first = d.substring(0, d.indexOf(' '));
8446
- var second = d.substring(d.indexOf(' ') + 1).trim();
8447
- return first + '\n' + second;
8448
- }
8449
- // Also keep previous logic for minimized view
8450
- if (isDateLabel) {
8451
- if (!self.isHeaderVisible && data.length > 8 && d.indexOf(' ') > -1) {
8452
- var first = d.substring(0, d.indexOf(' '));
8453
- var second = d.substring(d.indexOf(' ') + 1).trim();
8454
- return first + '\n' + second;
8455
- }
8456
- else {
8457
- return d;
8458
- }
8459
- }
8460
- if (d.trim().indexOf(' ') > -1) {
8461
- return d.trim().substring(0, d.indexOf(' ')).toLowerCase();
8462
- }
8463
- return d.toLowerCase();
8464
- // If label looks like a date (contains digits and - or /)
8465
- const isDateLabel2 = /\d{2,4}[-\/]/.test(d);
8466
- // Only split date/week labels if there are many grouped bars and header is not visible
8467
- if (isDateLabel) {
8468
- if (!self.isHeaderVisible && data.length > 8 && d.indexOf(' ') > -1) {
8469
- var first = d.substring(0, d.indexOf(' '));
8470
- var second = d.substring(d.indexOf(' ') + 1).trim();
8471
- return first + '\n' + second;
8472
- }
8473
- else {
8474
- return d;
8475
- }
8476
- }
8477
- if (d.trim().indexOf(' ') > -1) {
8478
- return d.trim().substring(0, d.indexOf(' ')).toLowerCase();
8479
- }
8480
- return d.toLowerCase();
8481
- });
8482
- // Now apply writing-mode: sideways-lr for grouped charts with date labels in zoomed-out view and many bars
8483
- xAxisLabels.each(function (d) {
8484
- // Only apply writing-mode for exact date labels, not those containing 'week' or similar
8485
- const isDateLabel = /^(\d{2,4}[-\/])?\d{2,4}[-\/]\d{2,4}$/.test(d.trim());
8486
- const isWeekLabel = /week|wk|w\d+/i.test(d);
8487
- if (subgroups.length > 1 && self.isZoomedOut && data.length > 8 && isDateLabel && !isWeekLabel) {
8488
- d3.select(this).style('writing-mode', 'sideways-lr');
8489
- }
8490
- });
8491
- if (!isMobile) {
8492
- svg
8493
- .selectAll('g.x1.axis1 g.tick')
8494
- .filter(function (d) {
8495
- return !/\d{2,4}[-\/]/.test(d); // Only process non-date labels
8496
- })
8497
- .append('text')
8498
- .attr('class', 'lib-xaxis-labels-texts-drilldown')
8499
- .attr('y', long_tick_length_bg)
8500
- .attr('fill', 'var(--chart-text-color)')
8501
- .attr('x', function (d) {
8502
- if (self.chartData.data.length > 8 && !self.isZoomedOut) {
8503
- return 1; // Move text slightly to the left
8504
- }
8505
- return 0; // Default position
8506
- })
8507
- .text(function (d) {
8508
- if (d.trim().indexOf(' ') > -1) {
8509
- return d.trim().substring(d.indexOf(' '), d.length).toLowerCase();
8510
- }
8511
- return '';
8512
- });
8513
- }
9615
+ this.applyXLabelsOnSameLine(svg, subgroups, data, metaData, self, shortTickLengthBg, isMobile, isria);
8514
9616
  }
9617
+ // Mobile override for RIA
8515
9618
  if (isria && self.chartData.data.length > 8) {
8516
- svg
8517
- .selectAll('g.x1.axis1 g.tick text')
9619
+ svg.selectAll('g.x1.axis1 g.tick text')
8518
9620
  .classed('mobile-xaxis-override', true)
8519
- .text(function (d) {
8520
- return d.substring(0, 3);
8521
- })
9621
+ .text((d) => d.substring(0, 3))
8522
9622
  .style('font-size', '12px')
8523
9623
  .attr('y', 5)
8524
9624
  .attr('x', 5)
8525
9625
  .style('text-anchor', 'middle');
8526
9626
  }
9627
+ // Mobile override
8527
9628
  if (isMobile && !this.isHeaderVisible) {
8528
- svg
8529
- .selectAll('g.x1.axis1 g.tick text')
9629
+ svg.selectAll('g.x1.axis1 g.tick text')
8530
9630
  .classed('mobile-xaxis-override', true);
8531
9631
  }
8532
- /**y scale for left y axis */
8533
- var y = d3.scaleLinear().rangeRound([height, 0]);
8534
- var maxValue = d3.max(data, (d) => d3.max(keyList, (key) => +d[key]));
8535
- if (maxValue == 0) {
9632
+ }
9633
+ applyXLabelsOnSameLine(svg, subgroups, data, metaData, self, shortTickLengthBg, isMobile, isria) {
9634
+ const xAxisLabels = svg.selectAll('g.x1.axis1 g.tick text')
9635
+ .attr('class', 'lib-xaxis-labels-texts-drilldown')
9636
+ .style('font-size', this.isHeaderVisible ? '18px' : '14px')
9637
+ .attr('text-anchor', 'middle')
9638
+ .attr('y', (d) => this.calculateXLabelYPosition(d, subgroups, data, metaData, self, shortTickLengthBg))
9639
+ .attr('x', (d) => (self.chartData.data.length > 8 && !self.isZoomedOut) ? 1 : 0)
9640
+ .text((d) => this.formatXLabelText(d, data, metaData, subgroups, self, isMobile));
9641
+ // Apply writing-mode for grouped charts with date labels in zoomed-out view
9642
+ xAxisLabels.each(function (d) {
9643
+ const isDateLabel = /^(\d{2,4}[-\/])?\d{2,4}[-\/]\d{2,4}$/.test(d.trim());
9644
+ const isWeekLabel = /week|wk|w\d+/i.test(d);
9645
+ if (subgroups.length > 1 && self.isZoomedOut && data.length > 8 && isDateLabel && !isWeekLabel) {
9646
+ d3.select(this).style('writing-mode', 'sideways-lr');
9647
+ }
9648
+ });
9649
+ // Add second line for non-date labels on desktop
9650
+ if (!isMobile) {
9651
+ svg.selectAll('g.x1.axis1 g.tick')
9652
+ .filter((d) => !/\d{2,4}[-\/]/.test(d))
9653
+ .append('text')
9654
+ .attr('class', 'lib-xaxis-labels-texts-drilldown')
9655
+ .attr('y', 30)
9656
+ .attr('fill', 'var(--chart-text-color)')
9657
+ .attr('x', (d) => (self.chartData.data.length > 8 && !self.isZoomedOut) ? 1 : 0)
9658
+ .text((d) => {
9659
+ if (d.trim().indexOf(' ') > -1) {
9660
+ return d.trim().substring(d.indexOf(' '), d.length).toLowerCase();
9661
+ }
9662
+ return '';
9663
+ });
9664
+ }
9665
+ }
9666
+ calculateXLabelYPosition(d, subgroups, data, metaData, self, shortTickLengthBg) {
9667
+ // For grouped bar charts with many bars and xLabel present
9668
+ if (subgroups.length > 1 && data.length > 8 && metaData.xLabel) {
9669
+ const isDateLabel = /\d{2,4}[-\/]/.test(d);
9670
+ return isDateLabel ? shortTickLengthBg + 14 : shortTickLengthBg;
9671
+ }
9672
+ // For grouped bar charts with many bars and NO xLabel
9673
+ if (subgroups.length > 1 && data.length > 8 && !metaData.xLabel) {
9674
+ const chartHasExtraBottom = self.chartConfiguration.margin && self.chartConfiguration.margin.bottom >= 40;
9675
+ if (self.chartConfiguration.isFullScreen) {
9676
+ return shortTickLengthBg + 2;
9677
+ }
9678
+ return chartHasExtraBottom ? shortTickLengthBg : shortTickLengthBg + 10;
9679
+ }
9680
+ // Default/fallback logic
9681
+ let baseY = self.isHeaderVisible ? shortTickLengthBg + 25 : shortTickLengthBg;
9682
+ if (subgroups.length > 1 && !metaData.xLabel &&
9683
+ (/\d{2,4}[-\/]\d{2}[-\/]\d{2,4}/.test(d) || /\d{2,4}[-\/]\d{2,4}/.test(d))) {
9684
+ baseY = self.isHeaderVisible ? shortTickLengthBg + 15 : shortTickLengthBg + 25;
9685
+ }
9686
+ if (/\d{2,4}[-\/]\d{2,4}/.test(d) && d.indexOf(' ') > -1) {
9687
+ baseY += 4;
9688
+ }
9689
+ if (self.chartConfiguration.isFullScreen && subgroups.length > 1) {
9690
+ baseY = Math.max(shortTickLengthBg, baseY - 10);
9691
+ }
9692
+ return baseY;
9693
+ }
9694
+ formatXLabelText(d, data, metaData, subgroups, self, isMobile) {
9695
+ if (isMobile && !self.isHeaderVisible) {
9696
+ const firstPart = d.split(/[\s\-]+/)[0];
9697
+ return firstPart.substring(0, 3).toLowerCase();
9698
+ }
9699
+ // Check if value should be ignored
9700
+ const isValueToBeIgnored = data.some((indiv) => indiv.name && indiv.name.toLowerCase() === d.trim().toLowerCase() &&
9701
+ indiv[metaData.keyList[0]] === -1);
9702
+ if (isValueToBeIgnored) {
9703
+ return '';
9704
+ }
9705
+ // Handle date range labels
9706
+ const dateRangeRegex = /(\d{2,4}[-\/]\d{2}[-\/]\d{2,4})\s*-\s*(\d{2,4}[-\/]\d{2}[-\/]\d{2,4})/;
9707
+ if (dateRangeRegex.test(d.trim())) {
9708
+ return d.trim().replace(dateRangeRegex, (m, d1, d2) => `${d1} - ${d2}`);
9709
+ }
9710
+ // Split date and week labels into two lines
9711
+ const isDateLabel = /\d{2,4}[-\/]/.test(d);
9712
+ const isWeekLabel = /week|wk|w\d+/i.test(d);
9713
+ if (subgroups.length > 1 && !self.isZoomedOut && data.length > 8 &&
9714
+ d.indexOf(' ') > -1 && (isDateLabel || isWeekLabel)) {
9715
+ const first = d.substring(0, d.indexOf(' '));
9716
+ const second = d.substring(d.indexOf(' ') + 1).trim();
9717
+ return `${first}\n${second}`;
9718
+ }
9719
+ // Handle date labels in minimized view
9720
+ if (isDateLabel) {
9721
+ if (!self.isHeaderVisible && data.length > 8 && d.indexOf(' ') > -1) {
9722
+ const first = d.substring(0, d.indexOf(' '));
9723
+ const second = d.substring(d.indexOf(' ') + 1).trim();
9724
+ return `${first}\n${second}`;
9725
+ }
9726
+ return d;
9727
+ }
9728
+ // Handle labels with spaces
9729
+ if (d.trim().indexOf(' ') > -1) {
9730
+ return d.trim().substring(0, d.indexOf(' ')).toLowerCase();
9731
+ }
9732
+ return d.toLowerCase();
9733
+ }
9734
+ calculateMaxValue(data, keyList) {
9735
+ let maxValue = d3.max(data, (d) => d3.max(keyList, (key) => +d[key]));
9736
+ if (maxValue === 0) {
8536
9737
  if (this.chartData.targetLineData) {
8537
9738
  maxValue = this.chartData.targetLineData.target + 20;
8538
9739
  }
@@ -8540,661 +9741,401 @@ class HorizontalGroupedBarWithScrollZoomComponent extends ComponentUniqueId {
8540
9741
  maxValue = 100;
8541
9742
  }
8542
9743
  }
8543
- if (this.chartConfiguration.customYscale) {
8544
- /**
8545
- * increase y-scale so that values wont cross or exceed out of range
8546
- * used in weekly charts
8547
- */
8548
- maxValue = maxValue * this.chartConfiguration.customYscale;
9744
+ return maxValue;
9745
+ }
9746
+ setupLineYScale(lineData, height, self) {
9747
+ let maxLineValue = d3.max(lineData, (d) => +d.value);
9748
+ maxLineValue = maxLineValue * self.chartConfiguration.customYscale;
9749
+ let minLineValue = d3.min(lineData, (d) => +d.value);
9750
+ if (maxLineValue > 0)
9751
+ minLineValue = minLineValue - 3;
9752
+ if (minLineValue > 0)
9753
+ minLineValue = 0;
9754
+ const lineYscale = d3.scaleLinear()
9755
+ .domain([minLineValue, maxLineValue])
9756
+ .range([height, minLineValue]);
9757
+ const yLineAxis = d3.axisRight(lineYscale)
9758
+ .ticks(self.chartConfiguration.numberOfYTicks)
9759
+ .tickSize(0)
9760
+ .tickFormat(self.chartConfiguration.yLineAxisLabelFomatter);
9761
+ return { lineYscale, yLineAxis };
9762
+ }
9763
+ renderGridLines(svg, x, y, height, width, self) {
9764
+ // X-axis grid between labels
9765
+ if (self.chartConfiguration.isXgridBetweenLabels) {
9766
+ svg.append('g')
9767
+ .attr('class', 'grid')
9768
+ .attr('transform', `translate(${x.bandwidth() / 2},${height})`)
9769
+ .call(d3.axisBottom(x).tickSize(-height).tickFormat(''))
9770
+ .style('stroke-dasharray', '5 5')
9771
+ .style('color', 'var(--chart-grid-color, #999999)')
9772
+ .call((g) => g.select('.domain').remove());
8549
9773
  }
8550
- if (this.chartData.targetLineData &&
8551
- maxValue < this.chartData.targetLineData.target) {
8552
- maxValue =
8553
- maxValue < 10 && this.chartData.targetLineData.target < 10
8554
- ? this.chartData.targetLineData.target + 3
8555
- : this.chartData.targetLineData.target + 20;
8556
- }
8557
- y.domain([0, maxValue]).nice();
8558
- let lineYscale;
8559
- if (lineData != null) {
8560
- let maxLineValue = d3.max(lineData, function (d) {
8561
- return +d.value;
8562
- });
8563
- maxLineValue = maxLineValue * this.chartConfiguration.customYscale;
8564
- let minLineValue = d3.min(lineData, function (d) {
8565
- return +d.value;
8566
- });
8567
- if (maxLineValue > 0)
8568
- minLineValue = minLineValue - 3;
8569
- if (minLineValue > 0) {
8570
- minLineValue = 0;
8571
- }
8572
- lineYscale = d3
8573
- .scaleLinear()
8574
- .domain([minLineValue, maxLineValue])
8575
- .range([height, minLineValue]);
8576
- }
8577
- let yLineAxis;
8578
- if (lineYscale != null) {
8579
- yLineAxis = d3
8580
- .axisRight(lineYscale)
8581
- .ticks(self.chartConfiguration.numberOfYTicks)
8582
- .tickSize(0)
8583
- .tickFormat(self.chartConfiguration.yLineAxisLabelFomatter);
8584
- }
8585
- /**
8586
- * show x-axis grid between labels
8587
- * used by weekly charts
8588
- */
8589
- if (self.chartConfiguration.isXgridBetweenLabels) {
8590
- svg
8591
- .append('g')
8592
- .attr('class', 'grid')
8593
- .attr('transform', 'translate(' + x.bandwidth() / 2 + ',' + height + ')')
8594
- .call(d3.axisBottom(x).tickSize(-height).tickFormat(''))
8595
- .style('stroke-dasharray', '5 5')
8596
- .style('color', 'var(--chart-grid-color, #999999)') // Use CSS variable
8597
- .call((g) => g.select('.domain').remove());
8598
- }
8599
- if (this.chartConfiguration.yAxisGrid) {
8600
- svg
8601
- .append('g')
8602
- .call(d3
8603
- .axisLeft(y)
8604
- .ticks(self.chartConfiguration.numberOfYTicks)
8605
- .tickSize(-width))
8606
- .style('color', 'var(--chart-axis-color, #B9B9B9)')
8607
- .style('opacity', '0.5')
8608
- .call((g) => {
8609
- g.select('.domain')
8610
- .remove()
8611
- .style('stroke', 'var(--chart-domain-color, #000000)'); // Add CSS variable for domain
8612
- });
9774
+ // Y-axis grid
9775
+ if (this.chartConfiguration.yAxisGrid) {
9776
+ svg.append('g')
9777
+ .call(d3.axisLeft(y).ticks(self.chartConfiguration.numberOfYTicks).tickSize(-width))
9778
+ .style('color', 'var(--chart-axis-color, #B9B9B9)')
9779
+ .style('opacity', '0.5')
9780
+ .call((g) => g.select('.domain').remove().style('stroke', 'var(--chart-domain-color, #000000)'));
8613
9781
  }
8614
9782
  else {
8615
- svg
8616
- .append('g')
9783
+ svg.append('g')
8617
9784
  .call(d3.axisLeft(y).ticks(self.chartConfiguration.numberOfYTicks))
8618
9785
  .style('color', 'var(--chart-axis-color, #B9B9B9)')
8619
9786
  .style('opacity', '0.5')
8620
- .call((g) => {
8621
- g.select('.domain')
8622
- .style('stroke', 'var(--chart-domain-color, #000000)') // Add CSS variable for domain
8623
- .style('stroke-width', '1px'); // Ensure visibility
8624
- });
9787
+ .call((g) => g.select('.domain')
9788
+ .style('stroke', 'var(--chart-domain-color, #000000)')
9789
+ .style('stroke-width', '1px'));
8625
9790
  }
8626
- var xSubgroup = d3.scaleBand().domain(subgroups);
9791
+ }
9792
+ setupXSubgroupScale(subgroups, x, self) {
9793
+ const xSubgroup = d3.scaleBand().domain(subgroups);
8627
9794
  if (subgroups.length > 1 && !this.isZoomedOut) {
8628
- // For grouped bar charts in zoom-in view, use full x.bandwidth() for subgroups
8629
9795
  xSubgroup.range([0, x.bandwidth()]);
8630
9796
  }
8631
9797
  else if (subgroups.length === 1 && !this.isZoomedOut) {
8632
- // For single-bar (non-grouped) charts in zoom-in view, set bar width to 100 (increased from 80)
8633
9798
  xSubgroup.range([0, 100]);
8634
9799
  }
8635
- else if (this.chartConfiguration.isMultiChartGridLine == undefined) {
9800
+ else if (this.chartConfiguration.isMultiChartGridLine === undefined) {
8636
9801
  xSubgroup.range([0, x.bandwidth()]);
8637
9802
  }
8638
9803
  else {
8639
- // used to make grouped bars with lesser width as we are not using padding for width
8640
9804
  xSubgroup.range([0, x.bandwidth()]);
8641
9805
  }
8642
- // if (this.chartConfiguration.isDrilldownChart) {
8643
- // }
8644
- var color = d3
8645
- .scaleOrdinal()
8646
- .domain(subgroups)
8647
- .range(Object.values(metaData.colors));
8648
- // var colorAboveTarget = d3
8649
- // .scaleOrdinal()
8650
- // .domain(subgroups)
8651
- // .range(Object.values(metaData.colorAboveTarget));
8652
- var state = svg
8653
- .append('g')
9806
+ return xSubgroup;
9807
+ }
9808
+ renderBars(svg, data, subgroups, x, xSubgroup, y, height, color, metaData, self, leftAndRightSpaces, tempScale, isria) {
9809
+ const state = svg.append('g')
8654
9810
  .selectAll('.state')
8655
9811
  .data(data)
8656
9812
  .enter()
8657
9813
  .append('g')
8658
- .attr('transform', function (d) {
8659
- return 'translate(' + x(d.name) + ',0)';
8660
- });
8661
- state
8662
- .selectAll('rect')
8663
- .data(function (d) {
8664
- let newList = [];
8665
- subgroups.map(function (key) {
8666
- // if (key !== "group") {
8667
- let obj = { key: key, value: d[key], name: d.name };
8668
- newList.push(obj);
8669
- // }
8670
- });
8671
- return newList;
8672
- })
9814
+ .attr('transform', (d) => `translate(${x(d.name)},0)`);
9815
+ const bars = state.selectAll('rect')
9816
+ .data((d) => this.prepareBarData(d, subgroups))
8673
9817
  .enter()
8674
9818
  .append('rect')
8675
9819
  .attr('class', 'bars')
8676
- .on('click', function (d) {
8677
- if (d.key != 'Target') {
8678
- if (!metaData.barWithoutClick ||
8679
- !metaData.barWithoutClick.length ||
8680
- (!metaData.barWithoutClick.includes(d?.name) &&
8681
- !metaData.barWithoutClick.includes(d?.key)))
8682
- // self.handleClick(d.data.name);
8683
- self.handleClick(d);
8684
- }
8685
- })
8686
- .attr('x', function (d) {
8687
- if (self.chartConfiguration.isDrilldownChart) {
8688
- data.map((indiv) => {
8689
- if (indiv.name == d.name) {
8690
- let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8691
- tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8692
- if (x.bandwidth() > 100) {
8693
- // Increase bar width a bit in zoom-in view
8694
- let reducedBarWidth = 60;
8695
- if (!self.isZoomedOut) {
8696
- reducedBarWidth = 30;
8697
- }
8698
- if (self.chartData.data.length == 1) {
8699
- if (Object.keys(self.chartData.data[0]).length == 2) {
8700
- tempScale.range([
8701
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8702
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8703
- ]);
8704
- }
8705
- else
8706
- tempScale.range([
8707
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8708
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8709
- ]);
8710
- }
8711
- else
8712
- tempScale.range([
8713
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8714
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8715
- ]);
8716
- }
8717
- }
8718
- });
8719
- return tempScale(d.key);
8720
- }
8721
- return xSubgroup(d.key);
8722
- })
8723
- .attr('y', function (d) {
8724
- if (d.value == -1) {
8725
- return y(0);
8726
- }
8727
- if (d.value >= 0) {
8728
- const barHeight = height - y(d.value);
8729
- const minHeight = self.chartConfiguration.defaultBarHeight || 2;
8730
- return barHeight < minHeight ? y(0) - minHeight : y(d.value);
8731
- }
8732
- return y(0);
8733
- })
8734
- .attr('width', function (d) {
8735
- // For grouped bar charts in zoom-in view, set bar width to 50 for maximum thickness
8736
- if (subgroups.length > 1 && !self.isZoomedOut) {
8737
- return 50;
8738
- }
8739
- // For single-bar (non-grouped) charts in zoom-in view, set bar width to 80
8740
- if (subgroups.length === 1 && !self.isZoomedOut) {
8741
- return 80;
8742
- }
8743
- let tempScale = d3.scaleBand().domain([]).range([0, 0]);
8744
- // Default logic for other chart types
8745
- if (self.chartConfiguration.isDrilldownChart) {
8746
- data.map((indiv) => {
8747
- if (indiv.name == d.name) {
8748
- let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8749
- tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8750
- if (x.bandwidth() > 100) {
8751
- // Increase bar width a bit in zoom-in view
8752
- let reducedBarWidth = 60;
8753
- if (!self.isZoomedOut) {
8754
- reducedBarWidth = 100;
8755
- }
8756
- if (self.chartData.data.length == 1) {
8757
- if (Object.keys(self.chartData.data[0]).length == 2) {
8758
- tempScale.range([
8759
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8760
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8761
- ]);
8762
- }
8763
- else
8764
- tempScale.range([
8765
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8766
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8767
- ]);
8768
- }
8769
- else
8770
- tempScale.range([
8771
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8772
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8773
- ]);
8774
- }
8775
- }
8776
- });
8777
- return self.isZoomedOut
8778
- ? tempScale.bandwidth()
8779
- : self.chartData.data.length && self.chartData.data.length > 8
8780
- ? tempScale.bandwidth()
8781
- : tempScale.bandwidth();
8782
- }
8783
- return self.isZoomedOut
8784
- ? tempScale.bandwidth()
8785
- : self.chartData.data.length && self.chartData.data.length > 8
8786
- ? tempScale.bandwidth()
8787
- : tempScale.bandwidth();
8788
- })
8789
- .attr('height', function (d) {
8790
- if (d.value == -1) {
8791
- return height - y(0);
8792
- }
8793
- if (d.value >= 0) {
8794
- const barHeight = height - y(d.value);
8795
- const minHeight = self.chartConfiguration.defaultBarHeight || 2;
8796
- return Math.max(barHeight, minHeight);
9820
+ .on('click', (d) => this.handleBarClick(d, metaData, self))
9821
+ .attr('x', (d) => this.calculateBarX(d, data, x, xSubgroup, self, tempScale))
9822
+ .attr('y', (d) => this.calculateBarY(d, y, height, self))
9823
+ .attr('width', (d) => this.calculateBarWidth(d, data, subgroups, x, xSubgroup, self, tempScale))
9824
+ .attr('height', (d) => this.calculateBarHeight(d, y, height, self))
9825
+ .style('cursor', () => (metaData.hasDrillDown && !isria) ? 'pointer' : 'default')
9826
+ .attr('fill', (d) => this.getBarColor(d, metaData, self));
9827
+ // Attach mouse events if not RIA
9828
+ if (!isria && (this.chartConfiguration.displayTitleOnTop ||
9829
+ (this.chartConfiguration.textsOnBar === undefined &&
9830
+ this.chartConfiguration.displayTitleOnTop === undefined))) {
9831
+ bars.on('mouseout', (d, i) => this.handleMouseOut(svg))
9832
+ .on('mouseover', (d, i) => this.handleMouseOver(d, svg, data, x, y, height, metaData, self, leftAndRightSpaces, tempScale));
9833
+ }
9834
+ }
9835
+ prepareBarData(d, subgroups) {
9836
+ const newList = [];
9837
+ subgroups.forEach((key) => {
9838
+ newList.push({ key: key, value: d[key], name: d.name });
9839
+ });
9840
+ return newList;
9841
+ }
9842
+ handleBarClick(d, metaData, self) {
9843
+ if (d.key !== 'Target') {
9844
+ if (!metaData.barWithoutClick || !metaData.barWithoutClick.length ||
9845
+ (!metaData.barWithoutClick.includes(d?.name) &&
9846
+ !metaData.barWithoutClick.includes(d?.key))) {
9847
+ self.handleClick(d);
8797
9848
  }
8798
- return height - y(0);
8799
- })
8800
- .style('cursor', function (d) {
8801
- if (metaData.hasDrillDown && !isria)
8802
- return 'pointer';
8803
- else
8804
- return 'default';
8805
- })
8806
- .attr('fill', function (d) {
8807
- if (d.value &&
8808
- self.chartData.targetLineData &&
8809
- d.value >= parseFloat(self.chartData.targetLineData.target) &&
8810
- self.chartData.metaData.colorAboveTarget) {
8811
- const key = d.key.toLowerCase();
8812
- const colorAboveTarget = Object.keys(self.chartData.metaData.colorAboveTarget).find(k => k.toLowerCase() === key);
8813
- if (colorAboveTarget) {
8814
- return self.chartData.metaData.colorAboveTarget[colorAboveTarget];
9849
+ }
9850
+ }
9851
+ calculateBarX(d, data, x, xSubgroup, self, tempScale) {
9852
+ if (self.chartConfiguration.isDrilldownChart) {
9853
+ return this.calculateDrilldownBarX(d, data, x, self, tempScale);
9854
+ }
9855
+ return xSubgroup(d.key);
9856
+ }
9857
+ calculateDrilldownBarX(d, data, x, self, tempScale) {
9858
+ data.forEach((indiv) => {
9859
+ if (indiv.name === d.name) {
9860
+ const keys = Object.keys(indiv).filter((temp, i) => i !== 0);
9861
+ tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
9862
+ if (x.bandwidth() > 100) {
9863
+ const reducedBarWidth = self.isZoomedOut ? 60 : 30;
9864
+ const offset = (x.bandwidth() - reducedBarWidth) / 2;
9865
+ tempScale.range([offset, x.bandwidth() - offset]);
8815
9866
  }
8816
9867
  }
8817
- return self.chartData.metaData.colors[d.key];
8818
9868
  });
8819
- /**
8820
- * display angled texts on the bars
8821
- */
8822
- if (this.chartConfiguration.textsOnBar != undefined && !this.isZoomedOut) {
8823
- state
8824
- .selectAll('text')
8825
- .data(function (d) {
8826
- let newList = [];
8827
- subgroups.map(function (key) {
8828
- let obj = { key: key, value: d[key], name: d.name };
8829
- newList.push(obj);
8830
- });
8831
- return newList;
8832
- })
8833
- .enter()
8834
- .append('text')
8835
- .attr('fill', 'var(--chart-text-color)')
8836
- .attr('x', function (d) {
8837
- return 0;
8838
- })
8839
- .attr('y', function (d) {
8840
- return 0;
8841
- })
8842
- .attr('class', 'lib-data-labels-weeklycharts')
8843
- .text(function (d) {
8844
- return d.key && d.value
8845
- ? d.key.length > 20
8846
- ? d.key.substring(0, 17) + '...'
8847
- : d.key
8848
- : '';
8849
- })
8850
- .style('fill', function (d) {
8851
- return '#000';
8852
- })
8853
- .style('font-weight', 'bold')
8854
- .style('font-size', function (d) {
8855
- if (self.isZoomedOut) {
8856
- return '9px'; // 👈 Zoomed out mode
8857
- }
8858
- if (self.chartConfiguration.isDrilldownChart) {
8859
- if (window.innerWidth > 1900) {
8860
- return '18px';
8861
- }
8862
- else if (window.innerWidth < 1400) {
8863
- return '10px';
8864
- }
8865
- else {
8866
- return '14px';
8867
- }
8868
- }
8869
- else {
8870
- return '14px';
8871
- }
8872
- })
8873
- .attr('transform', function (d) {
8874
- data.map((indiv) => {
8875
- if (indiv.name == d.name) {
8876
- let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8877
- var temp;
8878
- tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8879
- if (x.bandwidth() > 100) {
8880
- if (self.chartData.data.length == 1) {
8881
- if (Object.keys(self.chartData.data[0]).length == 2) {
8882
- tempScale.range([
8883
- 0 + (x.bandwidth() - 200) / 2,
8884
- x.bandwidth() - (x.bandwidth() - 200) / 2,
8885
- ]);
8886
- // .padding(0.05);
8887
- }
8888
- else
8889
- tempScale.range([
8890
- 0 + (x.bandwidth() - 300) / 2,
8891
- x.bandwidth() - (x.bandwidth() - 300) / 2,
8892
- ]);
8893
- // .padding(0.05);
8894
- }
8895
- else
8896
- tempScale.range([
8897
- 0 + (x.bandwidth() - 125) / 2,
8898
- x.bandwidth() - (x.bandwidth() - 125) / 2,
8899
- ]);
8900
- }
9869
+ return tempScale(d.key);
9870
+ }
9871
+ calculateBarY(d, y, height, self) {
9872
+ if (d.value === -1) {
9873
+ return y(0);
9874
+ }
9875
+ if (d.value >= 0) {
9876
+ const barHeight = height - y(d.value);
9877
+ const minHeight = self.chartConfiguration.defaultBarHeight || 2;
9878
+ return barHeight < minHeight ? y(0) - minHeight : y(d.value);
9879
+ }
9880
+ return y(0);
9881
+ }
9882
+ calculateBarWidth(d, data, subgroups, x, xSubgroup, self, tempScale) {
9883
+ // For grouped bar charts in zoom-in view
9884
+ if (subgroups.length > 1 && !self.isZoomedOut) {
9885
+ return 50;
9886
+ }
9887
+ // For single-bar charts in zoom-in view
9888
+ if (subgroups.length === 1 && !self.isZoomedOut) {
9889
+ return 80;
9890
+ }
9891
+ // Default logic for drilldown charts
9892
+ if (self.chartConfiguration.isDrilldownChart) {
9893
+ let calculatedScale = d3.scaleBand().domain([]).range([0, 0]);
9894
+ data.forEach((indiv) => {
9895
+ if (indiv.name === d.name) {
9896
+ const keys = Object.keys(indiv).filter((temp, i) => i !== 0);
9897
+ calculatedScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
9898
+ if (x.bandwidth() > 100) {
9899
+ const reducedBarWidth = self.isZoomedOut ? 60 : 100;
9900
+ const offset = (x.bandwidth() - reducedBarWidth) / 2;
9901
+ calculatedScale.range([offset, x.bandwidth() - offset]);
8901
9902
  }
8902
- });
8903
- /**
8904
- * if set, then all texts ll be horizontal
8905
- */
8906
- if (self.chartConfiguration.textAlwaysHorizontal) {
8907
- return ('translate(' + xSubgroup(d.key) + ',' + (y(d.value) - 3) + ')');
8908
9903
  }
8909
- /**
8910
- * rotate texts having more than one digits
8911
- */
8912
- // if (d.value > 9)
8913
- if (!isNaN(tempScale(d.key)))
8914
- return ('translate(' +
8915
- (tempScale(d.key) + tempScale.bandwidth() * 0.55) +
8916
- ',' +
8917
- (y(0) - 10) +
8918
- ') rotate(270)');
8919
- return 'translate(0,0)';
8920
- // else
8921
- // return (
8922
- // 'translate(' +
8923
- // (tempScale(d.key) + tempScale.bandwidth() / 2) +
8924
- // ',' +
8925
- // y(0) +
8926
- // ')'
8927
- // );
8928
- })
8929
- .on('click', function (d) {
8930
- if (!metaData.barWithoutClick ||
8931
- !metaData.barWithoutClick.length ||
8932
- (!metaData.barWithoutClick.includes(d?.name) &&
8933
- !metaData.barWithoutClick.includes(d?.key)))
8934
- self.handleClick(d);
8935
9904
  });
8936
- if (!isria) {
8937
- state
8938
- .selectAll('.lib-data-labels-weeklycharts')
8939
- .on('mouseout', handleMouseOut)
8940
- .on('mouseover', handleMouseOver);
8941
- }
9905
+ return calculatedScale.bandwidth();
8942
9906
  }
8943
- if (this.chartConfiguration.displayTitleOnTop || (this.chartConfiguration.textsOnBar == undefined &&
8944
- this.chartConfiguration.displayTitleOnTop == undefined)) {
8945
- if (!isria) {
8946
- state
8947
- .selectAll('rect')
8948
- .on('mouseout', handleMouseOut)
8949
- .on('mouseover', handleMouseOver);
9907
+ return xSubgroup.bandwidth();
9908
+ }
9909
+ calculateBarHeight(d, y, height, self) {
9910
+ if (d.value === -1) {
9911
+ return height - y(0);
9912
+ }
9913
+ if (d.value >= 0) {
9914
+ const barHeight = height - y(d.value);
9915
+ const minHeight = self.chartConfiguration.defaultBarHeight || 2;
9916
+ return Math.max(barHeight, minHeight);
9917
+ }
9918
+ return height - y(0);
9919
+ }
9920
+ getBarColor(d, metaData, self) {
9921
+ if (d.value && self.chartData.targetLineData &&
9922
+ d.value >= parseFloat(self.chartData.targetLineData.target) &&
9923
+ self.chartData.metaData.colorAboveTarget) {
9924
+ const key = d.key.toLowerCase();
9925
+ const colorAboveTarget = Object.keys(self.chartData.metaData.colorAboveTarget)
9926
+ .find(k => k.toLowerCase() === key);
9927
+ if (colorAboveTarget) {
9928
+ return self.chartData.metaData.colorAboveTarget[colorAboveTarget];
8950
9929
  }
8951
9930
  }
8952
- function handleMouseOver(d, i) {
8953
- svg.selectAll('.lib-verticalstack-title-ontop').remove();
8954
- svg
8955
- .append('foreignObject')
8956
- .attr('x', function () {
8957
- // ...existing code for tempScale calculation...
8958
- var elementsCounter;
8959
- data.map((indiv) => {
8960
- if (indiv.name == d.name) {
8961
- let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8962
- elementsCounter = keys.length;
8963
- tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8964
- if (x.bandwidth() > 100) {
8965
- if (self.chartData.data.length == 1) {
8966
- if (Object.keys(self.chartData.data[0]).length == 2) {
8967
- tempScale.range([
8968
- 0 + (x.bandwidth() - 200) / 2,
8969
- x.bandwidth() - (x.bandwidth() - 200) / 2,
8970
- ]);
8971
- }
8972
- else
8973
- tempScale.range([
8974
- 0 + (x.bandwidth() - 300) / 2,
8975
- x.bandwidth() - (x.bandwidth() - 300) / 2,
8976
- ]);
8977
- }
8978
- else
8979
- tempScale.range([
8980
- 0 + (x.bandwidth() - 125) / 2,
8981
- x.bandwidth() - (x.bandwidth() - 125) / 2,
8982
- ]);
8983
- }
8984
- }
8985
- });
8986
- if (metaData.hasDrillDown) {
8987
- if (tempScale.bandwidth() + leftAndRightSpaces * 2 > 180) {
8988
- return (x(d.name) + tempScale(d.key) + tempScale.bandwidth() / 2 - 90);
8989
- }
8990
- return (x(d.name) +
8991
- tempScale(d.key) -
8992
- (tempScale.bandwidth() + leftAndRightSpaces * 2) / 2 +
8993
- tempScale.bandwidth() / 2);
8994
- }
8995
- else
8996
- return x(d.name) + tempScale(d.key) - (tempScale.bandwidth() + leftAndRightSpaces * 2) / 2 + tempScale.bandwidth() / 2;
8997
- })
8998
- .attr('class', 'lib-verticalstack-title-ontop')
8999
- .attr('y', function () {
9000
- return y(d.value) - 3 - 40 - 10;
9001
- })
9002
- .attr('dy', function () {
9003
- return d.class;
9004
- })
9005
- .attr('width', function () {
9006
- data.map((indiv) => {
9007
- if (indiv.name == d.name) {
9008
- let keys = Object.keys(indiv).filter((temp, i) => i != 0);
9009
- tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
9010
- if (x.bandwidth() > 100) {
9011
- if (self.chartData.data.length == 1) {
9012
- if (Object.keys(self.chartData.data[0]).length == 2) {
9013
- tempScale.range([
9014
- 0 + (x.bandwidth() - 200) / 2,
9015
- x.bandwidth() - (x.bandwidth() - 200) / 2,
9016
- ]);
9017
- }
9018
- else
9019
- tempScale.range([
9020
- 0 + (x.bandwidth() - 300) / 2,
9021
- x.bandwidth() - (x.bandwidth() - 300) / 2,
9022
- ]);
9023
- }
9024
- else
9025
- tempScale.range([
9026
- 0 + (x.bandwidth() - 125) / 2,
9027
- x.bandwidth() - (x.bandwidth() - 125) / 2,
9028
- ]);
9029
- }
9030
- }
9031
- });
9032
- if (metaData.hasDrillDown) {
9033
- if (tempScale.bandwidth() + leftAndRightSpaces * 2 > 180) {
9034
- return '180px';
9931
+ return self.chartData.metaData.colors[d.key];
9932
+ }
9933
+ renderBarLabels(svg, data, subgroups, x, xSubgroup, y, height, metaData, self, tempScale, isria) {
9934
+ const state = svg.selectAll('.state');
9935
+ const labels = state.selectAll('text')
9936
+ .data((d) => this.prepareBarData(d, subgroups))
9937
+ .enter()
9938
+ .append('text')
9939
+ .attr('fill', 'var(--chart-text-color)')
9940
+ .attr('x', 0)
9941
+ .attr('y', 0)
9942
+ .attr('class', 'lib-data-labels-weeklycharts')
9943
+ .text((d) => this.formatBarLabel(d))
9944
+ .style('fill', '#000')
9945
+ .style('font-weight', 'bold')
9946
+ .style('font-size', (d) => this.calculateLabelFontSize(self))
9947
+ .attr('transform', (d) => this.calculateLabelTransform(d, data, x, xSubgroup, y, self, tempScale))
9948
+ .on('click', (d) => this.handleBarClick(d, metaData, self));
9949
+ if (!isria) {
9950
+ labels.on('mouseout', () => this.handleMouseOut(svg))
9951
+ .on('mouseover', (d) => this.handleMouseOver(d, svg, data, x, y, height, metaData, self, 50, tempScale));
9952
+ }
9953
+ }
9954
+ formatBarLabel(d) {
9955
+ if (!d.key || !d.value)
9956
+ return '';
9957
+ return d.key.length > 20 ? d.key.substring(0, 17) + '...' : d.key;
9958
+ }
9959
+ calculateLabelFontSize(self) {
9960
+ if (self.isZoomedOut)
9961
+ return '9px';
9962
+ if (self.chartConfiguration.isDrilldownChart) {
9963
+ if (window.innerWidth > 1900)
9964
+ return '18px';
9965
+ if (window.innerWidth < 1400)
9966
+ return '10px';
9967
+ return '14px';
9968
+ }
9969
+ return '14px';
9970
+ }
9971
+ calculateLabelTransform(d, data, x, xSubgroup, y, self, tempScale) {
9972
+ let calculatedScale;
9973
+ data.forEach((indiv) => {
9974
+ if (indiv.name === d.name) {
9975
+ const keys = Object.keys(indiv).filter((temp, i) => i !== 0);
9976
+ calculatedScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
9977
+ if (x.bandwidth() > 100) {
9978
+ if (self.chartData.data.length === 1) {
9979
+ const reducedWidth = Object.keys(self.chartData.data[0]).length === 2 ? 200 : 300;
9980
+ const offset = (x.bandwidth() - reducedWidth) / 2;
9981
+ calculatedScale.range([offset, x.bandwidth() - offset]);
9035
9982
  }
9036
- return tempScale.bandwidth() + leftAndRightSpaces * 2;
9037
- }
9038
- else
9039
- return tempScale.bandwidth() + leftAndRightSpaces * 2;
9040
- })
9041
- .attr('height', 50)
9042
- .append('xhtml:div')
9043
- .attr('class', 'title')
9044
- .style('z-index', 99)
9045
- .html(function () {
9046
- let barLabel = d.key;
9047
- let dataType = metaData.dataType ? metaData.dataType : '';
9048
- let value = d.value;
9049
- let desiredText = '<span class="title-bar-name">' + barLabel + '</span>';
9050
- desiredText +=
9051
- '<span class="title-bar-value"><span>' +
9052
- value +
9053
- '</span>' +
9054
- dataType +
9055
- '</span>';
9056
- return desiredText;
9057
- });
9058
- }
9059
- function handleMouseOut(d, i) {
9060
- svg.selectAll('.lib-verticalstack-title-ontop').remove();
9983
+ else {
9984
+ const offset = (x.bandwidth() - 125) / 2;
9985
+ calculatedScale.range([offset, x.bandwidth() - offset]);
9986
+ }
9987
+ }
9988
+ }
9989
+ });
9990
+ if (self.chartConfiguration.textAlwaysHorizontal) {
9991
+ return `translate(${xSubgroup(d.key)},${y(d.value) - 3})`;
9992
+ }
9993
+ if (!isNaN(calculatedScale(d.key))) {
9994
+ return `translate(${calculatedScale(d.key) + calculatedScale.bandwidth() * 0.55},${y(0) - 10}) rotate(270)`;
9995
+ }
9996
+ return 'translate(0,0)';
9997
+ }
9998
+ handleMouseOver(d, svg, data, x, y, height, metaData, self, leftAndRightSpaces, tempScale) {
9999
+ svg.selectAll('.lib-verticalstack-title-ontop').remove();
10000
+ let calculatedScale;
10001
+ let elementsCounter;
10002
+ data.forEach((indiv) => {
10003
+ if (indiv.name === d.name) {
10004
+ const keys = Object.keys(indiv).filter((temp, i) => i !== 0);
10005
+ elementsCounter = keys.length;
10006
+ calculatedScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
10007
+ if (x.bandwidth() > 100) {
10008
+ if (self.chartData.data.length === 1) {
10009
+ const reducedWidth = Object.keys(self.chartData.data[0]).length === 2 ? 200 : 300;
10010
+ const offset = (x.bandwidth() - reducedWidth) / 2;
10011
+ calculatedScale.range([offset, x.bandwidth() - offset]);
10012
+ }
10013
+ else {
10014
+ const offset = (x.bandwidth() - 125) / 2;
10015
+ calculatedScale.range([offset, x.bandwidth() - offset]);
10016
+ }
10017
+ }
10018
+ }
10019
+ });
10020
+ const xPosition = this.calculateTooltipX(d, x, calculatedScale, metaData, leftAndRightSpaces);
10021
+ const width = this.calculateTooltipWidth(calculatedScale, metaData, leftAndRightSpaces);
10022
+ svg.append('foreignObject')
10023
+ .attr('x', xPosition)
10024
+ .attr('class', 'lib-verticalstack-title-ontop')
10025
+ .attr('y', y(d.value) - 3 - 40 - 10)
10026
+ .attr('dy', d.class)
10027
+ .attr('width', width)
10028
+ .attr('height', 50)
10029
+ .append('xhtml:div')
10030
+ .attr('class', 'title')
10031
+ .style('z-index', 99)
10032
+ .html(() => this.generateTooltipHTML(d, metaData));
10033
+ }
10034
+ calculateTooltipX(d, x, calculatedScale, metaData, leftAndRightSpaces) {
10035
+ if (metaData.hasDrillDown) {
10036
+ if (calculatedScale.bandwidth() + leftAndRightSpaces * 2 > 180) {
10037
+ return x(d.name) + calculatedScale(d.key) + calculatedScale.bandwidth() / 2 - 90;
10038
+ }
10039
+ return x(d.name) + calculatedScale(d.key) -
10040
+ (calculatedScale.bandwidth() + leftAndRightSpaces * 2) / 2 +
10041
+ calculatedScale.bandwidth() / 2;
10042
+ }
10043
+ return x(d.name) + calculatedScale(d.key) -
10044
+ (calculatedScale.bandwidth() + leftAndRightSpaces * 2) / 2 +
10045
+ calculatedScale.bandwidth() / 2;
10046
+ }
10047
+ calculateTooltipWidth(calculatedScale, metaData, leftAndRightSpaces) {
10048
+ if (metaData.hasDrillDown) {
10049
+ if (calculatedScale.bandwidth() + leftAndRightSpaces * 2 > 180) {
10050
+ return '180px';
10051
+ }
10052
+ return calculatedScale.bandwidth() + leftAndRightSpaces * 2;
9061
10053
  }
9062
- svg
9063
- .append('g')
9064
- .attr('class', 'x2 axis2')
9065
- .attr('transform', 'translate(0,' + height + ')')
9066
- .style('color', 'var(--chart-axis-color, #000)') // Use CSS variable instead of hardcoded #000
9067
- .call(d3.axisBottom(xScaleFromOrigin).tickSize(0))
9068
- .call((g) => g.select('.domain').attr('fill', 'none'));
9069
- svg.selectAll('g.x2.axis2 g.tick text').style('display', 'none');
9070
- svg
9071
- .append('g')
10054
+ return calculatedScale.bandwidth() + leftAndRightSpaces * 2;
10055
+ }
10056
+ generateTooltipHTML(d, metaData) {
10057
+ const barLabel = d.key;
10058
+ const dataType = metaData.dataType || '';
10059
+ const value = d.value;
10060
+ let html = `<span class="title-bar-name">${barLabel}</span>`;
10061
+ html += `<span class="title-bar-value"><span>${value}</span>${dataType}</span>`;
10062
+ return html;
10063
+ }
10064
+ handleMouseOut(svg) {
10065
+ svg.selectAll('.lib-verticalstack-title-ontop').remove();
10066
+ }
10067
+ renderYAxis(svg, svgYAxisLeft, svgYAxisRight, y, yLineAxis, lineData, self, isria, margin) {
10068
+ // Hidden y-axis for reference
10069
+ svg.append('g')
9072
10070
  .attr('class', 'lib-stacked-y-axis-text yaxis-dashed')
9073
10071
  .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
9074
10072
  .attr('transform', 'translate(0,0)')
9075
10073
  .call(y)
9076
10074
  .style('display', 'none');
9077
- svgYAxisLeft
9078
- .append('g')
10075
+ // Left y-axis
10076
+ svgYAxisLeft.append('g')
9079
10077
  .append('g')
9080
10078
  .attr('class', 'lib-yaxis-labels-texts-drilldown yaxis-dashed')
9081
10079
  .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
9082
10080
  .attr('transform', 'translate(0,0)')
9083
- .call(d3
9084
- .axisLeft(y)
10081
+ .call(d3.axisLeft(y)
9085
10082
  .tickSize(0)
9086
10083
  .ticks(self.chartConfiguration.numberOfYTicks)
9087
- .tickFormat(function (d) {
10084
+ .tickFormat((d) => {
9088
10085
  const formatted = self.chartConfiguration.yAxisLabelFomatter
9089
10086
  ? self.chartConfiguration.yAxisLabelFomatter(d)
9090
10087
  : d;
9091
10088
  return formatted >= 1000 ? formatted / 1000 + 'k' : formatted;
9092
10089
  }))
9093
10090
  .call((g) => {
9094
- // Style the domain line for theme support
9095
10091
  g.select('.domain')
9096
10092
  .style('stroke', 'var(--chart-domain-color, #000000)')
9097
10093
  .style('stroke-width', '1px');
9098
10094
  })
9099
10095
  .selectAll('text')
9100
10096
  .style('fill', 'var(--chart-text-color)');
9101
- svgYAxisRight
9102
- .append('g')
10097
+ // Right y-axis (hidden by default)
10098
+ svgYAxisRight.append('g')
9103
10099
  .attr('class', 'lib-yaxis-labels-texts-drilldown yaxis-dashed')
9104
10100
  .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
9105
10101
  .attr('transform', 'translate(0,0)')
9106
10102
  .call(y)
9107
10103
  .style('display', 'none');
9108
- /**
9109
- * hide x axis labels
9110
- * config is there for future use
9111
- * used by weekly charts
9112
- */
9113
- if (this.chartConfiguration.isXaxisLabelHidden != undefined &&
9114
- this.chartConfiguration.isXaxisLabelHidden) {
9115
- d3.selectAll('g.lib-line-x-axis-text > g > text').attr('class', 'lib-display-hidden');
10104
+ // Line chart axis if applicable
10105
+ if (lineData != null && lineData && self.chartConfiguration.showLineChartAxis) {
10106
+ svgYAxisRight.append('g')
10107
+ .attr('class', 'lib-stacked-y-axis-text1')
10108
+ .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
10109
+ .attr('transform', 'translate(0,0)')
10110
+ .call(yLineAxis);
9116
10111
  }
9117
- /**
9118
- * hide y axis labels
9119
- * used by weekly charts
9120
- */
9121
- if (this.chartConfiguration.isYaxisLabelHidden != undefined &&
9122
- this.chartConfiguration.isYaxisLabelHidden) {
9123
- d3.selectAll('.yaxis-dashed > g > text').attr('class', 'lib-display-hidden');
10112
+ // Apply axis visibility configurations
10113
+ this.applyAxisVisibilityConfig(self);
10114
+ }
10115
+ applyAxisVisibilityConfig(self) {
10116
+ if (self.chartConfiguration.isXaxisLabelHidden) {
10117
+ d3.selectAll('g.lib-line-x-axis-text > g > text')
10118
+ .attr('class', 'lib-display-hidden');
9124
10119
  }
9125
- /**
9126
- * hide y axis labels
9127
- * config is there for future use
9128
- */
9129
- if (this.chartConfiguration.isYaxisHidden != undefined &&
9130
- this.chartConfiguration.isYaxisHidden) {
9131
- d3.selectAll('.yaxis-dashed').attr('class', 'lib-display-hidden');
10120
+ if (self.chartConfiguration.isYaxisLabelHidden) {
10121
+ d3.selectAll('.yaxis-dashed > g > text')
10122
+ .attr('class', 'lib-display-hidden');
9132
10123
  }
9133
- /**
9134
- * dashed y axis
9135
- * used by weekly charts
9136
- */
9137
- if (this.chartConfiguration.isYaxisDashed != undefined &&
9138
- this.chartConfiguration.isYaxisDashed) {
10124
+ if (self.chartConfiguration.isYaxisHidden) {
9139
10125
  d3.selectAll('.yaxis-dashed')
9140
- .style('stroke-dasharray', '5 5')
9141
- .style('color', 'var(--chart-axis-color, #999999)'); // Use CSS variable
9142
- }
9143
- if (lineData != null) {
9144
- if (lineData && self.chartConfiguration.showLineChartAxis) {
9145
- svgYAxisRight
9146
- .append('g')
9147
- .attr('class', 'lib-stacked-y-axis-text1')
9148
- .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
9149
- .attr('transform', 'translate(' + 0 + ',0)')
9150
- .call(yLineAxis);
9151
- }
10126
+ .attr('class', 'lib-display-hidden');
9152
10127
  }
9153
- /**
9154
- * used to display y label
9155
- */
9156
- // if (this.isZoomedOut) {
9157
- // svg
9158
- // .selectAll('.lib-xaxis-labels-texts-drilldown')
9159
- // .attr('class', 'lib-display-hidden');
9160
- // }
9161
- if (this.isZoomedOut) {
9162
- svg
9163
- .selectAll('.lib-xaxis-labels-texts-drilldown')
9164
- .each((d, i, nodes) => {
9165
- const text = d3.select(nodes[i]);
9166
- const label = text.text();
9167
- if (label.indexOf('\n') > -1) {
9168
- const lines = label.split('\n');
9169
- text.text(null);
9170
- lines.forEach((line, idx) => {
9171
- text.append('tspan')
9172
- .text(line)
9173
- .attr('x', 0)
9174
- .attr('dy', idx === 0 ? '1em' : '1.1em');
9175
- });
9176
- }
9177
- else {
9178
- const words = label.split(' ');
9179
- text.text(null);
9180
- words.forEach((word, index) => {
9181
- text.append('tspan').text(word);
9182
- });
9183
- }
9184
- })
9185
- .style('fill', 'var(--chart-text-color)')
9186
- .attr('transform', null);
9187
- svg
9188
- .select('.x-axis')
9189
- .attr('transform', `translate(0, ${height - margin.bottom + 10})`);
10128
+ if (self.chartConfiguration.isYaxisDashed) {
10129
+ d3.selectAll('.yaxis-dashed')
10130
+ .style('stroke-dasharray', '5 5')
10131
+ .style('color', 'var(--chart-axis-color, #999999)');
9190
10132
  }
9191
- /**
9192
- * used to write y labels based on configuration
9193
- */
10133
+ }
10134
+ renderAxisLabels(svg, svgYAxisLeft, svgYAxisRight, metaData, width, height, margin, self, isria, rightSvgWidth) {
10135
+ // Y-axis label
9194
10136
  if (metaData.yLabel) {
9195
10137
  const yPosition = isria ? 0 - margin.left / 2 - 30 : 0 - margin.left / 2 - 40;
9196
- svgYAxisLeft
9197
- .append('text')
10138
+ svgYAxisLeft.append('text')
9198
10139
  .attr('class', 'lib-axis-group-label font-size-1')
9199
10140
  .attr('style', self.chartConfiguration.yAxisCustomlabelStyles)
9200
10141
  .attr('transform', 'rotate(-90)')
@@ -9204,170 +10145,155 @@ class HorizontalGroupedBarWithScrollZoomComponent extends ComponentUniqueId {
9204
10145
  .style('text-anchor', 'middle')
9205
10146
  .attr('fill', 'var(--chart-text-color)');
9206
10147
  if (this.chartConfiguration.isMultiChartGridLine === undefined) {
9207
- svgYAxisLeft
9208
- .selectAll('.lib-axis-group-label')
10148
+ svgYAxisLeft.selectAll('.lib-axis-group-label')
9209
10149
  .style('font-size', 'smaller')
9210
10150
  .text(metaData.yLabel);
9211
10151
  }
9212
10152
  else {
9213
- svg
9214
- .selectAll('.lib-axis-group-label')
10153
+ svg.selectAll('.lib-axis-group-label')
9215
10154
  .attr('class', 'lib-ylabel-weeklyCharts')
9216
10155
  .text(metaData.yLabel.toLowerCase());
9217
10156
  }
9218
10157
  }
9219
- if (this.chartData.targetLineData) {
9220
- const yZero = y(this.chartData.targetLineData.target);
9221
- svg
9222
- .append('line')
9223
- .attr('x1', 0)
9224
- .attr('x2', width)
9225
- .attr('y1', yZero)
9226
- .attr('y2', yZero)
9227
- .style('stroke-dasharray', '5 5')
9228
- .style('stroke', this.chartData.targetLineData.color);
9229
- // svgYAxisRight
9230
- // .append('line')
9231
- // .attr('x1', 0)
9232
- // .attr('x2', rightSvgWidth)
9233
- // .attr('y1', yZero)
9234
- // .attr('y2', yZero)
9235
- // .style('stroke', this.chartData.targetLineData.color);
9236
- svgYAxisRight
9237
- .append('foreignObject')
9238
- .attr('transform', 'translate(' + 0 + ',' + (yZero - 30) + ')')
9239
- .attr('width', rightSvgWidth)
9240
- .attr('height', 50)
9241
- .append('xhtml:div')
9242
- .attr('class', 'target-display')
9243
- .style('color', 'var(--chart-text-color)')
9244
- .html(function () {
9245
- let dataTypeTemp = '';
9246
- let targetLineName = 'target';
9247
- if (metaData.dataType) {
9248
- dataTypeTemp = metaData.dataType;
9249
- }
9250
- if (self.chartData.targetLineData &&
9251
- self.chartData.targetLineData.targetName) {
9252
- targetLineName = self.chartData.targetLineData.targetName;
9253
- }
9254
- return (`<div>${targetLineName}</div>` +
9255
- '<div>' +
9256
- self.chartData.targetLineData.target +
9257
- '' +
9258
- dataTypeTemp +
9259
- '</div>');
9260
- });
9261
- }
9262
- if (this.chartConfiguration.isDrilldownChart) {
9263
- /**
9264
- * used by drilldown charts
9265
- */
9266
- // svg
9267
- // .selectAll('.lib-axis-group-label')
9268
- // .attr('class', 'lib-ylabel-drilldowncharts')
9269
- // .text(metaData.yLabel.toLowerCase());
9270
- svg.selectAll('g.x1.axis1 g.tick line').style('display', 'none');
9271
- }
10158
+ // X-axis label
9272
10159
  if (metaData.xLabel) {
9273
- function isAcronym(label) {
9274
- return ((label.length <= 4 && /^[A-Z]+$/.test(label)) ||
9275
- (label === label.toUpperCase() && /[A-Z]/.test(label)));
9276
- }
9277
- const xLabelText = metaData.xLabel;
9278
- const isAcr = isAcronym(xLabelText.replace(/[^A-Za-z]/g, ''));
9279
- const xPosition = isria ? (height + margin.top + margin.bottom) : (height + margin.top + margin.bottom + 40);
9280
- svg
9281
- .append('text')
9282
- .attr('class', function () {
9283
- let baseClass = 'lib-axis-group-label font-size-1';
9284
- if (self.chartConfiguration.isDrilldownChart)
9285
- return baseClass + ' lib-xlabel-drilldowncharts';
9286
- if (self.chartConfiguration.isMultiChartGridLine != undefined)
9287
- return baseClass + ' lib-xlabel-weeklyCharts';
9288
- return baseClass + ' lib-axis-waterfall-label';
9289
- })
10160
+ const isAcronym = this.isLabelAcronym(metaData.xLabel);
10161
+ const xPosition = isria
10162
+ ? (height + margin.top + margin.bottom)
10163
+ : (height + margin.top + margin.bottom + 40);
10164
+ svg.append('text')
10165
+ .attr('class', this.getXLabelClass(self))
9290
10166
  .attr('style', self.chartConfiguration.xAxisCustomlabelStyles)
9291
- .attr('transform', 'translate(' + width / 2 + ' ,' + xPosition + ')')
10167
+ .attr('transform', `translate(${width / 2},${xPosition})`)
9292
10168
  .style('text-anchor', 'middle')
9293
10169
  .style('fill', 'var(--chart-text-color)')
9294
- .text(isAcr ? xLabelText.toUpperCase() : xLabelText.toLowerCase())
9295
- .style('text-transform', isAcr ? 'none' : 'capitalize');
10170
+ .text(isAcronym ? metaData.xLabel.toUpperCase() : metaData.xLabel.toLowerCase())
10171
+ .style('text-transform', isAcronym ? 'none' : 'capitalize');
9296
10172
  }
10173
+ // Line y-axis label
9297
10174
  if (metaData.lineyLabel) {
9298
- svgYAxisRight
9299
- .append('text')
10175
+ svgYAxisRight.append('text')
9300
10176
  .attr('class', 'lib-axis-group-label lib-line-axis')
9301
10177
  .attr('fill', 'var(--chart-text-color)')
9302
10178
  .attr('style', self.chartConfiguration.yAxisCustomlabelStyles)
9303
10179
  .attr('transform', 'translate(0,0) rotate(90)')
9304
- .attr('y', 0 - 100)
9305
- .attr('x', 0 + 100)
10180
+ .attr('y', -100)
10181
+ .attr('x', 100)
9306
10182
  .attr('dy', '5em')
9307
10183
  .style('text-anchor', 'middle')
9308
10184
  .style('font-size', 'smaller')
9309
10185
  .text(metaData.lineyLabel);
9310
10186
  }
9311
- if (lineData) {
9312
- svg
9313
- .append('path')
9314
- .datum(lineData)
9315
- .attr('fill', 'none')
9316
- .attr('stroke', self.chartConfiguration.lineGraphColor)
9317
- .attr('stroke-width', 1.5)
9318
- .attr('d', d3
9319
- .line()
9320
- .x(function (d) {
9321
- return x(d.name) + x.bandwidth() / 2;
9322
- })
9323
- .y(function (d) {
9324
- return lineYscale(d.value);
9325
- }));
9326
- var dot = svg
9327
- .selectAll('myCircles')
9328
- .data(lineData)
9329
- .enter()
9330
- .append('g')
9331
- .on('click', function (d) {
9332
- if (!metaData.barWithoutClick ||
9333
- !metaData.barWithoutClick.length ||
9334
- (!metaData.barWithoutClick.includes(d?.name) &&
9335
- !metaData.barWithoutClick.includes(d?.key)))
9336
- self.handleClick(d);
9337
- });
9338
- dot
9339
- .append('circle')
9340
- .attr('fill', function (d) {
9341
- return self.chartConfiguration.lineGraphColor;
9342
- })
9343
- .attr('stroke', 'none')
9344
- .attr('cx', function (d) {
9345
- return x(d.name) + x.bandwidth() / 2;
9346
- })
9347
- .attr('cy', function (d) {
9348
- return lineYscale(d.value);
9349
- })
9350
- .style('cursor', () => self.chartData.metaData.hasDrillDown ? 'pointer' : 'default')
9351
- .attr('r', 3);
9352
- if (self.chartConfiguration.lineGraphColor) {
9353
- dot
9354
- .append('text')
9355
- .attr('class', 'dot')
9356
- .attr('fill', 'var(--chart-text-color)')
9357
- .attr('color', self.chartConfiguration.lineGraphColor)
9358
- .attr('style', 'font-size: ' + '.85em')
9359
- .attr('x', function (d, i) {
9360
- return x(d.name) + x.bandwidth() / 2;
9361
- })
9362
- .attr('y', function (d) {
9363
- return lineYscale(d.value);
9364
- })
9365
- .attr('dy', '-1em')
9366
- .text(function (d) {
9367
- return self.chartConfiguration.labelFormatter(d.value);
10187
+ // Apply drilldown chart specific styles
10188
+ if (this.chartConfiguration.isDrilldownChart) {
10189
+ svg.selectAll('g.x1.axis1 g.tick line').style('display', 'none');
10190
+ }
10191
+ }
10192
+ isLabelAcronym(label) {
10193
+ return (label.length <= 4 && /^[A-Z]+$/.test(label)) ||
10194
+ (label === label.toUpperCase() && /[A-Z]/.test(label));
10195
+ }
10196
+ getXLabelClass(self) {
10197
+ let baseClass = 'lib-axis-group-label font-size-1';
10198
+ if (self.chartConfiguration.isDrilldownChart) {
10199
+ return baseClass + ' lib-xlabel-drilldowncharts';
10200
+ }
10201
+ if (self.chartConfiguration.isMultiChartGridLine !== undefined) {
10202
+ return baseClass + ' lib-xlabel-weeklyCharts';
10203
+ }
10204
+ return baseClass + ' lib-axis-waterfall-label';
10205
+ }
10206
+ renderTargetLine(svg, svgYAxisRight, y, width, rightSvgWidth, metaData, self) {
10207
+ const yZero = y(this.chartData.targetLineData.target);
10208
+ // Draw target line
10209
+ svg.append('line')
10210
+ .attr('x1', 0)
10211
+ .attr('x2', width)
10212
+ .attr('y1', yZero)
10213
+ .attr('y2', yZero)
10214
+ .style('stroke-dasharray', '5 5')
10215
+ .style('stroke', this.chartData.targetLineData.color);
10216
+ // Add target label
10217
+ const dataTypeTemp = metaData.dataType || '';
10218
+ const targetLineName = this.chartData.targetLineData.targetName || 'target';
10219
+ svgYAxisRight.append('foreignObject')
10220
+ .attr('transform', `translate(0,${yZero - 30})`)
10221
+ .attr('width', rightSvgWidth)
10222
+ .attr('height', 50)
10223
+ .append('xhtml:div')
10224
+ .attr('class', 'target-display')
10225
+ .style('color', 'var(--chart-text-color)')
10226
+ .html(`<div>${targetLineName}</div><div>${self.chartData.targetLineData.target}${dataTypeTemp}</div>`);
10227
+ }
10228
+ renderLineChart(svg, lineData, x, lineYscale, metaData, self) {
10229
+ // Draw line path
10230
+ svg.append('path')
10231
+ .datum(lineData)
10232
+ .attr('fill', 'none')
10233
+ .attr('stroke', self.chartConfiguration.lineGraphColor)
10234
+ .attr('stroke-width', 1.5)
10235
+ .attr('d', d3.line()
10236
+ .x((d) => x(d.name) + x.bandwidth() / 2)
10237
+ .y((d) => lineYscale(d.value)));
10238
+ // Add dots
10239
+ const dot = svg.selectAll('myCircles')
10240
+ .data(lineData)
10241
+ .enter()
10242
+ .append('g')
10243
+ .on('click', (d) => {
10244
+ if (!metaData.barWithoutClick || !metaData.barWithoutClick.length ||
10245
+ (!metaData.barWithoutClick.includes(d?.name) &&
10246
+ !metaData.barWithoutClick.includes(d?.key))) {
10247
+ self.handleClick(d);
10248
+ }
10249
+ });
10250
+ dot.append('circle')
10251
+ .attr('fill', self.chartConfiguration.lineGraphColor)
10252
+ .attr('stroke', 'none')
10253
+ .attr('cx', (d) => x(d.name) + x.bandwidth() / 2)
10254
+ .attr('cy', (d) => lineYscale(d.value))
10255
+ .style('cursor', () => self.chartData.metaData.hasDrillDown ? 'pointer' : 'default')
10256
+ .attr('r', 3);
10257
+ // Add value labels
10258
+ if (self.chartConfiguration.lineGraphColor) {
10259
+ dot.append('text')
10260
+ .attr('class', 'dot')
10261
+ .attr('fill', 'var(--chart-text-color)')
10262
+ .attr('color', self.chartConfiguration.lineGraphColor)
10263
+ .attr('style', 'font-size: .85em')
10264
+ .attr('x', (d) => x(d.name) + x.bandwidth() / 2)
10265
+ .attr('y', (d) => lineYscale(d.value))
10266
+ .attr('dy', '-1em')
10267
+ .text((d) => self.chartConfiguration.labelFormatter(d.value));
10268
+ }
10269
+ }
10270
+ handleZoomOut(svg, height, margin) {
10271
+ svg.selectAll('.lib-xaxis-labels-texts-drilldown')
10272
+ .each((d, i, nodes) => {
10273
+ const text = d3.select(nodes[i]);
10274
+ const label = text.text();
10275
+ if (label.indexOf('\n') > -1) {
10276
+ const lines = label.split('\n');
10277
+ text.text(null);
10278
+ lines.forEach((line, idx) => {
10279
+ text.append('tspan')
10280
+ .text(line)
10281
+ .attr('x', 0)
10282
+ .attr('dy', idx === 0 ? '1em' : '1.1em');
9368
10283
  });
9369
10284
  }
9370
- }
10285
+ else {
10286
+ const words = label.split(' ');
10287
+ text.text(null);
10288
+ words.forEach((word) => {
10289
+ text.append('tspan').text(word);
10290
+ });
10291
+ }
10292
+ })
10293
+ .style('fill', 'var(--chart-text-color)')
10294
+ .attr('transform', null);
10295
+ svg.select('.x-axis')
10296
+ .attr('transform', `translate(0, ${height - margin.bottom + 10})`);
9371
10297
  }
9372
10298
  calculateChartDimensions(chartContainer, verticalstackedcontainer, margin, self) {
9373
10299
  let width = parseInt(chartContainer.style('width')) - margin.left - margin.right;