Repository navigation
Expand file tree
/
Copy pathChart.tsx
More file actions
144 lines (134 loc) · 6.13 KB
/
Copy pathChart.tsx
File metadata and controls
144 lines (134 loc) · 6.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import { forwardRef, useEffect, useRef, useState, useImperativeHandle, Ref } from 'react';
import { ChartProvider } from './layout/ChartProvider';
import { ChartComponentProps } from './base/interfaces';
import { stringToNumber } from './utils/helper';
import { defaultChartConfigs } from './base/default-properties';
import { preRender, useProviderContext } from '@syncfusion/react-base';
import { ElementWithSize, ChartSizeProps } from './chart-area/chart-interfaces';
import { ExportSourceContext } from '../common/interfaces';
import type { ExportSource } from '../common/interfaces';
/**
* Extends the base chart component properties with optional lifecycle methods.
*
*/
export interface IChart extends ChartComponentProps {
/**
* Specifies the root DOM element of the chart.
*
* @private
*/
element?: HTMLElement | null;
/**
* Returns the latest processed data used for spreadsheet export.
*
* @returns {ExportSource | undefined} Export data, or `undefined`
* before the initial chart layout is complete.
*
* @private
*/
getExportSource?: () => ExportSource | undefined;
}
/**
* **The React Chart component** enables developers to visualize data through a wide range of interactive and customizable chart types.
* It supports real-time updates, responsive layouts, and efficient rendering of large datasets for modern web applications.
*
* ```typescript
* import { Chart, ChartPrimaryXAxis, ChartSeries, ChartSeriesCollection } from '@syncfusion/react-charts';
*
* <Chart>
* <ChartPrimaryXAxis valueType='Category' />
* <ChartSeriesCollection>
* <ChartSeries dataSource={categoryData} xField="x" yField="y" type="Line" />
* </ChartSeriesCollection>
* </Chart>
* ```
*/
export const Chart: React.ForwardRefExoticComponent<ChartComponentProps & React.RefAttributes<IChart>> =
forwardRef<IChart, ChartComponentProps>((props: ChartComponentProps, ref: Ref<IChart>) => {
const chartRef: React.RefObject<HTMLDivElement | null> = useRef<HTMLDivElement>(null);
// Stores the latest processed data used for spreadsheet export.
const exportSourceRef: React.MutableRefObject<ExportSource | undefined> =
useRef<ExportSource | undefined>(undefined);
const { dir } = useProviderContext();
const [element, setElement] = useState<ElementWithSize | null>(null);
useEffect(() => {
const container: HTMLDivElement = chartRef.current as HTMLDivElement;
container.style.touchAction = 'element';
container.style.userSelect = 'none';
container.style.webkitUserSelect = 'none';
container.style.position = 'relative';
container.style.display = 'block';
// Apply width and height props to the container div
if (props.width && props.width.indexOf('%') > -1) {
container.style.width = props.width;
}
if (props.height && props.height.indexOf('%') > -1) {
container.style.height = props.height;
}
// If no explicit height prop provided, inherit from parent
if (!props.height) {
container.style.height = 'inherit';
}
const containerWidth: number = container?.clientWidth || container?.offsetWidth || 600;
const containerHeight: number = container?.clientHeight || 450;
container.id = sanitizeElementId(container.id);
const availableSize: ChartSizeProps = {
width: (props.width && props.width.indexOf('%') > -1) ? containerWidth : (stringToNumber(props.width, containerWidth) || containerWidth),
height: stringToNumber(props.height, containerHeight) || containerHeight
};
if (!container.classList.contains('sf-chart-focused')) {
container.classList.add('sf-chart-focused');
}
setElement({ element: container, availableSize });
}, [props.height, props.width, props.background]);
useImperativeHandle(ref, () => ({
element: chartRef.current,
theme: props.theme || 'Material',
getExportSource: (): ExportSource | undefined => exportSourceRef.current
}), [props.theme]);
useEffect(() => {
preRender('chart');
}, []);
const chartProps: ChartComponentProps = { ...defaultChartConfigs.chart, ...props };
chartProps.accessibility = { ...defaultChartConfigs.accessibility, ...props.accessibility };
return (
(
<ExportSourceContext.Provider value={exportSourceRef}>
<div ref={chartRef}
dir={dir}
id={props.id}
className="sf-control sf-chart sf-lib sf-touch"
aria-label={chartProps.accessibility?.ariaLabel || '. Syncfusion interactive chart.'}
role={chartProps.accessibility?.role || 'region'}
tabIndex={chartProps.accessibility?.focusable ? (chartProps.accessibility?.tabIndex) : -1}
style={{ outline: 'none' }}
>
{element && (
<ChartProvider props={chartProps} parentElement={element} />
)}
</div>
</ExportSourceContext.Provider>
)
);
});
export default Chart;
/**
* Sanitizes and returns a valid element ID for a chart.
*
* - If the `elementId` is an empty string, it generates a unique ID based on a static chart ID and
* the current number of `.sf-chart` elements in the DOM.
*
* @param {string} elementId - The input element ID to sanitize or use for generating a unique one.
* @returns {string} A valid and unique element ID string safe for use in the DOM.
* @private
*/
export function sanitizeElementId(elementId: string): string {
if (elementId === '') {
const uniqueSuffix: number = Math.floor(Math.random() * 1000000);
const childElementId: string = `chart_${uniqueSuffix}`;
return childElementId;
}
else {
return elementId;
}
}