@oliasoft-open-source/charts-library 4.8.0-beta-2 → 4.8.0-beta-4

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/dist/index.js CHANGED
@@ -6,10 +6,10 @@ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
6
6
  import * as React from "react";
7
7
  import React__default, { forwardRef, useRef, useEffect, createContext as createContext$2, memo, useLayoutEffect, useState, useCallback, useMemo, isValidElement, cloneElement, useContext, useReducer } from "react";
8
8
  import { produce } from "immer";
9
- import { round as round$2, displayNumber, roundByMagnitude } from "@oliasoft-open-source/units";
9
+ import { round as round$2, displayNumber, isCloseTo, roundByMagnitude } from "@oliasoft-open-source/units";
10
10
  import cx from "classnames";
11
11
  import { Portal, Icon, Menu, Tooltip as Tooltip$2, Button, Popover, Field, InputGroup, NumberInput, InputGroupAddon, Select, ButtonGroup, Spacer, Flex, Text } from "@oliasoft-open-source/react-ui-library";
12
- import { isEmpty, isArray as isArray$2, some, has, cloneDeep, defaultTo, findIndex, set as set$2, debounce as debounce$3, isNil, map as map$3, find, get as get$1, noop as noop$2 } from "lodash";
12
+ import { isEmpty, isArray as isArray$2, some, has, isNil, cloneDeep, defaultTo, findIndex, set as set$2, debounce as debounce$3, map as map$3, find, get as get$1, noop as noop$2 } from "lodash";
13
13
  /*!
14
14
  * @kurkle/color v0.3.2
15
15
  * https://github.com/kurkle/color#readme
@@ -22723,6 +22723,8 @@ const ANIMATION_DURATION = {
22723
22723
  };
22724
22724
  const DEFAULT_CHART_NAME = "new_chart";
22725
22725
  const CUSTOM_LEGEND_PLUGIN_NAME = "htmlLegend";
22726
+ const DECIMAL_POINT_TOLERANCE = 9;
22727
+ const MAX_DECIMAL_DIFF = 1 / 10 ** DECIMAL_POINT_TOLERANCE;
22726
22728
  const GRADIENT_COLORS = [
22727
22729
  { offset: 0, color: "rgba(144,238,144,0.8)" },
22728
22730
  // Light green
@@ -22876,6 +22878,10 @@ const generateAxisId = (axisType, index2 = 0, hasMultiAxes = false) => {
22876
22878
  const i2 = hasMultiAxes && index2 !== 0 ? index2 + 1 : "";
22877
22879
  return `${axisType}${i2}`;
22878
22880
  };
22881
+ const getAxisTypeFromKey = (string) => {
22882
+ var _a2;
22883
+ return ((_a2 = string == null ? void 0 : string.match(/[^0-9/]+/gi)) == null ? void 0 : _a2[0]) ?? "";
22884
+ };
22879
22885
  const generateKey = (values) => {
22880
22886
  const key = values.join("");
22881
22887
  return key;
@@ -25068,7 +25074,8 @@ var CUSTOM_OPTION = /* @__PURE__ */ ((CUSTOM_OPTION2) => {
25068
25074
  return CUSTOM_OPTION2;
25069
25075
  })(CUSTOM_OPTION || {});
25070
25076
  const generateLineChartDatasets = (datasets, state, options, { label }) => {
25071
- const copyDataset = [...datasets ?? []];
25077
+ var _a2, _b2;
25078
+ const copyDataset = datasets ?? [];
25072
25079
  const { annotations, graph } = options ?? {};
25073
25080
  const {
25074
25081
  controlAnnotation,
@@ -25076,12 +25083,14 @@ const generateLineChartDatasets = (datasets, state, options, { label }) => {
25076
25083
  annotationsData = []
25077
25084
  } = annotations ?? {};
25078
25085
  if (controlAnnotation && showAnnotations) {
25079
- const annotationDatasets = annotationsData.map((ann, index2) => {
25086
+ let index2 = 0;
25087
+ while (index2 < annotationsData.length) {
25088
+ const ann = annotationsData[index2];
25080
25089
  const { type, ...annotation2 } = ann;
25081
25090
  const color2 = annotation2.color ?? COLORS[index2];
25082
25091
  const borderDash = ANNOTATION_DASH;
25083
25092
  const borderWidth = BORDER_WIDTH.INITIAL;
25084
- return {
25093
+ copyDataset.push({
25085
25094
  ...annotation2,
25086
25095
  isAnnotation: true,
25087
25096
  annotationType: type,
@@ -25093,12 +25102,14 @@ const generateLineChartDatasets = (datasets, state, options, { label }) => {
25093
25102
  borderDash,
25094
25103
  borderWidth,
25095
25104
  data: [{}]
25096
- };
25097
- });
25098
- copyDataset.push(...annotationDatasets);
25105
+ });
25106
+ index2++;
25107
+ }
25099
25108
  }
25100
- return copyDataset == null ? void 0 : copyDataset.map((line, i2) => {
25101
- var _a2, _b2;
25109
+ const result = new Array(copyDataset.length);
25110
+ let i2 = 0;
25111
+ while (i2 < copyDataset.length) {
25112
+ const line = copyDataset[i2];
25102
25113
  const {
25103
25114
  formation,
25104
25115
  data = [],
@@ -25125,9 +25136,9 @@ const generateLineChartDatasets = (datasets, state, options, { label }) => {
25125
25136
  data[2].x = Math.min(axesMax, endPoint.x);
25126
25137
  }
25127
25138
  }
25139
+ const filteredData = (data == null ? void 0 : data.length) ? data == null ? void 0 : data.filter(Boolean) : [];
25128
25140
  const hasCustomOpt = checkCustomOption(line, CUSTOM_OPTION);
25129
- const filteredData = data.filter(Boolean) || [];
25130
- const isSinglePoint = (filteredData == null ? void 0 : filteredData.length) === 1;
25141
+ const isSinglePoint = filteredData.length === 1;
25131
25142
  let pointState, lineState;
25132
25143
  if (customShowPoints !== void 0) {
25133
25144
  pointState = customShowPoints;
@@ -25143,17 +25154,19 @@ const generateLineChartDatasets = (datasets, state, options, { label }) => {
25143
25154
  } else {
25144
25155
  lineState = lineEnabled;
25145
25156
  }
25146
- const linePointRadius = parseFloat(pointRadiusProp) || DEFAULT_POINT_RADIUS;
25147
- const hoverRadius = parseFloat(pointHoverRadius) || DEFAULT_HOVER_RADIUS;
25157
+ const parsedPointRadius = typeof pointRadiusProp === "string" ? parseFloat(pointRadiusProp) : pointRadiusProp;
25158
+ const linePointRadius = parsedPointRadius || DEFAULT_POINT_RADIUS;
25159
+ const parsedHoverRadius = typeof pointHoverRadius === "string" ? parseFloat(pointHoverRadius) : pointHoverRadius;
25160
+ const hoverRadius = parsedHoverRadius || DEFAULT_HOVER_RADIUS;
25148
25161
  const indexedColor = COLORS[i2];
25149
- return {
25162
+ result[i2] = {
25150
25163
  ...line,
25151
25164
  label: (line == null ? void 0 : line.label) ?? `${label} ${i2 + 1}`,
25152
25165
  data: filteredData,
25153
25166
  showLine: lineState,
25154
25167
  lineTension: (line == null ? void 0 : line.lineTension) ?? lineTension,
25155
25168
  spanGaps,
25156
- borderWidth: parseFloat(borderWidth) || DEFAULT_BORDER_WIDTH,
25169
+ borderWidth: (typeof borderWidth === "string" ? parseFloat(borderWidth) : borderWidth) || DEFAULT_BORDER_WIDTH,
25157
25170
  borderDash: borderDash || [],
25158
25171
  borderJoinStyle: BORDER_JOIN_STYLE,
25159
25172
  borderColor: borderColor ?? indexedColor ?? generateRandomColor(COLORS),
@@ -25164,7 +25177,32 @@ const generateLineChartDatasets = (datasets, state, options, { label }) => {
25164
25177
  pointHitRadius: (line == null ? void 0 : line.pointHitRadius) ?? hoverRadius,
25165
25178
  ...hasCustomOpt ? { hasCustomOpt } : {}
25166
25179
  };
25180
+ i2++;
25181
+ }
25182
+ return result;
25183
+ };
25184
+ const getAnnotationsData = (data) => {
25185
+ return data == null ? void 0 : data.reduce((acc, obj) => {
25186
+ return {
25187
+ ...acc,
25188
+ [obj.annotationAxis]: [...acc[obj.annotationAxis] || [], +obj.value]
25189
+ };
25190
+ }, {});
25191
+ };
25192
+ const getAxisRangeByType = (chartRef, axesType, annotationsData) => {
25193
+ if (!chartRef || !chartRef.current) return null;
25194
+ const metasets = chartRef.current.getSortedVisibleDatasetMetas();
25195
+ const annotDataByType = getAnnotationsData(annotationsData)[axesType] ?? [];
25196
+ let allData = [];
25197
+ metasets.forEach((metaset) => {
25198
+ const data = metaset._parsed.map((parsedData) => parsedData[axesType]).filter((value) => value != null && !isNaN(value));
25199
+ allData = allData.concat(data);
25167
25200
  });
25201
+ allData = allData.concat(annotDataByType);
25202
+ if (allData.length === 0) return null;
25203
+ const min = Math.min(...allData);
25204
+ const max = Math.max(...allData);
25205
+ return { min, max };
25168
25206
  };
25169
25207
  const calculateDelta$1 = (tickValue, ticks) => {
25170
25208
  let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;
@@ -25272,9 +25310,142 @@ const getLineChartScales = (options, state) => {
25272
25310
  ...yAxes
25273
25311
  };
25274
25312
  };
25275
- const autoScale = (options, state) => {
25313
+ const estimateDataSeriesHaveCloseValues = (generatedDatasets) => {
25314
+ var _a2;
25315
+ if (!Array.isArray(generatedDatasets) || !(generatedDatasets == null ? void 0 : generatedDatasets.length)) {
25316
+ return false;
25317
+ }
25318
+ const axesFirstLast = generatedDatasets == null ? void 0 : generatedDatasets.reduce((acc, dataset) => {
25319
+ var _a3, _b2, _c2, _d2;
25320
+ const xAxisId = (dataset == null ? void 0 : dataset.xAxisID) ?? "defaultX";
25321
+ const yAxisId = (dataset == null ? void 0 : dataset.yAxisID) ?? "defaultY";
25322
+ const data = (dataset == null ? void 0 : dataset.data) ?? [];
25323
+ if (data && (data == null ? void 0 : data.length)) {
25324
+ const { x: xFirstCurrent, y: yFirstCurrent } = (data == null ? void 0 : data[0]) ?? {};
25325
+ const { x: xLastCurrent = 0, y: yLastCurrent = 0 } = (data == null ? void 0 : data.at(-1)) ?? {};
25326
+ const xFirstAcc = ((_a3 = acc == null ? void 0 : acc[xAxisId]) == null ? void 0 : _a3.xFirst) ?? xFirstCurrent;
25327
+ const xLastAcc = ((_b2 = acc == null ? void 0 : acc[xAxisId]) == null ? void 0 : _b2.xLast) ?? xLastCurrent;
25328
+ const yFirstAcc = ((_c2 = acc == null ? void 0 : acc[yAxisId]) == null ? void 0 : _c2.yFirst) ?? yFirstCurrent;
25329
+ const yLastAcc = ((_d2 = acc == null ? void 0 : acc[yAxisId]) == null ? void 0 : _d2.yLast) ?? yLastCurrent;
25330
+ const xFirst = Math.min(xFirstCurrent, xFirstAcc);
25331
+ const xLast = Math.max(xLastCurrent, xLastAcc);
25332
+ const yFirst = Math.min(yFirstCurrent, yFirstAcc);
25333
+ const yLast = Math.max(yLastCurrent, yLastAcc);
25334
+ acc = {
25335
+ ...acc,
25336
+ [xAxisId]: {
25337
+ ...acc[xAxisId],
25338
+ xFirst,
25339
+ xLast
25340
+ },
25341
+ [yAxisId]: {
25342
+ yFirst,
25343
+ yLast
25344
+ }
25345
+ };
25346
+ }
25347
+ return acc;
25348
+ }, {});
25349
+ return (_a2 = Object.values(axesFirstLast)) == null ? void 0 : _a2.some(({ xFirst, xLast, yFirst, yLast }) => {
25350
+ return isCloseTo(xFirst, xLast, { absoluteDiff: MAX_DECIMAL_DIFF }) || isCloseTo(yFirst, yLast, { absoluteDiff: MAX_DECIMAL_DIFF });
25351
+ });
25352
+ };
25353
+ const whiteSpacePercentage = 0.05;
25354
+ const defaultRange = { min: -1, max: 1 };
25355
+ const getSuggestedAxisRange = ({
25356
+ data,
25357
+ beginAtZero = false,
25358
+ autoAxisPadding = false
25359
+ }) => {
25360
+ const dataMin = Math.min(
25361
+ ...data.filter((v2) => v2 !== null && v2 !== void 0 && !isNaN(v2))
25362
+ );
25363
+ const dataMax = Math.max(
25364
+ ...data.filter((v2) => v2 !== null && v2 !== void 0 && !isNaN(v2))
25365
+ );
25366
+ const isNegative = Math.sign(dataMin) === -1 || Math.sign(dataMax) === -1;
25367
+ const isCloseToZeroWithTolerance = isCloseTo(dataMin, 0, { absoluteDiff: MAX_DECIMAL_DIFF }) && isCloseTo(dataMax, 0, { absoluteDiff: MAX_DECIMAL_DIFF });
25368
+ if (!(data == null ? void 0 : data.length) || isCloseToZeroWithTolerance) {
25369
+ return defaultRange;
25370
+ }
25371
+ if (isCloseTo(dataMin, dataMax, { absoluteDiff: MAX_DECIMAL_DIFF })) {
25372
+ const point = dataMax;
25373
+ const padding2 = point * whiteSpacePercentage;
25374
+ const minAxisValue2 = beginAtZero && !isNegative ? 0 : point - padding2;
25375
+ const maxAxisValue2 = beginAtZero && isNegative ? 0 : point + padding2;
25376
+ const roundedMinAxisValue = round$2(maxAxisValue2, DECIMAL_POINT_TOLERANCE);
25377
+ const roundedMaxAxisValue = round$2(minAxisValue2, DECIMAL_POINT_TOLERANCE);
25378
+ return {
25379
+ min: roundedMinAxisValue < 0 ? roundedMinAxisValue : roundedMaxAxisValue,
25380
+ max: roundedMaxAxisValue < 0 ? roundedMaxAxisValue : roundedMinAxisValue
25381
+ };
25382
+ }
25383
+ if (!autoAxisPadding) {
25384
+ return {
25385
+ min: void 0,
25386
+ max: void 0
25387
+ };
25388
+ }
25389
+ const rangeBeginAtZero = dataMin === 0 || dataMax === 0 || beginAtZero;
25390
+ const positiveAndNegative = Math.sign(dataMin) === -1 && Math.sign(dataMax) === 1;
25391
+ const range = Math.abs(dataMax - dataMin);
25392
+ const padding = autoAxisPadding ? range * whiteSpacePercentage : 0;
25393
+ const minAxisValue = !positiveAndNegative && rangeBeginAtZero && beginAtZero && !isNegative ? 0 : dataMin - padding;
25394
+ const maxAxisValue = !positiveAndNegative && rangeBeginAtZero && beginAtZero && isNegative ? 0 : dataMax + padding;
25395
+ return {
25396
+ min: round$2(minAxisValue, DECIMAL_POINT_TOLERANCE),
25397
+ max: round$2(maxAxisValue, DECIMAL_POINT_TOLERANCE)
25398
+ };
25399
+ };
25400
+ const getAxesDataFromMetasets = (chartRef, scalesKeys, annotationsData) => {
25401
+ var _a2;
25402
+ if (!chartRef || !scalesKeys) return {};
25403
+ const metasets = ((_a2 = chartRef == null ? void 0 : chartRef.current) == null ? void 0 : _a2.getSortedVisibleDatasetMetas()) ?? [];
25404
+ const annotData = getAnnotationsData(annotationsData);
25405
+ return metasets && (scalesKeys == null ? void 0 : scalesKeys.reduce((acc, key) => {
25406
+ const data = metasets.filter((dataset) => Object.values(dataset).includes(key)).flatMap((dataset) => dataset._parsed).map((parsedData) => parsedData[getAxisTypeFromKey(key)]).concat((annotData == null ? void 0 : annotData[key]) ?? []);
25407
+ return {
25408
+ ...acc,
25409
+ [key]: [...new Set(data)]
25410
+ };
25411
+ }, {}));
25412
+ };
25413
+ const shouldCalculate = (min, max) => !isNil(min) || !isNil(max);
25414
+ const autoScale = (options, state, generatedDatasets, chartRef) => {
25415
+ const {
25416
+ additionalAxesOptions,
25417
+ annotations: { annotationsData = [], controlAnnotation = false } = {}
25418
+ } = options || {};
25276
25419
  const scales = getLineChartScales(options, state) || {};
25277
- return scales;
25420
+ const datasets = controlAnnotation ? generatedDatasets.filter(({ isAnnotation }) => !isAnnotation) : generatedDatasets;
25421
+ if (!(additionalAxesOptions == null ? void 0 : additionalAxesOptions.autoAxisPadding) && !estimateDataSeriesHaveCloseValues(datasets)) {
25422
+ return scales;
25423
+ }
25424
+ const scalesKeys = Object.keys(scales) ?? [];
25425
+ const data = getAxesDataFromMetasets(
25426
+ chartRef,
25427
+ scalesKeys,
25428
+ annotationsData
25429
+ );
25430
+ const adjustedScales = data && (scalesKeys == null ? void 0 : scalesKeys.reduce((acc, key) => {
25431
+ const scale = scales[key];
25432
+ const { min: propMin = void 0, max: propMax = void 0 } = scale;
25433
+ const { min: calcMin, max: calcMax } = getAxisRangeByType(chartRef, key, annotationsData) ?? {};
25434
+ const { min: suggestedMin, max: suggestedMax } = getSuggestedAxisRange({
25435
+ data: data[key],
25436
+ beginAtZero: additionalAxesOptions == null ? void 0 : additionalAxesOptions.beginAtZero,
25437
+ autoAxisPadding: additionalAxesOptions == null ? void 0 : additionalAxesOptions.autoAxisPadding
25438
+ });
25439
+ const res = {
25440
+ [key]: {
25441
+ ...scale,
25442
+ min: propMin ?? (shouldCalculate(propMin, propMax) ? calcMin : suggestedMin),
25443
+ max: propMax ?? (shouldCalculate(propMin, propMax) ? calcMax : suggestedMax)
25444
+ }
25445
+ };
25446
+ return { ...acc, ...res };
25447
+ }, {}));
25448
+ return adjustedScales ?? scales;
25278
25449
  };
25279
25450
  const getCondition = (x2, y2, left2, right2, bottom2) => {
25280
25451
  const threshold = 100;
@@ -25824,7 +25995,7 @@ const useChartOptions = ({
25824
25995
  const datalabels = getLineChartDataLabels(options);
25825
25996
  const tooltip = getLineChartToolTips(options);
25826
25997
  const scales = useMemo(
25827
- () => autoScale(options, state),
25998
+ () => autoScale(options, state, generatedDatasets, chartRef),
25828
25999
  [options, state, generatedDatasets, chartRef]
25829
26000
  );
25830
26001
  const dragData = useMemo(
@@ -25944,29 +26115,6 @@ const useChartPlugins = ({ options, resetZoom: resetZoom2 }) => {
25944
26115
  ];
25945
26116
  }, [handleDoubleClick]);
25946
26117
  };
25947
- const getAnnotationsData = (data) => {
25948
- return data == null ? void 0 : data.reduce((acc, obj) => {
25949
- return {
25950
- ...acc,
25951
- [obj.annotationAxis]: [...acc[obj.annotationAxis] || [], +obj.value]
25952
- };
25953
- }, {});
25954
- };
25955
- const getAxisRangeByType = (chartRef, axesType, annotationsData) => {
25956
- if (!chartRef || !chartRef.current) return null;
25957
- const metasets = chartRef.current.getSortedVisibleDatasetMetas();
25958
- const annotDataByType = getAnnotationsData(annotationsData)[axesType] ?? [];
25959
- let allData = [];
25960
- metasets.forEach((metaset) => {
25961
- const data = metaset._parsed.map((parsedData) => parsedData[axesType]).filter((value) => value != null && !isNaN(value));
25962
- allData = allData.concat(data);
25963
- });
25964
- allData = allData.concat(annotDataByType);
25965
- if (allData.length === 0) return null;
25966
- const min = Math.min(...allData);
25967
- const max = Math.max(...allData);
25968
- return { min, max };
25969
- };
25970
26118
  const useToggleCustomLegendVisibility = (memoState, memoOptions) => {
25971
26119
  var _a2, _b2;
25972
26120
  useEffect(() => {
@@ -27164,7 +27312,18 @@ const LineChart = (props) => {
27164
27312
  initialState
27165
27313
  );
27166
27314
  const generatedDatasets = useMemo(() => {
27167
- return generateLineChartDatasets(datasets, state, options, translations);
27315
+ const startTimeStamp = performance.now();
27316
+ const result = generateLineChartDatasets(
27317
+ datasets,
27318
+ state,
27319
+ options,
27320
+ translations
27321
+ );
27322
+ const endTimeStamp = performance.now();
27323
+ console.log(
27324
+ `generateLineChartDatasets execution time: ${(endTimeStamp - startTimeStamp).toFixed(5)} ms`
27325
+ );
27326
+ return result;
27168
27327
  }, [state.lineEnabled, state.pointsEnabled, axes, annotations, graph]);
27169
27328
  useChartState({
27170
27329
  chartRef,