|
| 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' |