UNPKG

32.3 kBJavaScriptView Raw
1import * as React from 'react';
2import React__default, { useState, useEffect } from 'react';
3
4/**
5 * Hook to load external script.
6 * @param src - Source url to load.
7 * @param onLoad - Success callback.
8 * @param onError - Error callback.
9 */ function useLoadScript(src) {
10 const [isLoading, setIsLoading] = useState(true);
11 const [error, setError] = useState(null);
12 const [isSuccess, setIsSuccess] = useState(false);
13 const onLoad = ()=>{
14 setIsLoading(false);
15 setIsSuccess(true);
16 };
17 useEffect(()=>{
18 if (!document) {
19 const error = new Error(`[ScriptLoadingError] document not defined when attempting to load ${src}`);
20 setError(error);
21 return;
22 }
23 // Find script tag with same src in DOM.
24 const foundScript = document.querySelector(`script[src="${src}"]`);
25 // Call onLoad if script marked as loaded.
26 if (foundScript?.dataset.loaded) {
27 onLoad();
28 return;
29 }
30 // Create or get existed tag.
31 const script = foundScript || document.createElement("script");
32 // Set src if no script was found.
33 if (!foundScript) {
34 script.src = src;
35 }
36 // Mark script as loaded on load event.
37 const onLoadWithMarker = ()=>{
38 script.dataset.loaded = "1";
39 onLoad();
40 };
41 script.addEventListener("load", onLoadWithMarker);
42 script.addEventListener("error", (err)=>{
43 console.error("Failed to load script:", src, err);
44 const error = new Error(`[ScriptLoadingError] Failed to load script: ${src}`);
45 setError(error);
46 });
47 // Add to DOM if not yet added.
48 if (!foundScript) {
49 document.head.append(script);
50 }
51 }, []);
52 return {
53 isLoading,
54 error,
55 isSuccess
56 };
57}
58
59const isGoogleReady = (google)=>{
60 return google && google.charts;
61};
62const isGoogleChartsReady = (props, google)=>{
63 const { controls, toolbarItems, getChartEditor } = props;
64 return google && google.charts && google.visualization && google.visualization.ChartWrapper && google.visualization.Dashboard && (!controls || google.visualization.ChartWrapper) && (!getChartEditor || google.visualization.ChartEditor) && (!toolbarItems || google.visualization.drawToolbar);
65};
66const getGoogleInstanceFromWindow = (props)=>{
67 // @ts-expect-error Getting object from global namespace.
68 const google = window.google;
69 return google;
70};
71/**
72 * Hook to load Google Charts JS API.
73 * @param params - Load parameters.
74 * @param [params.chartVersion] - Chart version to load.
75 * @param [params.chartPackages] - Packages to load.
76 * @param [params.chartLanguage] - Languages to load.
77 * @param [params.mapsApiKey] - Google Maps api key.
78 * @returns
79 */ function useLoadGoogleCharts(props) {
80 const { chartVersion = "current", chartPackages = [
81 "corechart",
82 "controls"
83 ], chartLanguage = "en", mapsApiKey } = props;
84 const [googleCharts, setGoogleCharts] = useState(null);
85 const [scriptInitializationError, setScriptInitializationError] = useState(null);
86 const [googleChartsInitializationError, setGoogleChartsInitializationError] = useState(null);
87 const { isLoading, error: scriptLoadingError, isSuccess } = useLoadScript(props.chartLoaderScriptUrl || "https://www.gstatic.com/charts/loader.js");
88 useEffect(()=>{
89 if (!isSuccess) {
90 return;
91 }
92 const google = getGoogleInstanceFromWindow();
93 if (!isGoogleReady(google)) {
94 const error = new Error("[ScriptInitializationError] Script loaded but Google not attached to window.");
95 setScriptInitializationError(error);
96 return;
97 }
98 if (isGoogleChartsReady(props, google)) {
99 setGoogleCharts(google);
100 return;
101 }
102 google.charts.load(chartVersion, {
103 packages: chartPackages,
104 language: chartLanguage,
105 mapsApiKey
106 });
107 google.charts.setOnLoadCallback(()=>{
108 if (!isGoogleChartsReady(props, google)) {
109 const error = new Error("[GoogleChartsInitializationError] Google Charts not ready after load callback.");
110 console.error(error);
111 setGoogleChartsInitializationError(error);
112 return;
113 }
114 setGoogleCharts(google);
115 });
116 }, [
117 isSuccess
118 ]);
119 return {
120 error: scriptLoadingError || scriptInitializationError || googleChartsInitializationError,
121 isLoading,
122 google: googleCharts
123 };
124}
125
126const chartDefaultProps = {
127 // <DEPRECATED_PROPS>
128 legend_toggle: false,
129 // </DEPRECATED_PROPS>
130 options: {},
131 legendToggle: false,
132 getChartWrapper: ()=>{},
133 spreadSheetQueryParameters: {
134 headers: 1,
135 gid: 1
136 },
137 rootProps: {},
138 chartWrapperParams: {},
139 chartLoaderScriptUrl: "https://www.gstatic.com/charts/loader.js"
140};
141
142const GoogleChartControls = (props)=>{
143 const { isReady, chartControls, filter } = props;
144 if (!isReady || !chartControls || !chartControls?.length) {
145 return null;
146 }
147 return /*#__PURE__*/ React__default.createElement(React__default.Fragment, null, chartControls.filter((param)=>{
148 let { controlProp, control } = param;
149 return filter ? filter({
150 control,
151 controlProp
152 }) : true;
153 }).map((param)=>{
154 let { control } = param;
155 return /*#__PURE__*/ React__default.createElement("div", {
156 key: control.getContainerId(),
157 id: control.getContainerId()
158 });
159 }));
160};
161
162let uniqueID = 0;
163const generateUniqueID = ()=>{
164 uniqueID += 1;
165 return `reactgooglegraph-${uniqueID}`;
166};
167
168/**
169 * An internal helper class for creating and managing Google Charts controls.
170 * Offers high-level methods to interact with the Google Chart Controls.
171 */ class GoogleChartControlsInternal {
172 /**
173 * Initialize the controls once chart is ready
174 */ static initializeControls = (googleChartControls)=>{
175 for(let i = 0; i < googleChartControls.length; i += 1){
176 const { controlType, options, controlWrapperParams } = googleChartControls[i].controlProp;
177 if (controlWrapperParams && "state" in controlWrapperParams) {
178 googleChartControls[i].control.setState(controlWrapperParams["state"]);
179 }
180 googleChartControls[i].control.setOptions(options);
181 googleChartControls[i].control.setControlType(controlType);
182 }
183 };
184 /**
185 * listen to the control events (ready, statechange, error) specified in the controlEvents prop
186 */ static listenToControlEvents = (googleChartControls, props)=>{
187 const { google } = props;
188 return googleChartControls.flatMap((chartControl)=>{
189 const { control, controlProp } = chartControl;
190 const { controlEvents = [] } = controlProp;
191 return controlEvents.map((event)=>{
192 const { callback, eventName } = event;
193 return google.visualization.events.addListener(control, eventName, function() {
194 for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
195 args[_key] = arguments[_key];
196 }
197 callback({
198 chartWrapper: null,
199 controlWrapper: control,
200 props: props,
201 google: google,
202 eventArgs: args
203 });
204 });
205 });
206 });
207 };
208 /**
209 * If controlID is not provided, generate a unique controlID
210 */ static createControlId = (id)=>{
211 let controlID;
212 if (typeof id === "undefined") {
213 controlID = `googlechart-control-${generateUniqueID()}`;
214 } else {
215 controlID = id;
216 }
217 return controlID;
218 };
219 /**
220 * Map the control props to Google Chart Controls
221 */ static createChartControls = (props)=>{
222 const { controls, google } = props;
223 if (!controls) {
224 return null;
225 }
226 return controls.map((control, i)=>{
227 const { controlID: controlIDMaybe, controlType, options: controlOptions, controlWrapperParams } = control;
228 const controlID = this.createControlId(controlIDMaybe);
229 return {
230 controlProp: control,
231 control: new google.visualization.ControlWrapper({
232 containerId: controlID,
233 controlType,
234 options: controlOptions,
235 ...controlWrapperParams
236 })
237 };
238 });
239 };
240 static addControls = (props)=>{
241 const { chartWrapper, chartDashboard } = props;
242 const googleChartControls = this.createChartControls(props);
243 if (!googleChartControls || !chartDashboard || !chartWrapper) {
244 return null;
245 }
246 chartDashboard.bind(googleChartControls.map((param)=>{
247 let { control } = param;
248 return control;
249 }), chartWrapper);
250 this.initializeControls(googleChartControls);
251 return googleChartControls;
252 };
253}
254
255const useCreateChartControls = (controls)=>{
256 const [chartControls, setChartControls] = React.useState(null);
257 const controlAndProp = React.useMemo(()=>{
258 if (!chartControls || !controls) return null;
259 return controls.map((controlProp, i)=>{
260 const control = chartControls[i];
261 return control ? {
262 controlProp,
263 control
264 } : undefined;
265 }).flatMap((controlAndProp)=>controlAndProp ? [
266 controlAndProp
267 ] : []);
268 }, [
269 chartControls,
270 controls
271 ]);
272 return [
273 controlAndProp,
274 setChartControls
275 ];
276};
277const useListenToControlEvents = (chartControls, props)=>{
278 React.useEffect(()=>{
279 const listeners = GoogleChartControlsInternal.listenToControlEvents(chartControls ?? [], props);
280 return ()=>{
281 listeners.forEach((listener)=>{
282 props.google.visualization.events.removeListener(listener);
283 });
284 };
285 }, [
286 chartControls,
287 props
288 ]);
289};
290const useChartControls = (props)=>{
291 const [chartControls, setChartControls] = useCreateChartControls(props.controls);
292 useListenToControlEvents(chartControls ?? [], props);
293 /**
294 * Render the container divs for the controls
295 */ const renderControl = (filter)=>{
296 const { chartWrapper, chartDashboard } = props;
297 return /*#__PURE__*/ React.createElement(GoogleChartControls, {
298 ...props,
299 isReady: Boolean(chartWrapper && chartDashboard),
300 chartControls: chartControls,
301 filter: filter
302 });
303 };
304 return {
305 addControls: (props)=>{
306 const controls = GoogleChartControlsInternal.addControls(props);
307 setChartControls(controls?.map((control)=>control.control) ?? null);
308 },
309 renderControl
310 };
311};
312
313const useChartId = (props)=>{
314 const chartIdRef = React.useRef(null);
315 const getChartId = ()=>{
316 const { graphID, graph_id } = props;
317 const chartIdFromProps = graphID || graph_id;
318 let currentChartId;
319 if (chartIdFromProps) {
320 currentChartId = chartIdFromProps;
321 } else {
322 currentChartId = chartIdRef.current || generateUniqueID();
323 }
324 chartIdRef.current = currentChartId;
325 return chartIdRef.current;
326 };
327 const chartId = getChartId();
328 return {
329 chartId
330 };
331};
332
333const DEFAULT_CHART_COLORS = [
334 "#3366CC",
335 "#DC3912",
336 "#FF9900",
337 "#109618",
338 "#990099",
339 "#3B3EAC",
340 "#0099C6",
341 "#DD4477",
342 "#66AA00",
343 "#B82E2E",
344 "#316395",
345 "#994499",
346 "#22AA99",
347 "#AAAA11",
348 "#6633CC",
349 "#E67300",
350 "#8B0707",
351 "#329262",
352 "#5574A6",
353 "#3B3EAC"
354];
355
356const loadDataTableFromSpreadSheet = async function(googleViz, spreadSheetUrl) {
357 let urlParams = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {};
358 return new Promise((resolve, reject)=>{
359 const headers = `${urlParams.headers ? `headers=${urlParams.headers}` : `headers=0`}`;
360 const queryString = `${urlParams.query ? `&tq=${encodeURIComponent(urlParams.query)}` : ``}`;
361 const gid = `${urlParams.gid ? `&gid=${urlParams.gid}` : ""}`;
362 const sheet = `${urlParams.sheet ? `&sheet=${urlParams.sheet}` : ""}`;
363 const access_token = `${urlParams.access_token ? `&access_token=${urlParams.access_token}` : ""}`;
364 const urlQueryString = `${headers}${gid}${sheet}${queryString}${access_token}`;
365 const urlToSpreadSheet = `${spreadSheetUrl}/gviz/tq?${urlQueryString}`; //&tq=${queryString}`;
366 const query = new googleViz.visualization.Query(urlToSpreadSheet);
367 query.send((response)=>{
368 if (response.isError()) {
369 reject(`Error in query: ${response.getMessage()} ${response.getDetailedMessage()}`);
370 } else {
371 resolve(response.getDataTable());
372 }
373 });
374 });
375};
376
377const GRAY_COLOR = "#CCCCCC";
378/**
379 * An internal helper class around the Google Chart API.
380 * Offers high-level methods to interact with the Google Chart API.
381 */ class GoogleChartInternal {
382 static grayOutHiddenColumnsLabel = (props, hiddenColumns)=>{
383 const { googleChartWrapper, options } = props;
384 if (!googleChartWrapper) {
385 console.error("googleChartWrapper is not defined");
386 return;
387 }
388 const dataTable = googleChartWrapper.getDataTable();
389 if (!dataTable) return;
390 const columnCount = dataTable.getNumberOfColumns();
391 const hasAHiddenColumn = hiddenColumns.length > 0;
392 if (hasAHiddenColumn === false) return;
393 const colors = Array.from({
394 length: columnCount - 1
395 }).map((_dontcare, i)=>{
396 const columnID = this.getColumnId(dataTable, i + 1);
397 if (hiddenColumns.includes(columnID)) {
398 return GRAY_COLOR;
399 } else if (options && options.colors) {
400 return options.colors[i];
401 } else {
402 return DEFAULT_CHART_COLORS[i];
403 }
404 });
405 googleChartWrapper.setOptions({
406 ...options,
407 colors
408 });
409 googleChartWrapper.draw();
410 };
411 /**
412 * Listens to user clicking on the legend to toggle the visibility of a column.
413 * When a user clicks on a legend item, the column id is added to / removed from the hiddenColumns state.
414 */ static listenToLegendToggle = (props, hiddenColumnsState)=>{
415 const [hiddenColumns, setHiddenColumns] = hiddenColumnsState;
416 const { google, googleChartWrapper } = props;
417 if (!googleChartWrapper) {
418 console.error("googleChartWrapper is not defined");
419 return;
420 }
421 return google.visualization.events.addListener(googleChartWrapper, "select", ()=>{
422 const chart = googleChartWrapper.getChart();
423 const selection = chart.getSelection();
424 const dataTable = googleChartWrapper.getDataTable();
425 if (selection.length === 0 || // We want to listen to when a whole row is selected. This is the case only when row === null
426 selection[0].row !== null || !dataTable) {
427 return;
428 }
429 const columnIndex = selection[0].column;
430 const columnID = this.getColumnId(dataTable, columnIndex);
431 // If the column is hidden remove it from state, otherwise add it
432 if (hiddenColumns?.includes(columnID)) {
433 setHiddenColumns((state)=>[
434 ...state.filter((colID)=>colID !== columnID)
435 ]);
436 } else {
437 setHiddenColumns((state)=>[
438 ...state,
439 columnID
440 ]);
441 }
442 });
443 };
444 /**
445 * (Re-)Draw a Google Chart with the given data, options, and chart type.
446 */ static draw = async (props)=>{
447 const { data, diffdata, rows, columns, options, chartType, formatters, spreadSheetUrl, spreadSheetQueryParameters, googleChartDashboard, googleChartWrapper, google, hiddenColumns, legendToggle, legend_toggle } = props;
448 if (!googleChartWrapper) {
449 console.error("draw was called with googleChartWrapper = null");
450 return;
451 }
452 let dataTable;
453 let chartDiff = null;
454 if (diffdata) {
455 const oldData = google.visualization.arrayToDataTable(diffdata.old);
456 const newData = google.visualization.arrayToDataTable(diffdata.new);
457 chartDiff = google.visualization[chartType].prototype.computeDiff(oldData, newData);
458 }
459 if (data) {
460 if (data instanceof google.visualization.DataTable) {
461 dataTable = data;
462 } else if (Array.isArray(data)) {
463 dataTable = google.visualization.arrayToDataTable(data);
464 } else {
465 dataTable = new google.visualization.DataTable(data);
466 }
467 } else if (rows && columns) {
468 dataTable = google.visualization.arrayToDataTable([
469 columns,
470 ...rows
471 ]);
472 } else if (spreadSheetUrl) {
473 dataTable = await loadDataTableFromSpreadSheet(google, spreadSheetUrl, spreadSheetQueryParameters);
474 } else {
475 dataTable = google.visualization.arrayToDataTable([]);
476 }
477 const columnCount = dataTable.getNumberOfColumns();
478 const viewColumns = Array(columnCount).fill(0).map((_c, i)=>{
479 const columnID = this.getColumnId(dataTable, i);
480 if (hiddenColumns.includes(columnID)) {
481 return {
482 label: dataTable.getColumnLabel(i),
483 type: dataTable.getColumnType(i),
484 calc: ()=>null
485 };
486 } else {
487 return i;
488 }
489 });
490 const chart = googleChartWrapper.getChart();
491 if (googleChartWrapper.getChartType() === "Timeline") {
492 chart && chart.clearChart();
493 }
494 googleChartWrapper.setChartType(chartType);
495 googleChartWrapper.setOptions(options || {});
496 const viewTable = new google.visualization.DataView(dataTable);
497 viewTable.setColumns(viewColumns);
498 googleChartWrapper.setDataTable(viewTable);
499 googleChartWrapper.draw();
500 if (googleChartDashboard) {
501 googleChartDashboard.draw(dataTable);
502 }
503 if (chartDiff) {
504 googleChartWrapper.setDataTable(chartDiff);
505 googleChartWrapper.draw();
506 }
507 if (formatters) {
508 this.applyFormatters({
509 dataTable,
510 formatters,
511 google
512 });
513 googleChartWrapper.setDataTable(dataTable);
514 googleChartWrapper.draw();
515 }
516 if (legendToggle === true || legend_toggle === true) {
517 this.grayOutHiddenColumnsLabel(props, hiddenColumns);
518 }
519 return;
520 };
521 /**
522 * Get the column ID of a column in a GoogleDataTable.
523 * If the column has an ID, return the ID, otherwise return the label.
524 */ static getColumnId = (dataTable, columnIndex)=>{
525 return dataTable.getColumnId(columnIndex) || dataTable.getColumnLabel(columnIndex);
526 };
527 /**
528 * Apply Chart Formatters passed under the formatters prop to the GoogleDataTable
529 */ static applyFormatters = (param)=>{
530 let { dataTable, formatters, google } = param;
531 for (let formatter of formatters){
532 switch(formatter.type){
533 case "ArrowFormat":
534 {
535 const vizFormatter = new google.visualization.ArrowFormat(formatter.options);
536 vizFormatter.format(dataTable, formatter.column);
537 return;
538 }
539 case "BarFormat":
540 {
541 const vizFormatter = new google.visualization.BarFormat(formatter.options);
542 vizFormatter.format(dataTable, formatter.column);
543 return;
544 }
545 case "ColorFormat":
546 {
547 const vizFormatter = new google.visualization.ColorFormat(formatter.options);
548 const { ranges } = formatter;
549 if (ranges) {
550 for (let range of ranges){
551 vizFormatter.addRange(...range);
552 }
553 }
554 vizFormatter.format(dataTable, formatter.column);
555 return;
556 }
557 case "DateFormat":
558 {
559 const vizFormatter = new google.visualization.DateFormat(formatter.options);
560 vizFormatter.format(dataTable, formatter.column);
561 return;
562 }
563 case "NumberFormat":
564 {
565 const vizFormatter = new google.visualization.NumberFormat(formatter.options);
566 vizFormatter.format(dataTable, formatter.column);
567 return;
568 }
569 case "PatternFormat":
570 {
571 const vizFormatter = new google.visualization.PatternFormat(formatter.options);
572 vizFormatter.format(dataTable, formatter.column);
573 return;
574 }
575 default:
576 {
577 console.warn(`Unknown formatter type: ${formatter.type}`);
578 return;
579 }
580 }
581 }
582 };
583}
584
585const useGoogleChartDataTable = (props)=>{
586 const { google, googleChartWrapper, googleChartDashboard } = props;
587 const [hiddenColumns, setHiddenColumns] = React.useState([]);
588 // Re-draw the chart when hiddenColumns change
589 React.useEffect(()=>{
590 if (!googleChartWrapper) {
591 return;
592 }
593 GoogleChartInternal.draw({
594 ...props,
595 hiddenColumns,
596 googleChartWrapper,
597 googleChartDashboard,
598 google
599 });
600 }, [
601 hiddenColumns,
602 props.data,
603 props.rows,
604 props.columns,
605 props.options,
606 props.chartLoaderScriptUrl,
607 props.chartType,
608 props.formatters,
609 props.spreadSheetUrl,
610 props.spreadSheetQueryParameters,
611 props.legendToggle,
612 props.legend_toggle
613 ]);
614 // Re-draw the chart when the window is resized
615 const onResize = ()=>{
616 const { googleChartWrapper } = props;
617 if (!googleChartWrapper) {
618 return;
619 }
620 googleChartWrapper.draw();
621 };
622 // Draw the chart when the google charts wrapper is ready and when the hiddenColumns change
623 const initialize = (googleChartWrapper)=>{
624 const listeners = [];
625 const { legendToggle, legend_toggle } = props;
626 GoogleChartInternal.draw({
627 ...props,
628 hiddenColumns,
629 googleChartWrapper,
630 googleChartDashboard,
631 google
632 });
633 window.addEventListener("resize", onResize);
634 if (legend_toggle || legendToggle) {
635 const listener = GoogleChartInternal.listenToLegendToggle(props, [
636 hiddenColumns,
637 setHiddenColumns
638 ]);
639 if (listener) listeners.push(listener);
640 }
641 return listeners;
642 };
643 // Remove event listeners and clear the chart when the component is unmounted
644 const destroy = (googleChartWrapper, listeners)=>{
645 window.removeEventListener("resize", onResize);
646 listeners.forEach((listener)=>{
647 google.visualization.events.removeListener(listener);
648 });
649 if (googleChartWrapper.getChartType() === "Timeline") {
650 googleChartWrapper.getChart() && googleChartWrapper.getChart().clearChart();
651 }
652 };
653 React.useEffect(()=>{
654 if (!googleChartWrapper) {
655 return;
656 }
657 const listeners = initialize(googleChartWrapper);
658 return ()=>{
659 destroy(googleChartWrapper, listeners);
660 };
661 }, [
662 googleChartWrapper,
663 initialize,
664 destroy
665 ]);
666};
667
668const listenToEvents = (props)=>{
669 const { chartEvents, google, googleChartWrapper } = props;
670 if (!chartEvents) {
671 return;
672 }
673 if (!googleChartWrapper) {
674 console.warn("listenToEvents was called before chart wrapper ready.");
675 return;
676 }
677 return chartEvents.map((param)=>{
678 let { eventName, callback } = param;
679 return google.visualization.events.addListener(googleChartWrapper, eventName, function() {
680 for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){
681 args[_key] = arguments[_key];
682 }
683 callback({
684 chartWrapper: googleChartWrapper,
685 props,
686 google: google,
687 eventArgs: args
688 });
689 });
690 });
691};
692const useGoogleChartEvents = (props)=>{
693 useEffect(()=>{
694 if (!props.googleChartWrapper) return;
695 const listeners = listenToEvents(props);
696 return ()=>{
697 listeners?.forEach((listener)=>{
698 props.google.visualization.events.removeListener(listener);
699 });
700 };
701 }, [
702 props
703 ]);
704};
705
706const GoogleChart = (props)=>{
707 const [googleChartWrapper, setGoogleChartWrapper] = React.useState(null);
708 // const [isReady, setIsReady] = React.useState<boolean>(false);
709 const [googleChartDashboard, setGoogleChartDashboard] = React.useState(null);
710 const { addControls, renderControl } = useChartControls({
711 ...props,
712 chartDashboard: googleChartDashboard,
713 chartWrapper: googleChartWrapper
714 });
715 useGoogleChartEvents({
716 ...props,
717 googleChartWrapper
718 });
719 const { chartId } = useChartId(props);
720 const dashboardRef = React.useRef(null);
721 const toolbarRef = React.useRef(null);
722 React.useEffect(()=>{
723 const { options, google, chartType, chartWrapperParams, toolbarItems, getChartEditor, getChartWrapper, onLoad } = props;
724 const chartConfig = {
725 chartType,
726 options,
727 containerId: chartId,
728 ...chartWrapperParams
729 };
730 // Create ChartWrapper instance, pass it to the user and store it in state
731 const chartWrapper = new google.visualization.ChartWrapper(chartConfig);
732 chartWrapper.setOptions(options || {});
733 getChartWrapper?.(chartWrapper, google);
734 // Create Dashboard instance, needed for controls
735 const chartDashboard = new google.visualization.Dashboard(dashboardRef.current);
736 // Create toolbar if needed
737 if (toolbarItems) {
738 google.visualization.drawToolbar(toolbarRef.current, toolbarItems);
739 }
740 // Create ChartEditor instance if needed and pass it to the user
741 let chartEditor = null;
742 if (getChartEditor) {
743 chartEditor = new google.visualization.ChartEditor();
744 getChartEditor({
745 chartEditor,
746 chartWrapper,
747 google
748 });
749 }
750 // Create and add controls to the chart / dashboard
751 addControls({
752 ...props,
753 chartDashboard,
754 chartWrapper
755 });
756 setGoogleChartWrapper(chartWrapper);
757 setGoogleChartDashboard(chartDashboard);
758 onLoad?.(google, {
759 google,
760 chartWrapper,
761 chartEditor,
762 chartDashboard
763 });
764 }, []);
765 useGoogleChartDataTable({
766 ...props,
767 googleChartWrapper,
768 googleChartDashboard
769 });
770 const renderChart = ()=>{
771 const { width, height, options, style, className, rootProps, google } = props;
772 const divStyle = {
773 height: height || options && options.height,
774 width: width || options && options.width,
775 ...style
776 };
777 return /*#__PURE__*/ React.createElement("div", {
778 id: chartId,
779 style: divStyle,
780 className: className,
781 ...rootProps
782 });
783 };
784 const renderToolBar = ()=>{
785 if (!props.toolbarItems) return null;
786 return /*#__PURE__*/ React.createElement("div", {
787 ref: toolbarRef
788 });
789 };
790 const { width, height, options, style } = props;
791 const divStyle = {
792 height: height || options && options.height,
793 width: width || options && options.width,
794 ...style
795 };
796 // If render prop is provided, give the user full control over the rendering by passing renderChart, renderControl and renderToolbar functions
797 if (props.render) {
798 return /*#__PURE__*/ React.createElement("div", {
799 ref: dashboardRef,
800 style: divStyle
801 }, /*#__PURE__*/ React.createElement("div", {
802 ref: toolbarRef,
803 id: "toolbar"
804 }), props.render({
805 renderChart,
806 renderControl,
807 renderToolbar: renderToolBar
808 }));
809 } else {
810 return /*#__PURE__*/ React.createElement("div", {
811 ref: dashboardRef,
812 style: divStyle
813 }, renderControl((param)=>{
814 let { controlProp } = param;
815 return controlProp.controlPosition !== "bottom";
816 }), renderChart(), renderControl((param)=>{
817 let { controlProp } = param;
818 return controlProp.controlPosition === "bottom";
819 }), renderToolBar());
820 }
821};
822
823const ChartContext = /*#__PURE__*/ React.createContext(chartDefaultProps);
824const ContextProvider = (param)=>{
825 let { children, value } = param;
826 return /*#__PURE__*/ React.createElement(ChartContext.Provider, {
827 value: value
828 }, children);
829};
830
831/**
832 * Loads Google Charts JS and renders the GoogleChart component.
833 */ const ChartView = (props)=>{
834 const { google, isLoading, error } = useLoadGoogleCharts(props);
835 if (isLoading) {
836 return props.loader ?? null;
837 }
838 if (error) {
839 return props.errorElement ?? null;
840 }
841 if (google) {
842 return /*#__PURE__*/ React__default.createElement(GoogleChart, {
843 google: google,
844 ...props
845 });
846 }
847 return null;
848};
849/**
850 * Updates the context with the props and renders ChartView.
851 */ const Chart = (userProps)=>{
852 const props = {
853 ...chartDefaultProps,
854 ...userProps
855 };
856 return /*#__PURE__*/ React__default.createElement(ContextProvider, {
857 value: props
858 }, /*#__PURE__*/ React__default.createElement(ChartView, props));
859};
860
861// Complete Google Charts Type Definition : https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/google.visualization/index.d.ts
862var GoogleDataTableColumnRoleType;
863(function(GoogleDataTableColumnRoleType) {
864 GoogleDataTableColumnRoleType["annotation"] = "annotation";
865 GoogleDataTableColumnRoleType["annotationText"] = "annotationText";
866 GoogleDataTableColumnRoleType["certainty"] = "certainty";
867 GoogleDataTableColumnRoleType["emphasis"] = "emphasis";
868 GoogleDataTableColumnRoleType["interval"] = "interval";
869 GoogleDataTableColumnRoleType["scope"] = "scope";
870 GoogleDataTableColumnRoleType["style"] = "style";
871 GoogleDataTableColumnRoleType["tooltip"] = "tooltip";
872 GoogleDataTableColumnRoleType["domain"] = "domain";
873})(GoogleDataTableColumnRoleType || (GoogleDataTableColumnRoleType = {}));
874
875export { Chart, GoogleDataTableColumnRoleType, Chart as default };
876//# sourceMappingURL=index.js.map