angular-google-charts
Version:
A wrapper for the Google Charts library written with Angular
1 lines • 71.8 kB
Source Map (JSON)
{"version":3,"file":"angular-google-charts.mjs","sources":["../../../projects/angular-google-charts/src/lib/components/chart-editor/chart-editor-ref.ts","../../../projects/angular-google-charts/src/lib/types/chart-type.ts","../../../projects/angular-google-charts/src/lib/helpers/chart.helper.ts","../../../projects/angular-google-charts/src/lib/types/google-charts-config.ts","../../../projects/angular-google-charts/src/lib/services/script-loader.service.ts","../../../projects/angular-google-charts/src/lib/components/chart-editor/chart-editor.component.ts","../../../projects/angular-google-charts/src/lib/services/data-table.service.ts","../../../projects/angular-google-charts/src/lib/helpers/id.helper.ts","../../../projects/angular-google-charts/src/lib/types/control-type.ts","../../../projects/angular-google-charts/src/lib/components/control-wrapper/control-wrapper.component.ts","../../../projects/angular-google-charts/src/lib/components/dashboard/dashboard.component.ts","../../../projects/angular-google-charts/src/lib/components/google-chart/google-chart.component.ts","../../../projects/angular-google-charts/src/lib/components/chart-wrapper/chart-wrapper.component.ts","../../../projects/angular-google-charts/src/lib/google-charts.module.ts","../../../projects/angular-google-charts/src/index.ts","../../../projects/angular-google-charts/src/angular-google-charts.ts"],"sourcesContent":["/// <reference path=\"./chart-editor.ts\" />\n\nimport { Observable, Subject } from 'rxjs';\n\nexport type EditChartResult = google.visualization.ChartWrapper | null;\n\nexport class ChartEditorRef {\n private readonly doneSubject = new Subject<EditChartResult>();\n\n constructor(private readonly editor: google.visualization.ChartEditor) {\n this.addEventListeners();\n }\n\n /**\n * Gets an observable that is notified when the dialog is saved.\n * Emits either the result if the dialog was saved or `null` if editing was cancelled.\n */\n public afterClosed(): Observable<EditChartResult> {\n return this.doneSubject.asObservable();\n }\n\n /**\n * Stops editing the chart and closes the dialog.\n */\n public cancel() {\n this.editor.closeDialog();\n }\n\n private addEventListeners() {\n google.visualization.events.addOneTimeListener(this.editor, 'ok', () => {\n google.visualization.events.removeAllListeners(this.editor);\n\n const updatedChartWrapper = this.editor.getChartWrapper();\n\n this.doneSubject.next(updatedChartWrapper);\n this.doneSubject.complete();\n });\n\n google.visualization.events.addOneTimeListener(this.editor, 'cancel', () => {\n google.visualization.events.removeAllListeners(this.editor);\n\n this.doneSubject.next(null);\n this.doneSubject.complete();\n });\n }\n}\n","export enum ChartType {\n AnnotationChart = 'AnnotationChart',\n AreaChart = 'AreaChart',\n Bar = 'Bar',\n BarChart = 'BarChart',\n BubbleChart = 'BubbleChart',\n Calendar = 'Calendar',\n CandlestickChart = 'CandlestickChart',\n ColumnChart = 'ColumnChart',\n ComboChart = 'ComboChart',\n PieChart = 'PieChart',\n Gantt = 'Gantt',\n Gauge = 'Gauge',\n GeoChart = 'GeoChart',\n Histogram = 'Histogram',\n Line = 'Line',\n LineChart = 'LineChart',\n Map = 'Map',\n OrgChart = 'OrgChart',\n Sankey = 'Sankey',\n Scatter = 'Scatter',\n ScatterChart = 'ScatterChart',\n SteppedAreaChart = 'SteppedAreaChart',\n Table = 'Table',\n Timeline = 'Timeline',\n TreeMap = 'TreeMap',\n WordTree = 'WordTree'\n}\n","import { ChartType } from '../types/chart-type';\nimport { GoogleChartsConfig } from '../types/google-charts-config';\n\nconst ChartTypesToPackages = {\n [ChartType.AnnotationChart]: 'annotationchart',\n [ChartType.AreaChart]: 'corechart',\n [ChartType.Bar]: 'bar',\n [ChartType.BarChart]: 'corechart',\n [ChartType.BubbleChart]: 'corechart',\n [ChartType.Calendar]: 'calendar',\n [ChartType.CandlestickChart]: 'corechart',\n [ChartType.ColumnChart]: 'corechart',\n [ChartType.ComboChart]: 'corechart',\n [ChartType.PieChart]: 'corechart',\n [ChartType.Gantt]: 'gantt',\n [ChartType.Gauge]: 'gauge',\n [ChartType.GeoChart]: 'geochart',\n [ChartType.Histogram]: 'corechart',\n [ChartType.Line]: 'line',\n [ChartType.LineChart]: 'corechart',\n [ChartType.Map]: 'map',\n [ChartType.OrgChart]: 'orgchart',\n [ChartType.Sankey]: 'sankey',\n [ChartType.Scatter]: 'scatter',\n [ChartType.ScatterChart]: 'corechart',\n [ChartType.SteppedAreaChart]: 'corechart',\n [ChartType.Table]: 'table',\n [ChartType.Timeline]: 'timeline',\n [ChartType.TreeMap]: 'treemap',\n [ChartType.WordTree]: 'wordtree'\n};\n\nexport function getPackageForChart(type: ChartType): string {\n return ChartTypesToPackages[type];\n}\n\nexport function getDefaultConfig(): GoogleChartsConfig {\n return {\n version: 'current',\n safeMode: false\n };\n}\n","import { inject, InjectFlags, InjectionToken } from '@angular/core';\nimport { Observable, of } from 'rxjs';\n\nimport { getDefaultConfig } from '../helpers/chart.helper';\n\nexport interface GoogleChartsConfig {\n /**\n * This setting lets you specify a key that you may use with Geochart and Map Chart.\n * You may want to do this rather than using the default behavior which may result in\n * occasional throttling of service for your users.\n *\n * Only available when using Google Charts 45 or higher.\n *\n * {@link https://developers.google.com/chart/interactive/docs/basic_load_libs#load-settings Parameter documentation }\n * {@link https://developers.google.com/chart/interactive/docs/gallery/geochart GeoChart Documentation}\n */\n mapsApiKey?: string;\n\n /**\n * Which version of Google Charts to use.\n *\n * Please note that this library does only work with Google Charts 45 or higher.\n *\n * @description\n * Can be either a number specifying a\n * {@link https://developers.google.com/chart/interactive/docs/release_notes#current:-january-6,-2020 frozen version } of Google Charts\n * or one of the special versions `current` and `upcoming`.\n *\n * Defaults to `current`.\n *\n * {@link https://developers.google.com/chart/interactive/docs/basic_load_libs#basic-library-loading Offical Documentation}\n */\n version?: string;\n\n /**\n * When set to true, all charts and tooltips that generate HTML from user-supplied data will sanitize it\n * by stripping out unsafe elements and attributes.\n *\n * Only available when using GoogleCharts 47 or higher.\n *\n * {@link https://developers.google.com/chart/interactive/docs/basic_load_libs#load-settings Parameter documentation }\n */\n safeMode?: boolean;\n}\n\nexport const GOOGLE_CHARTS_CONFIG = new InjectionToken<Observable<GoogleChartsConfig>>('GOOGLE_CHARTS_CONFIG');\nexport const GOOGLE_CHARTS_LAZY_CONFIG = new InjectionToken<Observable<GoogleChartsConfig>>(\n 'GOOGLE_CHARTS_LAZY_CONFIG',\n {\n providedIn: 'root',\n factory: () => {\n const configFromModule = inject(GOOGLE_CHARTS_CONFIG, InjectFlags.Optional);\n return of({ ...getDefaultConfig(), ...(configFromModule || {}) });\n }\n }\n);\n","import { Inject, Injectable, LOCALE_ID, NgZone } from '@angular/core';\nimport { Observable, of, Subject } from 'rxjs';\nimport { map, mergeMap, switchMap } from 'rxjs/operators';\n\nimport { getDefaultConfig } from '../helpers/chart.helper';\nimport { GoogleChartsConfig, GOOGLE_CHARTS_LAZY_CONFIG } from '../types/google-charts-config';\n\n@Injectable()\nexport class ScriptLoaderService {\n private readonly scriptSource = 'https://www.gstatic.com/charts/loader.js';\n private readonly scriptLoadSubject = new Subject<void>();\n\n constructor(\n private zone: NgZone,\n @Inject(LOCALE_ID) private localeId: string,\n @Inject(GOOGLE_CHARTS_LAZY_CONFIG) private readonly config$: Observable<GoogleChartsConfig>\n ) {}\n\n /**\n * Checks whether `google.charts` is available.\n *\n * If not, it can be loaded by calling `loadChartPackages`.\n *\n * @returns `true` if `google.charts` is available, `false` otherwise.\n */\n public isGoogleChartsAvailable(): boolean {\n if (typeof google === 'undefined' || typeof google.charts === 'undefined') {\n return false;\n }\n\n return true;\n }\n\n /**\n * Loads the Google Chart script and the provided chart packages.\n * Can be called multiple times to load more packages.\n *\n * When called without any arguments, this will just load the default package\n * containing the namespaces `google.charts` and `google.visualization` without any charts.\n *\n * @param packages The packages to load.\n * @returns A stream emitting as soon as the chart packages are loaded.\n */\n public loadChartPackages(...packages: string[]): Observable<null> {\n return this.loadGoogleCharts().pipe(\n mergeMap(() => this.config$),\n map(config => {\n return { ...getDefaultConfig(), ...(config || {}) };\n }),\n switchMap((googleChartsConfig: GoogleChartsConfig) => {\n return new Observable<null>(observer => {\n const config = {\n packages,\n language: this.localeId,\n mapsApiKey: googleChartsConfig.mapsApiKey,\n safeMode: googleChartsConfig.safeMode\n };\n\n google.charts.load(googleChartsConfig.version!, config);\n google.charts.setOnLoadCallback(() => {\n this.zone.run(() => {\n observer.next();\n observer.complete();\n });\n });\n });\n })\n );\n }\n\n /**\n * Loads the Google Charts script. After the script is loaded, `google.charts` is defined.\n *\n * @returns A stream emitting as soon as loading has completed.\n * If the google charts script is already loaded, the stream emits immediately.\n */\n private loadGoogleCharts(): Observable<void> {\n if (this.isGoogleChartsAvailable()) {\n return of(undefined);\n } else if (!this.isLoadingGoogleCharts()) {\n const script = this.createGoogleChartsScript();\n script.onload = () => {\n this.zone.run(() => {\n this.scriptLoadSubject.next();\n this.scriptLoadSubject.complete();\n });\n };\n\n script.onerror = () => {\n this.zone.run(() => {\n console.error('Failed to load the google charts script!');\n this.scriptLoadSubject.error(new Error('Failed to load the google charts script!'));\n });\n };\n }\n\n return this.scriptLoadSubject.asObservable();\n }\n\n private isLoadingGoogleCharts() {\n return this.getGoogleChartsScript() != null;\n }\n\n private getGoogleChartsScript(): HTMLScriptElement | undefined {\n const pageScripts = Array.from(document.getElementsByTagName('script'));\n return pageScripts.find(script => script.src === this.scriptSource);\n }\n\n private createGoogleChartsScript(): HTMLScriptElement {\n const script = document.createElement('script');\n script.type = 'text/javascript';\n script.src = this.scriptSource;\n script.async = true;\n document.getElementsByTagName('head')[0].appendChild(script);\n return script;\n }\n}\n","/// <reference path=\"./chart-editor.ts\" />\n\nimport { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\nimport { Subject } from 'rxjs';\n\nimport { ScriptLoaderService } from '../../services/script-loader.service';\nimport { ChartBase } from '../chart-base/chart-base.component';\n\nimport { ChartEditorRef } from './chart-editor-ref';\n\n@Component({\n selector: 'chart-editor',\n template: `<ng-content></ng-content>`,\n host: { class: 'chart-editor' },\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ChartEditorComponent implements OnInit {\n private editor: google.visualization.ChartEditor | undefined;\n private initializedSubject = new Subject<google.visualization.ChartEditor>();\n\n constructor(private scriptLoaderService: ScriptLoaderService) {}\n\n /**\n * Emits as soon as the chart editor is fully initialized.\n */\n public get initialized$() {\n return this.initializedSubject.asObservable();\n }\n\n public ngOnInit() {\n this.scriptLoaderService.loadChartPackages('charteditor').subscribe(() => {\n this.editor = new google.visualization.ChartEditor();\n this.initializedSubject.next(this.editor);\n this.initializedSubject.complete();\n });\n }\n\n /**\n * Opens the chart editor as an embedded dialog box on the page.\n * If the editor gets saved, the components' chart will be updated with the result.\n *\n * @param component The chart to be edited.\n * @returns A reference to the open editor.\n */\n public editChart(component: ChartBase): ChartEditorRef;\n public editChart(component: ChartBase, options: google.visualization.ChartEditorOptions): ChartEditorRef;\n public editChart(component: ChartBase, options?: google.visualization.ChartEditorOptions) {\n if (!component.chartWrapper) {\n throw new Error(\n 'Chart wrapper is `undefined`. Please wait for the `initialized$` observable before trying to edit a chart.'\n );\n }\n if (!this.editor) {\n throw new Error(\n 'Chart editor is `undefined`. Please wait for the `initialized$` observable before trying to edit a chart.'\n );\n }\n\n const handle = new ChartEditorRef(this.editor);\n this.editor.openDialog(component.chartWrapper, options || {});\n\n handle.afterClosed().subscribe(result => {\n if (result) {\n component.chartWrapper = result;\n }\n });\n\n return handle;\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { Column, Row } from '../components/chart-base/chart-base.component';\nimport { Formatter } from '../types/formatter';\n\n@Injectable({ providedIn: 'root' })\nexport class DataTableService {\n public create(\n data: Row[] | undefined,\n columns?: Column[],\n formatters?: Formatter[]\n ): google.visualization.DataTable | undefined {\n if (data == null) {\n return undefined;\n }\n\n let firstRowIsData = true;\n if (columns != null) {\n firstRowIsData = false;\n }\n\n const dataTable = google.visualization.arrayToDataTable(this.getDataAsTable(data, columns), firstRowIsData);\n if (formatters) {\n this.applyFormatters(dataTable, formatters);\n }\n\n return dataTable;\n }\n\n private getDataAsTable(data: Row[], columns: Column[] | undefined): (Row | Column[])[] {\n if (columns) {\n return [columns, ...data];\n } else {\n return data;\n }\n }\n\n private applyFormatters(dataTable: google.visualization.DataTable, formatters: Formatter[]): void {\n for (const val of formatters) {\n val.formatter.format(dataTable, val.colIndex);\n }\n }\n}\n","/**\n * Generates a random ID which can be used to uniquely identify an element.\n */\nexport function generateRandomId() {\n // Math.random should be unique because of its seeding algorithm.\n // Convert it to base 36 (numbers + letters), and grab the first 9 characters\n // after the decimal.\n return '_' + Math.random().toString(36).substr(2, 9);\n}\n","export enum FilterType {\n Category = 'CategoryFilter',\n ChartRange = 'ChartRangeFilter',\n DateRange = 'DateRangeFilter',\n NumberRange = 'NumberRangeFilter',\n String = 'StringFilter'\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n EventEmitter,\n HostBinding,\n Input,\n OnChanges,\n OnInit,\n Output,\n SimpleChanges\n} from '@angular/core';\nimport { ReplaySubject } from 'rxjs';\n\nimport { generateRandomId } from '../../helpers/id.helper';\nimport { ScriptLoaderService } from '../../services/script-loader.service';\nimport { FilterType } from '../../types/control-type';\nimport { ChartErrorEvent, ChartReadyEvent } from '../../types/events';\nimport { ChartBase } from '../chart-base/chart-base.component';\n\n@Component({\n selector: 'control-wrapper',\n template: '',\n host: { class: 'control-wrapper' },\n exportAs: 'controlWrapper',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ControlWrapperComponent implements OnInit, OnChanges {\n /**\n * Charts controlled by this control wrapper. Can be a single chart or an array of charts.\n */\n @Input()\n public for!: ChartBase | ChartBase[];\n\n /**\n * The class name of the control.\n * The `google.visualization` package name can be omitted for Google controls.\n *\n * @example\n *\n * ```html\n * <control-wrapper type=\"CategoryFilter\"></control-wrapper>\n * ```\n */\n @Input()\n public type!: FilterType;\n\n /**\n * An object describing the options for the control.\n * You can use either JavaScript literal notation, or provide a handle to the object.\n *\n * @example\n *\n * ```html\n * <control-wrapper [options]=\"{'filterColumnLabel': 'Age', 'minValue': 10, 'maxValue': 80}\"></control-wrapper>\n * ```\n */\n @Input()\n public options?: object;\n\n /**\n * An object describing the state of the control.\n * The state collects all the variables that the user operating the control can affect.\n *\n * For example, a range slider state can be described in term of the positions that the low and high thumb\n * of the slider occupy.\n * You can use either Javascript literal notation, or provide a handle to the object.\n *\n * @example\n *\n * ```html\n * <control-wrapper [state]=\"{'lowValue': 20, 'highValue': 50}\"></control-wrapper>\n * ```\n */\n @Input()\n public state?: object;\n\n /**\n * Emits when an error occurs when attempting to render the control.\n */\n @Output()\n public error = new EventEmitter<ChartErrorEvent>();\n\n /**\n * The control is ready to accept user interaction and for external method calls.\n *\n * Alternatively, you can listen for a ready event on the dashboard holding the control\n * and call control methods only after the event was fired.\n */\n @Output()\n public ready = new EventEmitter<ChartReadyEvent>();\n\n /**\n * Emits when the user interacts with the control, affecting its state.\n * For example, a `stateChange` event will be emitted whenever you move the thumbs of a range slider control.\n *\n * To retrieve an updated control state after the event fired, call `ControlWrapper.getState()`.\n */\n @Output()\n public stateChange = new EventEmitter<unknown>();\n\n /**\n * A generated id assigned to this components DOM element.\n */\n @HostBinding('id')\n public readonly id = generateRandomId();\n\n private _controlWrapper?: google.visualization.ControlWrapper;\n private wrapperReadySubject = new ReplaySubject<google.visualization.ControlWrapper>(1);\n\n constructor(private loaderService: ScriptLoaderService) {}\n\n /**\n * Emits after the `ControlWrapper` was created.\n */\n public get wrapperReady$() {\n return this.wrapperReadySubject.asObservable();\n }\n\n public get controlWrapper(): google.visualization.ControlWrapper {\n if (!this._controlWrapper) {\n throw new Error(`Cannot access the control wrapper before it being initialized.`);\n }\n\n return this._controlWrapper;\n }\n\n public ngOnInit() {\n this.loaderService.loadChartPackages('controls').subscribe(() => {\n this.createControlWrapper();\n });\n }\n\n public ngOnChanges(changes: SimpleChanges): void {\n if (!this._controlWrapper) {\n return;\n }\n\n if (changes.type) {\n this._controlWrapper.setControlType(this.type);\n }\n\n if (changes.options) {\n this._controlWrapper.setOptions(this.options || {});\n }\n\n if (changes.state) {\n this._controlWrapper.setState(this.state || {});\n }\n }\n\n private createControlWrapper() {\n this._controlWrapper = new google.visualization.ControlWrapper({\n containerId: this.id,\n controlType: this.type,\n state: this.state,\n options: this.options\n });\n\n this.addEventListeners();\n this.wrapperReadySubject.next(this._controlWrapper);\n }\n\n private addEventListeners() {\n google.visualization.events.removeAllListeners(this._controlWrapper);\n\n google.visualization.events.addListener(this._controlWrapper, 'ready', (event: ChartReadyEvent) =>\n this.ready.emit(event)\n );\n google.visualization.events.addListener(this._controlWrapper, 'error', (event: ChartErrorEvent) =>\n this.error.emit(event)\n );\n google.visualization.events.addListener(this._controlWrapper, 'statechange', (event: unknown) =>\n this.stateChange.emit(event)\n );\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ContentChildren,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n OnInit,\n Output,\n QueryList,\n SimpleChanges\n} from '@angular/core';\nimport { combineLatest } from 'rxjs';\n\nimport { DataTableService } from '../../services/data-table.service';\nimport { ScriptLoaderService } from '../../services/script-loader.service';\nimport { ChartErrorEvent } from '../../types/events';\nimport { Formatter } from '../../types/formatter';\nimport { Column, Row } from '../chart-base/chart-base.component';\nimport { ControlWrapperComponent } from '../control-wrapper/control-wrapper.component';\n\n@Component({\n selector: 'dashboard',\n template: '<ng-content></ng-content>',\n changeDetection: ChangeDetectionStrategy.OnPush,\n exportAs: 'dashboard',\n host: { class: 'dashboard' }\n})\nexport class DashboardComponent implements OnInit, OnChanges {\n /**\n * Data used to initialize the table.\n *\n * This must also contain all roles that are set in the `columns` property.\n */\n @Input()\n public data!: Row[];\n\n /**\n * The columns the `data` consists of.\n * The length of this array must match the length of each row in the `data` object.\n *\n * If {@link https://developers.google.com/chart/interactive/docs/roles roles} should be applied, they must be included in this array as well.\n */\n @Input()\n public columns?: Column[];\n\n /**\n * Used to change the displayed value of the specified column in all rows.\n *\n * Each array element must consist of an instance of a [`formatter`](https://developers.google.com/chart/interactive/docs/reference#formatters)\n * and the index of the column you want the formatter to get applied to.\n */\n @Input()\n public formatters?: Formatter[];\n\n /**\n * The dashboard has completed drawing and is ready to accept changes.\n *\n * The ready event will also fire:\n * - after the completion of a dashboard refresh triggered by a user or programmatic interaction with one of the controls,\n * - after redrawing any chart on the dashboard.\n */\n @Output()\n public ready = new EventEmitter<void>();\n\n /**\n * Emits when an error occurs when attempting to render the dashboard.\n * One or more of the controls and charts that are part of the dashboard may have failed rendering.\n */\n @Output()\n public error = new EventEmitter<ChartErrorEvent>();\n\n @ContentChildren(ControlWrapperComponent)\n private controlWrappers!: QueryList<ControlWrapperComponent>;\n\n private dashboard?: google.visualization.Dashboard;\n private dataTable?: google.visualization.DataTable;\n private initialized = false;\n\n constructor(\n private element: ElementRef,\n private loaderService: ScriptLoaderService,\n private dataTableService: DataTableService\n ) {}\n\n public ngOnInit() {\n this.loaderService.loadChartPackages('controls').subscribe(() => {\n this.dataTable = this.dataTableService.create(this.data, this.columns, this.formatters);\n this.createDashboard();\n this.initialized = true;\n });\n }\n\n public ngOnChanges(changes: SimpleChanges): void {\n if (!this.initialized) {\n return;\n }\n\n if (changes.data || changes.columns || changes.formatters) {\n this.dataTable = this.dataTableService.create(this.data, this.columns, this.formatters);\n this.dashboard!.draw(this.dataTable!);\n }\n }\n\n private createDashboard(): void {\n // TODO: This should happen in the control wrapper\n // However, I don't yet know how to do this because then `bind()` would get called multiple times\n // for the same control if something changes. This is not supported by google charts as far as I can tell\n // from their source code.\n const controlWrappersReady$ = this.controlWrappers.map(control => control.wrapperReady$);\n const chartsReady$ = this.controlWrappers\n .map(control => control.for)\n .map(charts => {\n if (Array.isArray(charts)) {\n // CombineLatest waits for all observables\n return combineLatest(charts.map(chart => chart.wrapperReady$));\n } else {\n return charts.wrapperReady$;\n }\n });\n\n // We have to wait for all chart wrappers and control wrappers to be initialized\n // before we can compose them together to create the dashboard\n combineLatest([...controlWrappersReady$, ...chartsReady$]).subscribe(() => {\n this.dashboard = new google.visualization.Dashboard(this.element.nativeElement);\n this.initializeBindings();\n this.registerEvents();\n this.dashboard.draw(this.dataTable!);\n });\n }\n\n private registerEvents(): void {\n google.visualization.events.removeAllListeners(this.dashboard);\n\n const registerDashEvent = (object: any, eventName: string, callback: Function) => {\n google.visualization.events.addListener(object, eventName, callback);\n };\n\n registerDashEvent(this.dashboard, 'ready', () => this.ready.emit());\n registerDashEvent(this.dashboard, 'error', (error: ChartErrorEvent) => this.error.emit(error));\n }\n\n private initializeBindings(): void {\n this.controlWrappers.forEach(control => {\n if (Array.isArray(control.for)) {\n const chartWrappers = control.for.map(chart => chart.chartWrapper);\n this.dashboard!.bind(control.controlWrapper, chartWrappers);\n } else {\n this.dashboard!.bind(control.controlWrapper, control.for.chartWrapper);\n }\n });\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n OnDestroy,\n OnInit,\n Optional,\n Output,\n SimpleChanges\n} from '@angular/core';\nimport { fromEvent, Observable, ReplaySubject, Subscription } from 'rxjs';\nimport { debounceTime } from 'rxjs/operators';\n\nimport { getPackageForChart } from '../../helpers/chart.helper';\nimport { DataTableService } from '../../services/data-table.service';\nimport { ScriptLoaderService } from '../../services/script-loader.service';\nimport { ChartType } from '../../types/chart-type';\nimport {\n ChartErrorEvent,\n ChartMouseLeaveEvent,\n ChartMouseOverEvent,\n ChartReadyEvent,\n ChartSelectionChangedEvent\n} from '../../types/events';\nimport { Formatter } from '../../types/formatter';\nimport { ChartBase, Column, Row } from '../chart-base/chart-base.component';\nimport { DashboardComponent } from '../dashboard/dashboard.component';\n\n@Component({\n selector: 'google-chart',\n template: '',\n styles: [':host { width: fit-content; display: block; }'],\n host: { class: 'google-chart' },\n exportAs: 'googleChart',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class GoogleChartComponent implements ChartBase, OnInit, OnChanges, OnDestroy {\n /**\n * The type of the chart to create.\n */\n @Input()\n public type!: ChartType;\n\n /**\n * Data used to initialize the table.\n *\n * This must also contain all roles that are set in the `columns` property.\n */\n @Input()\n public data!: Row[];\n\n /**\n * The columns the `data` consists of.\n * The length of this array must match the length of each row in the `data` object.\n *\n * If {@link https://developers.google.com/chart/interactive/docs/roles roles} should be applied, they must be included in this array as well.\n */\n @Input()\n public columns?: Column[];\n\n /**\n * A convenience property used to set the title of the chart.\n *\n * This can also be set using `options.title`, which, if existant, will overwrite this value.\n */\n @Input()\n public title?: string;\n\n /**\n * A convenience property used to set the width of the chart in pixels.\n *\n * This can also be set using `options.width`, which, if existant, will overwrite this value.\n */\n @Input()\n public width?: number;\n\n /**\n * A convenience property used to set the height of the chart in pixels.\n *\n * This can also be set using `options.height`, which, if existant, will overwrite this value.\n */\n @Input()\n public height?: number;\n\n /**\n * The chart-specific options. All options listen in the Google Charts documentation applying\n * to the chart type specified can be used here.\n */\n @Input()\n public options: object = {};\n\n /**\n * Used to change the displayed value of the specified column in all rows.\n *\n * Each array element must consist of an instance of a [`formatter`](https://developers.google.com/chart/interactive/docs/reference#formatters)\n * and the index of the column you want the formatter to get applied to.\n */\n @Input()\n public formatters?: Formatter[];\n\n /**\n * If this is set to `true`, the chart will be redrawn if the browser window is resized.\n * Defaults to `false` and should only be used when specifying the width or height of the chart\n * in percent.\n *\n * Note that this can impact performance.\n */\n @Input()\n public dynamicResize = false;\n\n @Output()\n public ready = new EventEmitter<ChartReadyEvent>();\n\n @Output()\n public error = new EventEmitter<ChartErrorEvent>();\n\n @Output()\n public select = new EventEmitter<ChartSelectionChangedEvent>();\n\n @Output()\n public mouseover = new EventEmitter<ChartMouseOverEvent>();\n\n @Output()\n public mouseleave = new EventEmitter<ChartMouseLeaveEvent>();\n\n private resizeSubscription?: Subscription;\n\n private dataTable: google.visualization.DataTable | undefined;\n private wrapper: google.visualization.ChartWrapper | undefined;\n private wrapperReadySubject = new ReplaySubject<google.visualization.ChartWrapper>(1);\n private initialized = false;\n private eventListeners = new Map<any, { eventName: string; callback: Function; handle: any }>();\n\n constructor(\n private element: ElementRef,\n private scriptLoaderService: ScriptLoaderService,\n private dataTableService: DataTableService,\n @Optional() private dashboard?: DashboardComponent\n ) {}\n\n public get chart(): google.visualization.ChartBase | null {\n return this.chartWrapper.getChart();\n }\n\n public get wrapperReady$(): Observable<google.visualization.ChartWrapper> {\n return this.wrapperReadySubject.asObservable();\n }\n\n public get chartWrapper(): google.visualization.ChartWrapper {\n if (!this.wrapper) {\n throw new Error('Trying to access the chart wrapper before it was fully initialized');\n }\n\n return this.wrapper;\n }\n\n public set chartWrapper(wrapper: google.visualization.ChartWrapper) {\n this.wrapper = wrapper;\n this.drawChart();\n }\n\n public ngOnInit() {\n // We don't need to load any chart packages, the chart wrapper will handle this for us\n this.scriptLoaderService.loadChartPackages(getPackageForChart(this.type)).subscribe(() => {\n this.dataTable = this.dataTableService.create(this.data, this.columns, this.formatters);\n\n // Only ever create the wrapper once to allow animations to happen when something changes.\n this.wrapper = new google.visualization.ChartWrapper({\n container: this.element.nativeElement,\n chartType: this.type,\n dataTable: this.dataTable,\n options: this.mergeOptions()\n });\n\n this.registerChartEvents();\n\n this.wrapperReadySubject.next(this.wrapper);\n this.initialized = true;\n\n this.drawChart();\n });\n }\n\n public ngOnChanges(changes: SimpleChanges) {\n if (changes.dynamicResize) {\n this.updateResizeListener();\n }\n\n if (this.initialized) {\n let shouldRedraw = false;\n if (changes.data || changes.columns || changes.formatters) {\n this.dataTable = this.dataTableService.create(this.data, this.columns, this.formatters);\n this.wrapper!.setDataTable(this.dataTable!);\n shouldRedraw = true;\n }\n\n if (changes.type) {\n this.wrapper!.setChartType(this.type);\n shouldRedraw = true;\n }\n\n if (changes.options || changes.width || changes.height || changes.title) {\n this.wrapper!.setOptions(this.mergeOptions());\n shouldRedraw = true;\n }\n\n if (shouldRedraw) {\n this.drawChart();\n }\n }\n }\n\n public ngOnDestroy(): void {\n this.unsubscribeToResizeIfSubscribed();\n }\n\n /**\n * For listening to events other than the most common ones (available via Output properties).\n *\n * Can be called after the chart emits that it's \"ready\".\n *\n * Returns a handle that can be used for `removeEventListener`.\n */\n public addEventListener(eventName: string, callback: Function): any {\n const handle = this.registerChartEvent(this.chart, eventName, callback);\n this.eventListeners.set(handle, { eventName, callback, handle });\n return handle;\n }\n\n public removeEventListener(handle: any): void {\n const entry = this.eventListeners.get(handle);\n if (entry) {\n google.visualization.events.removeListener(entry.handle);\n this.eventListeners.delete(handle);\n }\n }\n\n private updateResizeListener() {\n this.unsubscribeToResizeIfSubscribed();\n\n if (this.dynamicResize) {\n this.resizeSubscription = fromEvent(window, 'resize', { passive: true })\n .pipe(debounceTime(100))\n .subscribe(() => {\n if (this.initialized) {\n this.drawChart();\n }\n });\n }\n }\n\n private unsubscribeToResizeIfSubscribed() {\n if (this.resizeSubscription != null) {\n this.resizeSubscription.unsubscribe();\n this.resizeSubscription = undefined;\n }\n }\n\n private mergeOptions(): object {\n return {\n title: this.title,\n width: this.width,\n height: this.height,\n ...this.options\n };\n }\n\n private registerChartEvents() {\n google.visualization.events.removeAllListeners(this.wrapper);\n\n this.registerChartEvent(this.wrapper, 'ready', () => {\n // This could also be done by checking if we already subscribed to the events\n google.visualization.events.removeAllListeners(this.chart);\n this.registerChartEvent(this.chart, 'onmouseover', (event: ChartMouseOverEvent) => this.mouseover.emit(event));\n this.registerChartEvent(this.chart, 'onmouseout', (event: ChartMouseLeaveEvent) => this.mouseleave.emit(event));\n this.registerChartEvent(this.chart, 'select', () => {\n const selection = this.chart!.getSelection();\n this.select.emit({ selection });\n });\n this.eventListeners.forEach(x => (x.handle = this.registerChartEvent(this.chart, x.eventName, x.callback)));\n\n this.ready.emit({ chart: this.chart! });\n });\n\n this.registerChartEvent(this.wrapper, 'error', (error: ChartErrorEvent) => this.error.emit(error));\n }\n\n private registerChartEvent(object: any, eventName: string, callback: Function): any {\n return google.visualization.events.addListener(object, eventName, callback);\n }\n\n private drawChart() {\n if (this.dashboard != null) {\n // If this chart is part of a dashboard, the dashboard takes care of drawing\n return;\n }\n\n this.wrapper!.draw();\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n OnInit,\n Output,\n SimpleChanges\n} from '@angular/core';\nimport { ReplaySubject } from 'rxjs';\n\nimport { ScriptLoaderService } from '../../services/script-loader.service';\nimport { ChartErrorEvent, ChartReadyEvent, ChartSelectionChangedEvent } from '../../types/events';\nimport { ChartBase } from '../chart-base/chart-base.component';\n\n@Component({\n selector: 'chart-wrapper',\n template: '',\n styles: [':host { width: fit-content; display: block; }'],\n host: { class: 'chart-wrapper' },\n exportAs: 'chartWrapper',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ChartWrapperComponent implements ChartBase, OnChanges, OnInit {\n /**\n * Either a JSON object defining the chart, or a serialized string version of that object.\n * The format of this object is shown in the\n * {@link https://developers.google.com/chart/interactive/docs/reference#google.visualization.drawchart `drawChart()`} documentation.\n *\n * The `container` and `containerId` will be overwritten by this component to allow\n * rendering the chart into the components' template.\n */\n @Input()\n public specs?: google.visualization.ChartSpecs;\n\n @Output()\n public error = new EventEmitter<ChartErrorEvent>();\n\n @Output()\n public ready = new EventEmitter<ChartReadyEvent>();\n\n @Output()\n public select = new EventEmitter<ChartSelectionChangedEvent>();\n\n private wrapper: google.visualization.ChartWrapper | undefined;\n private wrapperReadySubject = new ReplaySubject<google.visualization.ChartWrapper>(1);\n private initialized = false;\n\n constructor(private element: ElementRef, private scriptLoaderService: ScriptLoaderService) {}\n\n public get chart(): google.visualization.ChartBase | null {\n return this.chartWrapper.getChart();\n }\n\n public get wrapperReady$() {\n return this.wrapperReadySubject.asObservable();\n }\n\n public get chartWrapper(): google.visualization.ChartWrapper {\n if (!this.wrapper) {\n throw new Error('Cannot access the chart wrapper before initialization.');\n }\n\n return this.wrapper;\n }\n\n public set chartWrapper(wrapper: google.visualization.ChartWrapper) {\n this.wrapper = wrapper;\n this.drawChart();\n }\n\n public ngOnInit() {\n // We don't need to load any chart packages, the chart wrapper will handle this else for us\n this.scriptLoaderService.loadChartPackages().subscribe(() => {\n if (!this.specs) {\n this.specs = {} as google.visualization.ChartSpecs;\n }\n\n const { containerId, container, ...specs } = this.specs;\n\n // Only ever create the wrapper once to allow animations to happen if something changes.\n this.wrapper = new google.visualization.ChartWrapper({\n ...specs,\n container: this.element.nativeElement\n });\n this.registerChartEvents();\n\n this.wrapperReadySubject.next(this.wrapper);\n\n this.drawChart();\n this.initialized = true;\n });\n }\n\n public ngOnChanges(changes: SimpleChanges) {\n if (!this.initialized) {\n return;\n }\n\n if (changes.specs) {\n this.updateChart();\n this.drawChart();\n }\n }\n\n private updateChart() {\n if (!this.specs) {\n // When creating the wrapper with empty specs, the google charts library will show an error\n // If we don't do this, a javascript error will be thrown, which is not as visible to the user\n this.specs = {} as google.visualization.ChartSpecs;\n }\n\n // The typing here are not correct. These methods accept `undefined` as well.\n // That's why we have to cast to `any`\n\n this.wrapper!.setChartType(this.specs.chartType);\n this.wrapper!.setDataTable(this.specs.dataTable as any);\n this.wrapper!.setDataSourceUrl(this.specs.dataSourceUrl as any);\n this.wrapper!.setDataSourceUrl(this.specs.dataSourceUrl as any);\n this.wrapper!.setQuery(this.specs.query as any);\n this.wrapper!.setOptions(this.specs.options as any);\n this.wrapper!.setRefreshInterval(this.specs.refreshInterval as any);\n this.wrapper!.setView(this.specs.view);\n }\n\n private drawChart() {\n if (this.wrapper) {\n this.wrapper.draw();\n }\n }\n\n private registerChartEvents() {\n google.visualization.events.removeAllListeners(this.wrapper);\n\n const registerChartEvent = (object: any, eventName: string, callback: Function) => {\n google.visualization.events.addListener(object, eventName, callback);\n };\n\n registerChartEvent(this.wrapper, 'ready', () => this.ready.emit({ chart: this.chart! }));\n registerChartEvent(this.wrapper, 'error', (error: ChartErrorEvent) => this.error.emit(error));\n registerChartEvent(this.wrapper, 'select', () => {\n const selection = this.chart!.getSelection();\n this.select.emit({ selection });\n });\n }\n}\n","import { ModuleWithProviders, NgModule } from '@angular/core';\n\nimport { ChartEditorComponent } from './components/chart-editor/chart-editor.component';\nimport { ChartWrapperComponent } from './components/chart-wrapper/chart-wrapper.component';\nimport { ControlWrapperComponent } from './components/control-wrapper/control-wrapper.component';\nimport { DashboardComponent } from './components/dashboard/dashboard.component';\nimport { GoogleChartComponent } from './components/google-chart/google-chart.component';\nimport { ScriptLoaderService } from './services/script-loader.service';\nimport { GoogleChartsConfig, GOOGLE_CHARTS_CONFIG } from './types/google-charts-config';\n\n@NgModule({\n declarations: [\n GoogleChartComponent,\n ChartWrapperComponent,\n DashboardComponent,\n ControlWrapperComponent,\n ChartEditorComponent\n ],\n providers: [ScriptLoaderService],\n exports: [\n GoogleChartComponent,\n ChartWrapperComponent,\n DashboardComponent,\n ControlWrapperComponent,\n ChartEditorComponent\n ]\n})\nexport class GoogleChartsModule {\n public static forRoot(config: GoogleChartsConfig = {}): ModuleWithProviders<GoogleChartsModule> {\n return {\n ngModule: GoogleChartsModule,\n providers: [{ provide: GOOGLE_CHARTS_CONFIG, useValue: config }]\n };\n }\n}\n","/*\n * Public API Surface of angular-google-charts\n */\n\nexport * from './lib/components/chart-editor/chart-editor-ref';\nexport * from './lib/components/chart-editor/chart-editor.component';\nexport * from './lib/components/google-chart/google-chart.component';\nexport * from './lib/components/chart-wrapper/chart-wrapper.component';\nexport * from './lib/components/dashboard/dashboard.component';\nexport * from './lib/components/control-wrapper/control-wrapper.component';\nexport * from './lib/components/chart-base/chart-base.component';\n\nexport * from './lib/helpers/chart.helper';\n\nexport * from './lib/types/chart-type';\nexport * from './lib/types/control-type';\nexport * from './lib/types/events';\nexport * from './lib/types/formatter';\nexport * from './lib/types/google-charts-config';\n\nexport * from './lib/services/script-loader.service';\n\nexport * from './lib/google-charts.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1.ScriptLoaderService","i2.DataTableService","i3.DashboardComponent"],"mappings":";;;;;;AAAA;MAMa,cAAc,CAAA;AAGzB,IAAA,WAAA,CAA6B,MAAwC,EAAA;QAAxC,IAAM,CAAA,MAAA,GAAN,MAAM,CAAkC;AAFpD,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,OAAO,EAAmB,CAAC;QAG5D,IAAI,CAAC,iBAAiB,EAAE,CAAC;KAC1B;AAED;;;AAGG;IACI,WAAW,GAAA;AAChB,QAAA,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;KACxC;AAED;;AAEG;IACI,MAAM,GAAA;AACX,QAAA,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;KAC3B;IAEO,iBAAiB,GAAA;AACvB,QAAA,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,MAAK;YACrE,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAE5D,MAAM,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;AAE1D,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;AAC3C,YAAA,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;AAC9B,SAAC,CAAC,CAAC;AAEH,QAAA,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAK;YACzE,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAE5D,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5B,YAAA,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;AAC9B,SAAC,CAAC,CAAC;KACJ;AACF;;IC7CW,UA2BX;AA3BD,CAAA,UAAY,SAAS,EAAA;AACnB,IAAA,SAAA,CAAA,iBAAA,CAAA,GAAA,iBAAmC,CAAA;AACnC,IAAA,SAAA,CAAA,WAAA,CAAA,GAAA,WAAuB,CAAA;AACvB,IAAA,SAAA,CAAA,KAAA,CAAA,GAAA,KAAW,CAAA;AACX,IAAA,SAAA,CAAA,UAAA,CAAA,GAAA,UAAqB,CAAA;AACrB,IAAA,SAAA,CAAA,aAAA,CAAA,GAAA,aAA2B,CAAA;AAC3B,IAAA,SAAA,CAAA,UAAA,CAAA,GAAA,UAAqB,CAAA;AACrB,IAAA,SAAA,CAAA,kBAAA,CAAA,GAAA,kBAAqC,CAAA;AACrC,IAAA,SAAA,CAAA,aAAA,CAAA,GAAA,aAA2B,CAAA;AAC3B,IAAA,SAAA,CAAA,YAAA,CAAA,GAAA,YAAyB,CAAA;AACzB,IAAA,SAAA,CAAA,UAAA,CAAA,GAAA,UAAqB,CAAA;AACrB,IAAA,SAAA,CAAA,OAAA,CAAA,GAAA,OAAe,CAAA;AACf,IAAA,SAAA,CAAA,OAAA,CAAA,GAAA,OAAe,CAAA;AACf,IAAA,SAAA,CAAA,UAAA,CAAA,GAAA,UAAqB,CAAA;AACrB,IAAA,SAAA,CAAA,WAAA,CAAA,GAAA,WAAuB,CAAA;AACvB,IAAA,SAAA,CAAA,MAAA,CAAA,GAAA,MAAa,CAAA;AACb,IAAA,SAAA,CAAA,WAAA,CAAA,GAAA,WAAuB,CAAA;AACvB,IAAA,SAAA,CAAA,KAAA,CAAA,GAAA,KAAW,CAAA;AACX,IAAA,SAAA,CAAA,UAAA,CAAA,GAAA,UAAqB,CAAA;AACrB,IAAA,SAAA,CAAA,QAAA,CAAA,GAAA,QAAiB,CAAA;AACjB,IAAA,SAAA,CAAA,SAAA,CAAA,GAAA,SAAmB,CAAA;AACnB,IAAA,SAAA,CAAA,cAAA,CAAA,GAAA,cAA6B,CAAA;AAC7B,IAAA,SAAA,CAAA,kBAAA,CAAA,GAAA,kBAAqC,CAAA;AACrC,IAAA,SAAA,CAAA,OAAA,CAAA,GAAA,OAAe,CAAA;AACf,IAAA,SAAA,CAAA,UAAA,CAAA,GAAA,UAAqB,CAAA;AACrB,IAAA,SAAA,CAAA,SAAA,CAAA,GAAA,SAAmB,CAAA;AACnB,IAAA,SAAA,CAAA,UAAA,CAAA,GAAA,UAAqB,CAAA;AACvB,CAAC,EA3BW,SAAS,KAAT,SAAS,GA2BpB,EAAA,CAAA,CAAA;;ACxBD,MAAM,oBAAoB,GAAG;AAC3B,IAAA,CAAC,SAAS,CAAC,eAAe,GAAG,iBAAiB;AAC9C,IAAA,CAAC,SAAS,CAAC,SAAS,GAAG,WAAW;AAClC,IAAA,CAAC,SAAS,CAAC,GAAG,GAAG,KAAK;AACtB,IAAA,CAAC,SAAS,CAAC,QAAQ,GAAG,WAAW;AACjC,IAAA,CAAC,SAAS,CAAC,WAAW,GAAG,WAAW;AACpC,IAAA,CAAC,SAAS,CAAC,QAAQ,GAAG,UAAU;AAChC,IAAA,CAAC,SAAS,CAAC,gBAAgB,GAAG,WAAW;AACzC,IAAA,CAAC,SAAS,CAAC,WAAW,GAAG,WAAW;AACpC,IAAA,CAAC,SAAS,CAAC,UAAU,GAAG,WAAW;AACnC,IAAA,CAAC,SAAS,CAAC,QAAQ,GAAG,WAAW;AACjC,IAAA,CAAC,SAAS,CAAC,KAAK,GAAG,OAAO;AAC1B,IAAA,CAAC,SAAS,CAAC,KAAK,GAAG,OAAO;AAC1B,IAAA,CAAC,SAAS,CAAC,QAAQ,GAAG,UAAU;AAChC,IAAA,CAAC,SAAS,CAAC,SAAS,GAAG,WAAW;AAClC,IAAA,CAAC,SAAS,CAAC,IAAI,GAAG,MAAM;AACxB,IAAA,CAAC,SAAS,CAAC,SAAS,GAAG,WAAW;AAClC,IAAA,CAAC,SAAS,CAAC,GAAG,GAAG,KAAK;AACtB,IAAA,CAAC,SAAS,CAAC,QAAQ,GAAG,UAAU;AAChC,IAAA,CAAC,SAAS,CAAC,MAAM,GAAG,QAAQ;AAC5B,IAAA,CAAC,SAAS,CAAC,OAAO,GAAG,SAAS;AAC9B,IAAA,CAAC,SAAS,CAAC,YAAY,GAAG,WAAW;AACrC,IAAA,CAAC,SAAS,CAAC,gBAAgB,GAAG,WAAW;AACzC,IAAA,CAAC,SAAS,CAAC,KAAK,GAAG,OAAO;AAC1B,IAAA,CAAC,SAAS,CAAC,QAAQ,GAAG,UAAU;AAChC,IAAA,CAAC,SAAS,CAAC,OAAO,GAAG,SAAS;AAC9B,IAAA,CAAC,SAAS,CAAC,QAAQ,GAAG,UAAU;CACjC,CAAC;AAEI,SAAU,kBAAkB,CAAC,IAAe,EAAA;AAChD,IAAA,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;SAEe,gBAAgB,GAAA;IAC9B,OAAO;AACL,QAAA,OAAO,EAAE,SAAS;AAClB,QAAA,QAAQ,EAAE,KAAK;KAChB,CAAC;AACJ;;MCIa,oBAAoB,GAAG,IAAI,cAAc,CAAiC,sBAAsB,EAAE;MAClG,yBAAyB,GAAG,IAAI,cAAc,CACzD,2BAA2B,EAC3B;AACE,IAAA,UAAU,EAAE,MAAM;IAClB,OAAO,EAAE,MAAK;QACZ,MAAM,gBAAgB,GAAG,MAAM,CAAC,oBAAoB,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;AAC5E,QAAA,OAAO,EAAE,CAAC,EAAE,GAAG,gBAAgB,EAAE,EAAE,IAAI,gBAAgB,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;KACnE;AACF,CAAA;;MC9CU,mBAAmB,CAAA;AAI9B,IAAA,WAAA,CACU,IAAY,EACO,QAAgB,EACS,OAAuC,EAAA;QAFnF,IAAI,CAAA,IAAA,GAAJ,IAAI,CAAQ;QACO,IAAQ,CAAA,QAAA,GAAR,QAAQ,CAAQ;QACS,IAAO,CAAA,OAAA,GAAP,OAAO,CAAgC;QAN5E,IAAY,CAAA,YAAA,GAAG,0CAA0C,CAAC;AAC1D,QAAA,IAAA,CAAA,iBAAiB,GAAG,IAAI,OAAO,EAAQ,CAAC;KAMrD;AAEJ;;;;;;AAMG;IACI,uBAAuB,GAAA;QAC5B,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE;AACzE,YAAA,OAAO,KAAK,CAAC;AACd,SAAA;AAED,QAAA,OAAO,IAAI,CAAC;KACb;AAED;;;;;;;;;AASG;IACI,iBAAiB,CAAC,GAAG,QAAkB,EAAA;QAC5C,OAAO,IAAI,CAAC,gBAAgB,EAAE,CAAC,IAAI,CACjC,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,EAC5B,GAAG,CAAC,MAAM,IAAG;AACX,YAAA,OAAO,EAAE,GAAG,gBAAgB,EAAE,EAAE,IAAI,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;AACtD,SAAC,CAAC,EACF,SAAS,CAAC,CAAC,kBAAsC,KAAI;AACnD,YAAA,OAAO,IAAI,UAAU,CAAO,QAAQ,IAAG;AACrC,gBAAA,MAAM,MAAM,GAAG;oBACb,QAAQ;oBACR,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,UAAU,EAAE,kBAAkB,CAAC,UAAU;oBACzC,QAAQ,EAAE,kBAAkB,CAAC,QAAQ;iBACtC,CAAC;gBAEF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,OAAQ,EAAE,MAAM,CAAC,CAAC;AACxD,gBAAA,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,MAAK;AACnC,oBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAK;wBACjB,QAAQ,CAAC,IAAI,EAAE,CAAC;wBAChB,QAAQ,CAAC,QAAQ,EAAE,CAAC;AACtB,qBAAC,CAAC,CAAC;AACL,iBAAC,CAAC,CAAC;AACL,aAAC,CAAC,CAAC;SACJ,CAAC,CACH,CAAC;KACH;AAED;;;;;AAKG;IACK,gBAAgB,GAAA;AACtB,QAAA,IAAI,IAAI,CAAC,uBAAuB,EAAE,EAAE;AAClC,YAAA,OAAO,EAAE,CAAC,SAAS,CAAC,CAAC;AACtB,SAAA;AAAM,aAAA,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE;AACxC,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,wBAAwB,EAAE,CAAC;AAC/C,YAAA,MAAM,CAAC,MAAM,GAAG,MAAK;AACnB,gBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAK;AACjB,oBAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC;AAC9B,oBAAA,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;AACpC,iBAAC,CAAC,CAAC;AACL,aAAC,CAAC;AAEF,YAAA,MAAM,CAAC,OAAO,GAAG,MAAK;AACpB,gBAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAK;AACjB,oBAAA,OAAO,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;oBAC1D,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC,CAAC;AACtF,iBAAC,CAAC,CAAC;AACL,aAAC,CAAC;AACH,SAAA;AAED,QAAA,OAAO,IAAI,CAAC,iBAAiB,CAAC,YAAY,EAAE,CAAC;KAC9C;IAEO,qBAAqB,GAAA;AAC3B,QAAA,OAAO,IAAI,CAAC,qBAAqB,EAAE,IAAI,IAAI,CAAC;KAC7C;IAEO,qBAAqB,GAAA;AAC3B,QAAA,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAC;AACxE,QAAA,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,KAAK,IAAI,CAAC,YAAY,CAAC,CAAC;KACrE;IAEO,wBAAwB,GAAA;QAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;AAChD,QAAA,MAAM,CAAC,IAAI,GAAG,iBAAiB,CAAC;AAChC,QAAA,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC;AAC/B,QAAA,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;AACpB,QAAA,QAAQ,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;AAC7D,QAAA,OAAO,MAAM,CAAC;KACf;+GA3GU,mBAAmB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,MAAA,EAAA,EAAA,EAAA,KAAA,EAMpB,SAAS,EAAA,EAAA,EAAA,KAAA,EACT,yBAAyB,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA,EAAA;m