react-google-charts
Version:
react-google-charts React component
1 lines • 89.1 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/hooks/useLoadScript.ts","../src/hooks/useLoadGoogleCharts.ts","../src/default-props.ts","../src/components/GoogleChartControls.tsx","../src/generate-unique-id.ts","../src/utils/GoogleChartControlsInternal.ts","../src/hooks/internal/useGoogleChartControls.tsx","../src/hooks/internal/useChartId.ts","../src/constants.ts","../src/load-data-table-from-spreadsheet.ts","../src/utils/GoogleChartInternal.ts","../src/hooks/internal/useGoogleChartDataTable.ts","../src/hooks/internal/useGoogleChartEvents.ts","../src/components/GoogleChart.tsx","../src/Context.tsx","../src/Chart.tsx","../src/types.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\n/**\n * Hook to load external script.\n * @param src - Source url to load.\n * @param onLoad - Success callback.\n * @param onError - Error callback.\n */\nexport function useLoadScript(src: string) {\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [isSuccess, setIsSuccess] = useState(false);\n const onLoad = () => {\n setIsLoading(false);\n setIsSuccess(true);\n };\n useEffect(() => {\n if (!document) {\n const error = new Error(\n `[ScriptLoadingError] document not defined when attempting to load ${src}`,\n );\n setError(error);\n return;\n }\n\n // Find script tag with same src in DOM.\n const foundScript = document.querySelector<HTMLScriptElement>(\n `script[src=\"${src}\"]`,\n );\n\n // Call onLoad if script marked as loaded.\n if (foundScript?.dataset.loaded) {\n onLoad();\n return;\n }\n\n // Create or get existed tag.\n const script = foundScript || document.createElement(\"script\");\n\n // Set src if no script was found.\n if (!foundScript) {\n script.src = src;\n }\n\n // Mark script as loaded on load event.\n const onLoadWithMarker = () => {\n script.dataset.loaded = \"1\";\n onLoad();\n };\n\n script.addEventListener(\"load\", onLoadWithMarker);\n\n script.addEventListener(\"error\", (err) => {\n console.error(\"Failed to load script:\", src, err);\n const error = new Error(\n `[ScriptLoadingError] Failed to load script: ${src}`,\n );\n setError(error);\n });\n\n // Add to DOM if not yet added.\n if (!foundScript) {\n document.head.append(script);\n }\n }, []);\n return {\n isLoading,\n error,\n isSuccess,\n };\n}\n","import { useState, useEffect } from \"react\";\nimport {\n GoogleChartVersion,\n GoogleChartPackages,\n GoogleViz,\n ReactGoogleChartProps,\n} from \"../types\";\nimport { useLoadScript } from \"./useLoadScript\";\n\nexport interface IUseLoadGoogleChartsParams {\n chartVersion?: GoogleChartVersion;\n chartPackages?: GoogleChartPackages[];\n chartLanguage?: string;\n mapsApiKey?: string;\n}\n\nconst isGoogleReady = (google?: GoogleViz) => {\n return google && google.charts;\n};\n\nconst isGoogleChartsReady = (\n props: ReactGoogleChartProps,\n google?: GoogleViz,\n) => {\n const { controls, toolbarItems, getChartEditor } = props;\n return (\n google &&\n google.charts &&\n google.visualization &&\n google.visualization.ChartWrapper &&\n google.visualization.Dashboard &&\n (!controls || google.visualization.ChartWrapper) &&\n (!getChartEditor || google.visualization.ChartEditor) &&\n (!toolbarItems || google.visualization.drawToolbar)\n );\n};\n\nconst getGoogleInstanceFromWindow = (props: ReactGoogleChartProps) => {\n // @ts-expect-error Getting object from global namespace.\n const google = window.google as GoogleViz;\n return google;\n};\n\n/**\n * Hook to load Google Charts JS API.\n * @param params - Load parameters.\n * @param [params.chartVersion] - Chart version to load.\n * @param [params.chartPackages] - Packages to load.\n * @param [params.chartLanguage] - Languages to load.\n * @param [params.mapsApiKey] - Google Maps api key.\n * @returns\n */\nexport function useLoadGoogleCharts(props: ReactGoogleChartProps) {\n const {\n chartVersion = \"current\",\n chartPackages = [\"corechart\", \"controls\"],\n chartLanguage = \"en\",\n mapsApiKey,\n } = props;\n const [googleCharts, setGoogleCharts] = useState<GoogleViz | null>(null);\n const [scriptInitializationError, setScriptInitializationError] =\n useState<Error | null>(null);\n const [googleChartsInitializationError, setGoogleChartsInitializationError] =\n useState<Error | null>(null);\n const {\n isLoading,\n error: scriptLoadingError,\n isSuccess,\n } = useLoadScript(\n props.chartLoaderScriptUrl || \"https://www.gstatic.com/charts/loader.js\",\n );\n\n useEffect(() => {\n if (!isSuccess) {\n return;\n }\n const google = getGoogleInstanceFromWindow(props);\n if (!isGoogleReady(google)) {\n const error = new Error(\n \"[ScriptInitializationError] Script loaded but Google not attached to window.\",\n );\n setScriptInitializationError(error);\n return;\n }\n if (isGoogleChartsReady(props, google)) {\n setGoogleCharts(google);\n return;\n }\n google.charts.load(chartVersion, {\n packages: chartPackages,\n language: chartLanguage,\n mapsApiKey,\n });\n google.charts.setOnLoadCallback(() => {\n if (!isGoogleChartsReady(props, google)) {\n const error = new Error(\n \"[GoogleChartsInitializationError] Google Charts not ready after load callback.\",\n );\n console.error(error);\n setGoogleChartsInitializationError(error);\n return;\n }\n setGoogleCharts(google);\n });\n }, [isSuccess]);\n return {\n error:\n scriptLoadingError ||\n scriptInitializationError ||\n googleChartsInitializationError,\n isLoading,\n google: googleCharts,\n };\n}\n\nexport interface ILoadGoogleChartsProps extends IUseLoadGoogleChartsParams {\n onLoad?(googleCharts: GoogleViz): void;\n onError?(): void;\n}\n","import { ReactGoogleChartProps } from \"./types\";\n\nexport const chartDefaultProps: Partial<ReactGoogleChartProps> = {\n // <DEPRECATED_PROPS>\n legend_toggle: false,\n // </DEPRECATED_PROPS>\n options: {},\n legendToggle: false,\n getChartWrapper: () => {},\n spreadSheetQueryParameters: {\n headers: 1,\n gid: 1,\n },\n rootProps: {},\n chartWrapperParams: {},\n chartLoaderScriptUrl: \"https://www.gstatic.com/charts/loader.js\",\n};\n","import React from \"react\";\nimport { GoogleChartControlAndProp } from \"../hooks/internal/useGoogleChartControls\";\n\nexport type FilterControl = (control: GoogleChartControlAndProp) => boolean;\n\ntype Props = {\n isReady: boolean;\n chartControls: GoogleChartControlAndProp[] | null;\n filter?: FilterControl;\n};\nexport const GoogleChartControls = (props: Props) => {\n const { isReady, chartControls, filter } = props;\n if (!isReady || !chartControls || !chartControls?.length) {\n return null;\n }\n return (\n <>\n {chartControls\n .filter(({ controlProp, control }) => {\n return filter ? filter({ control, controlProp }) : true;\n })\n .map(({ control }) => {\n return (\n <div key={control.getContainerId()} id={control.getContainerId()} />\n );\n })}\n </>\n );\n};\n","let uniqueID = 0;\nexport const generateUniqueID = () => {\n uniqueID += 1;\n return `reactgooglegraph-${uniqueID}`;\n};\n","import {\n GoogleViz,\n ReactGoogleChartProps,\n GoogleChartControlProp,\n GoogleChartControl,\n UseChartControlsParams,\n} from \"../types\";\nimport { generateUniqueID } from \"../generate-unique-id\";\n\nexport type Props = ReactGoogleChartProps & {\n google: GoogleViz;\n};\n\nexport type GoogleChartControlAndProp = {\n controlProp: GoogleChartControlProp;\n control: GoogleChartControl;\n};\n\n/**\n * An internal helper class for creating and managing Google Charts controls.\n * Offers high-level methods to interact with the Google Chart Controls.\n */\nexport class GoogleChartControlsInternal {\n /**\n * Initialize the controls once chart is ready\n */\n private static initializeControls = (\n googleChartControls: GoogleChartControlAndProp[],\n ) => {\n for (let i = 0; i < googleChartControls.length; i += 1) {\n const { controlType, options, controlWrapperParams } =\n googleChartControls[i].controlProp;\n if (controlWrapperParams && \"state\" in controlWrapperParams) {\n googleChartControls[i].control.setState(controlWrapperParams[\"state\"]);\n }\n googleChartControls[i].control.setOptions(options);\n googleChartControls[i].control.setControlType(controlType);\n }\n };\n\n /**\n * listen to the control events (ready, statechange, error) specified in the controlEvents prop\n */\n public static listenToControlEvents = (\n googleChartControls: GoogleChartControlAndProp[],\n props: UseChartControlsParams,\n ) => {\n const { google } = props;\n return googleChartControls.flatMap((chartControl) => {\n const { control, controlProp } = chartControl;\n const { controlEvents = [] } = controlProp;\n return controlEvents.map((event) => {\n const { callback, eventName } = event;\n return google.visualization.events.addListener(\n control,\n eventName,\n (...args) => {\n callback({\n chartWrapper: null,\n controlWrapper: control,\n props: props,\n google: google,\n eventArgs: args,\n });\n },\n );\n });\n });\n };\n\n /**\n * If controlID is not provided, generate a unique controlID\n */\n private static createControlId = (id: undefined | string) => {\n let controlID: string;\n if (typeof id === \"undefined\") {\n controlID = `googlechart-control-${generateUniqueID()}`;\n } else {\n controlID = id;\n }\n return controlID;\n };\n\n /**\n * Map the control props to Google Chart Controls\n */\n private static createChartControls = (props: UseChartControlsParams) => {\n const { controls, google } = props;\n if (!controls) {\n return null;\n }\n\n return controls.map((control, i) => {\n const {\n controlID: controlIDMaybe,\n controlType,\n options: controlOptions,\n controlWrapperParams,\n } = control;\n const controlID = this.createControlId(controlIDMaybe);\n return {\n controlProp: control,\n control: new google.visualization.ControlWrapper({\n containerId: controlID,\n controlType,\n options: controlOptions,\n ...controlWrapperParams,\n }),\n };\n });\n };\n\n static addControls = (props: UseChartControlsParams) => {\n const { chartWrapper, chartDashboard } = props;\n const googleChartControls = this.createChartControls(props);\n if (!googleChartControls || !chartDashboard || !chartWrapper) {\n return null;\n }\n chartDashboard.bind(\n googleChartControls.map(({ control }) => control),\n chartWrapper,\n );\n this.initializeControls(googleChartControls);\n return googleChartControls;\n };\n}\n","import * as React from \"react\";\nimport {\n GoogleViz,\n ReactGoogleChartProps,\n GoogleChartControlProp,\n GoogleChartControl,\n UseChartControlsParams,\n} from \"../../types\";\nimport {\n FilterControl,\n GoogleChartControls,\n} from \"../../components/GoogleChartControls\";\nimport { GoogleChartControlsInternal } from \"../../utils/GoogleChartControlsInternal\";\n\nconst useCreateChartControls = (\n controls: ReactGoogleChartProps[\"controls\"],\n) => {\n const [chartControls, setChartControls] = React.useState<\n GoogleChartControl[] | null\n >(null);\n\n const controlAndProp = React.useMemo(() => {\n if (!chartControls || !controls) return null;\n\n return controls\n .map((controlProp, i): GoogleChartControlAndProp | undefined => {\n const control: GoogleChartControl | undefined = chartControls[i];\n return control ? { controlProp, control } : undefined;\n })\n .flatMap((controlAndProp) => (controlAndProp ? [controlAndProp] : []));\n }, [chartControls, controls]);\n\n return [controlAndProp, setChartControls] as const;\n};\n\nconst useListenToControlEvents = (\n chartControls: GoogleChartControlAndProp[],\n props: UseChartControlsParams,\n) => {\n React.useEffect(() => {\n const listeners = GoogleChartControlsInternal.listenToControlEvents(\n chartControls ?? [],\n props,\n );\n\n return () => {\n listeners.forEach((listener) => {\n props.google.visualization.events.removeListener(listener);\n });\n };\n }, [chartControls, props]);\n};\n\nexport type Props = ReactGoogleChartProps & {\n google: GoogleViz;\n};\n\nexport type GoogleChartControlAndProp = {\n controlProp: GoogleChartControlProp;\n control: GoogleChartControl;\n};\n\nexport const useChartControls = (props: UseChartControlsParams) => {\n const [chartControls, setChartControls] = useCreateChartControls(\n props.controls,\n );\n\n useListenToControlEvents(chartControls ?? [], props);\n\n /**\n * Render the container divs for the controls\n */\n const renderControl = (filter: FilterControl) => {\n const { chartWrapper, chartDashboard } = props;\n return (\n <GoogleChartControls\n {...props}\n isReady={Boolean(chartWrapper && chartDashboard)}\n chartControls={chartControls}\n filter={filter}\n />\n );\n };\n\n return {\n addControls: (props: UseChartControlsParams) => {\n const controls = GoogleChartControlsInternal.addControls(props);\n setChartControls(controls?.map((control) => control.control) ?? null);\n },\n renderControl,\n };\n};\n","import * as React from \"react\";\nimport { ReactGoogleChartProps } from \"../../types\";\nimport { generateUniqueID } from \"../../generate-unique-id\";\n\nexport const useChartId = (\n props: Pick<ReactGoogleChartProps, \"graphID\" | \"graph_id\">,\n) => {\n const chartIdRef = React.useRef<string | null>(null);\n const getChartId = (): string => {\n const { graphID, graph_id } = props;\n const chartIdFromProps = graphID || graph_id;\n let currentChartId: string;\n if (chartIdFromProps) {\n currentChartId = chartIdFromProps as string;\n } else {\n currentChartId = chartIdRef.current || generateUniqueID();\n }\n chartIdRef.current = currentChartId;\n return chartIdRef.current as string;\n };\n const chartId = getChartId();\n return { chartId };\n};\n","export const DEFAULT_CHART_COLORS = [\n \"#3366CC\",\n \"#DC3912\",\n \"#FF9900\",\n \"#109618\",\n \"#990099\",\n \"#3B3EAC\",\n \"#0099C6\",\n \"#DD4477\",\n \"#66AA00\",\n \"#B82E2E\",\n \"#316395\",\n \"#994499\",\n \"#22AA99\",\n \"#AAAA11\",\n \"#6633CC\",\n \"#E67300\",\n \"#8B0707\",\n \"#329262\",\n \"#5574A6\",\n \"#3B3EAC\",\n];\n","import { GoogleViz } from \"./types\";\n\nexport const loadDataTableFromSpreadSheet = async (\n googleViz: GoogleViz,\n spreadSheetUrl: string,\n urlParams: {\n headers?: number;\n gid?: any;\n sheet?: string;\n query?: string;\n access_token?: string;\n } = {},\n) => {\n return new Promise((resolve, reject) => {\n const headers = `${\n urlParams.headers ? `headers=${urlParams.headers}` : `headers=0`\n }`;\n const queryString = `${\n urlParams.query ? `&tq=${encodeURIComponent(urlParams.query)}` : ``\n }`;\n const gid = `${urlParams.gid ? `&gid=${urlParams.gid}` : \"\"}`;\n const sheet = `${urlParams.sheet ? `&sheet=${urlParams.sheet}` : \"\"}`;\n const access_token = `${\n urlParams.access_token ? `&access_token=${urlParams.access_token}` : \"\"\n }`;\n const urlQueryString = `${headers}${gid}${sheet}${queryString}${access_token}`;\n const urlToSpreadSheet = `${spreadSheetUrl}/gviz/tq?${urlQueryString}`; //&tq=${queryString}`;\n const query = new googleViz.visualization.Query(urlToSpreadSheet);\n query.send((response: any) => {\n if (response.isError()) {\n reject(\n `Error in query: ${response.getMessage()} ${response.getDetailedMessage()}`,\n );\n } else {\n resolve(response.getDataTable());\n }\n });\n });\n};\n","import { DEFAULT_CHART_COLORS } from \"../constants\";\nimport { UseGoogleChartDataTableParams } from \"../hooks/internal/useGoogleChartDataTable\";\nimport { loadDataTableFromSpreadSheet } from \"../load-data-table-from-spreadsheet\";\nimport { ApplyFormattersParams, GoogleDataTable } from \"../types\";\n\nconst GRAY_COLOR = \"#CCCCCC\";\n\n/**\n * An internal helper class around the Google Chart API.\n * Offers high-level methods to interact with the Google Chart API.\n */\nexport class GoogleChartInternal {\n private static grayOutHiddenColumnsLabel = (\n props: UseGoogleChartDataTableParams,\n hiddenColumns: string[],\n ) => {\n const { googleChartWrapper, options } = props;\n if (!googleChartWrapper) {\n console.error(\"googleChartWrapper is not defined\");\n return;\n }\n const dataTable = googleChartWrapper.getDataTable();\n if (!dataTable) return;\n const columnCount = dataTable.getNumberOfColumns();\n const hasAHiddenColumn = hiddenColumns.length > 0;\n if (hasAHiddenColumn === false) return;\n const colors = Array.from({ length: columnCount - 1 }).map(\n (_dontcare, i) => {\n const columnID = this.getColumnId(dataTable, i + 1);\n if (hiddenColumns.includes(columnID)) {\n return GRAY_COLOR;\n } else if (options && options.colors) {\n return options.colors[i];\n } else {\n return DEFAULT_CHART_COLORS[i];\n }\n },\n );\n googleChartWrapper.setOptions({\n ...options,\n colors,\n });\n googleChartWrapper.draw();\n };\n /**\n * Listens to user clicking on the legend to toggle the visibility of a column.\n * When a user clicks on a legend item, the column id is added to / removed from the hiddenColumns state.\n */\n public static listenToLegendToggle = (\n props: UseGoogleChartDataTableParams,\n hiddenColumnsState: [\n string[],\n React.Dispatch<React.SetStateAction<string[]>>,\n ],\n ) => {\n const [hiddenColumns, setHiddenColumns] = hiddenColumnsState;\n const { google, googleChartWrapper } = props;\n if (!googleChartWrapper) {\n console.error(\"googleChartWrapper is not defined\");\n return;\n }\n return google.visualization.events.addListener(\n googleChartWrapper,\n \"select\",\n () => {\n const chart = googleChartWrapper.getChart();\n const selection = chart.getSelection();\n const dataTable = googleChartWrapper.getDataTable();\n if (\n selection.length === 0 ||\n // We want to listen to when a whole row is selected. This is the case only when row === null\n selection[0].row !== null ||\n !dataTable\n ) {\n return;\n }\n\n const columnIndex = selection[0].column;\n const columnID = this.getColumnId(dataTable, columnIndex);\n // If the column is hidden remove it from state, otherwise add it\n if (hiddenColumns?.includes(columnID)) {\n setHiddenColumns((state) => [\n ...state.filter((colID) => colID !== columnID),\n ]);\n } else {\n setHiddenColumns((state) => [...state, columnID]);\n }\n },\n );\n };\n\n /**\n * (Re-)Draw a Google Chart with the given data, options, and chart type.\n */\n public static draw = async (\n props: UseGoogleChartDataTableParams & { hiddenColumns: string[] },\n ) => {\n const {\n data,\n diffdata,\n rows,\n columns,\n options,\n chartType,\n formatters,\n spreadSheetUrl,\n spreadSheetQueryParameters,\n googleChartDashboard,\n googleChartWrapper,\n google,\n hiddenColumns,\n legendToggle,\n legend_toggle,\n } = props;\n if (!googleChartWrapper) {\n console.error(\"draw was called with googleChartWrapper = null\");\n return;\n }\n let dataTable: GoogleDataTable;\n let chartDiff = null;\n if (diffdata) {\n const oldData = google.visualization.arrayToDataTable(diffdata.old);\n const newData = google.visualization.arrayToDataTable(diffdata.new);\n chartDiff = google.visualization[chartType].prototype.computeDiff(\n oldData,\n newData,\n );\n }\n if (data) {\n if (data instanceof google.visualization.DataTable) {\n dataTable = data;\n } else if (Array.isArray(data)) {\n dataTable = google.visualization.arrayToDataTable(data);\n } else {\n dataTable = new google.visualization.DataTable(data);\n }\n } else if (rows && columns) {\n dataTable = google.visualization.arrayToDataTable([columns, ...rows]);\n } else if (spreadSheetUrl) {\n dataTable = (await loadDataTableFromSpreadSheet(\n google,\n spreadSheetUrl,\n spreadSheetQueryParameters,\n )) as GoogleDataTable;\n } else {\n dataTable = google.visualization.arrayToDataTable([]);\n }\n const columnCount = dataTable.getNumberOfColumns();\n\n const viewColumns = Array(columnCount)\n .fill(0)\n .map((_c, i) => {\n const columnID = this.getColumnId(dataTable, i);\n if (hiddenColumns.includes(columnID)) {\n return {\n label: dataTable.getColumnLabel(i),\n type: dataTable.getColumnType(i),\n calc: () => null,\n };\n } else {\n return i;\n }\n });\n const chart = googleChartWrapper.getChart();\n if (googleChartWrapper.getChartType() === \"Timeline\") {\n chart && chart.clearChart();\n }\n googleChartWrapper.setChartType(chartType);\n googleChartWrapper.setOptions(options || {});\n const viewTable = new google.visualization.DataView(dataTable);\n viewTable.setColumns(viewColumns);\n googleChartWrapper.setDataTable(viewTable);\n googleChartWrapper.draw();\n if (googleChartDashboard) {\n googleChartDashboard.draw(dataTable);\n }\n\n if (chartDiff) {\n googleChartWrapper.setDataTable(chartDiff);\n googleChartWrapper.draw();\n }\n if (formatters) {\n this.applyFormatters({ dataTable, formatters, google });\n googleChartWrapper.setDataTable(dataTable);\n googleChartWrapper.draw();\n }\n if (legendToggle === true || legend_toggle === true) {\n this.grayOutHiddenColumnsLabel(props, hiddenColumns);\n }\n return;\n };\n /**\n * Get the column ID of a column in a GoogleDataTable.\n * If the column has an ID, return the ID, otherwise return the label.\n */\n private static getColumnId = (\n dataTable: GoogleDataTable,\n columnIndex: number,\n ) => {\n return (\n dataTable.getColumnId(columnIndex) ||\n dataTable.getColumnLabel(columnIndex)\n );\n };\n\n /**\n * Apply Chart Formatters passed under the formatters prop to the GoogleDataTable\n */\n private static applyFormatters = ({\n dataTable,\n formatters,\n google,\n }: ApplyFormattersParams) => {\n for (let formatter of formatters) {\n switch (formatter.type) {\n case \"ArrowFormat\": {\n const vizFormatter = new google.visualization.ArrowFormat(\n formatter.options,\n );\n vizFormatter.format(dataTable, formatter.column);\n return;\n }\n case \"BarFormat\": {\n const vizFormatter = new google.visualization.BarFormat(\n formatter.options,\n );\n vizFormatter.format(dataTable, formatter.column);\n return;\n }\n case \"ColorFormat\": {\n const vizFormatter = new google.visualization.ColorFormat(\n formatter.options,\n );\n const { ranges } = formatter;\n if (ranges) {\n for (let range of ranges) {\n vizFormatter.addRange(...range);\n }\n }\n vizFormatter.format(dataTable, formatter.column);\n return;\n }\n case \"DateFormat\": {\n const vizFormatter = new google.visualization.DateFormat(\n formatter.options,\n );\n vizFormatter.format(dataTable, formatter.column);\n return;\n }\n case \"NumberFormat\": {\n const vizFormatter = new google.visualization.NumberFormat(\n formatter.options,\n );\n vizFormatter.format(dataTable, formatter.column);\n return;\n }\n case \"PatternFormat\": {\n const vizFormatter = new google.visualization.PatternFormat(\n formatter.options,\n );\n vizFormatter.format(dataTable, formatter.column);\n return;\n }\n default: {\n console.warn(`Unknown formatter type: ${formatter.type}`);\n return;\n }\n }\n }\n };\n}\n","import * as React from \"react\";\nimport {\n GoogleViz,\n GoogleChartWrapper,\n ReactGoogleChartProps,\n GoogleChartDashboard,\n GoogleVizEventListener,\n} from \"../../types\";\nimport { GoogleChartInternal } from \"../../utils\";\n\nexport type ChartDrawArgs = {\n data: ReactGoogleChartProps[\"data\"];\n};\n\nexport type UseGoogleChartDataTableParams = ReactGoogleChartProps & {\n googleChartWrapper?: GoogleChartWrapper | null;\n google: GoogleViz;\n googleChartDashboard?: GoogleChartDashboard | null;\n};\n\nexport const useGoogleChartDataTable = (\n props: UseGoogleChartDataTableParams,\n) => {\n const { google, googleChartWrapper, googleChartDashboard } = props;\n const [hiddenColumns, setHiddenColumns] = React.useState<string[]>([]);\n // Re-draw the chart when hiddenColumns change\n React.useEffect(() => {\n if (!googleChartWrapper) {\n return;\n }\n GoogleChartInternal.draw({\n ...props,\n hiddenColumns,\n googleChartWrapper,\n googleChartDashboard,\n google,\n });\n }, [\n hiddenColumns,\n props.data,\n props.rows,\n props.columns,\n props.options,\n props.chartLoaderScriptUrl,\n props.chartType,\n props.formatters,\n props.spreadSheetUrl,\n props.spreadSheetQueryParameters,\n props.legendToggle,\n props.legend_toggle,\n ]);\n\n // Re-draw the chart when the window is resized\n const onResize = () => {\n const { googleChartWrapper } = props;\n if (!googleChartWrapper) {\n return;\n }\n googleChartWrapper.draw();\n };\n\n // Draw the chart when the google charts wrapper is ready and when the hiddenColumns change\n const initialize = (googleChartWrapper: GoogleChartWrapper) => {\n const listeners: GoogleVizEventListener[] = [];\n\n const { legendToggle, legend_toggle } = props;\n GoogleChartInternal.draw({\n ...props,\n hiddenColumns,\n googleChartWrapper,\n googleChartDashboard,\n google,\n });\n window.addEventListener(\"resize\", onResize);\n if (legend_toggle || legendToggle) {\n const listener = GoogleChartInternal.listenToLegendToggle(props, [\n hiddenColumns,\n setHiddenColumns,\n ]);\n\n if (listener) listeners.push(listener);\n }\n\n return listeners;\n };\n\n // Remove event listeners and clear the chart when the component is unmounted\n const destroy = (\n googleChartWrapper: GoogleChartWrapper,\n listeners: GoogleVizEventListener[],\n ) => {\n window.removeEventListener(\"resize\", onResize);\n listeners.forEach((listener) => {\n google.visualization.events.removeListener(listener);\n });\n if (googleChartWrapper.getChartType() === \"Timeline\") {\n googleChartWrapper.getChart() &&\n googleChartWrapper.getChart().clearChart();\n }\n };\n\n React.useEffect(() => {\n if (!googleChartWrapper) {\n return;\n }\n const listeners = initialize(googleChartWrapper);\n return () => {\n destroy(googleChartWrapper, listeners);\n };\n }, [googleChartWrapper, initialize, destroy]);\n};\n","import { useEffect } from \"react\";\nimport {\n GoogleChartWrapper,\n GoogleViz,\n ReactGoogleChartProps,\n} from \"../../types\";\n\nexport type GoogleChartEventsParams = ReactGoogleChartProps & {\n googleChartWrapper?: GoogleChartWrapper | null;\n google: GoogleViz;\n};\n\nconst listenToEvents = (props: GoogleChartEventsParams) => {\n const { chartEvents, google, googleChartWrapper } = props;\n if (!chartEvents) {\n return;\n }\n if (!googleChartWrapper) {\n console.warn(\"listenToEvents was called before chart wrapper ready.\");\n return;\n }\n return chartEvents.map(({ eventName, callback }) => {\n return google.visualization.events.addListener(\n googleChartWrapper,\n eventName,\n (...args) => {\n callback({\n chartWrapper: googleChartWrapper,\n props,\n google: google,\n eventArgs: args,\n });\n },\n );\n });\n};\n\nexport const useGoogleChartEvents = (props: GoogleChartEventsParams) => {\n useEffect(() => {\n if (!props.googleChartWrapper) return;\n\n const listeners = listenToEvents(props);\n\n return () => {\n listeners?.forEach((listener) => {\n props.google.visualization.events.removeListener(listener);\n });\n };\n }, [props]);\n};\n","import * as React from \"react\";\nimport {\n GoogleViz,\n GoogleChartWrapper,\n ReactGoogleChartProps,\n GoogleChartDashboard,\n GoogleChartEditor,\n} from \"../types\";\nimport { useChartControls } from \"../hooks/internal/useGoogleChartControls\";\nimport { useChartId } from \"../hooks/internal/useChartId\";\nimport { useGoogleChartDataTable } from \"../hooks/internal/useGoogleChartDataTable\";\nimport { useGoogleChartEvents } from \"../hooks/internal/useGoogleChartEvents\";\n\ntype Props = ReactGoogleChartProps & {\n google: GoogleViz;\n};\n\nexport const GoogleChart: React.FC<Props> = (props) => {\n const [googleChartWrapper, setGoogleChartWrapper] =\n React.useState<GoogleChartWrapper | null>(null);\n // const [isReady, setIsReady] = React.useState<boolean>(false);\n const [googleChartDashboard, setGoogleChartDashboard] =\n React.useState<GoogleChartDashboard | null>(null);\n\n const { addControls, renderControl } = useChartControls({\n ...props,\n chartDashboard: googleChartDashboard,\n chartWrapper: googleChartWrapper,\n });\n useGoogleChartEvents({\n ...props,\n googleChartWrapper,\n });\n const { chartId } = useChartId(props);\n const dashboardRef = React.useRef<HTMLDivElement>(null);\n const toolbarRef = React.useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n const {\n options,\n google,\n chartType,\n chartWrapperParams,\n toolbarItems,\n getChartEditor,\n getChartWrapper,\n onLoad,\n } = props;\n\n const chartConfig = {\n chartType,\n options,\n containerId: chartId,\n ...chartWrapperParams,\n };\n // Create ChartWrapper instance, pass it to the user and store it in state\n const chartWrapper = new google.visualization.ChartWrapper(chartConfig);\n chartWrapper.setOptions(options || {});\n getChartWrapper?.(chartWrapper, google);\n\n // Create Dashboard instance, needed for controls\n const chartDashboard = new google.visualization.Dashboard(\n dashboardRef.current,\n );\n\n // Create toolbar if needed\n if (toolbarItems) {\n google.visualization.drawToolbar(\n toolbarRef.current as HTMLDivElement,\n toolbarItems,\n );\n }\n\n // Create ChartEditor instance if needed and pass it to the user\n let chartEditor: GoogleChartEditor | null = null;\n if (getChartEditor) {\n chartEditor = new google.visualization.ChartEditor();\n getChartEditor({\n chartEditor,\n chartWrapper,\n google,\n });\n }\n // Create and add controls to the chart / dashboard\n addControls({ ...props, chartDashboard, chartWrapper });\n setGoogleChartWrapper(chartWrapper);\n setGoogleChartDashboard(chartDashboard);\n onLoad?.(google, {\n google,\n chartWrapper,\n chartEditor,\n chartDashboard,\n });\n }, []);\n\n useGoogleChartDataTable({\n ...props,\n googleChartWrapper,\n googleChartDashboard,\n });\n const renderChart = () => {\n const { width, height, options, style, className, rootProps, google } =\n props;\n\n const divStyle = {\n height: height || (options && options.height),\n width: width || (options && options.width),\n ...style,\n };\n return (\n <div id={chartId} style={divStyle} className={className} {...rootProps} />\n );\n };\n\n const renderToolBar = () => {\n if (!props.toolbarItems) return null;\n return <div ref={toolbarRef} />;\n };\n\n const { width, height, options, style } = props;\n\n const divStyle = {\n height: height || (options && options.height),\n width: width || (options && options.width),\n ...style,\n };\n\n // If render prop is provided, give the user full control over the rendering by passing renderChart, renderControl and renderToolbar functions\n if (props.render) {\n return (\n <div ref={dashboardRef} style={divStyle}>\n <div ref={toolbarRef} id=\"toolbar\" />\n {props.render({\n renderChart,\n renderControl,\n renderToolbar: renderToolBar,\n })}\n </div>\n );\n } else {\n return (\n <div ref={dashboardRef} style={divStyle}>\n {renderControl(\n ({ controlProp }) => controlProp.controlPosition !== \"bottom\",\n )}\n {renderChart()}\n {renderControl(\n ({ controlProp }) => controlProp.controlPosition === \"bottom\",\n )}\n {renderToolBar()}\n </div>\n );\n }\n};\n\nexport default GoogleChart;\n","import * as React from \"react\";\nimport { chartDefaultProps } from \"./default-props\";\nimport { ReactGoogleChartProps } from \"./types\";\n\nexport const ChartContext = React.createContext(chartDefaultProps);\n\nexport const ContextProvider = ({\n children,\n value,\n}: {\n children: any;\n value: ReactGoogleChartProps;\n}) => {\n return (\n <ChartContext.Provider value={value}>{children}</ChartContext.Provider>\n );\n};\n","import React from \"react\";\nimport { ReactGoogleChartProps } from \"./types\";\nimport { useLoadGoogleCharts } from \"./hooks\";\nimport { chartDefaultProps } from \"./default-props\";\nimport { GoogleChart } from \"./components/GoogleChart\";\nimport { ContextProvider } from \"./Context\";\n\n/**\n * Loads Google Charts JS and renders the GoogleChart component.\n */\nconst ChartView: React.FC<ReactGoogleChartProps> = (props) => {\n const { google, isLoading, error } = useLoadGoogleCharts(props);\n if (isLoading) {\n return props.loader ?? null;\n }\n if (error) {\n return props.errorElement ?? null;\n }\n if (google) {\n return <GoogleChart google={google} {...props} />;\n }\n return null;\n};\n\n/**\n * Updates the context with the props and renders ChartView.\n */\nexport const Chart: React.FC<ReactGoogleChartProps> = (userProps) => {\n const props = { ...chartDefaultProps, ...userProps };\n return (\n <ContextProvider value={props}>\n <ChartView {...props} />\n </ContextProvider>\n );\n};\n\nexport default Chart;\n","// Complete Google Charts Type Definition : https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/google.visualization/index.d.ts\n\nexport type GoogleVizDrawToolbar = (\n toolbarContainer: HTMLDivElement,\n components: GoogleChartToolbarItem[],\n) => any;\n\nexport type GoogleViz = {\n charts: GoogleChartLoader;\n visualization: {\n ChartWrapper: GoogleChartWrapper;\n ControlWrapper: GoogleChartControl;\n ChartEditor: GoogleChartEditor;\n DataTable: GoogleDataTable;\n events: GoogleVizEvents;\n arrayToDataTable: GoogleArrayToDataTable;\n drawToolbar: GoogleVizDrawToolbar;\n [otherKeys: string]: any;\n };\n};\n\nexport type GoogleChartTicks = (number | Date)[];\n\nexport type GoogleChartEditor = {\n new (): GoogleChartEditor;\n openDialog: (\n chartWrapper: GoogleChartWrapper,\n chartEditorOptions?: {\n dataSourceInput?: any;\n [otherKeyMaybe: string]: any;\n },\n ) => null;\n getChartWrapper: () => GoogleChartWrapper;\n setChartWrapper: (chartWrapper: GoogleChartWrapper) => GoogleChartWrapper;\n closeDialog: () => null;\n};\n\nexport type GoogleChartLoaderOptions = {\n packages?: GoogleChartPackages[];\n language?: string;\n mapsApiKey?: string;\n};\nexport type GoogleChartLoader = {\n load: (\n version: GoogleChartVersion,\n googleChartOptions: GoogleChartLoaderOptions,\n ) => void;\n setOnLoadCallback: (callback: () => void) => void;\n};\nexport interface ChartWrapperProps {\n chartType: GoogleChartWrapperChartType;\n containerId?: string;\n options?: {\n width?: number;\n height?: number;\n is3D?: boolean;\n title?: string;\n backgroundColor: string;\n };\n dataTable?: {};\n dataSourceUrl?: string;\n query?: string;\n refreshInterval?: number;\n view?: any[] | {};\n render?: (props: ChartWrapperProps, chartWrapper: GoogleChartWrapper) => any;\n children?: (\n props: ChartWrapperProps,\n chartWrapper: GoogleChartWrapper,\n ) => any;\n}\n\nexport type VizEventsProps = {\n chartWrapper: GoogleChartWrapper;\n onReady?: (chartWrapper: GoogleChartWrapper) => any;\n onError?: (chartWrapper: GoogleChartWrapper) => any;\n onSelect?: (selection: Array<{ row?: any; column?: any }>) => any;\n render?: (props: VizEventsProps, chartWrapper: GoogleChartWrapper) => any;\n children?: (props: VizEventsProps, chartWrapper: GoogleChartWrapper) => any;\n};\n\n/*\n *\n * <GoogleChartsTypes>\n *\n */\n\n/*\n *\n * Reference + Docs:\n * https://developers.google.com/chart/interactive/docs/reference#constructor_3\n * https://developers.google.com/chart/interactive/docs/reference#google.visualization.drawchart\n *\n */\nexport type GoogleChartWrapperChartType =\n | \"AnnotationChart\"\n | \"AreaChart\"\n | \"BarChart\"\n | \"BubbleChart\"\n | \"Calendar\"\n | \"CandlestickChart\"\n | \"ColumnChart\"\n | \"ComboChart\"\n | \"DiffChart\"\n | \"DonutChart\"\n | \"Gantt\"\n | \"Gauge\"\n | \"GeoChart\"\n | \"Histogram\"\n | \"LineChart\"\n | \"Line\"\n | \"Bar\"\n | \"Map\"\n | \"OrgChart\"\n | \"PieChart\"\n | \"Sankey\"\n | \"ScatterChart\"\n | \"Scatter\"\n | \"SteppedAreaChart\"\n | \"Table\"\n | \"Timeline\"\n | \"TreeMap\"\n | \"WaterfallChart\"\n | \"WordTree\";\n\n// https://developers.google.com/chart/interactive/docs/reference#google.visualization.drawchart\nexport interface ChartWrapperOptions {\n chartType: string;\n containerId: string;\n options: Partial<{\n width: number;\n height: number;\n is3D: boolean;\n title: string;\n backgroundColor:\n | string\n | { fill: string; stroke: string; strokeWidth: number };\n hAxis?: {\n minValue?: any;\n maxValue?: any;\n ticks?: GoogleChartTicks;\n title?: string;\n viewWindow?: { max?: any; min?: any };\n [otherOptionKey: string]: any;\n };\n vAxis?: {\n minValue?: any;\n maxValue?: any;\n ticks?: GoogleChartTicks;\n title?: string;\n viewWindow?: { max?: any; min?: any };\n [otherOptionKey: string]: any;\n };\n legend: any;\n colors: string[];\n [otherOptionKey: string]: any;\n }>;\n dataTable?: GoogleDataTable;\n dataSourceUrl?: string;\n query?: string;\n refreshInterval?: number;\n view: any[] | {};\n [otherOptionKey: string]: any;\n}\n\nexport type GoogleChartAction = {\n id: string;\n text: string;\n action: (chartWrapper: GoogleChartWrapper) => void;\n};\n\nexport type GoogleChartControlProp = {\n controlType:\n | \"CategoryFilter\"\n | \"ChartRangeFilter\"\n | \"DateRangeFilter\"\n | \"NumberRangeFilter\"\n | \"StringFilter\";\n options: {};\n controlWrapperParams?: {};\n controlID?: string;\n controlPosition?: \"top\" | \"bottom\";\n controlEvents?: ReactGoogleChartEvent[];\n};\n\nexport type GoogleChartWrapper = {\n new (chartWrapperOptions: Partial<ChartWrapperOptions>): GoogleChartWrapper;\n draw: (chartArgs?: ChartWrapperProps) => any;\n toJSON: () => string;\n clone: () => GoogleChartWrapper;\n getDataSourceUrl: () => string;\n getDataTable: () => GoogleDataTable | null; // null if datasourceurl set or ref to DataTable\n getChartType: () => GoogleChartWrapperChartType;\n getChartName: () => string;\n getChart: () => {\n removeAction: (actionID: string) => void;\n getSelection: () => { row?: any; column?: any }[];\n setAction: (ChartAction: GoogleChartAction) => void;\n getImageURI: () => void;\n clearChart: () => void; // Clears the chart, and releases all of its allocated resources.\n }; // ref to chart\n getContainerId: () => string;\n getQuery: () => string;\n getRefreshInterval: () => number;\n getOption: (key: string, opt_default_value?: any) => any; // returns opt_default_value if key not found\n getOptions: () => {};\n getSelection: () => { row?: any; column?: any }[];\n getView: () => {} | any[]; // Same format as toJSON\n\n setDataSourceUrl: (url: string) => void;\n setDataTable: (table: any) => void;\n setChartType: (chartType: GoogleChartWrapperChartType) => void;\n setChartName: (name: string) => void; // Sets an arbitrary name for the chart. This is not shown anywhere on the chart, unless a custom chart is explicitly designed to use it.\n setContainerId: (id: string) => void; // Sets the ID of the containing DOM element for the chart.\n setQuery: (query_string: string) => void; // Sets a query string, if this chart queries a data source. You must also set the data source URL if specifying this value.\n setRefreshInterval: (interval: number) => void; // Sets the refresh interval for this chart, if it queries a data source. You must also set a data source URL if specifying this value. Zero indicates no refresh.\n setOption: (key: string, value: any) => void; // \tSets a single chart option value, where key is the option name and value is the value. To unset an option, pass in null for the value. Note that key may be a qualified name, such as 'vAxis.title'.\n setOptions: (options_obj: Partial<ChartWrapperOptions[\"options\"]>) => void; //\n};\n\nexport type GoogleVizEventListener = {\n key: Record<string, unknown>;\n};\n\nexport type GoogleVizEventName =\n | \"ready\"\n | \"error\"\n | \"select\"\n | \"animationfinish\"\n | \"statechange\"\n | \"ok\"\n | \"cancel\"\n | \"animationstart\";\n\nexport type GoogleVizEvents = {\n addListener: (\n chartWrapper: GoogleChartWrapper | GoogleChartControl | GoogleChartEditor,\n name: GoogleVizEventName,\n onEvent: (chartWrapper: GoogleChartWrapper) => any,\n ) => GoogleVizEventListener;\n removeListener: (eventListener: GoogleVizEventListener) => any;\n removeAllListeners: (chartWrapper: GoogleChartWrapper) => any;\n};\n\nexport type GoogleChartPackages =\n | \"corechart\"\n | \"charteditor\"\n | \"controls\"\n | \"calendar\"\n | \"gantt\"\n | \"gauge\"\n | \"geochart\"\n | \"map\"\n | \"orgchart\"\n | \"sankey\"\n | \"table\"\n | \"timeline\"\n | \"treemap\"\n | \"wordtree\";\n\nexport type GoogleChartVersion = \"current\" | \"upcoming\" | string;\n\nexport type GoogleDataTableColumnType =\n | \"string\"\n | \"number\"\n | \"boolean\"\n | \"date\"\n | \"datetime\"\n | \"timeofday\";\n\n// export type GoogleDataTable = {\n// addColumn: (type: GoogleDataTableColumnType) => number;\n// };\n\n// Reference https://developers.google.com/chart/interactive/docs/roles\nexport enum GoogleDataTableColumnRoleType {\n annotation = \"annotation\",\n annotationText = \"annotationText\",\n certainty = \"certainty\",\n emphasis = \"emphasis\",\n interval = \"interval\",\n scope = \"scope\",\n style = \"style\",\n tooltip = \"tooltip\",\n domain = \"domain\",\n}\n\nexport type GoogleDataTableColumn =\n | {\n type: GoogleDataTableColumnType;\n label?: string; // A label for the column.\n role?: GoogleDataTableColumnRoleType;\n pattern?: string;\n p?: {};\n id?: string;\n }\n | string;\n\n// Ref : https://developers.google.com/chart/interactive/docs/reference#dataparam\n\nexport type GoogleDataTableCell =\n | {\n v?: any; // The cell value. Type should match DataTableColumn type field\n f?: string; // A string version of the v value, formatted for display.\n p?: {};\n }\n | string\n | number\n | boolean\n | Date\n | null;\n\nexport type GoogleDataTableRow = GoogleDataTableCell[];\n\nexport type GoogleDataTableJS = {\n cols: GoogleDataTableColumn[];\n rows: {\n c: GoogleDataTableRow;\n }[];\n p?: {};\n};\n\n// Reference : https://developers.google.com/chart/interactive/docs/reference#DataTable\n\nexport type GoogleDataTableRowFilter = {\n column: number;\n value: any;\n minValue?: any;\n maxValue?: any;\n};\n\nexport type GoogleDataTableSortColumns =\n | number\n | {\n column: number;\n desc: boolean;\n }\n | number[]\n | {\n column: number;\n desc: boolean;\n }[];\n\nexport type GoogleDataTable = {\n // https://developers.google.com/chart/interactive/docs/reference#dataparam\n new (dataParam: any): GoogleDataTable;\n addColumn: (column: GoogleDataTableColumn) => number;\n addRow: (row?: GoogleDataTableRow) => number;\n addRows: (rows?: GoogleDataTableRow[] | number[] | any[]) => number;\n clone: () => GoogleDataTable;\n\n getColumnId: (columnIndex: number) => string;\n getColumnLabel: (columnIndex: number) => string;\n getColumnPattern: (columnIndex: number) => string;\n getColumnProperties: (columnIndex: number) => {};\n getColumnProperty: (columnIndex: number, name: string) => any;\n getColumnRange: (columnIndex: number) => {\n min: number | null;\n max: number | null;\n };\n getColumnRole: (columnIndex: number) => GoogleDataTableColumnRoleType;\n getColumnType: (columnIndex: number) => GoogleDataTableColumnType;\n getDistinctValues: (columnIndex: number) => any[];\n getFilteredRows: (filters: GoogleDataTableRowFilter[]) => number[];\n getFormattedValue: (rowIndex: number, columnIndex: number) => string;\n getNumberOfColumns: () => number;\n getNumberOfRows: () => number;\n getProperties: (rowIndex: number, columnIndex: number) => {};\n getProperty: (rowIndex: number, columnIndex: number, name: string) => any;\n getRowProperties: (rowIndex: number) => {};\n getRowProperty: (rowIndex: number, name: string) => any;\n getSortedRows: (sortColumns: GoogleDataTableSortColumns) => number[];\n getTableProperties: () => {};\n getTableProperty: (name: string) => any;\n getValue: (\n rowIndex: number,\n columnIndex: number,\n ) => boolean | string | number | Date | number[] | null;\n insertColumn: (\n columnIndex: number,\n type: GoogleDataTableColumnType,\n label?: string,\n id?: string,\n ) => void;\n insertRows: (\n rowIndex: number,\n numberOrArray: GoogleDataTableRow[] | number,\n ) => void;\n removeColumn: (columnIndex: number) => void;\n removeColumns: (columnIndex: number, numberOfColumns: number) => void;\n removeRow: (rowIndex: number) => void;\n removeRows: (rowIndex: number, numberOfColumns: number) => void;\n setCell: (\n rowIndex: number,\n columnIndex: number,\n value?: any,\n formattedValue?: string,\n properties?: {},\n ) => {};\n setColumnLabel: (columnIndex: number, label: string) => void;\n setColumnProperty: (columnIndex: number, name: string, value: any) => void;\n setColumnProperties: (columnIndex: number, properties: {} | null) => void;\n setFormattedValue: (\n rowIndex: number,\n columnIndex: number,\n formattedValue: string,\n ) => void;\n setProperty: (\n rowIndex: number,\n columnIndex: number,\n name: string,\n value: any,\n ) => void;\n setProperties: (\n rowIndex: number,\n columnIndex: number,\n properties: {} | null,\n ) => void;\n\n setRowProperty: (rowIndex: number, name: string, value: any) => void;\n setRowProperties: (rowIndex: number, properties: {} | null) => void;\n setTableProperties: (properties: {} | null) => void;\n setValue: (rowIndex: number, columnIndex: number, value: boolean | string | number | Date | number[] | null) => void;\n sort: (sortColumns: GoogleDataTableSortColumns) => void;\n toJSON: () => string; // GoogleDataTableJS\n};\n\nexport type GoogleArrayToDataTable = (\n data: any[][],\n isFirstRowLabels?: boolean,\n) => GoogleDataTable;\n\nexport type GoogleChartOptions = {\n width?: number;\n height?: number;\n is3D?: boolean;\n backgroundColor: string;\n\n title?: string;\n hAxis?: {\n minValue?: any;\n maxValue?: any;\n ticks?: GoogleChartTicks;\n title?: string;\n viewWindow?: { max?: any; min?: any; [otherOptionKey: string]: any };\n [otherOptionKey: string]: any;\n };\n vAxis?: {\n minValue?: any;\n maxValue?: any;\n ticks?: GoogleChartTicks;\n title?: string;\n viewWindow?: { max?: any; min?: any; [otherOptionKey: string]: any };\n [otherOptionKey: string]: any;\n };\n bubble?: {};\n pieHole?: number;\n redColor?: string;\n redFrom?: number;\n redTo?: number;\n yellowColor?: string;\n yellowFrom?: number;\n yellowTo?: number;\n greenColor?: string;\n greenFrom?: number;\n greenTo?: number;\n minorTicks?: num