UNPKG

react-google-charts

Version:
797 lines (778 loc) 31.6 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var React = require('react'); function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var React__namespace = /*#__PURE__*/_interopNamespace(React); /** * Hook to load external script. * @param src - Source url to load. * @param onLoad - Success callback. * @param onError - Error callback. */ function useLoadScript(src, onLoad, onError) { React.useEffect(()=>{ if (!document) { return; } // Find script tag with same src in DOM. const foundScript = document.querySelector('script[src="'.concat(src, '"]')); // Call onLoad if script marked as loaded. if (foundScript === null || foundScript === void 0 ? void 0 : foundScript.dataset.loaded) { onLoad === null || onLoad === void 0 ? void 0 : onLoad(); return; } // Create or get existed tag. const script = foundScript || document.createElement("script"); // Set src if no script was found. if (!foundScript) { script.src = src; } // Mark script as loaded on load event. const onLoadWithMarker = ()=>{ script.dataset.loaded = "1"; onLoad === null || onLoad === void 0 ? void 0 : onLoad(); }; script.addEventListener("load", onLoadWithMarker); if (onError) { script.addEventListener("error", onError); } // Add to DOM if not yet added. if (!foundScript) { document.head.append(script); } return ()=>{ script.removeEventListener("load", onLoadWithMarker); if (onError) { script.removeEventListener("error", onError); } }; }, []); } /** * Hook to load Google Charts JS API. * @param params - Load parameters. * @param [params.chartVersion] - Chart version to load. * @param [params.chartPackages] - Packages to load. * @param [params.chartLanguage] - Languages to load. * @param [params.mapsApiKey] - Google Maps api key. * @returns */ function useLoadGoogleCharts(param) { let { chartVersion ="current" , chartPackages =[ "corechart", "controls" ] , chartLanguage ="en" , mapsApiKey } = param; const [googleCharts, setGoogleCharts] = React.useState(null); const [failed, setFailed] = React.useState(false); useLoadScript("https://www.gstatic.com/charts/loader.js", ()=>{ // @ts-expect-error Getting object from global namespace. const google = window === null || window === void 0 ? void 0 : window.google; if (!google) { return; } google.charts.load(chartVersion, { packages: chartPackages, language: chartLanguage, mapsApiKey }); google.charts.setOnLoadCallback(()=>{ setGoogleCharts(google); }); }, ()=>{ setFailed(true); }); return [ googleCharts, failed ]; } /** * Wrapper around useLoadGoogleCharts to use in legacy components. */ function LoadGoogleCharts(param) { let { onLoad , onError , ...params } = param; const [googleCharts, failed] = useLoadGoogleCharts(params); React.useEffect(()=>{ if (googleCharts && onLoad) { onLoad(googleCharts); } }, [ googleCharts ]); React.useEffect(()=>{ if (failed && onError) { onError(); } }, [ failed ]); return null; } const chartDefaultProps = { // <DEPRECATED_PROPS> legend_toggle: false, // </DEPRECATED_PROPS> options: {}, legendToggle: false, getChartWrapper: ()=>{}, spreadSheetQueryParameters: { headers: 1, gid: 1 }, rootProps: {}, chartWrapperParams: {} }; let uniqueID = 0; const generateUniqueID = ()=>{ uniqueID += 1; return "reactgooglegraph-".concat(uniqueID); }; const DEFAULT_CHART_COLORS = [ "#3366CC", "#DC3912", "#FF9900", "#109618", "#990099", "#3B3EAC", "#0099C6", "#DD4477", "#66AA00", "#B82E2E", "#316395", "#994499", "#22AA99", "#AAAA11", "#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#3B3EAC" ]; const loadDataTableFromSpreadSheet = async function(googleViz, spreadSheetUrl) { let urlParams = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {}; return new Promise((resolve, reject)=>{ const headers = "".concat(urlParams.headers ? "headers=".concat(urlParams.headers) : "headers=0"); const queryString = "".concat(urlParams.query ? "&tq=".concat(encodeURIComponent(urlParams.query)) : ""); const gid = "".concat(urlParams.gid ? "&gid=".concat(urlParams.gid) : ""); const sheet = "".concat(urlParams.sheet ? "&sheet=".concat(urlParams.sheet) : ""); const access_token = "".concat(urlParams.access_token ? "&access_token=".concat(urlParams.access_token) : ""); const urlQueryString = "".concat(headers).concat(gid).concat(sheet).concat(queryString).concat(access_token); const urlToSpreadSheet = "".concat(spreadSheetUrl, "/gviz/tq?").concat(urlQueryString); //&tq=${queryString}`; const query = new googleViz.visualization.Query(urlToSpreadSheet); query.send((response)=>{ if (response.isError()) { reject("Error in query: ".concat(response.getMessage(), " ").concat(response.getDetailedMessage())); } else { resolve(response.getDataTable()); } }); }); }; const { Provider , Consumer } = /*#__PURE__*/ React__namespace.createContext(chartDefaultProps); const ContextProvider = (param)=>{ let { children , value } = param; return /*#__PURE__*/ React__namespace.createElement(Provider, { value: value }, children); }; const ContextConsumer = (param)=>{ let { render } = param; return /*#__PURE__*/ React__namespace.createElement(Consumer, null, (context)=>{ return render(context); }); }; const GRAY_COLOR = "#CCCCCC"; class GoogleChartDataTableInner extends React__namespace.Component { componentDidMount() { this.draw(this.props); window.addEventListener("resize", this.onResize); if (this.props.legend_toggle || this.props.legendToggle) { this.listenToLegendToggle(); } } componentWillUnmount() { const { google , googleChartWrapper } = this.props; window.removeEventListener("resize", this.onResize); google.visualization.events.removeAllListeners(googleChartWrapper); if (googleChartWrapper.getChartType() === "Timeline") { googleChartWrapper.getChart() && googleChartWrapper.getChart().clearChart(); } } componentDidUpdate() { this.draw(this.props); } render() { return null; } constructor(...args){ super(...args); this.state = { hiddenColumns: [] }; this.listenToLegendToggle = ()=>{ const { google , googleChartWrapper } = this.props; google.visualization.events.addListener(googleChartWrapper, "select", ()=>{ const chart = googleChartWrapper.getChart(); const selection = chart.getSelection(); const dataTable = googleChartWrapper.getDataTable(); if (selection.length === 0 || // We want to listen to when a whole row is selected. This is the case only when row === null selection[0].row || !dataTable) { return; } const columnIndex = selection[0].column; const columnID = this.getColumnID(dataTable, columnIndex); if (this.state.hiddenColumns.includes(columnID)) { this.setState((state)=>({ ...state, hiddenColumns: [ ...state.hiddenColumns.filter((colID)=>colID !== columnID), ] })); } else { this.setState((state)=>({ ...state, hiddenColumns: [ ...state.hiddenColumns, columnID ] })); } }); }; this.applyFormatters = (dataTable, formatters)=>{ const { google } = this.props; for (let formatter of formatters){ switch(formatter.type){ case "ArrowFormat": { const vizFormatter = new google.visualization.ArrowFormat(formatter.options); vizFormatter.format(dataTable, formatter.column); break; } case "BarFormat": { const vizFormatter = new google.visualization.BarFormat(formatter.options); vizFormatter.format(dataTable, formatter.column); break; } case "ColorFormat": { const vizFormatter = new google.visualization.ColorFormat(formatter.options); const { ranges } = formatter; for (let range of ranges){ vizFormatter.addRange(...range); } vizFormatter.format(dataTable, formatter.column); break; } case "DateFormat": { const vizFormatter = new google.visualization.DateFormat(formatter.options); vizFormatter.format(dataTable, formatter.column); break; } case "NumberFormat": { const vizFormatter = new google.visualization.NumberFormat(formatter.options); vizFormatter.format(dataTable, formatter.column); break; } case "PatternFormat": { const vizFormatter = new google.visualization.PatternFormat(formatter.options); vizFormatter.format(dataTable, formatter.column); break; } } } }; this.getColumnID = (dataTable, columnIndex)=>{ return dataTable.getColumnId(columnIndex) || dataTable.getColumnLabel(columnIndex); }; this.draw = async (param)=>{ let { data , diffdata , rows , columns , options , legend_toggle , legendToggle , chartType , formatters , spreadSheetUrl , spreadSheetQueryParameters } = param; const { google , googleChartWrapper } = this.props; let dataTable; let chartDiff = null; if (diffdata) { const oldData = google.visualization.arrayToDataTable(diffdata.old); const newData = google.visualization.arrayToDataTable(diffdata.new); chartDiff = google.visualization[chartType].prototype.computeDiff(oldData, newData); } if (data !== null) { if (Array.isArray(data)) { dataTable = google.visualization.arrayToDataTable(data); } else { dataTable = new google.visualization.DataTable(data); } } else if (rows && columns) { dataTable = google.visualization.arrayToDataTable([ columns, ...rows ]); } else if (spreadSheetUrl) { dataTable = await loadDataTableFromSpreadSheet(google, spreadSheetUrl, spreadSheetQueryParameters); } else { dataTable = google.visualization.arrayToDataTable([]); } const columnCount = dataTable.getNumberOfColumns(); for(let i = 0; i < columnCount; i += 1){ const columnID = this.getColumnID(dataTable, i); if (this.state.hiddenColumns.includes(columnID)) { const previousColumnLabel = dataTable.getColumnLabel(i); const previousColumnID = dataTable.getColumnId(i); const previousColumnType = dataTable.getColumnType(i); dataTable.removeColumn(i); dataTable.addColumn({ label: previousColumnLabel, id: previousColumnID, type: previousColumnType }); } } const chart = googleChartWrapper.getChart(); if (googleChartWrapper.getChartType() === "Timeline") { chart && chart.clearChart(); } googleChartWrapper.setChartType(chartType); googleChartWrapper.setOptions(options || {}); googleChartWrapper.setDataTable(dataTable); googleChartWrapper.draw(); if (this.props.googleChartDashboard !== null) { this.props.googleChartDashboard.draw(dataTable); } if (chartDiff) { googleChartWrapper.setDataTable(chartDiff); googleChartWrapper.draw(); } if (formatters) { this.applyFormatters(dataTable, formatters); googleChartWrapper.setDataTable(dataTable); googleChartWrapper.draw(); } if (legendToggle === true || legend_toggle === true) { this.grayOutHiddenColumns({ options }); } return; }; this.grayOutHiddenColumns = (param)=>{ let { options } = param; const { googleChartWrapper } = this.props; const dataTable = googleChartWrapper.getDataTable(); if (!dataTable) return; const columnCount = dataTable.getNumberOfColumns(); const hasAHiddenColumn = this.state.hiddenColumns.length > 0; if (hasAHiddenColumn === false) return; const colors = Array.from({ length: columnCount - 1 }).map((dontcare, i)=>{ const columnID = this.getColumnID(dataTable, i + 1); if (this.state.hiddenColumns.includes(columnID)) { return GRAY_COLOR; } else if (options && options.colors) { return options.colors[i]; } else { return DEFAULT_CHART_COLORS[i]; } }); googleChartWrapper.setOptions({ ...options, colors }); googleChartWrapper.draw(); }; this.onResize = ()=>{ const { googleChartWrapper } = this.props; googleChartWrapper.draw(); }; } } class GoogleChartDataTable extends React__namespace.Component { componentDidMount() {} componentWillUnmount() {} shouldComponentUpdate() { return false; } render() { const { google , googleChartWrapper , googleChartDashboard } = this.props; return /*#__PURE__*/ React__namespace.createElement(ContextConsumer, { render: (props)=>{ return /*#__PURE__*/ React__namespace.createElement(GoogleChartDataTableInner, Object.assign({}, props, { google: google, googleChartWrapper: googleChartWrapper, googleChartDashboard: googleChartDashboard })); } }); } } class GoogleChartEvents extends React__namespace.Component { shouldComponentUpdate() { return false; } listenToEvents(param) { let { chartEvents , google , googleChartWrapper } = param; if (!chartEvents) { return; } google.visualization.events.removeAllListeners(googleChartWrapper); for (let event of chartEvents){ var _this = this; const { eventName , callback } = event; google.visualization.events.addListener(googleChartWrapper, eventName, function() { for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){ args[_key] = arguments[_key]; } callback({ chartWrapper: googleChartWrapper, props: _this.props, google: google, eventArgs: args }); }); } } componentDidMount() { var ref; const { google , googleChartWrapper } = this.props; this.listenToEvents({ chartEvents: ((ref = this.propsFromContext) === null || ref === void 0 ? void 0 : ref.chartEvents) || null, google, googleChartWrapper }); } render() { this.props; return /*#__PURE__*/ React__namespace.createElement(ContextConsumer, { render: (propsFromContext)=>{ this.propsFromContext = propsFromContext; return null; } }); } constructor(props){ super(props); this.propsFromContext = null; } } let controlCounter = 0; class GoogleChart extends React__namespace.Component { componentDidMount() { const { options , google , chartType , chartWrapperParams , toolbarItems , getChartEditor , getChartWrapper , } = this.props; const chartConfig = { chartType, options, containerId: this.getGraphID(), ...chartWrapperParams }; const googleChartWrapper = new google.visualization.ChartWrapper(chartConfig); googleChartWrapper.setOptions(options || {}); if (getChartWrapper) { getChartWrapper(googleChartWrapper, google); } const googleChartDashboard = new google.visualization.Dashboard(this.dashboard_ref); const googleChartControls = this.addControls(googleChartWrapper, googleChartDashboard); if (toolbarItems) { google.visualization.drawToolbar(this.toolbar_ref.current, toolbarItems); } let googleChartEditor = null; if (getChartEditor) { googleChartEditor = new google.visualization.ChartEditor(); getChartEditor({ chartEditor: googleChartEditor, chartWrapper: googleChartWrapper, google }); } this.setState({ googleChartEditor, googleChartControls: googleChartControls, googleChartDashboard: googleChartDashboard, googleChartWrapper, isReady: true }); } componentDidUpdate() { if (!this.state.googleChartWrapper) return; if (!this.state.googleChartDashboard) return; if (!this.state.googleChartControls) return; const { controls } = this.props; if (controls) { for(let i = 0; i < controls.length; i += 1){ const { controlType , options , controlWrapperParams } = controls[i]; if (controlWrapperParams && "state" in controlWrapperParams) { this.state.googleChartControls[i].control.setState(controlWrapperParams["state"]); } this.state.googleChartControls[i].control.setOptions(options); this.state.googleChartControls[i].control.setControlType(controlType); } } } shouldComponentUpdate(nextProps, nextState) { return this.state.isReady !== nextState.isReady || nextProps.controls !== this.props.controls; } render() { const { width , height , options , style } = this.props; const divStyle = { height: height || options && options.height, width: width || options && options.width, ...style }; if (this.props.render) { return /*#__PURE__*/ React__namespace.createElement("div", { ref: this.dashboard_ref, style: divStyle }, /*#__PURE__*/ React__namespace.createElement("div", { ref: this.toolbar_ref, id: "toolbar" }), this.props.render({ renderChart: this.renderChart, renderControl: this.renderControl, renderToolbar: this.renderToolBar })); } else { return /*#__PURE__*/ React__namespace.createElement("div", { ref: this.dashboard_ref, style: divStyle }, this.renderControl((param)=>{ let { controlProp } = param; return controlProp.controlPosition !== "bottom"; }), this.renderChart(), this.renderControl((param)=>{ let { controlProp } = param; return controlProp.controlPosition === "bottom"; }), this.renderToolBar()); } } constructor(...args1){ var _this1; super(...args1), _this1 = this; this.state = { googleChartWrapper: null, googleChartDashboard: null, googleChartControls: null, googleChartEditor: null, isReady: false }; this.graphID = null; this.dashboard_ref = /*#__PURE__*/ React__namespace.createRef(); this.toolbar_ref = /*#__PURE__*/ React__namespace.createRef(); this.getGraphID = ()=>{ const { graphID , graph_id } = this.props; let instanceGraphID; if (!graphID && !graph_id) { if (!this.graphID) { instanceGraphID = generateUniqueID(); } else { instanceGraphID = this.graphID; } } else if (graphID && !graph_id) { instanceGraphID = graphID; } else if (graph_id && !graphID) { instanceGraphID = graph_id; } else { instanceGraphID = graphID; } this.graphID = instanceGraphID; return this.graphID; }; this.getControlID = (id, index)=>{ controlCounter += 1; let controlID; if (typeof id === "undefined") { controlID = "googlechart-control-".concat(index, "-").concat(controlCounter); } else { controlID = id; } return controlID; }; this.addControls = (googleChartWrapper, googleChartDashboard)=>{ const { google , controls } = this.props; const googleChartControls = !controls ? null : controls.map((control, i)=>{ const { controlID: controlIDMaybe , controlType , options: controlOptions , controlWrapperParams , } = control; const controlID = this.getControlID(controlIDMaybe, i); return { controlProp: control, control: new google.visualization.ControlWrapper({ containerId: controlID, controlType, options: controlOptions, ...controlWrapperParams }) }; }); if (!googleChartControls) { return null; } googleChartDashboard.bind(googleChartControls.map((param)=>{ let { control } = param; return control; }), googleChartWrapper); for (let chartControl of googleChartControls){ const { control , controlProp } = chartControl; const { controlEvents =[] } = controlProp; for (let event of controlEvents){ var _this = this; const { callback , eventName } = event; google.visualization.events.removeListener(control, eventName, callback); google.visualization.events.addListener(control, eventName, function() { for(var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++){ args[_key] = arguments[_key]; } callback({ chartWrapper: googleChartWrapper, controlWrapper: control, props: _this.props, google: google, eventArgs: args }); }); } } return googleChartControls; }; this.renderChart = ()=>{ const { width , height , options , style , className , rootProps , google } = this.props; const divStyle = { height: height || options && options.height, width: width || options && options.width, ...style }; return /*#__PURE__*/ React__namespace.createElement("div", Object.assign({ id: this.getGraphID(), style: divStyle, className: className }, rootProps), this.state.isReady && this.state.googleChartWrapper !== null ? /*#__PURE__*/ React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/ React__namespace.createElement(GoogleChartDataTable, { googleChartWrapper: this.state.googleChartWrapper, google: google, googleChartDashboard: this.state.googleChartDashboard }), /*#__PURE__*/ React__namespace.createElement(GoogleChartEvents, { googleChartWrapper: this.state.googleChartWrapper, google: google })) : null); }; this.renderControl = function() { let filter = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : (param)=>{ return true; }; return _this1.state.isReady && _this1.state.googleChartControls !== null ? /*#__PURE__*/ React__namespace.createElement(React__namespace.Fragment, null, _this1.state.googleChartControls.filter((param)=>{ let { controlProp , control } = param; return filter({ control, controlProp }); }).map((param)=>{ let { control , controlProp } = param; return /*#__PURE__*/ React__namespace.createElement("div", { key: control.getContainerId(), id: control.getContainerId() }); })) : null; }; this.renderToolBar = ()=>{ if (!this.props.toolbarItems) return null; return /*#__PURE__*/ React__namespace.createElement("div", { ref: this.toolbar_ref }); }; } } class Chart$1 extends (React__namespace.Component) { render() { const { chartLanguage , chartPackages , chartVersion , mapsApiKey , loader , errorElement , } = this.props; return /*#__PURE__*/ React__namespace.createElement(ContextProvider, { value: this.props }, this.state.loadingStatus === "ready" && this.state.google !== null ? /*#__PURE__*/ React__namespace.createElement(GoogleChart, Object.assign({}, this.props, { google: this.state.google })) : this.state.loadingStatus === "errored" && errorElement ? errorElement : loader, /*#__PURE__*/ React__namespace.createElement(LoadGoogleCharts, { chartLanguage: chartLanguage, chartPackages: chartPackages, chartVersion: chartVersion, mapsApiKey: mapsApiKey, onLoad: this.onLoad, onError: this.onError })); } componentDidMount() { this._isMounted = true; } componentWillUnmount() { this._isMounted = false; } isFullyLoaded(google) { const { controls , toolbarItems , getChartEditor } = this.props; return google && google.visualization && google.visualization.ChartWrapper && google.visualization.Dashboard && (!controls || google.visualization.ChartWrapper) && (!getChartEditor || google.visualization.ChartEditor) && (!toolbarItems || google.visualization.drawToolbar); } constructor(...args){ super(...args); this._isMounted = false; this.state = { loadingStatus: "loading", google: null }; this.onLoad = (google1)=>{ if (this.props.onLoad) { this.props.onLoad(google1); } if (this.isFullyLoaded(google1)) { this.onSuccess(google1); } else { // IE11: window.google is not fully set, we have to wait const id = setInterval(()=>{ const google = window.google; if (this._isMounted) { if (google && this.isFullyLoaded(google)) { clearInterval(id); this.onSuccess(google); } } else { clearInterval(id); } }, 1000); } }; this.onSuccess = (google)=>{ this.setState({ loadingStatus: "ready", google }); }; this.onError = ()=>{ this.setState({ loadingStatus: "errored" }); }; } } Chart$1.defaultProps = chartDefaultProps; exports.GoogleDataTableColumnRoleType = void 0; (function(GoogleDataTableColumnRoleType) { GoogleDataTableColumnRoleType["annotation"] = "annotation"; GoogleDataTableColumnRoleType["annotationText"] = "annotationText"; GoogleDataTableColumnRoleType["certainty"] = "certainty"; GoogleDataTableColumnRoleType["emphasis"] = "emphasis"; GoogleDataTableColumnRoleType["interval"] = "interval"; GoogleDataTableColumnRoleType["scope"] = "scope"; GoogleDataTableColumnRoleType["style"] = "style"; GoogleDataTableColumnRoleType["tooltip"] = "tooltip"; GoogleDataTableColumnRoleType["domain"] = "domain"; })(exports.GoogleDataTableColumnRoleType || (exports.GoogleDataTableColumnRoleType = {})); var Chart = Chart$1; exports.Chart = Chart$1; exports["default"] = Chart; //# sourceMappingURL=index.cjs.map