@fluentui/react-charts 9.3.7 → 9.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -2
- package/dist/index.d.ts +55 -7
- package/lib/components/AreaChart/AreaChart.js +1 -28
- package/lib/components/AreaChart/AreaChart.js.map +1 -1
- package/lib/components/AreaChart/useAreaChartStyles.styles.js +1 -2
- package/lib/components/AreaChart/useAreaChartStyles.styles.js.map +1 -1
- package/lib/components/ChartTable/ChartTable.js +6 -1
- package/lib/components/ChartTable/ChartTable.js.map +1 -1
- package/lib/components/CommonComponents/Annotations/ChartAnnotationLayer.js +107 -67
- package/lib/components/CommonComponents/Annotations/ChartAnnotationLayer.js.map +1 -1
- package/lib/components/CommonComponents/Annotations/useChartAnnotationLayer.styles.js +7 -1
- package/lib/components/CommonComponents/Annotations/useChartAnnotationLayer.styles.js.map +1 -1
- package/lib/components/CommonComponents/Annotations/useChartAnnotationLayer.styles.raw.js +7 -1
- package/lib/components/CommonComponents/Annotations/useChartAnnotationLayer.styles.raw.js.map +1 -1
- package/lib/components/CommonComponents/CartesianChart.js +50 -32
- package/lib/components/CommonComponents/CartesianChart.js.map +1 -1
- package/lib/components/CommonComponents/CartesianChart.types.js.map +1 -1
- package/lib/components/CommonComponents/useCartesianChartStyles.styles.js +5 -5
- package/lib/components/CommonComponents/useCartesianChartStyles.styles.js.map +1 -1
- package/lib/components/CommonComponents/useCartesianChartStyles.styles.raw.js +4 -3
- package/lib/components/CommonComponents/useCartesianChartStyles.styles.raw.js.map +1 -1
- package/lib/components/DeclarativeChart/PlotlySchemaAdapter.js +261 -187
- package/lib/components/DeclarativeChart/PlotlySchemaAdapter.js.map +1 -1
- package/lib/components/DonutChart/DonutChart.js +6 -3
- package/lib/components/DonutChart/DonutChart.js.map +1 -1
- package/lib/components/FunnelChart/FunnelChart.js +6 -3
- package/lib/components/FunnelChart/FunnelChart.js.map +1 -1
- package/lib/components/GanttChart/GanttChart.js +1 -1
- package/lib/components/GanttChart/GanttChart.js.map +1 -1
- package/lib/components/GaugeChart/GaugeChart.js +6 -3
- package/lib/components/GaugeChart/GaugeChart.js.map +1 -1
- package/lib/components/GroupedVerticalBarChart/GroupedVerticalBarChart.js +17 -17
- package/lib/components/GroupedVerticalBarChart/GroupedVerticalBarChart.js.map +1 -1
- package/lib/components/GroupedVerticalBarChart/useGroupedVerticalBarChartStyles.styles.js +1 -2
- package/lib/components/GroupedVerticalBarChart/useGroupedVerticalBarChartStyles.styles.js.map +1 -1
- package/lib/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxis.js +2 -4
- package/lib/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxis.js.map +1 -1
- package/lib/components/Legends/Legends.js +3 -4
- package/lib/components/Legends/Legends.js.map +1 -1
- package/lib/components/LineChart/LineChart.js +66 -64
- package/lib/components/LineChart/LineChart.js.map +1 -1
- package/lib/components/LineChart/useLineChartStyles.styles.js +1 -2
- package/lib/components/LineChart/useLineChartStyles.styles.js.map +1 -1
- package/lib/components/SankeyChart/SankeyChart.js +1 -1
- package/lib/components/SankeyChart/SankeyChart.js.map +1 -1
- package/lib/components/SankeyChart/useSankeyChartStyles.styles.js +1 -2
- package/lib/components/SankeyChart/useSankeyChartStyles.styles.js.map +1 -1
- package/lib/components/ScatterChart/ScatterChart.js +18 -26
- package/lib/components/ScatterChart/ScatterChart.js.map +1 -1
- package/lib/components/ScatterChart/ScatterChart.types.js.map +1 -1
- package/lib/components/ScatterChart/useScatterChartStyles.styles.js +1 -2
- package/lib/components/ScatterChart/useScatterChartStyles.styles.js.map +1 -1
- package/lib/components/VerticalBarChart/VerticalBarChart.js +13 -78
- package/lib/components/VerticalBarChart/VerticalBarChart.js.map +1 -1
- package/lib/components/VerticalBarChart/useVerticalBarChartStyles.styles.js +1 -2
- package/lib/components/VerticalBarChart/useVerticalBarChartStyles.styles.js.map +1 -1
- package/lib/components/VerticalStackedBarChart/VerticalStackedBarChart.js +21 -32
- package/lib/components/VerticalStackedBarChart/VerticalStackedBarChart.js.map +1 -1
- package/lib/components/VerticalStackedBarChart/useVerticalStackedBarChartStyles.styles.js +1 -2
- package/lib/components/VerticalStackedBarChart/useVerticalStackedBarChartStyles.styles.js.map +1 -1
- package/lib/types/ChartAnnotation.js.map +1 -1
- package/lib/types/DataPoint.js.map +1 -1
- package/lib/utilities/Common.styles.js +0 -1
- package/lib/utilities/Common.styles.js.map +1 -1
- package/lib/utilities/Common.styles.raw.js +0 -1
- package/lib/utilities/Common.styles.raw.js.map +1 -1
- package/lib/utilities/image-export-utils.js +4 -4
- package/lib/utilities/image-export-utils.js.map +1 -1
- package/lib/utilities/utilities.js +220 -78
- package/lib/utilities/utilities.js.map +1 -1
- package/lib-commonjs/components/AreaChart/AreaChart.js +0 -26
- package/lib-commonjs/components/AreaChart/AreaChart.js.map +1 -1
- package/lib-commonjs/components/AreaChart/useAreaChartStyles.styles.js +0 -2
- package/lib-commonjs/components/AreaChart/useAreaChartStyles.styles.js.map +1 -1
- package/lib-commonjs/components/ChartTable/ChartTable.js +6 -1
- package/lib-commonjs/components/ChartTable/ChartTable.js.map +1 -1
- package/lib-commonjs/components/CommonComponents/Annotations/ChartAnnotationLayer.js +107 -67
- package/lib-commonjs/components/CommonComponents/Annotations/ChartAnnotationLayer.js.map +1 -1
- package/lib-commonjs/components/CommonComponents/Annotations/useChartAnnotationLayer.styles.js +7 -1
- package/lib-commonjs/components/CommonComponents/Annotations/useChartAnnotationLayer.styles.js.map +1 -1
- package/lib-commonjs/components/CommonComponents/Annotations/useChartAnnotationLayer.styles.raw.js +7 -1
- package/lib-commonjs/components/CommonComponents/Annotations/useChartAnnotationLayer.styles.raw.js.map +1 -1
- package/lib-commonjs/components/CommonComponents/CartesianChart.js +49 -31
- package/lib-commonjs/components/CommonComponents/CartesianChart.js.map +1 -1
- package/lib-commonjs/components/CommonComponents/CartesianChart.types.js.map +1 -1
- package/lib-commonjs/components/CommonComponents/useCartesianChartStyles.styles.js +3 -4
- package/lib-commonjs/components/CommonComponents/useCartesianChartStyles.styles.js.map +1 -1
- package/lib-commonjs/components/CommonComponents/useCartesianChartStyles.styles.raw.js +3 -2
- package/lib-commonjs/components/CommonComponents/useCartesianChartStyles.styles.raw.js.map +1 -1
- package/lib-commonjs/components/DeclarativeChart/PlotlySchemaAdapter.js +261 -186
- package/lib-commonjs/components/DeclarativeChart/PlotlySchemaAdapter.js.map +1 -1
- package/lib-commonjs/components/DonutChart/DonutChart.js +5 -2
- package/lib-commonjs/components/DonutChart/DonutChart.js.map +1 -1
- package/lib-commonjs/components/FunnelChart/FunnelChart.js +5 -2
- package/lib-commonjs/components/FunnelChart/FunnelChart.js.map +1 -1
- package/lib-commonjs/components/GanttChart/GanttChart.js +1 -1
- package/lib-commonjs/components/GanttChart/GanttChart.js.map +1 -1
- package/lib-commonjs/components/GaugeChart/GaugeChart.js +5 -2
- package/lib-commonjs/components/GaugeChart/GaugeChart.js.map +1 -1
- package/lib-commonjs/components/GroupedVerticalBarChart/GroupedVerticalBarChart.js +15 -15
- package/lib-commonjs/components/GroupedVerticalBarChart/GroupedVerticalBarChart.js.map +1 -1
- package/lib-commonjs/components/GroupedVerticalBarChart/useGroupedVerticalBarChartStyles.styles.js +0 -2
- package/lib-commonjs/components/GroupedVerticalBarChart/useGroupedVerticalBarChartStyles.styles.js.map +1 -1
- package/lib-commonjs/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxis.js +2 -4
- package/lib-commonjs/components/HorizontalBarChartWithAxis/HorizontalBarChartWithAxis.js.map +1 -1
- package/lib-commonjs/components/Legends/Legends.js +3 -4
- package/lib-commonjs/components/Legends/Legends.js.map +1 -1
- package/lib-commonjs/components/LineChart/LineChart.js +65 -63
- package/lib-commonjs/components/LineChart/LineChart.js.map +1 -1
- package/lib-commonjs/components/LineChart/useLineChartStyles.styles.js +0 -2
- package/lib-commonjs/components/LineChart/useLineChartStyles.styles.js.map +1 -1
- package/lib-commonjs/components/SankeyChart/SankeyChart.js +1 -1
- package/lib-commonjs/components/SankeyChart/SankeyChart.js.map +1 -1
- package/lib-commonjs/components/SankeyChart/useSankeyChartStyles.styles.js +0 -2
- package/lib-commonjs/components/SankeyChart/useSankeyChartStyles.styles.js.map +1 -1
- package/lib-commonjs/components/ScatterChart/ScatterChart.js +17 -25
- package/lib-commonjs/components/ScatterChart/ScatterChart.js.map +1 -1
- package/lib-commonjs/components/ScatterChart/ScatterChart.types.js.map +1 -1
- package/lib-commonjs/components/ScatterChart/useScatterChartStyles.styles.js +0 -2
- package/lib-commonjs/components/ScatterChart/useScatterChartStyles.styles.js.map +1 -1
- package/lib-commonjs/components/VerticalBarChart/VerticalBarChart.js +12 -77
- package/lib-commonjs/components/VerticalBarChart/VerticalBarChart.js.map +1 -1
- package/lib-commonjs/components/VerticalBarChart/useVerticalBarChartStyles.styles.js +0 -2
- package/lib-commonjs/components/VerticalBarChart/useVerticalBarChartStyles.styles.js.map +1 -1
- package/lib-commonjs/components/VerticalStackedBarChart/VerticalStackedBarChart.js +20 -31
- package/lib-commonjs/components/VerticalStackedBarChart/VerticalStackedBarChart.js.map +1 -1
- package/lib-commonjs/components/VerticalStackedBarChart/useVerticalStackedBarChartStyles.styles.js +0 -2
- package/lib-commonjs/components/VerticalStackedBarChart/useVerticalStackedBarChartStyles.styles.js.map +1 -1
- package/lib-commonjs/types/ChartAnnotation.js.map +1 -1
- package/lib-commonjs/types/DataPoint.js.map +1 -1
- package/lib-commonjs/utilities/Common.styles.js +0 -1
- package/lib-commonjs/utilities/Common.styles.js.map +1 -1
- package/lib-commonjs/utilities/Common.styles.raw.js +0 -1
- package/lib-commonjs/utilities/Common.styles.raw.js.map +1 -1
- package/lib-commonjs/utilities/image-export-utils.js +3 -3
- package/lib-commonjs/utilities/image-export-utils.js.map +1 -1
- package/lib-commonjs/utilities/utilities.js +232 -81
- package/lib-commonjs/utilities/utilities.js.map +1 -1
- package/package.json +9 -9
- package/lib/components/DeclarativeChart/imageExporter.js +0 -223
- package/lib/components/DeclarativeChart/imageExporter.js.map +0 -1
- package/lib-commonjs/components/DeclarativeChart/imageExporter.js +0 -233
- package/lib-commonjs/components/DeclarativeChart/imageExporter.js.map +0 -1
|
@@ -13,6 +13,8 @@ import { formatDateToLocaleString, formatToLocaleString, getMultiLevelDateTimeFo
|
|
|
13
13
|
export const MIN_DOMAIN_MARGIN = 8;
|
|
14
14
|
export const MIN_DONUT_RADIUS = 1;
|
|
15
15
|
export const DEFAULT_DATE_STRING = '2000-01-01';
|
|
16
|
+
export const CARTESIAN_XAXIS_CLASSNAME = 'fui-cart__xAxis';
|
|
17
|
+
const CARTESIAN_XAXIS_TEXT_SELECTOR = `.${CARTESIAN_XAXIS_CLASSNAME} text`;
|
|
16
18
|
export var ChartTypes = /*#__PURE__*/ function(ChartTypes) {
|
|
17
19
|
ChartTypes[ChartTypes["AreaChart"] = 0] = "AreaChart";
|
|
18
20
|
ChartTypes[ChartTypes["LineChart"] = 1] = "LineChart";
|
|
@@ -90,7 +92,7 @@ function yAxisTickFormatterInternal(value, limitWidth = false) {
|
|
|
90
92
|
const xAxisValue = typeof domainValue === 'number' ? domainValue : domainValue.valueOf();
|
|
91
93
|
return (defaultFormat === null || defaultFormat === void 0 ? void 0 : defaultFormat(xAxisValue)) === '' ? '' : formatToLocaleString(xAxisValue, culture);
|
|
92
94
|
};
|
|
93
|
-
if (hideTickOverlap
|
|
95
|
+
if (hideTickOverlap) {
|
|
94
96
|
const longestLabelWidth = calcMaxLabelWidth(xAxisScale.ticks().map((v, i)=>tickFormat(v, i))) + 20;
|
|
95
97
|
const [start, end] = xAxisScale.range();
|
|
96
98
|
tickCount = Math.min(Math.max(1, Math.floor(Math.abs(end - start) / longestLabelWidth)), 10);
|
|
@@ -114,10 +116,12 @@ function yAxisTickFormatterInternal(value, limitWidth = false) {
|
|
|
114
116
|
if (xAxisElement) {
|
|
115
117
|
d3Select(xAxisElement).call(xAxis).selectAll('text').attr('aria-hidden', 'true').style('direction', 'ltr').style('unicode-bidi', 'isolate');
|
|
116
118
|
}
|
|
117
|
-
const tickValues =
|
|
119
|
+
const tickValues = customTickValues !== null && customTickValues !== void 0 ? customTickValues : xAxisScale.ticks(tickCount);
|
|
120
|
+
const tickLabels = tickValues.map(xAxis.tickFormat());
|
|
118
121
|
return {
|
|
119
122
|
xScale: xAxisScale,
|
|
120
|
-
tickValues
|
|
123
|
+
tickValues,
|
|
124
|
+
tickLabels
|
|
121
125
|
};
|
|
122
126
|
}
|
|
123
127
|
/**
|
|
@@ -310,7 +314,7 @@ export function getDateFormatLevel(date, useUTC) {
|
|
|
310
314
|
* @param {IXAxisParams} xAxisParams
|
|
311
315
|
* @param {ITickParams} tickParams
|
|
312
316
|
*/ export function createDateXAxis(xAxisParams, tickParams, culture, options, timeFormatLocale, customDateTimeFormatter, useUTC, chartType) {
|
|
313
|
-
const { domainNRangeValues, xAxisElement, tickPadding = 6, xAxistickSize = 6, xAxisCount, calcMaxLabelWidth, tickStep, tick0, tickText } = xAxisParams;
|
|
317
|
+
const { domainNRangeValues, xAxisElement, tickPadding = 6, xAxistickSize = 6, xAxisCount, hideTickOverlap, calcMaxLabelWidth, tickStep, tick0, tickText } = xAxisParams;
|
|
314
318
|
const isUtcSet = useUTC === true || useUTC === 'utc';
|
|
315
319
|
const xAxisScale = isUtcSet ? d3ScaleUtc() : d3ScaleTime();
|
|
316
320
|
xAxisScale.domain([
|
|
@@ -354,10 +358,11 @@ export function getDateFormatLevel(date, useUTC) {
|
|
|
354
358
|
}
|
|
355
359
|
return formatDateToLocaleString(domainValue, culture, useUTC ? true : false, false, formatOptions);
|
|
356
360
|
};
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
+
if (hideTickOverlap) {
|
|
362
|
+
const longestLabelWidth = calcMaxLabelWidth(xAxisScale.ticks().map(tickFormat)) + 40;
|
|
363
|
+
const [start, end] = xAxisScale.range();
|
|
364
|
+
tickCount = Math.max(1, Math.floor(Math.abs(end - start) / longestLabelWidth));
|
|
365
|
+
}
|
|
361
366
|
const xAxis = d3AxisBottom(xAxisScale).tickSize(xAxistickSize).tickPadding(tickPadding).ticks(tickCount).tickFormat(tickFormat);
|
|
362
367
|
if ([
|
|
363
368
|
8
|
|
@@ -376,10 +381,12 @@ export function getDateFormatLevel(date, useUTC) {
|
|
|
376
381
|
if (xAxisElement) {
|
|
377
382
|
d3Select(xAxisElement).call(xAxis).selectAll('text').attr('aria-hidden', 'true');
|
|
378
383
|
}
|
|
379
|
-
const tickValues =
|
|
384
|
+
const tickValues = customTickValues !== null && customTickValues !== void 0 ? customTickValues : xAxisScale.ticks(tickCount);
|
|
385
|
+
const tickLabels = tickValues.map(xAxis.tickFormat());
|
|
380
386
|
return {
|
|
381
387
|
xScale: xAxisScale,
|
|
382
|
-
tickValues
|
|
388
|
+
tickValues,
|
|
389
|
+
tickLabels
|
|
383
390
|
};
|
|
384
391
|
}
|
|
385
392
|
/**
|
|
@@ -436,7 +443,8 @@ export function getDateFormatLevel(date, useUTC) {
|
|
|
436
443
|
}
|
|
437
444
|
return {
|
|
438
445
|
xScale: xAxisScale,
|
|
439
|
-
tickValues
|
|
446
|
+
tickValues,
|
|
447
|
+
tickLabels: tickValues.map(xAxis.tickFormat())
|
|
440
448
|
};
|
|
441
449
|
}
|
|
442
450
|
export function useRtl() {
|
|
@@ -774,14 +782,14 @@ export const DEFAULT_WRAP_WIDTH = 10;
|
|
|
774
782
|
* @param {IWrapLabelProps} wrapLabelProps
|
|
775
783
|
* @returns
|
|
776
784
|
*/ export function createWrapOfXLabels(wrapLabelProps) {
|
|
777
|
-
const { node, xAxis, noOfCharsToTruncate, showXAxisLablesTooltip, width = DEFAULT_WRAP_WIDTH } = wrapLabelProps;
|
|
785
|
+
const { node, xAxis, noOfCharsToTruncate, showXAxisLablesTooltip, width = DEFAULT_WRAP_WIDTH, container } = wrapLabelProps;
|
|
778
786
|
if (node === null) {
|
|
779
787
|
return;
|
|
780
788
|
}
|
|
781
789
|
const axisNode = d3Select(node).call(xAxis);
|
|
782
790
|
let removeVal = 0;
|
|
783
791
|
let maxLines = 1;
|
|
784
|
-
axisNode.selectAll('.tick text').each(function() {
|
|
792
|
+
axisNode.selectAll('.tick text').each(function(_, tickIndex) {
|
|
785
793
|
const text = d3Select(this);
|
|
786
794
|
const totalWord = text.text();
|
|
787
795
|
const truncatedWord = `${text.text().slice(0, noOfCharsToTruncate)}...`;
|
|
@@ -793,33 +801,33 @@ export const DEFAULT_WRAP_WIDTH = 10;
|
|
|
793
801
|
const lineHeight = 1.1; // ems
|
|
794
802
|
const y = text.attr('y');
|
|
795
803
|
const dy = parseFloat(text.attr('dy'));
|
|
796
|
-
let tspan = text.text(null).append('tspan').attr('x', 0).attr('y', y).attr('
|
|
797
|
-
if (showXAxisLablesTooltip
|
|
798
|
-
tspan
|
|
799
|
-
} else if (showXAxisLablesTooltip && totalWordLength <= noOfCharsToTruncate) {
|
|
800
|
-
tspan = text.append('tspan').attr('id', 'LessLength').attr('x', 0).attr('y', y).attr('dy', dy + 'em').text(totalWord);
|
|
804
|
+
let tspan = text.text(null).attr('data-full', totalWord).append('tspan').attr('x', 0).attr('y', y).attr('dy', dy + 'em');
|
|
805
|
+
if (showXAxisLablesTooltip) {
|
|
806
|
+
tspan.text(totalWordLength > noOfCharsToTruncate ? truncatedWord : totalWord);
|
|
801
807
|
} else {
|
|
808
|
+
const maxWidth = Array.isArray(width) ? width[tickIndex] : width;
|
|
802
809
|
while(word = words.pop()){
|
|
803
810
|
line.push(word);
|
|
804
|
-
|
|
805
|
-
|
|
811
|
+
const label = line.join(' ');
|
|
812
|
+
tspan.text(label);
|
|
813
|
+
const labelWidth = getTextSize(label, CARTESIAN_XAXIS_TEXT_SELECTOR, container).width;
|
|
814
|
+
if (labelWidth > maxWidth && line.length > 1) {
|
|
806
815
|
line.pop();
|
|
807
816
|
tspan.text(line.join(' '));
|
|
808
817
|
line = [
|
|
809
818
|
word
|
|
810
819
|
];
|
|
811
|
-
tspan = text.append('tspan').attr('
|
|
820
|
+
tspan = text.append('tspan').attr('x', 0).attr('y', y).attr('dy', ++lineNumber * lineHeight + dy + 'em').text(word);
|
|
812
821
|
}
|
|
813
822
|
}
|
|
814
823
|
}
|
|
815
824
|
maxLines = Math.max(maxLines, lineNumber + 1);
|
|
816
825
|
});
|
|
817
826
|
if (!showXAxisLablesTooltip) {
|
|
827
|
+
var _querySelector;
|
|
818
828
|
let maxHeight = 12; // intial value to render corretly first time
|
|
819
|
-
|
|
820
|
-
const
|
|
821
|
-
const BoxCordinates = outerHTMLElement && outerHTMLElement.getBoundingClientRect();
|
|
822
|
-
const boxHeight = BoxCordinates && BoxCordinates.height;
|
|
829
|
+
var _querySelector_getBoundingClientRect_height;
|
|
830
|
+
const boxHeight = (_querySelector_getBoundingClientRect_height = (_querySelector = (container !== null && container !== void 0 ? container : document).querySelector(`.${CARTESIAN_XAXIS_CLASSNAME} tspan`)) === null || _querySelector === void 0 ? void 0 : _querySelector.getBoundingClientRect().height) !== null && _querySelector_getBoundingClientRect_height !== void 0 ? _querySelector_getBoundingClientRect_height : 0;
|
|
823
831
|
if (boxHeight > maxHeight) {
|
|
824
832
|
maxHeight = boxHeight;
|
|
825
833
|
}
|
|
@@ -835,24 +843,18 @@ yAxis, noOfCharsToTruncate, truncateLabel, isRtl) {
|
|
|
835
843
|
if (node === null) {
|
|
836
844
|
return;
|
|
837
845
|
}
|
|
838
|
-
let tickIndex = 0;
|
|
839
846
|
const axisNode = d3Select(node).call(yAxis);
|
|
840
847
|
axisNode.selectAll('.tick text').each(function() {
|
|
841
848
|
const text = d3Select(this);
|
|
842
849
|
const totalWord = text.text();
|
|
843
850
|
const truncatedWord = isRtl ? `...${text.text().slice(0, noOfCharsToTruncate)}` : `${text.text().slice(0, noOfCharsToTruncate)}...`;
|
|
844
851
|
const totalWordLength = text.text().length;
|
|
845
|
-
const padding = 0; // ems
|
|
846
852
|
const y = text.attr('y');
|
|
847
853
|
const x = text.attr('x');
|
|
848
854
|
const dy = parseFloat(text.attr('dy'));
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
if (truncateLabel && totalWordLength > noOfCharsToTruncate) {
|
|
853
|
-
text.append('tspan').attr('id', `showDots-${uid}`).attr('x', x).attr('y', y).attr('dy', dy + 'em').attr('dx', padding + dx + 'em').text(truncatedWord);
|
|
854
|
-
} else {
|
|
855
|
-
text.append('tspan').attr('id', `LessLength-${uid}`).attr('x', x).attr('y', y).attr('dx', padding + dx + 'em').text(totalWord);
|
|
855
|
+
const tspan = text.text(null).attr('data-full', totalWord).append('tspan').attr('x', x).attr('y', y).attr('dy', dy + 'em');
|
|
856
|
+
if (truncateLabel) {
|
|
857
|
+
tspan.text(totalWordLength > noOfCharsToTruncate ? truncatedWord : totalWord);
|
|
856
858
|
}
|
|
857
859
|
});
|
|
858
860
|
}
|
|
@@ -901,30 +903,30 @@ export const wrapContent = (content, id, maxWidth)=>{
|
|
|
901
903
|
* On hover of the truncated word(at x axis labels tick), a tooltip will be appeared.
|
|
902
904
|
*/ // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
903
905
|
export function tooltipOfAxislabels(axistooltipProps) {
|
|
904
|
-
const { tooltipCls, axis, id } = axistooltipProps;
|
|
906
|
+
const { tooltipCls, axis, id, container } = axistooltipProps;
|
|
905
907
|
if (axis === null) {
|
|
906
908
|
return null;
|
|
907
909
|
}
|
|
908
|
-
const div = d3Select('body').append('div').attr('id', id).attr('class', tooltipCls).style('opacity', 0);
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
const tickObjectLength = tickObject && Object.keys(tickObject).length;
|
|
918
|
-
for(let i = 0; i < tickObjectLength; i++){
|
|
919
|
-
const d1 = tickObject[i];
|
|
920
|
-
d3Select(d1)// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
910
|
+
const div = (container ? d3Select(container) : d3Select('body')).append('div').attr('id', id).attr('class', tooltipCls).style('opacity', 0);
|
|
911
|
+
axis.selectAll('.tick text').each(function() {
|
|
912
|
+
const tickSelection = d3Select(this);
|
|
913
|
+
const fullLabel = tickSelection.attr('data-full');
|
|
914
|
+
if (tickSelection.text() === fullLabel) {
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
const tickEl = this;
|
|
918
|
+
tickSelection// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
921
919
|
.on('mouseover', (event, d)=>{
|
|
922
|
-
|
|
923
|
-
|
|
920
|
+
const containerBounds = container === null || container === void 0 ? void 0 : container.getBoundingClientRect();
|
|
921
|
+
const tickBounds = tickEl.getBoundingClientRect();
|
|
922
|
+
const tooltipBottom = containerBounds ? containerBounds.bottom - (tickBounds.top - 4) : tickBounds.top - 4;
|
|
923
|
+
var _containerBounds_left;
|
|
924
|
+
const tooltipLeft = (tickBounds.left + tickBounds.right) / 2 - ((_containerBounds_left = containerBounds === null || containerBounds === void 0 ? void 0 : containerBounds.left) !== null && _containerBounds_left !== void 0 ? _containerBounds_left : 0);
|
|
925
|
+
div.text(fullLabel).style('bottom', `${tooltipBottom}px`).style('left', `${tooltipLeft}px`).style('transform', 'translateX(-50%)').style('opacity', 0.9);
|
|
924
926
|
}).on('mouseout', (d)=>{
|
|
925
927
|
div.style('opacity', 0);
|
|
926
928
|
});
|
|
927
|
-
}
|
|
929
|
+
});
|
|
928
930
|
}
|
|
929
931
|
/**
|
|
930
932
|
* Find the axis type of line chart and area chart from given data
|
|
@@ -950,11 +952,11 @@ export function tooltipOfAxislabels(axistooltipProps) {
|
|
|
950
952
|
* @param {number} width
|
|
951
953
|
* @param {boolean} isRTL
|
|
952
954
|
* @returns {IDomainNRange}
|
|
953
|
-
*/ export function domainRangeOfNumericForAreaLineScatterCharts(points, margins, width, isRTL, scaleType, hasMarkersMode) {
|
|
955
|
+
*/ export function domainRangeOfNumericForAreaLineScatterCharts(points, margins, width, isRTL, scaleType, hasMarkersMode, xMinVal, xMaxVal) {
|
|
954
956
|
const isScatterPolar = isScatterPolarSeries(points);
|
|
955
957
|
let [xMin, xMax] = getScatterXDomainExtent(points, scaleType);
|
|
956
958
|
if (hasMarkersMode) {
|
|
957
|
-
const xPadding = getDomainPaddingForMarkers(xMin, xMax, scaleType);
|
|
959
|
+
const xPadding = getDomainPaddingForMarkers(xMin, xMax, scaleType, xMinVal, xMaxVal);
|
|
958
960
|
xMin = xMin - xPadding.start;
|
|
959
961
|
xMax = xMax + xPadding.end;
|
|
960
962
|
}
|
|
@@ -1466,8 +1468,8 @@ export function areArraysEqual(arr1, arr2) {
|
|
|
1466
1468
|
return true;
|
|
1467
1469
|
}
|
|
1468
1470
|
const cssVarRegExp = /var\((--[a-zA-Z0-9\-]+)\)/g;
|
|
1469
|
-
export function resolveCSSVariables(
|
|
1470
|
-
const containerStyles = getComputedStyle(
|
|
1471
|
+
export function resolveCSSVariables(container, styleRules) {
|
|
1472
|
+
const containerStyles = getComputedStyle(container);
|
|
1471
1473
|
return styleRules.replace(cssVarRegExp, (match, group1)=>{
|
|
1472
1474
|
return containerStyles.getPropertyValue(group1);
|
|
1473
1475
|
});
|
|
@@ -1570,11 +1572,6 @@ export function copyStyle(properties, fromEl, toEl) {
|
|
|
1570
1572
|
});
|
|
1571
1573
|
}
|
|
1572
1574
|
}
|
|
1573
|
-
let measurementSpanCounter = 0;
|
|
1574
|
-
function getUniqueMeasurementSpanId() {
|
|
1575
|
-
measurementSpanCounter++;
|
|
1576
|
-
return `measurement_span_${measurementSpanCounter}`;
|
|
1577
|
-
}
|
|
1578
1575
|
const MEASUREMENT_SPAN_STYLE = {
|
|
1579
1576
|
position: 'absolute',
|
|
1580
1577
|
visibility: 'hidden',
|
|
@@ -1585,23 +1582,60 @@ const MEASUREMENT_SPAN_STYLE = {
|
|
|
1585
1582
|
border: 'none',
|
|
1586
1583
|
whiteSpace: 'pre'
|
|
1587
1584
|
};
|
|
1588
|
-
|
|
1589
|
-
|
|
1585
|
+
const MEASUREMENT_SPAN_ID = 'fui_measurement_span';
|
|
1586
|
+
const TEXT_STYLE_PROPERTIES = [
|
|
1587
|
+
'font-size',
|
|
1588
|
+
'font-family',
|
|
1589
|
+
'font-weight',
|
|
1590
|
+
'font-style',
|
|
1591
|
+
'letter-spacing',
|
|
1592
|
+
'text-transform'
|
|
1593
|
+
];
|
|
1594
|
+
export const measureTextWithDOM = (text, cssSelector, container)=>{
|
|
1590
1595
|
let measurementSpan = document.getElementById(MEASUREMENT_SPAN_ID);
|
|
1591
1596
|
if (!measurementSpan) {
|
|
1592
1597
|
measurementSpan = document.createElement('span');
|
|
1593
1598
|
measurementSpan.setAttribute('id', MEASUREMENT_SPAN_ID);
|
|
1594
1599
|
measurementSpan.setAttribute('aria-hidden', 'true');
|
|
1595
|
-
|
|
1596
|
-
parentElement.appendChild(measurementSpan);
|
|
1597
|
-
} else {
|
|
1598
|
-
document.body.appendChild(measurementSpan);
|
|
1599
|
-
}
|
|
1600
|
+
(container !== null && container !== void 0 ? container : document.body).appendChild(measurementSpan);
|
|
1600
1601
|
}
|
|
1601
|
-
measurementSpan.setAttribute('class', className);
|
|
1602
1602
|
Object.assign(measurementSpan.style, MEASUREMENT_SPAN_STYLE);
|
|
1603
|
+
const refEl = (container !== null && container !== void 0 ? container : document).querySelector(cssSelector);
|
|
1604
|
+
if (refEl) {
|
|
1605
|
+
copyStyle(TEXT_STYLE_PROPERTIES, refEl, measurementSpan);
|
|
1606
|
+
}
|
|
1603
1607
|
measurementSpan.textContent = `${text}`;
|
|
1604
|
-
|
|
1608
|
+
const rect = measurementSpan.getBoundingClientRect();
|
|
1609
|
+
return {
|
|
1610
|
+
node: measurementSpan,
|
|
1611
|
+
width: rect.width,
|
|
1612
|
+
height: rect.height
|
|
1613
|
+
};
|
|
1614
|
+
};
|
|
1615
|
+
const CACHE_SIZE = 2000;
|
|
1616
|
+
const textSizeCache = new Map();
|
|
1617
|
+
export const getTextSize = (text, cssSelector, container)=>{
|
|
1618
|
+
const cacheKey = `${text}|${cssSelector}`;
|
|
1619
|
+
const cachedResult = textSizeCache.get(cacheKey);
|
|
1620
|
+
if (cachedResult) {
|
|
1621
|
+
return cachedResult;
|
|
1622
|
+
}
|
|
1623
|
+
const { width, height } = measureTextWithDOM(text, cssSelector, container);
|
|
1624
|
+
// TODO: Improve cache eviction strategy if needed (e.g., LRU)
|
|
1625
|
+
if (textSizeCache.size >= CACHE_SIZE) {
|
|
1626
|
+
const firstKey = textSizeCache.keys().next().value;
|
|
1627
|
+
if (!isInvalidValue(firstKey)) {
|
|
1628
|
+
textSizeCache.delete(firstKey);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
textSizeCache.set(cacheKey, {
|
|
1632
|
+
width,
|
|
1633
|
+
height
|
|
1634
|
+
});
|
|
1635
|
+
return {
|
|
1636
|
+
width,
|
|
1637
|
+
height
|
|
1638
|
+
};
|
|
1605
1639
|
};
|
|
1606
1640
|
/**
|
|
1607
1641
|
* Utility function to check if an array of points is scatterpolar
|
|
@@ -1633,17 +1667,26 @@ const createNumericScale = (scaleType)=>{
|
|
|
1633
1667
|
return d3ScaleLinear();
|
|
1634
1668
|
}
|
|
1635
1669
|
};
|
|
1636
|
-
export const getDomainPaddingForMarkers = (minVal, maxVal, scaleType)=>{
|
|
1670
|
+
export const getDomainPaddingForMarkers = (minVal, maxVal, scaleType, userMinVal, userMaxVal)=>{
|
|
1637
1671
|
if (scaleType === 'log') {
|
|
1638
1672
|
return {
|
|
1639
1673
|
start: minVal * 0.5,
|
|
1640
1674
|
end: maxVal
|
|
1641
1675
|
};
|
|
1642
1676
|
}
|
|
1643
|
-
|
|
1677
|
+
/* if user explicitly sets userMinVal or userMaxVal, we will check that to avoid excessive padding on either side.
|
|
1678
|
+
If the difference between minVal and userMinVal is more than 10% of the data range, we set padding to 0 on that side.
|
|
1679
|
+
this is to avoid cases where userMinVal is significantly smaller than minVal or userMaxVal is significantly larger than
|
|
1680
|
+
maxVal, which would lead to excessive padding. In other cases, we apply the default 10% padding on both sides.
|
|
1681
|
+
*/ const rangePadding = (maxVal - minVal) * 0.1;
|
|
1682
|
+
// If explicit bounds are set and they're far from the data range, don't add extra padding
|
|
1683
|
+
const paddingAlreadySatisfiedAtMin = userMinVal !== undefined && rangePadding > Math.abs(minVal - Math.min(minVal, userMinVal));
|
|
1684
|
+
const paddingAlreadySatisfiedAtMax = userMaxVal !== undefined && rangePadding > Math.abs(maxVal - Math.max(maxVal, userMaxVal));
|
|
1685
|
+
const startPadding = paddingAlreadySatisfiedAtMin ? 0 : rangePadding;
|
|
1686
|
+
const endPadding = paddingAlreadySatisfiedAtMax ? 0 : rangePadding;
|
|
1644
1687
|
return {
|
|
1645
|
-
start:
|
|
1646
|
-
end:
|
|
1688
|
+
start: startPadding,
|
|
1689
|
+
end: endPadding
|
|
1647
1690
|
};
|
|
1648
1691
|
};
|
|
1649
1692
|
/**
|
|
@@ -1672,7 +1715,7 @@ export const getScatterXDomainExtent = (points, scaleType)=>{
|
|
|
1672
1715
|
xMax
|
|
1673
1716
|
];
|
|
1674
1717
|
};
|
|
1675
|
-
export const getRangeForScatterMarkerSize = ({ data, xScale, yScalePrimary, yScaleSecondary, useSecondaryYScale, xScaleType, yScaleType: primaryYScaleType, secondaryYScaleType })=>{
|
|
1718
|
+
export const getRangeForScatterMarkerSize = ({ data, xScale, yScalePrimary, yScaleSecondary, useSecondaryYScale, xScaleType, yScaleType: primaryYScaleType, secondaryYScaleType, xMinValue, xMaxValue, yMinValue, yMaxValue })=>{
|
|
1676
1719
|
// Note: This function is executed after the scale is created, so the actual padding can be
|
|
1677
1720
|
// obtained by calculating the difference between the respective minimums or maximums of the
|
|
1678
1721
|
// scale domain and the data. However, doing so often causes the marker size to scale up
|
|
@@ -1683,13 +1726,13 @@ export const getRangeForScatterMarkerSize = ({ data, xScale, yScalePrimary, ySca
|
|
|
1683
1726
|
// it the other way around (i.e., adjusting the scale domain first with padding and then scaling
|
|
1684
1727
|
// the markers to fit inside the plot area).
|
|
1685
1728
|
const [xMin, xMax] = getScatterXDomainExtent(data, xScaleType);
|
|
1686
|
-
const xPadding = getDomainPaddingForMarkers(+xMin, +xMax, xScaleType);
|
|
1729
|
+
const xPadding = getDomainPaddingForMarkers(+xMin, +xMax, xScaleType, xMinValue, xMaxValue);
|
|
1687
1730
|
const scaleXMin = xMin instanceof Date ? new Date(+xMin - xPadding.start) : xMin - xPadding.start;
|
|
1688
1731
|
const scaleXMax = xMax instanceof Date ? new Date(+xMax + xPadding.end) : xMax + xPadding.end;
|
|
1689
1732
|
const extraXPixels = Math.min(Math.abs(xScale(xMin) - xScale(scaleXMin)), Math.abs(xScale(scaleXMax) - xScale(xMax)));
|
|
1690
1733
|
const yScaleType = useSecondaryYScale ? secondaryYScaleType : primaryYScaleType;
|
|
1691
1734
|
const { startValue: yMin, endValue: yMax } = findNumericMinMaxOfY(data, undefined, useSecondaryYScale, yScaleType);
|
|
1692
|
-
const yPadding = getDomainPaddingForMarkers(yMin, yMax, yScaleType);
|
|
1735
|
+
const yPadding = getDomainPaddingForMarkers(yMin, yMax, yScaleType, yMinValue, yMaxValue);
|
|
1693
1736
|
const scaleYMin = yMin - yPadding.start;
|
|
1694
1737
|
const scaleYMax = yMax + yPadding.end;
|
|
1695
1738
|
const yScale = useSecondaryYScale ? yScaleSecondary : yScalePrimary;
|
|
@@ -1741,7 +1784,7 @@ const generateNumericTicks = (scaleType, tickStep, tick0, scaleDomain)=>{
|
|
|
1741
1784
|
const refTick = typeof tick0 === 'number' ? tick0 : 0;
|
|
1742
1785
|
if (scaleType === 'log') {
|
|
1743
1786
|
if (typeof tickStep === 'number' && tickStep > 0) {
|
|
1744
|
-
return generateLinearTicks(refTick, tickStep, scaleDomain.map((d)=>Math.log10(d))).map((t)=>
|
|
1787
|
+
return generateLinearTicks(refTick, tickStep, scaleDomain.map((d)=>Math.log10(d))).map((t)=>10 ** t);
|
|
1745
1788
|
}
|
|
1746
1789
|
if (typeof tickStep === 'string') {
|
|
1747
1790
|
const prefix = tickStep[0];
|
|
@@ -1798,7 +1841,7 @@ const generateDateTicks = (tickStep, tick0, scaleDomain, useUTC)=>{
|
|
|
1798
1841
|
* @param value - The value that is being rounded.
|
|
1799
1842
|
* @param precision - The number of decimal places to round the number to
|
|
1800
1843
|
*/ export function precisionRound(value, precision, base = 10) {
|
|
1801
|
-
const exp =
|
|
1844
|
+
const exp = base ** precision;
|
|
1802
1845
|
return Math.round(value * exp) / exp;
|
|
1803
1846
|
}
|
|
1804
1847
|
export const findCalloutPoints = (calloutPointsByX, x)=>{
|
|
@@ -1814,3 +1857,102 @@ export const findCalloutPoints = (calloutPointsByX, x)=>{
|
|
|
1814
1857
|
values: calloutPointsByX[key]
|
|
1815
1858
|
};
|
|
1816
1859
|
};
|
|
1860
|
+
export const autoLayoutXAxisLabels = (tickValues, tickLabels, scale, axisNode, containerWidth, container)=>{
|
|
1861
|
+
let requiresWrap = false;
|
|
1862
|
+
let requiresTruncate = false;
|
|
1863
|
+
const maxWidths = [];
|
|
1864
|
+
const [rangeStart, rangeEnd] = scale.range();
|
|
1865
|
+
const isRTL = rangeEnd - rangeStart < 0;
|
|
1866
|
+
const start = isRTL ? containerWidth : 0;
|
|
1867
|
+
const end = isRTL ? 0 : containerWidth;
|
|
1868
|
+
const getTickPosition = (index)=>{
|
|
1869
|
+
var _scale;
|
|
1870
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1871
|
+
return ((_scale = scale(tickValues[index])) !== null && _scale !== void 0 ? _scale : 0) + ('bandwidth' in scale ? scale.bandwidth() / 2 : 0);
|
|
1872
|
+
};
|
|
1873
|
+
const getLabelWidth = (text)=>{
|
|
1874
|
+
return getTextSize(text, CARTESIAN_XAXIS_TEXT_SELECTOR, container).width;
|
|
1875
|
+
};
|
|
1876
|
+
for(let i = 0; i < tickValues.length; i++){
|
|
1877
|
+
const position = getTickPosition(i);
|
|
1878
|
+
const leftSpace = Math.abs(i > 0 ? (position - getTickPosition(i - 1)) / 2 : position - start);
|
|
1879
|
+
const rightSpace = Math.abs(i + 1 < tickValues.length ? (getTickPosition(i + 1) - position) / 2 : end - position);
|
|
1880
|
+
const maxAvailableWidth = Math.min(leftSpace, rightSpace) * 2 - 8; // 4px padding on both sides
|
|
1881
|
+
const label = tickLabels[i];
|
|
1882
|
+
const labelWidth = getLabelWidth(label);
|
|
1883
|
+
maxWidths.push(maxAvailableWidth);
|
|
1884
|
+
if (labelWidth > maxAvailableWidth) {
|
|
1885
|
+
const longestWordWidth = Math.max(...label.split(/\s+/).map((word)=>getLabelWidth(word)));
|
|
1886
|
+
if (longestWordWidth <= maxAvailableWidth) {
|
|
1887
|
+
requiresWrap = true;
|
|
1888
|
+
} else {
|
|
1889
|
+
requiresTruncate = true;
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
if (requiresTruncate) {
|
|
1894
|
+
return truncateAndStaggerXAxisLabels(tickValues, tickLabels, scale, axisNode, containerWidth, container);
|
|
1895
|
+
}
|
|
1896
|
+
if (requiresWrap) {
|
|
1897
|
+
var _createWrapOfXLabels;
|
|
1898
|
+
return (_createWrapOfXLabels = createWrapOfXLabels({
|
|
1899
|
+
node: axisNode,
|
|
1900
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1901
|
+
xAxis: scale,
|
|
1902
|
+
noOfCharsToTruncate: 100,
|
|
1903
|
+
showXAxisLablesTooltip: false,
|
|
1904
|
+
width: maxWidths,
|
|
1905
|
+
container
|
|
1906
|
+
})) !== null && _createWrapOfXLabels !== void 0 ? _createWrapOfXLabels : 0;
|
|
1907
|
+
}
|
|
1908
|
+
return 0;
|
|
1909
|
+
};
|
|
1910
|
+
const truncateAndStaggerXAxisLabels = (tickValues, tickLabels, scale, axisNode, containerWidth, container)=>{
|
|
1911
|
+
if (!axisNode) {
|
|
1912
|
+
return 0;
|
|
1913
|
+
}
|
|
1914
|
+
let maxHeight = 12;
|
|
1915
|
+
const [rangeStart, rangeEnd] = scale.range();
|
|
1916
|
+
const isRTL = rangeEnd - rangeStart < 0;
|
|
1917
|
+
const start = isRTL ? containerWidth : 0;
|
|
1918
|
+
const end = isRTL ? 0 : containerWidth;
|
|
1919
|
+
const getTickPosition = (index)=>{
|
|
1920
|
+
var _scale;
|
|
1921
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1922
|
+
return ((_scale = scale(tickValues[index])) !== null && _scale !== void 0 ? _scale : 0) + ('bandwidth' in scale ? scale.bandwidth() / 2 : 0);
|
|
1923
|
+
};
|
|
1924
|
+
const getLabelSize = (text)=>{
|
|
1925
|
+
return getTextSize(text, CARTESIAN_XAXIS_TEXT_SELECTOR, container);
|
|
1926
|
+
};
|
|
1927
|
+
d3Select(axisNode).selectAll('.tick text').each(function(_, i) {
|
|
1928
|
+
const position = getTickPosition(i);
|
|
1929
|
+
const leftSpace = Math.abs(i > 0 ? position - getTickPosition(i - 1) : position - start);
|
|
1930
|
+
const rightSpace = Math.abs(i + 1 < tickValues.length ? getTickPosition(i + 1) - position : end - position);
|
|
1931
|
+
const maxAvailableWidth = Math.min(leftSpace, rightSpace) * 2 - 8; // 4px padding on both sides
|
|
1932
|
+
const label = tickLabels[i];
|
|
1933
|
+
const textNode = d3Select(this).text(null).attr('data-full', label);
|
|
1934
|
+
const lineHeight = 1.1; // ems
|
|
1935
|
+
const y = textNode.attr('y');
|
|
1936
|
+
const dy = parseFloat(textNode.attr('dy'));
|
|
1937
|
+
textNode.append('tspan').attr('x', 0).attr('y', y).attr('dy', (i % 2 === 1 ? lineHeight : 0) + dy + 'em').text(truncateTextToFitWidth(label, maxAvailableWidth, (s)=>getLabelSize(s).width));
|
|
1938
|
+
maxHeight = Math.max(maxHeight, getLabelSize(label).height);
|
|
1939
|
+
});
|
|
1940
|
+
return tickValues.length > 1 ? maxHeight : 0;
|
|
1941
|
+
};
|
|
1942
|
+
const truncateTextToFitWidth = (text, maxWidth, measure)=>{
|
|
1943
|
+
if (measure(text) <= maxWidth) {
|
|
1944
|
+
return text;
|
|
1945
|
+
}
|
|
1946
|
+
let lo = 1;
|
|
1947
|
+
let hi = text.length;
|
|
1948
|
+
while(lo < hi){
|
|
1949
|
+
const mid = Math.floor((lo + hi + 1) / 2);
|
|
1950
|
+
const candidate = text.slice(0, mid) + '...';
|
|
1951
|
+
if (measure(candidate) <= maxWidth) {
|
|
1952
|
+
lo = mid;
|
|
1953
|
+
} else {
|
|
1954
|
+
hi = mid - 1;
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
return text.slice(0, lo) + '...';
|
|
1958
|
+
};
|