|
| 1 | +importPropTypesfrom'prop-types' |
1 | 2 | importReact,{
|
| 3 | +forwardRef, |
2 | 4 | HTMLAttributes,
|
3 | 5 | useEffect,
|
4 |
| -useState, |
5 |
| -useRef, |
6 | 6 | useImperativeHandle,
|
7 | 7 | useMemo,
|
8 |
| -forwardRef, |
| 8 | +useState, |
| 9 | +useRef, |
9 | 10 | }from'react'
|
10 | 11 |
|
11 | 12 | importChartfrom'chart.js/auto'
|
12 |
| -import*aschartjsfrom'chart.js'; |
| 13 | +import*aschartjsfrom'chart.js' |
13 | 14 | import{customTooltipsascuiCustomTooltips}from'@coreui/chartjs'
|
14 | 15 |
|
15 | 16 | importmergefrom'lodash/merge'
|
16 | 17 | importassignfrom'lodash/assign'
|
17 | 18 | importfindfrom'lodash/find'
|
18 | 19 |
|
19 | 20 | exportinterfaceCChartPropsextendsHTMLAttributes<HTMLCanvasElement|HTMLDivElement>{
|
20 |
| -id?:string |
| 21 | +/** |
| 22 | + * A string of all className you want applied to the base component. |
| 23 | + */ |
21 | 24 | className?:string
|
22 |
| -defaults?:any |
23 |
| -height?:number |
24 |
| -width?:number |
25 |
| -redraw?:boolean |
26 |
| -type:Chart.ChartType |
| 25 | +/** |
| 26 | + * Enables custom html based tooltips instead of standard tooltips. |
| 27 | + * |
| 28 | + *@default true |
| 29 | + */ |
| 30 | +customTooltips?:boolean |
| 31 | +/** |
| 32 | + * The data object that is passed into the Chart.js chart (more info). |
| 33 | + */ |
27 | 34 | data:Chart.ChartData|((canvas:HTMLCanvasElement)=>Chart.ChartData)
|
28 |
| -options?:Chart.ChartOptions |
| 35 | +/** |
| 36 | + * A fallback for when the canvas cannot be rendered. Can be used for accessible chart descriptions. |
| 37 | + * |
| 38 | + * {@link https://www.chartjs.org/docs/latest/general/accessibility.html More Info} |
| 39 | + */ |
29 | 40 | fallbackContent?:React.ReactNode
|
30 |
| -plugins?:Chart.PluginServiceRegistrationOptions[] |
| 41 | +/** |
| 42 | + * Proxy for Chart.js getDatasetAtEvent. Calls with dataset and triggering event. |
| 43 | + */ |
31 | 44 | getDatasetAtEvent?:(dataset:Array<{}>,event:React.MouseEvent<HTMLCanvasElement>)=>void
|
| 45 | +/** |
| 46 | + * Proxy for Chart.js getElementAtEvent. Calls with single element array and triggering event. |
| 47 | + */ |
32 | 48 | getElementAtEvent?:(element:[{}],event:React.MouseEvent<HTMLCanvasElement>)=>void
|
| 49 | +/** |
| 50 | + * Proxy for Chart.js getElementsAtEvent. Calls with element array and triggering event. |
| 51 | + */ |
33 | 52 | getElementsAtEvent?:(elements:Array<{}>,event:React.MouseEvent<HTMLCanvasElement>)=>void
|
| 53 | +/** |
| 54 | + * Height attribute applied to the rendered canvas. |
| 55 | + * |
| 56 | + *@default 150 |
| 57 | + */ |
| 58 | +height?:number |
| 59 | +/** |
| 60 | + * ID attribute applied to the rendered canvas. |
| 61 | + */ |
| 62 | +id?:string |
| 63 | +/** |
| 64 | + * The options object that is passed into the Chart.js chart. |
| 65 | + * |
| 66 | + * {@link https://www.chartjs.org/docs/latest/general/options.html More Info} |
| 67 | + */ |
| 68 | +options?:Chart.ChartOptions |
| 69 | +/** |
| 70 | + * The plugins array that is passed into the Chart.js chart (more info) |
| 71 | + * |
| 72 | + * {@link https://www.chartjs.org/docs/latest/developers/plugins.html More Info} |
| 73 | + */ |
| 74 | +plugins?:Chart.PluginServiceRegistrationOptions[] |
| 75 | +/** |
| 76 | + * If true, will tear down and redraw chart on all updates. |
| 77 | + * |
| 78 | + *@default false |
| 79 | + */ |
| 80 | +redraw?:boolean |
| 81 | +/** |
| 82 | + * Chart.js chart type. |
| 83 | + * |
| 84 | + *@type {'line' | 'bar' | 'horizontalBar' | 'radar' | 'doughnut' | 'polarArea' | 'bubble' | 'pie' | 'scatter'} |
| 85 | + */ |
| 86 | +type:Chart.ChartType |
| 87 | +/** |
| 88 | + * Width attribute applied to the rendered canvas. |
| 89 | + * |
| 90 | + *@default 300 |
| 91 | + */ |
| 92 | +width?:number |
| 93 | +/** |
| 94 | + * Put the chart into the wrapper div element. |
| 95 | + * |
| 96 | + *@default true |
| 97 | + */ |
| 98 | +wrapper?:boolean |
34 | 99 | }
|
35 | 100 |
|
36 | 101 | exportconstCChart=forwardRef<Chart|undefined,CChartProps>((props,ref)=>{
|
37 | 102 | const{
|
38 |
| - id, |
39 | 103 | className,
|
40 |
| - height=150, |
41 |
| - width=300, |
42 |
| - redraw=false, |
43 |
| - type, |
| 104 | + customTooltips=true, |
44 | 105 | data,
|
45 |
| -options, |
46 |
| -plugins=[], |
| 106 | +id, |
| 107 | +fallbackContent, |
47 | 108 | getDatasetAtEvent,
|
48 | 109 | getElementAtEvent,
|
49 | 110 | getElementsAtEvent,
|
50 |
| - fallbackContent, |
| 111 | + height=150, |
| 112 | + options, |
| 113 | + plugins=[], |
| 114 | + redraw=false, |
| 115 | + type, |
| 116 | + width=300, |
| 117 | + wrapper=true, |
51 | 118 | ...rest
|
52 | 119 | }=props
|
53 | 120 |
|
54 |
| -constcanvas=useRef<HTMLCanvasElement>(null) |
| 121 | +constcanvasRef=useRef<HTMLCanvasElement>(null) |
55 | 122 |
|
56 | 123 | constcomputedData=useMemo<Chart.ChartData>(()=>{
|
57 | 124 | if(typeofdata==='function'){
|
58 |
| -returncanvas.current ?data(canvas.current) :{} |
| 125 | +returncanvasRef.current ?data(canvasRef.current) :{} |
59 | 126 | }elsereturnmerge({},data)
|
60 |
| -},[data,canvas.current]) |
| 127 | +},[data,canvasRef.current]) |
61 | 128 |
|
62 | 129 | const[chart,setChart]=useState<Chart>()
|
63 | 130 |
|
64 | 131 | useImperativeHandle<Chart|undefined,Chart|undefined>(ref,()=>chart,[chart])
|
65 | 132 |
|
66 | 133 | constrenderChart=()=>{
|
67 |
| -if(!canvas.current)return |
| 134 | +if(!canvasRef.current)return |
| 135 | + |
| 136 | +if(customTooltips){ |
| 137 | +chartjs.defaults.plugins.tooltip.enabled=false |
| 138 | +chartjs.defaults.plugins.tooltip.mode='index' |
| 139 | +chartjs.defaults.plugins.tooltip.position='nearest' |
| 140 | +chartjs.defaults.plugins.tooltip.external=cuiCustomTooltips |
| 141 | +} |
68 | 142 |
|
69 |
| -chartjs.defaults.plugins.tooltip.enabled=false |
70 |
| -chartjs.defaults.plugins.tooltip.mode='index' |
71 |
| -chartjs.defaults.plugins.tooltip.position='nearest' |
72 |
| -chartjs.defaults.plugins.tooltip.external=cuiCustomTooltips |
73 |
| - |
74 | 143 | setChart(
|
75 |
| -newChart(canvas.current,{ |
| 144 | +newChart(canvasRef.current,{ |
76 | 145 | type,
|
77 | 146 | data:computedData,
|
78 | 147 | options,
|
@@ -167,19 +236,73 @@ export const CChart = forwardRef<Chart | undefined, CChartProps>((props, ref) =>
|
167 | 236 | }
|
168 | 237 | },[props,computedData])
|
169 | 238 |
|
170 |
| -return( |
171 |
| -<divclassName={`chart-wrapper${className}`}{...rest}> |
| 239 | +constcanvas=(ref:React.Ref<HTMLCanvasElement>)=>{ |
| 240 | +return( |
172 | 241 | <canvas
|
173 | 242 | height={height}
|
174 | 243 | width={width}
|
175 |
| -ref={canvas} |
| 244 | +ref={ref} |
176 | 245 | id={id}
|
177 | 246 | onClick={onClick}
|
178 | 247 | data-testid="canvas"
|
179 | 248 | role="img"
|
180 | 249 | >
|
181 | 250 | {fallbackContent}
|
182 | 251 | </canvas>
|
| 252 | +) |
| 253 | +} |
| 254 | + |
| 255 | +returnwrapper ?( |
| 256 | +<divclassName={`chart-wrapper${className}`}{...rest}> |
| 257 | +{canvas(canvasRef)} |
183 | 258 | </div>
|
| 259 | +) :( |
| 260 | +canvas(canvasRef) |
184 | 261 | )
|
| 262 | + |
| 263 | +// return ( |
| 264 | +// <div className={`chart-wrapper ${className}`} {...rest}> |
| 265 | +// <canvas |
| 266 | +// height={height} |
| 267 | +// width={width} |
| 268 | +// ref={canvasRef} |
| 269 | +// id={id} |
| 270 | +// onClick={onClick} |
| 271 | +// data-testid="canvas" |
| 272 | +// role="img" |
| 273 | +// > |
| 274 | +// {fallbackContent} |
| 275 | +// </canvas> |
| 276 | +// </div> |
| 277 | +// ) |
185 | 278 | })
|
| 279 | + |
| 280 | +CChart.propTypes={ |
| 281 | +className:PropTypes.string, |
| 282 | +customTooltips:PropTypes.bool, |
| 283 | +data:PropTypes.oneOfType([PropTypes.object,PropTypes.func]),// TODO: check |
| 284 | +fallbackContent:PropTypes.node, |
| 285 | +getDatasetAtEvent:PropTypes.func,// TODO: check |
| 286 | +getElementAtEvent:PropTypes.func,// TODO: check |
| 287 | +getElementsAtEvent:PropTypes.func,// TODO: check |
| 288 | +height:PropTypes.number, |
| 289 | +id:PropTypes.string, |
| 290 | +options:PropTypes.object,// TODO: check |
| 291 | +plugins:PropTypes.array,// TODO: check |
| 292 | +redraw:PropTypes.bool, |
| 293 | +type:PropTypes.oneOf([ |
| 294 | +'line', |
| 295 | +'bar', |
| 296 | +'horizontalBar', |
| 297 | +'radar', |
| 298 | +'doughnut', |
| 299 | +'polarArea', |
| 300 | +'bubble', |
| 301 | +'pie', |
| 302 | +'scatter', |
| 303 | +]), |
| 304 | +width:PropTypes.number, |
| 305 | +wrapper:PropTypes.bool |
| 306 | +} |
| 307 | + |
| 308 | +CChart.displayName='CChart' |