axidio-styleguide-library1-v2 0.2.26 → 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,734 +8187,1955 @@ 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;
9461
+ // Setup color mappings
8221
9462
  if (!metaData.colorAboveTarget) {
8222
9463
  metaData['colorAboveTarget'] = metaData.colors;
8223
9464
  }
8224
9465
  colorMap = metaData.colors;
8225
9466
  keyList = metaData.keyList;
8226
- var chartContainer = d3.select(this.containerElt.nativeElement);
8227
- var verticalstackedcontainer = d3.select(this.groupcontainerElt.nativeElement);
8228
- 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;
8229
9471
  const { width, height } = this.calculateChartDimensions(chartContainer, verticalstackedcontainer, margin, self);
8230
- if (this.chartConfiguration.isHeaderVisible != undefined)
9472
+ // ==================== VISIBILITY CONFIGURATION ====================
9473
+ if (this.chartConfiguration.isHeaderVisible !== undefined) {
8231
9474
  this.isHeaderVisible = this.chartConfiguration.isHeaderVisible;
8232
- if (this.chartConfiguration.legendVisible != undefined) {
9475
+ }
9476
+ if (this.chartConfiguration.legendVisible !== undefined) {
8233
9477
  this.legendVisible = this.chartConfiguration.legendVisible;
8234
9478
  }
8235
- if (this.chartConfiguration.isTransparentBackground != undefined) {
8236
- this.isTransparentBackground =
8237
- this.chartConfiguration.isTransparentBackground;
9479
+ if (this.chartConfiguration.isTransparentBackground !== undefined) {
9480
+ this.isTransparentBackground = this.chartConfiguration.isTransparentBackground;
8238
9481
  }
8239
- if (this.chartConfiguration.textFormatter != undefined) {
9482
+ // ==================== DATA FORMATTING ====================
9483
+ if (this.chartConfiguration.textFormatter !== undefined) {
8240
9484
  formatFromBackend = ChartHelper.dataValueFormatter(this.chartConfiguration.textFormatter);
8241
9485
  formatForHugeNumbers = ChartHelper.dataValueFormatter('.2s');
8242
9486
  }
8243
- const { outerContainer, svgYAxisLeft, svgYAxisRight, innerContainer, svg } = this.createChartContainers(chartContainer, margin, height, rightSvgWidth, self, width);
8244
- var subgroups = keyList;
8245
- var groups = d3
8246
- .map(data, function (d) {
8247
- return d.name;
8248
- })
8249
- .keys();
8250
- if (this.chartConfiguration.isMultiChartGridLine != undefined) {
8251
- x = d3
8252
- .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()
8253
9495
  .rangeRound([width, 0])
8254
9496
  .align(0.5)
8255
9497
  .padding([0.5])
8256
- .domain(data.map(function (d) {
8257
- return d.name.toLowerCase();
8258
- }));
9498
+ .domain(data.map((d) => d.name.toLowerCase()));
8259
9499
  }
8260
9500
  else {
8261
- x = d3
8262
- .scaleBand()
9501
+ x = d3.scaleBand()
8263
9502
  .domain(groups)
8264
- .range([leftAndRightSpaces, width - rightSvgWidth - leftAndRightSpaces])
9503
+ .range([LEFT_AND_RIGHT_SPACES, width - RIGHT_SVG_WIDTH - LEFT_AND_RIGHT_SPACES])
8265
9504
  .padding([0.3]);
8266
9505
  }
8267
- var xScaleFromOrigin = d3
8268
- .scaleBand()
9506
+ const xScaleFromOrigin = d3.scaleBand()
8269
9507
  .domain(groups)
8270
- .range([0, width - rightSvgWidth]);
8271
- this.renderXAxis(svg, x, height, subgroups, metaData, this.chartConfiguration, alternate_text, short_tick_length_bg, long_tick_length_bg, this);
8272
- this.renderXAxisLabels(svg, data, subgroups, metaData, this.chartConfiguration, short_tick_length_bg, long_tick_length_bg, isMobile, isria, this);
8273
- var y = d3.scaleLinear().rangeRound([height, 0]);
8274
- var maxValue = d3.max(data, (d) => d3.max(keyList, (key) => +d[key]));
8275
- maxValue = this.calculateMaxValue(maxValue);
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);
8276
9514
  if (this.chartConfiguration.customYscale) {
8277
9515
  maxValue = maxValue * this.chartConfiguration.customYscale;
8278
9516
  }
8279
- if (this.chartData.targetLineData &&
8280
- maxValue < this.chartData.targetLineData.target) {
8281
- maxValue =
8282
- maxValue < 10 && this.chartData.targetLineData.target < 10
8283
- ? this.chartData.targetLineData.target + 3
8284
- : this.chartData.targetLineData.target + 20;
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;
8285
9521
  }
8286
9522
  y.domain([0, maxValue]).nice();
9523
+ // ==================== LINE CHART Y-SCALE ====================
8287
9524
  let lineYscale;
9525
+ let yLineAxis;
8288
9526
  if (lineData != null) {
8289
- let maxLineValue = d3.max(lineData, function (d) {
8290
- return +d.value;
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')
9566
+ .attr('class', 'x1 axis1')
9567
+ .attr('transform', `translate(0,${height})`)
9568
+ .call(d3.axisBottom(x))
9569
+ .call((g) => g.select('.domain').remove());
9570
+ svg.selectAll('g.x1.axis1 g.tick line').remove();
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);
9576
+ }
9577
+ else {
9578
+ // Bigger ticks for weekly charts
9579
+ svg.append('g')
9580
+ .attr('class', 'x1 axis1')
9581
+ .attr('transform', `translate(0,${height})`)
9582
+ .call(d3.axisBottom(x).tickSize(0))
9583
+ .call((g) => g.select('.domain').attr('fill', 'none'));
9584
+ // Alternate tick line sizes
9585
+ svg.selectAll('g.x1.axis1 g.tick line').attr('y2', function () {
9586
+ if (alternate_text && self.chartConfiguration.isNoAlternateXaxisText === undefined) {
9587
+ alternate_text = false;
9588
+ return longTickLengthBg - 7;
9589
+ }
9590
+ else {
9591
+ alternate_text = true;
9592
+ return shortTickLengthBg - 4;
9593
+ }
8291
9594
  });
8292
- maxLineValue = maxLineValue * this.chartConfiguration.customYscale;
8293
- let minLineValue = d3.min(lineData, function (d) {
8294
- return +d.value;
9595
+ alternate_text = false;
9596
+ // X-axis label texts
9597
+ svg.selectAll('g.x1.axis1 g.tick text')
9598
+ .attr('class', 'lib-xaxis-labels-texts-weeklycharts')
9599
+ .attr('y', function () {
9600
+ if (self.chartConfiguration.isFullScreen) {
9601
+ return shortTickLengthBg;
9602
+ }
9603
+ if (alternate_text) {
9604
+ alternate_text = false;
9605
+ return longTickLengthBg;
9606
+ }
9607
+ else {
9608
+ alternate_text = true;
9609
+ return shortTickLengthBg;
9610
+ }
8295
9611
  });
8296
- if (maxLineValue > 0)
8297
- minLineValue = minLineValue - 3;
8298
- if (minLineValue > 0) {
8299
- minLineValue = 0;
9612
+ }
9613
+ // Apply labels on same line configuration
9614
+ if (self.chartConfiguration.xLabelsOnSameLine) {
9615
+ this.applyXLabelsOnSameLine(svg, subgroups, data, metaData, self, shortTickLengthBg, isMobile, isria);
9616
+ }
9617
+ // Mobile override for RIA
9618
+ if (isria && self.chartData.data.length > 8) {
9619
+ svg.selectAll('g.x1.axis1 g.tick text')
9620
+ .classed('mobile-xaxis-override', true)
9621
+ .text((d) => d.substring(0, 3))
9622
+ .style('font-size', '12px')
9623
+ .attr('y', 5)
9624
+ .attr('x', 5)
9625
+ .style('text-anchor', 'middle');
9626
+ }
9627
+ // Mobile override
9628
+ if (isMobile && !this.isHeaderVisible) {
9629
+ svg.selectAll('g.x1.axis1 g.tick text')
9630
+ .classed('mobile-xaxis-override', true);
9631
+ }
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');
8300
9647
  }
8301
- lineYscale = d3
8302
- .scaleLinear()
8303
- .domain([minLineValue, maxLineValue])
8304
- .range([height, minLineValue]);
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
+ });
8305
9664
  }
8306
- let yLineAxis;
8307
- if (lineYscale != null) {
8308
- yLineAxis = d3
8309
- .axisRight(lineYscale)
8310
- .ticks(self.chartConfiguration.numberOfYTicks)
8311
- .tickSize(0)
8312
- .tickFormat(self.chartConfiguration.yLineAxisLabelFomatter);
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) {
9737
+ if (this.chartData.targetLineData) {
9738
+ maxValue = this.chartData.targetLineData.target + 20;
9739
+ }
9740
+ else {
9741
+ maxValue = 100;
9742
+ }
8313
9743
  }
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
8314
9765
  if (self.chartConfiguration.isXgridBetweenLabels) {
8315
- svg
8316
- .append('g')
9766
+ svg.append('g')
8317
9767
  .attr('class', 'grid')
8318
- .attr('transform', 'translate(' + x.bandwidth() / 2 + ',' + height + ')')
9768
+ .attr('transform', `translate(${x.bandwidth() / 2},${height})`)
8319
9769
  .call(d3.axisBottom(x).tickSize(-height).tickFormat(''))
8320
9770
  .style('stroke-dasharray', '5 5')
8321
9771
  .style('color', 'var(--chart-grid-color, #999999)')
8322
9772
  .call((g) => g.select('.domain').remove());
8323
9773
  }
9774
+ // Y-axis grid
8324
9775
  if (this.chartConfiguration.yAxisGrid) {
8325
- svg
8326
- .append('g')
8327
- .call(d3
8328
- .axisLeft(y)
8329
- .ticks(self.chartConfiguration.numberOfYTicks)
8330
- .tickSize(-width))
9776
+ svg.append('g')
9777
+ .call(d3.axisLeft(y).ticks(self.chartConfiguration.numberOfYTicks).tickSize(-width))
8331
9778
  .style('color', 'var(--chart-axis-color, #B9B9B9)')
8332
9779
  .style('opacity', '0.5')
8333
- .call((g) => {
8334
- g.select('.domain')
8335
- .remove()
8336
- .style('stroke', 'var(--chart-domain-color, #000000)');
8337
- });
9780
+ .call((g) => g.select('.domain').remove().style('stroke', 'var(--chart-domain-color, #000000)'));
8338
9781
  }
8339
9782
  else {
8340
- svg
8341
- .append('g')
9783
+ svg.append('g')
8342
9784
  .call(d3.axisLeft(y).ticks(self.chartConfiguration.numberOfYTicks))
8343
9785
  .style('color', 'var(--chart-axis-color, #B9B9B9)')
8344
9786
  .style('opacity', '0.5')
8345
- .call((g) => {
8346
- g.select('.domain')
8347
- .style('stroke', 'var(--chart-domain-color, #000000)')
8348
- .style('stroke-width', '1px');
8349
- });
9787
+ .call((g) => g.select('.domain')
9788
+ .style('stroke', 'var(--chart-domain-color, #000000)')
9789
+ .style('stroke-width', '1px'));
8350
9790
  }
8351
- var xSubgroup = d3.scaleBand().domain(subgroups);
9791
+ }
9792
+ setupXSubgroupScale(subgroups, x, self) {
9793
+ const xSubgroup = d3.scaleBand().domain(subgroups);
8352
9794
  if (subgroups.length > 1 && !this.isZoomedOut) {
8353
9795
  xSubgroup.range([0, x.bandwidth()]);
8354
9796
  }
8355
9797
  else if (subgroups.length === 1 && !this.isZoomedOut) {
8356
9798
  xSubgroup.range([0, 100]);
8357
9799
  }
8358
- else if (this.chartConfiguration.isMultiChartGridLine == undefined) {
9800
+ else if (this.chartConfiguration.isMultiChartGridLine === undefined) {
8359
9801
  xSubgroup.range([0, x.bandwidth()]);
8360
9802
  }
8361
9803
  else {
8362
9804
  xSubgroup.range([0, x.bandwidth()]);
8363
9805
  }
8364
- var color = d3
8365
- .scaleOrdinal()
8366
- .domain(subgroups)
8367
- .range(Object.values(metaData.colors));
8368
- var state = svg
8369
- .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')
8370
9810
  .selectAll('.state')
8371
9811
  .data(data)
8372
9812
  .enter()
8373
9813
  .append('g')
8374
- .attr('transform', function (d) {
8375
- return 'translate(' + x(d.name) + ',0)';
8376
- });
8377
- state
8378
- .selectAll('rect')
8379
- .data(function (d) {
8380
- let newList = [];
8381
- subgroups.map(function (key) {
8382
- // if (key !== "group") {
8383
- let obj = { key: key, value: d[key], name: d.name };
8384
- newList.push(obj);
8385
- // }
8386
- });
8387
- return newList;
8388
- })
9814
+ .attr('transform', (d) => `translate(${x(d.name)},0)`);
9815
+ const bars = state.selectAll('rect')
9816
+ .data((d) => this.prepareBarData(d, subgroups))
8389
9817
  .enter()
8390
9818
  .append('rect')
8391
9819
  .attr('class', 'bars')
8392
- .on('click', function (d) {
8393
- if (d.key != 'Target') {
8394
- if (!metaData.barWithoutClick ||
8395
- !metaData.barWithoutClick.length ||
8396
- (!metaData.barWithoutClick.includes(d?.name) &&
8397
- !metaData.barWithoutClick.includes(d?.key)))
8398
- // self.handleClick(d.data.name);
8399
- self.handleClick(d);
8400
- }
8401
- })
8402
- .attr('x', function (d) {
8403
- if (self.chartConfiguration.isDrilldownChart) {
8404
- data.map((indiv) => {
8405
- if (indiv.name == d.name) {
8406
- let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8407
- tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8408
- if (x.bandwidth() > 100) {
8409
- // Increase bar width a bit in zoom-in view
8410
- let reducedBarWidth = 60;
8411
- if (!self.isZoomedOut) {
8412
- reducedBarWidth = 30;
8413
- }
8414
- if (self.chartData.data.length == 1) {
8415
- if (Object.keys(self.chartData.data[0]).length == 2) {
8416
- tempScale.range([
8417
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8418
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8419
- ]);
8420
- }
8421
- else
8422
- tempScale.range([
8423
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8424
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8425
- ]);
8426
- }
8427
- else
8428
- tempScale.range([
8429
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8430
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8431
- ]);
8432
- }
8433
- }
8434
- });
8435
- return tempScale(d.key);
8436
- }
8437
- return xSubgroup(d.key);
8438
- })
8439
- .attr('y', function (d) {
8440
- if (d.value == -1) {
8441
- return y(0);
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);
8442
9848
  }
8443
- if (d.value >= 0) {
8444
- const barHeight = height - y(d.value);
8445
- const minHeight = self.chartConfiguration.defaultBarHeight || 2;
8446
- return barHeight < minHeight ? y(0) - minHeight : y(d.value);
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]);
9866
+ }
8447
9867
  }
9868
+ });
9869
+ return tempScale(d.key);
9870
+ }
9871
+ calculateBarY(d, y, height, self) {
9872
+ if (d.value === -1) {
8448
9873
  return y(0);
8449
- })
8450
- .attr('width', function (d) {
8451
- // For grouped bar charts in zoom-in view, set bar width to 50 for maximum thickness
8452
- if (subgroups.length > 1 && !self.isZoomedOut) {
8453
- return 50;
8454
- }
8455
- // For single-bar (non-grouped) charts in zoom-in view, set bar width to 80
8456
- if (subgroups.length === 1 && !self.isZoomedOut) {
8457
- return 80;
8458
- }
8459
- let tempScale = d3.scaleBand().domain([]).range([0, 0]);
8460
- // Default logic for other chart types
8461
- if (self.chartConfiguration.isDrilldownChart) {
8462
- data.map((indiv) => {
8463
- if (indiv.name == d.name) {
8464
- let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8465
- tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8466
- if (x.bandwidth() > 100) {
8467
- // Increase bar width a bit in zoom-in view
8468
- let reducedBarWidth = 60;
8469
- if (!self.isZoomedOut) {
8470
- reducedBarWidth = 100;
8471
- }
8472
- if (self.chartData.data.length == 1) {
8473
- if (Object.keys(self.chartData.data[0]).length == 2) {
8474
- tempScale.range([
8475
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8476
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8477
- ]);
8478
- }
8479
- else
8480
- tempScale.range([
8481
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8482
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8483
- ]);
8484
- }
8485
- else
8486
- tempScale.range([
8487
- 0 + (x.bandwidth() - reducedBarWidth) / 2,
8488
- x.bandwidth() - (x.bandwidth() - reducedBarWidth) / 2,
8489
- ]);
8490
- }
8491
- }
8492
- });
8493
- return self.isZoomedOut
8494
- ? tempScale.bandwidth()
8495
- : self.chartData.data.length && self.chartData.data.length > 8
8496
- ? tempScale.bandwidth()
8497
- : tempScale.bandwidth();
8498
- }
8499
- return self.isZoomedOut
8500
- ? tempScale.bandwidth()
8501
- : self.chartData.data.length && self.chartData.data.length > 8
8502
- ? tempScale.bandwidth()
8503
- : tempScale.bandwidth();
8504
- })
8505
- .attr('height', function (d) {
8506
- if (d.value == -1) {
8507
- return height - y(0);
8508
- }
8509
- if (d.value >= 0) {
8510
- const barHeight = height - y(d.value);
8511
- const minHeight = self.chartConfiguration.defaultBarHeight || 2;
8512
- return Math.max(barHeight, minHeight);
8513
- }
8514
- return height - y(0);
8515
- })
8516
- .style('cursor', function (d) {
8517
- if (metaData.hasDrillDown && !isria)
8518
- return 'pointer';
8519
- else
8520
- return 'default';
8521
- })
8522
- .attr('fill', function (d) {
8523
- if (d.value &&
8524
- self.chartData.targetLineData &&
8525
- d.value >= parseFloat(self.chartData.targetLineData.target) &&
8526
- self.chartData.metaData.colorAboveTarget) {
8527
- const key = d.key.toLowerCase();
8528
- const colorAboveTarget = Object.keys(self.chartData.metaData.colorAboveTarget).find((k) => k.toLowerCase() === key);
8529
- if (colorAboveTarget) {
8530
- return self.chartData.metaData.colorAboveTarget[colorAboveTarget];
8531
- }
8532
- }
8533
- return self.chartData.metaData.colors[d.key];
8534
- });
8535
- /**
8536
- * display angled texts on the bars
8537
- */
8538
- if (this.chartConfiguration.textsOnBar != undefined && !this.isZoomedOut) {
8539
- state
8540
- .selectAll('text')
8541
- .data(function (d) {
8542
- let newList = [];
8543
- subgroups.map(function (key) {
8544
- let obj = { key: key, value: d[key], name: d.name };
8545
- newList.push(obj);
8546
- });
8547
- return newList;
8548
- })
8549
- .enter()
8550
- .append('text')
8551
- .attr('fill', 'var(--chart-text-color)')
8552
- .attr('x', function (d) {
8553
- return 0;
8554
- })
8555
- .attr('y', function (d) {
8556
- return 0;
8557
- })
8558
- .attr('class', 'lib-data-labels-weeklycharts')
8559
- .text(function (d) {
8560
- return d.key && d.value
8561
- ? d.key.length > 20
8562
- ? d.key.substring(0, 17) + '...'
8563
- : d.key
8564
- : '';
8565
- })
8566
- .style('fill', function (d) {
8567
- return '#000';
8568
- })
8569
- .style('font-weight', 'bold')
8570
- .style('font-size', function (d) {
8571
- if (self.isZoomedOut) {
8572
- return '9px'; // 👈 Zoomed out mode
8573
- }
8574
- if (self.chartConfiguration.isDrilldownChart) {
8575
- if (window.innerWidth > 1900) {
8576
- return '18px';
8577
- }
8578
- else if (window.innerWidth < 1400) {
8579
- return '10px';
8580
- }
8581
- else {
8582
- return '14px';
8583
- }
8584
- }
8585
- else {
8586
- return '14px';
8587
- }
8588
- })
8589
- .attr('transform', function (d) {
8590
- data.map((indiv) => {
8591
- if (indiv.name == d.name) {
8592
- let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8593
- var temp;
8594
- tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8595
- if (x.bandwidth() > 100) {
8596
- if (self.chartData.data.length == 1) {
8597
- if (Object.keys(self.chartData.data[0]).length == 2) {
8598
- tempScale.range([
8599
- 0 + (x.bandwidth() - 200) / 2,
8600
- x.bandwidth() - (x.bandwidth() - 200) / 2,
8601
- ]);
8602
- // .padding(0.05);
8603
- }
8604
- else
8605
- tempScale.range([
8606
- 0 + (x.bandwidth() - 300) / 2,
8607
- x.bandwidth() - (x.bandwidth() - 300) / 2,
8608
- ]);
8609
- // .padding(0.05);
8610
- }
8611
- else
8612
- tempScale.range([
8613
- 0 + (x.bandwidth() - 125) / 2,
8614
- x.bandwidth() - (x.bandwidth() - 125) / 2,
8615
- ]);
8616
- }
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]);
8617
9902
  }
8618
- });
8619
- /**
8620
- * if set, then all texts ll be horizontal
8621
- */
8622
- if (self.chartConfiguration.textAlwaysHorizontal) {
8623
- return ('translate(' + xSubgroup(d.key) + ',' + (y(d.value) - 3) + ')');
8624
9903
  }
8625
- /**
8626
- * rotate texts having more than one digits
8627
- */
8628
- // if (d.value > 9)
8629
- if (!isNaN(tempScale(d.key)))
8630
- return ('translate(' +
8631
- (tempScale(d.key) + tempScale.bandwidth() * 0.55) +
8632
- ',' +
8633
- (y(0) - 10) +
8634
- ') rotate(270)');
8635
- return 'translate(0,0)';
8636
- // else
8637
- // return (
8638
- // 'translate(' +
8639
- // (tempScale(d.key) + tempScale.bandwidth() / 2) +
8640
- // ',' +
8641
- // y(0) +
8642
- // ')'
8643
- // );
8644
- })
8645
- .on('click', function (d) {
8646
- if (!metaData.barWithoutClick ||
8647
- !metaData.barWithoutClick.length ||
8648
- (!metaData.barWithoutClick.includes(d?.name) &&
8649
- !metaData.barWithoutClick.includes(d?.key)))
8650
- self.handleClick(d);
8651
9904
  });
8652
- if (!isria) {
8653
- state
8654
- .selectAll('.lib-data-labels-weeklycharts')
8655
- .on('mouseout', handleMouseOut)
8656
- .on('mouseover', handleMouseOver);
8657
- }
9905
+ return calculatedScale.bandwidth();
8658
9906
  }
8659
- if (this.chartConfiguration.displayTitleOnTop ||
8660
- (this.chartConfiguration.textsOnBar == undefined &&
8661
- this.chartConfiguration.displayTitleOnTop == undefined)) {
8662
- if (!isria) {
8663
- state
8664
- .selectAll('rect')
8665
- .on('mouseout', handleMouseOut)
8666
- .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];
8667
9929
  }
8668
9930
  }
8669
- function handleMouseOver(d, i) {
8670
- svg.selectAll('.lib-verticalstack-title-ontop').remove();
8671
- svg
8672
- .append('foreignObject')
8673
- .attr('x', function () {
8674
- // ...existing code for tempScale calculation...
8675
- var elementsCounter;
8676
- data.map((indiv) => {
8677
- if (indiv.name == d.name) {
8678
- let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8679
- elementsCounter = keys.length;
8680
- tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8681
- if (x.bandwidth() > 100) {
8682
- if (self.chartData.data.length == 1) {
8683
- if (Object.keys(self.chartData.data[0]).length == 2) {
8684
- tempScale.range([
8685
- 0 + (x.bandwidth() - 200) / 2,
8686
- x.bandwidth() - (x.bandwidth() - 200) / 2,
8687
- ]);
8688
- }
8689
- else
8690
- tempScale.range([
8691
- 0 + (x.bandwidth() - 300) / 2,
8692
- x.bandwidth() - (x.bandwidth() - 300) / 2,
8693
- ]);
8694
- }
8695
- else
8696
- tempScale.range([
8697
- 0 + (x.bandwidth() - 125) / 2,
8698
- x.bandwidth() - (x.bandwidth() - 125) / 2,
8699
- ]);
8700
- }
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]);
8701
9982
  }
8702
- });
8703
- if (metaData.hasDrillDown) {
8704
- if (tempScale.bandwidth() + leftAndRightSpaces * 2 > 180) {
8705
- return (x(d.name) + tempScale(d.key) + tempScale.bandwidth() / 2 - 90);
9983
+ else {
9984
+ const offset = (x.bandwidth() - 125) / 2;
9985
+ calculatedScale.range([offset, x.bandwidth() - offset]);
8706
9986
  }
8707
- return (x(d.name) +
8708
- tempScale(d.key) -
8709
- (tempScale.bandwidth() + leftAndRightSpaces * 2) / 2 +
8710
- tempScale.bandwidth() / 2);
8711
9987
  }
8712
- else
8713
- return x(d.name) + tempScale(d.key) - (tempScale.bandwidth() + leftAndRightSpaces * 2) / 2 + tempScale.bandwidth() / 2;
8714
- })
8715
- .attr('class', 'lib-verticalstack-title-ontop')
8716
- .attr('y', function () {
8717
- return y(d.value) - 3 - 40 - 10;
8718
- })
8719
- .attr('dy', function () {
8720
- return d.class;
8721
- })
8722
- .attr('width', function () {
8723
- data.map((indiv) => {
8724
- if (indiv.name == d.name) {
8725
- let keys = Object.keys(indiv).filter((temp, i) => i != 0);
8726
- tempScale = d3.scaleBand().domain(keys).range([0, x.bandwidth()]);
8727
- if (x.bandwidth() > 100) {
8728
- if (self.chartData.data.length == 1) {
8729
- if (Object.keys(self.chartData.data[0]).length == 2) {
8730
- tempScale.range([
8731
- 0 + (x.bandwidth() - 200) / 2,
8732
- x.bandwidth() - (x.bandwidth() - 200) / 2,
8733
- ]);
8734
- }
8735
- else
8736
- tempScale.range([
8737
- 0 + (x.bandwidth() - 300) / 2,
8738
- x.bandwidth() - (x.bandwidth() - 300) / 2,
8739
- ]);
8740
- }
8741
- else
8742
- tempScale.range([
8743
- 0 + (x.bandwidth() - 125) / 2,
8744
- x.bandwidth() - (x.bandwidth() - 125) / 2,
8745
- ]);
8746
- }
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]);
8747
10012
  }
8748
- });
8749
- if (metaData.hasDrillDown) {
8750
- if (tempScale.bandwidth() + leftAndRightSpaces * 2 > 180) {
8751
- return '180px';
10013
+ else {
10014
+ const offset = (x.bandwidth() - 125) / 2;
10015
+ calculatedScale.range([offset, x.bandwidth() - offset]);
8752
10016
  }
8753
- return tempScale.bandwidth() + leftAndRightSpaces * 2;
8754
10017
  }
8755
- else
8756
- return tempScale.bandwidth() + leftAndRightSpaces * 2;
8757
- })
8758
- .attr('height', 50)
8759
- .append('xhtml:div')
8760
- .attr('class', 'title')
8761
- .style('z-index', 99)
8762
- .html(function () {
8763
- let barLabel = d.key;
8764
- let dataType = metaData.dataType ? metaData.dataType : '';
8765
- let value = d.value;
8766
- let desiredText = '<span class="title-bar-name">' + barLabel + '</span>';
8767
- desiredText +=
8768
- '<span class="title-bar-value"><span>' +
8769
- value +
8770
- '</span>' +
8771
- dataType +
8772
- '</span>';
8773
- return desiredText;
8774
- });
8775
- }
8776
- function handleMouseOut(d, i) {
8777
- svg.selectAll('.lib-verticalstack-title-ontop').remove();
8778
- }
8779
- svg
8780
- .append('g')
8781
- .attr('class', 'x2 axis2')
8782
- .attr('transform', 'translate(0,' + height + ')')
8783
- .style('color', 'var(--chart-axis-color, #000)') // Use CSS variable instead of hardcoded #000
8784
- .call(d3.axisBottom(xScaleFromOrigin).tickSize(0))
8785
- .call((g) => g.select('.domain').attr('fill', 'none'));
8786
- svg.selectAll('g.x2.axis2 g.tick text').style('display', 'none');
8787
- svg
8788
- .append('g')
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;
10053
+ }
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')
8789
10070
  .attr('class', 'lib-stacked-y-axis-text yaxis-dashed')
8790
10071
  .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
8791
10072
  .attr('transform', 'translate(0,0)')
8792
10073
  .call(y)
8793
10074
  .style('display', 'none');
8794
- svgYAxisLeft
8795
- .append('g')
10075
+ // Left y-axis
10076
+ svgYAxisLeft.append('g')
8796
10077
  .append('g')
8797
10078
  .attr('class', 'lib-yaxis-labels-texts-drilldown yaxis-dashed')
8798
10079
  .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
8799
10080
  .attr('transform', 'translate(0,0)')
8800
- .call(d3
8801
- .axisLeft(y)
10081
+ .call(d3.axisLeft(y)
8802
10082
  .tickSize(0)
8803
10083
  .ticks(self.chartConfiguration.numberOfYTicks)
8804
- .tickFormat(function (d) {
10084
+ .tickFormat((d) => {
8805
10085
  const formatted = self.chartConfiguration.yAxisLabelFomatter
8806
10086
  ? self.chartConfiguration.yAxisLabelFomatter(d)
8807
10087
  : d;
8808
10088
  return formatted >= 1000 ? formatted / 1000 + 'k' : formatted;
8809
10089
  }))
8810
10090
  .call((g) => {
8811
- // Style the domain line for theme support
8812
10091
  g.select('.domain')
8813
10092
  .style('stroke', 'var(--chart-domain-color, #000000)')
8814
10093
  .style('stroke-width', '1px');
8815
10094
  })
8816
10095
  .selectAll('text')
8817
10096
  .style('fill', 'var(--chart-text-color)');
8818
- svgYAxisRight
8819
- .append('g')
10097
+ // Right y-axis (hidden by default)
10098
+ svgYAxisRight.append('g')
8820
10099
  .attr('class', 'lib-yaxis-labels-texts-drilldown yaxis-dashed')
8821
10100
  .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
8822
10101
  .attr('transform', 'translate(0,0)')
8823
10102
  .call(y)
8824
10103
  .style('display', 'none');
8825
- /**
8826
- * hide x axis labels
8827
- * config is there for future use
8828
- * used by weekly charts
8829
- */
8830
- if (this.chartConfiguration.isXaxisLabelHidden != undefined &&
8831
- this.chartConfiguration.isXaxisLabelHidden) {
8832
- d3.selectAll('g.lib-line-x-axis-text > g > text').attr('class', 'lib-display-hidden');
8833
- }
8834
- /**
8835
- * hide y axis labels
8836
- * used by weekly charts
8837
- */
8838
- if (this.chartConfiguration.isYaxisLabelHidden != undefined &&
8839
- this.chartConfiguration.isYaxisLabelHidden) {
8840
- d3.selectAll('.yaxis-dashed > g > text').attr('class', 'lib-display-hidden');
8841
- }
8842
- /**
8843
- * hide y axis labels
8844
- * config is there for future use
8845
- */
8846
- if (this.chartConfiguration.isYaxisHidden != undefined &&
8847
- this.chartConfiguration.isYaxisHidden) {
8848
- d3.selectAll('.yaxis-dashed').attr('class', 'lib-display-hidden');
8849
- }
8850
- /**
8851
- * dashed y axis
8852
- * used by weekly charts
8853
- */
8854
- if (this.chartConfiguration.isYaxisDashed != undefined &&
8855
- this.chartConfiguration.isYaxisDashed) {
8856
- d3.selectAll('.yaxis-dashed')
8857
- .style('stroke-dasharray', '5 5')
8858
- .style('color', 'var(--chart-axis-color, #999999)'); // Use CSS variable
8859
- }
8860
- if (lineData != null) {
8861
- if (lineData && self.chartConfiguration.showLineChartAxis) {
8862
- svgYAxisRight
8863
- .append('g')
8864
- .attr('class', 'lib-stacked-y-axis-text1')
8865
- .attr('style', self.chartConfiguration.yAxisCustomTextStyles)
8866
- .attr('transform', 'translate(' + 0 + ',0)')
8867
- .call(yLineAxis);
8868
- }
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);
8869
10111
  }
8870
- /**
8871
- * used to display y label
8872
- */
8873
- // if (this.isZoomedOut) {
8874
- // svg
8875
- // .selectAll('.lib-xaxis-labels-texts-drilldown')
8876
- // .attr('class', 'lib-display-hidden');
8877
- // }
8878
- if (this.isZoomedOut) {
8879
- svg
8880
- .selectAll('.lib-xaxis-labels-texts-drilldown')
8881
- .each((d, i, nodes) => {
8882
- const text = d3.select(nodes[i]);
8883
- const label = text.text();
8884
- if (label.indexOf('\n') > -1) {
8885
- const lines = label.split('\n');
8886
- text.text(null);
8887
- lines.forEach((line, idx) => {
8888
- text
8889
- .append('tspan')
8890
- .text(line)
8891
- .attr('x', 0)
8892
- .attr('dy', idx === 0 ? '1em' : '1.1em');
8893
- });
8894
- }
8895
- else {
8896
- const words = label.split(' ');
8897
- text.text(null);
8898
- words.forEach((word, index) => {
8899
- text.append('tspan').text(word);
8900
- });
8901
- }
8902
- })
8903
- .style('fill', 'var(--chart-text-color)')
8904
- .attr('transform', null);
8905
- svg
8906
- .select('.x-axis')
8907
- .attr('transform', `translate(0, ${height - margin.bottom + 10})`);
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');
8908
10119
  }
8909
- /**
8910
- * used to write y labels based on configuration
8911
- */
10120
+ if (self.chartConfiguration.isYaxisLabelHidden) {
10121
+ d3.selectAll('.yaxis-dashed > g > text')
10122
+ .attr('class', 'lib-display-hidden');
10123
+ }
10124
+ if (self.chartConfiguration.isYaxisHidden) {
10125
+ d3.selectAll('.yaxis-dashed')
10126
+ .attr('class', 'lib-display-hidden');
10127
+ }
10128
+ if (self.chartConfiguration.isYaxisDashed) {
10129
+ d3.selectAll('.yaxis-dashed')
10130
+ .style('stroke-dasharray', '5 5')
10131
+ .style('color', 'var(--chart-axis-color, #999999)');
10132
+ }
10133
+ }
10134
+ renderAxisLabels(svg, svgYAxisLeft, svgYAxisRight, metaData, width, height, margin, self, isria, rightSvgWidth) {
10135
+ // Y-axis label
8912
10136
  if (metaData.yLabel) {
8913
- const yPosition = isria
8914
- ? 0 - margin.left / 2 - 30
8915
- : 0 - margin.left / 2 - 40;
8916
- svgYAxisLeft
8917
- .append('text')
10137
+ const yPosition = isria ? 0 - margin.left / 2 - 30 : 0 - margin.left / 2 - 40;
10138
+ svgYAxisLeft.append('text')
8918
10139
  .attr('class', 'lib-axis-group-label font-size-1')
8919
10140
  .attr('style', self.chartConfiguration.yAxisCustomlabelStyles)
8920
10141
  .attr('transform', 'rotate(-90)')
@@ -8924,172 +10145,155 @@ class HorizontalGroupedBarWithScrollZoomComponent extends ComponentUniqueId {
8924
10145
  .style('text-anchor', 'middle')
8925
10146
  .attr('fill', 'var(--chart-text-color)');
8926
10147
  if (this.chartConfiguration.isMultiChartGridLine === undefined) {
8927
- svgYAxisLeft
8928
- .selectAll('.lib-axis-group-label')
10148
+ svgYAxisLeft.selectAll('.lib-axis-group-label')
8929
10149
  .style('font-size', 'smaller')
8930
10150
  .text(metaData.yLabel);
8931
10151
  }
8932
10152
  else {
8933
- svg
8934
- .selectAll('.lib-axis-group-label')
10153
+ svg.selectAll('.lib-axis-group-label')
8935
10154
  .attr('class', 'lib-ylabel-weeklyCharts')
8936
10155
  .text(metaData.yLabel.toLowerCase());
8937
10156
  }
8938
10157
  }
8939
- if (this.chartData.targetLineData) {
8940
- const yZero = y(this.chartData.targetLineData.target);
8941
- svg
8942
- .append('line')
8943
- .attr('x1', 0)
8944
- .attr('x2', width)
8945
- .attr('y1', yZero)
8946
- .attr('y2', yZero)
8947
- .style('stroke-dasharray', '5 5')
8948
- .style('stroke', this.chartData.targetLineData.color);
8949
- // svgYAxisRight
8950
- // .append('line')
8951
- // .attr('x1', 0)
8952
- // .attr('x2', rightSvgWidth)
8953
- // .attr('y1', yZero)
8954
- // .attr('y2', yZero)
8955
- // .style('stroke', this.chartData.targetLineData.color);
8956
- svgYAxisRight
8957
- .append('foreignObject')
8958
- .attr('transform', 'translate(' + 0 + ',' + (yZero - 30) + ')')
8959
- .attr('width', rightSvgWidth)
8960
- .attr('height', 50)
8961
- .append('xhtml:div')
8962
- .attr('class', 'target-display')
8963
- .style('color', 'var(--chart-text-color)')
8964
- .html(function () {
8965
- let dataTypeTemp = '';
8966
- let targetLineName = 'target';
8967
- if (metaData.dataType) {
8968
- dataTypeTemp = metaData.dataType;
8969
- }
8970
- if (self.chartData.targetLineData &&
8971
- self.chartData.targetLineData.targetName) {
8972
- targetLineName = self.chartData.targetLineData.targetName;
8973
- }
8974
- return (`<div>${targetLineName}</div>` +
8975
- '<div>' +
8976
- self.chartData.targetLineData.target +
8977
- '' +
8978
- dataTypeTemp +
8979
- '</div>');
8980
- });
8981
- }
8982
- if (this.chartConfiguration.isDrilldownChart) {
8983
- /**
8984
- * used by drilldown charts
8985
- */
8986
- // svg
8987
- // .selectAll('.lib-axis-group-label')
8988
- // .attr('class', 'lib-ylabel-drilldowncharts')
8989
- // .text(metaData.yLabel.toLowerCase());
8990
- svg.selectAll('g.x1.axis1 g.tick line').style('display', 'none');
8991
- }
10158
+ // X-axis label
8992
10159
  if (metaData.xLabel) {
8993
- function isAcronym(label) {
8994
- return ((label.length <= 4 && /^[A-Z]+$/.test(label)) ||
8995
- (label === label.toUpperCase() && /[A-Z]/.test(label)));
8996
- }
8997
- const xLabelText = metaData.xLabel;
8998
- const isAcr = isAcronym(xLabelText.replace(/[^A-Za-z]/g, ''));
10160
+ const isAcronym = this.isLabelAcronym(metaData.xLabel);
8999
10161
  const xPosition = isria
9000
- ? height + margin.top + margin.bottom
9001
- : height + margin.top + margin.bottom + 40;
9002
- svg
9003
- .append('text')
9004
- .attr('class', function () {
9005
- let baseClass = 'lib-axis-group-label font-size-1';
9006
- if (self.chartConfiguration.isDrilldownChart)
9007
- return baseClass + ' lib-xlabel-drilldowncharts';
9008
- if (self.chartConfiguration.isMultiChartGridLine != undefined)
9009
- return baseClass + ' lib-xlabel-weeklyCharts';
9010
- return baseClass + ' lib-axis-waterfall-label';
9011
- })
10162
+ ? (height + margin.top + margin.bottom)
10163
+ : (height + margin.top + margin.bottom + 40);
10164
+ svg.append('text')
10165
+ .attr('class', this.getXLabelClass(self))
9012
10166
  .attr('style', self.chartConfiguration.xAxisCustomlabelStyles)
9013
- .attr('transform', 'translate(' + width / 2 + ' ,' + xPosition + ')')
10167
+ .attr('transform', `translate(${width / 2},${xPosition})`)
9014
10168
  .style('text-anchor', 'middle')
9015
10169
  .style('fill', 'var(--chart-text-color)')
9016
- .text(isAcr ? xLabelText.toUpperCase() : xLabelText.toLowerCase())
9017
- .style('text-transform', isAcr ? 'none' : 'capitalize');
10170
+ .text(isAcronym ? metaData.xLabel.toUpperCase() : metaData.xLabel.toLowerCase())
10171
+ .style('text-transform', isAcronym ? 'none' : 'capitalize');
9018
10172
  }
10173
+ // Line y-axis label
9019
10174
  if (metaData.lineyLabel) {
9020
- svgYAxisRight
9021
- .append('text')
10175
+ svgYAxisRight.append('text')
9022
10176
  .attr('class', 'lib-axis-group-label lib-line-axis')
9023
10177
  .attr('fill', 'var(--chart-text-color)')
9024
10178
  .attr('style', self.chartConfiguration.yAxisCustomlabelStyles)
9025
10179
  .attr('transform', 'translate(0,0) rotate(90)')
9026
- .attr('y', 0 - 100)
9027
- .attr('x', 0 + 100)
10180
+ .attr('y', -100)
10181
+ .attr('x', 100)
9028
10182
  .attr('dy', '5em')
9029
10183
  .style('text-anchor', 'middle')
9030
10184
  .style('font-size', 'smaller')
9031
10185
  .text(metaData.lineyLabel);
9032
10186
  }
9033
- if (lineData) {
9034
- svg
9035
- .append('path')
9036
- .datum(lineData)
9037
- .attr('fill', 'none')
9038
- .attr('stroke', self.chartConfiguration.lineGraphColor)
9039
- .attr('stroke-width', 1.5)
9040
- .attr('d', d3
9041
- .line()
9042
- .x(function (d) {
9043
- return x(d.name) + x.bandwidth() / 2;
9044
- })
9045
- .y(function (d) {
9046
- return lineYscale(d.value);
9047
- }));
9048
- var dot = svg
9049
- .selectAll('myCircles')
9050
- .data(lineData)
9051
- .enter()
9052
- .append('g')
9053
- .on('click', function (d) {
9054
- if (!metaData.barWithoutClick ||
9055
- !metaData.barWithoutClick.length ||
9056
- (!metaData.barWithoutClick.includes(d?.name) &&
9057
- !metaData.barWithoutClick.includes(d?.key)))
9058
- self.handleClick(d);
9059
- });
9060
- dot
9061
- .append('circle')
9062
- .attr('fill', function (d) {
9063
- return self.chartConfiguration.lineGraphColor;
9064
- })
9065
- .attr('stroke', 'none')
9066
- .attr('cx', function (d) {
9067
- return x(d.name) + x.bandwidth() / 2;
9068
- })
9069
- .attr('cy', function (d) {
9070
- return lineYscale(d.value);
9071
- })
9072
- .style('cursor', () => self.chartData.metaData.hasDrillDown ? 'pointer' : 'default')
9073
- .attr('r', 3);
9074
- if (self.chartConfiguration.lineGraphColor) {
9075
- dot
9076
- .append('text')
9077
- .attr('class', 'dot')
9078
- .attr('fill', 'var(--chart-text-color)')
9079
- .attr('color', self.chartConfiguration.lineGraphColor)
9080
- .attr('style', 'font-size: ' + '.85em')
9081
- .attr('x', function (d, i) {
9082
- return x(d.name) + x.bandwidth() / 2;
9083
- })
9084
- .attr('y', function (d) {
9085
- return lineYscale(d.value);
9086
- })
9087
- .attr('dy', '-1em')
9088
- .text(function (d) {
9089
- 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');
9090
10283
  });
9091
10284
  }
9092
- }
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})`);
9093
10297
  }
9094
10298
  calculateChartDimensions(chartContainer, verticalstackedcontainer, margin, self) {
9095
10299
  let width = parseInt(chartContainer.style('width')) - margin.left - margin.right;
@@ -9112,7 +10316,8 @@ class HorizontalGroupedBarWithScrollZoomComponent extends ComponentUniqueId {
9112
10316
  width = dataLength * 120;
9113
10317
  }
9114
10318
  if (dataLength > 8 && !this.isZoomedOut) {
9115
- if (this.chartData.dropdownData2 && width < dataLength * 250) {
10319
+ if (this.chartData.dropdownData2 &&
10320
+ width < dataLength * 250) {
9116
10321
  width = dataLength * 250;
9117
10322
  }
9118
10323
  else {
@@ -9194,155 +10399,6 @@ class HorizontalGroupedBarWithScrollZoomComponent extends ComponentUniqueId {
9194
10399
  .attr('transform', `translate(0,${margin.top})`);
9195
10400
  return { outerContainer, svgYAxisLeft, svgYAxisRight, innerContainer, svg };
9196
10401
  }
9197
- renderXAxis(svg, x, height, subgroups, metaData, chartConfig, alternate_text, short_tick_length_bg, long_tick_length_bg, self) {
9198
- if (chartConfig.isMultiChartGridLine == undefined) {
9199
- // Normal dashboard charts
9200
- svg
9201
- .append('g')
9202
- .attr('class', 'x1 axis1')
9203
- .attr('transform', `translate(0,${height})`)
9204
- .call(d3.axisBottom(x))
9205
- .call((g) => g.select('.domain').remove());
9206
- svg.selectAll('g.x1.axis1 g.tick line').remove();
9207
- if (subgroups.length > 1 && !metaData.xLabel) {
9208
- svg
9209
- .selectAll('g.x1.axis1 g.tick text')
9210
- .attr('class', 'lib-xaxis-labels-texts-drilldown')
9211
- .style('fill', 'var(--chart-text-color)')
9212
- .attr('y', 32);
9213
- }
9214
- else {
9215
- svg
9216
- .selectAll('g.x1.axis1 g.tick text')
9217
- .attr('class', 'lib-xaxis-labels-texts-drilldown')
9218
- .style('fill', 'var(--chart-text-color)');
9219
- }
9220
- }
9221
- else {
9222
- // Weekly charts / multi-chart
9223
- svg
9224
- .append('g')
9225
- .attr('class', 'x1 axis1')
9226
- .attr('transform', `translate(0,${height})`)
9227
- .call(d3.axisBottom(x).tickSize(0))
9228
- .call((g) => g.select('.domain').attr('fill', 'none'));
9229
- // Tick line size in alternate fashion
9230
- svg.selectAll('g.x1.axis1 g.tick line').attr('y2', function () {
9231
- if (alternate_text && chartConfig.isNoAlternateXaxisText == undefined) {
9232
- alternate_text = false;
9233
- return long_tick_length_bg - 7;
9234
- }
9235
- else {
9236
- alternate_text = true;
9237
- return short_tick_length_bg - 4;
9238
- }
9239
- });
9240
- // Reset flag
9241
- alternate_text = false;
9242
- // X-axis labels
9243
- svg
9244
- .selectAll('g.x1.axis1 g.tick text')
9245
- .attr('class', 'lib-xaxis-labels-texts-weeklycharts')
9246
- .attr('y', function () {
9247
- if (chartConfig.isFullScreen)
9248
- return short_tick_length_bg;
9249
- if (alternate_text) {
9250
- alternate_text = false;
9251
- return long_tick_length_bg;
9252
- }
9253
- else {
9254
- alternate_text = true;
9255
- return short_tick_length_bg;
9256
- }
9257
- });
9258
- }
9259
- }
9260
- renderXAxisLabels(svg, data, subgroups, metaData, chartConfig, short_tick_length_bg, long_tick_length_bg, isMobile, isria, self) {
9261
- if (!chartConfig.xLabelsOnSameLine)
9262
- return;
9263
- const xAxisLabels = svg.selectAll('g.x1.axis1 g.tick text');
9264
- this.applyLabelStyles(xAxisLabels, data, subgroups, metaData, chartConfig, short_tick_length_bg, long_tick_length_bg, isMobile, self);
9265
- this.handleLabelText(xAxisLabels, data, subgroups, metaData, chartConfig, isMobile, self);
9266
- if (isria && data.length > 8) {
9267
- this.applyRiaLabelOverride(xAxisLabels);
9268
- }
9269
- if (isMobile && !self.isHeaderVisible) {
9270
- xAxisLabels.classed('mobile-xaxis-override', true);
9271
- }
9272
- }
9273
- applyLabelStyles(labels, data, subgroups, metaData, chartConfig, short_tick_length_bg, long_tick_length_bg, isMobile, self) {
9274
- labels
9275
- .attr('class', 'lib-xaxis-labels-texts-drilldown')
9276
- .style('font-size', self.isHeaderVisible ? '18px' : '14px')
9277
- .attr('text-anchor', 'middle')
9278
- .attr('y', (d) => this.calculateLabelY(d, data, subgroups, metaData, chartConfig, short_tick_length_bg, long_tick_length_bg, self))
9279
- .attr('x', (d) => this.calculateLabelX(d, data, self));
9280
- }
9281
- calculateLabelY(d, data, subgroups, metaData, chartConfig, short_tick_length_bg, long_tick_length_bg, self) {
9282
- // Logic from your original code for y positioning
9283
- if (subgroups.length > 1 && data.length > 8 && metaData.xLabel) {
9284
- return short_tick_length_bg + 14;
9285
- }
9286
- if (subgroups.length > 1 && data.length > 8 && !metaData.xLabel) {
9287
- return chartConfig.isFullScreen
9288
- ? short_tick_length_bg + 2
9289
- : short_tick_length_bg + 10;
9290
- }
9291
- let baseY = self.isHeaderVisible
9292
- ? short_tick_length_bg + 25
9293
- : short_tick_length_bg;
9294
- return baseY;
9295
- }
9296
- calculateLabelX(d, data, self) {
9297
- if (data.length > 8 && !self.isZoomedOut)
9298
- return 1;
9299
- return 0;
9300
- }
9301
- handleLabelText(labels, data, subgroups, metaData, chartConfig, isMobile, self) {
9302
- labels.text((d) => {
9303
- if (isMobile && !self.isHeaderVisible) {
9304
- return d
9305
- .split(/[\s\-]+/)[0]
9306
- .substring(0, 3)
9307
- .toLowerCase();
9308
- }
9309
- // Split dates or weeks, ignore -1 values, etc.
9310
- // Keep all your previous text-processing logic here
9311
- return d.toLowerCase(); // fallback
9312
- });
9313
- // Example of handling sideways labels for grouped zoomed-out charts
9314
- labels.each(function (d) {
9315
- const isDateLabel = /^(\d{2,4}[-\/])?\d{2,4}[-\/]\d{2,4}$/.test(d.trim());
9316
- const isWeekLabel = /week|wk|w\d+/i.test(d);
9317
- if (subgroups.length > 1 &&
9318
- self.isZoomedOut &&
9319
- data.length > 8 &&
9320
- isDateLabel &&
9321
- !isWeekLabel) {
9322
- d3.select(this).style('writing-mode', 'sideways-lr');
9323
- }
9324
- });
9325
- }
9326
- applyRiaLabelOverride(labels) {
9327
- labels
9328
- .classed('mobile-xaxis-override', true)
9329
- .text((d) => d.substring(0, 3))
9330
- .style('font-size', '12px')
9331
- .attr('y', 5)
9332
- .attr('x', 5)
9333
- .style('text-anchor', 'middle');
9334
- }
9335
- calculateMaxValue(maxValue) {
9336
- if (maxValue === 0) {
9337
- if (this.chartData.targetLineData) {
9338
- return this.chartData.targetLineData.target + 20;
9339
- }
9340
- else {
9341
- return 100;
9342
- }
9343
- }
9344
- return maxValue;
9345
- }
9346
10402
  handleClick(d) {
9347
10403
  if (this.chartData.metaData.hasDrillDown || d?.toggleFrom)
9348
10404
  this.clickEvent.emit(d);