UNPKG

@hpcc-js/composite

Version:
377 lines (350 loc) 15.3 kB
import { IGraph, INDChart } from "@hpcc-js/api"; import { Database, HTMLWidget, Utility, Widget } from "@hpcc-js/common"; import { map as d3Map } from "d3-collection"; import { requireWidget } from "./Utility.ts"; declare const require: any; export class MultiChart extends HTMLWidget { _allCharts = {}; _chartTypeDefaults; _chartTypeProperties; _chartMonitor; _switchingTo; constructor() { super(); INDChart.call(this); IGraph.call(this); this._tag = "div"; this._allCharts = {}; this._allChartTypes.forEach(function (item) { const newItem = JSON.parse(JSON.stringify(item)); newItem.widget = null; this._allCharts[item.id] = newItem; this._allCharts[item.display] = newItem; this._allCharts[item.widgetClass] = newItem; }, this); this._chartTypeDefaults = {}; this._chartTypeProperties = {}; } fields(): Database.Field[]; fields(_: Database.Field[]): this; fields(_?: Database.Field[]): Database.Field[] | this { const retVal = super.fields.apply(this, arguments); if (this.chart()) { if (!arguments.length) return this.chart().fields(); this.chart().fields(_); } return retVal; } columns(): string[]; columns(_, asDefault?: boolean): this; columns(_?, asDefault?: boolean) { const retVal = HTMLWidget.prototype.columns.apply(this, arguments); if (this.chart()) { if (!arguments.length) return this.chart().columns(); this.chart().columns(_, asDefault); } return retVal; } data(_?) { const retVal = HTMLWidget.prototype.data.apply(this, arguments); if (this.chart()) { if (!arguments.length) return this.chart().data(); this.chart().data(_); } return retVal; } hasOverlay() { return this.chart() && this.chart().hasOverlay(); } visible(): boolean; visible(_: boolean): this; visible(_?: boolean): boolean | this { if (!arguments.length) return this.chart() && this.chart().visible(); if (this.chart()) { this.chart().visible(_); } return this; } chartTypeDefaults(): object; chartTypeDefaults(_: object): this; chartTypeDefaults(_?: object): object | this { if (!arguments.length) return this._chartTypeDefaults; this._chartTypeDefaults = _; return this; } chartTypeProperties(): object; chartTypeProperties(_: object): this; chartTypeProperties(_?: object): object | this { if (!arguments.length) return this._chartTypeProperties; this._chartTypeProperties = _; return this; } getChartDataFamily() { return this._allCharts[this.chartType()].family; } requireContent(chartType, callback) { const classInfo = Utility.parseClassID(this._allCharts[chartType].widgetClass); switch (classInfo.package) { case "@hpcc-js/chart": import("@hpcc-js/chart").then(mod => { callback(new mod[classInfo.widgetID]()); }); break; case "@hpcc-js/dgrid": import("@hpcc-js/dgrid").then(mod => { callback(new mod[classInfo.widgetID]()); }); break; default: requireWidget(this._allCharts[chartType].widgetClass).then(function (WidgetClass: any) { callback(new WidgetClass()); }); } } switchChart(callback) { if (this._switchingTo === this.chartType()) { if (callback) { callback(this); } return; } else if (this._switchingTo) { console.warn("Attempting switch to: " + this.chartType() + ", before previous switch is complete (" + this._switchingTo + ")"); } this._switchingTo = this.chartType(); const oldContent = this.chart(); const context = this; this.requireContent(this.chartType(), function (newContent) { if (newContent !== oldContent) { const size = context.size(); newContent .fields(context.fields()) .data(context.data()) .size(size) ; context.chart(newContent); if (oldContent) { oldContent .size({ width: 1, height: 1 }) .render() ; } } delete context._switchingTo; if (callback) { callback(this); } }); } update(domNode, element) { super.update(domNode, element); const content = element.selectAll(".multiChart").data(this.chart() ? [this.chart()] : [], function (d) { return d._id; }); content.enter().append("div") .attr("class", "multiChart") .each(function (d) { d.target(this); }) ; const currChart = this.chart(); if (currChart) { for (const key in this._chartTypeDefaults) { if (currChart[key + "_default"]) { try { currChart[key + "_default"](this._chartTypeDefaults[key]); } catch (e) { console.warn("Exception Setting Default: " + key); } } else { console.warn("Unknown Default: " + key); } } this._chartTypeDefaults = {}; for (const propKey in this._chartTypeProperties) { if (currChart[propKey]) { try { currChart[propKey](this._chartTypeProperties[propKey]); } catch (e) { console.warn("Exception Setting Property: " + propKey); } } else { console.warn("Unknown Property: " + propKey); } } this._chartTypeProperties = {}; } const context = this; content .each(function (d) { d.resize(context.size()); }) ; content.exit().transition() .each(function (d) { d.target(null); }) .remove() ; } exit(domNode, element) { if (this._chartMonitor) { this._chartMonitor.remove(); delete this._chartMonitor; } if (this.chart()) { this.chart().target(null); } super.exit(domNode, element); } render(_callback?) { if (this.chartType() && (!this.chart() || (this.chart().classID() !== this._allCharts[this.chartType()].widgetClass))) { const context = this; const args = arguments; this.switchChart(function () { HTMLWidget.prototype.render.apply(context, args); }); return this; } return HTMLWidget.prototype.render.apply(this, arguments); } } MultiChart.prototype._class += " composite_MultiChart"; MultiChart.prototype.implements(INDChart.prototype); MultiChart.prototype.implements(IGraph.prototype); export interface ChartMeta { id: string; display: string; widgetClass: string; widgetPath?: string; } export interface MultiChart { _otherChartTypes: ChartMeta[]; _graphChartTypes: ChartMeta[]; _1DChartTypes: ChartMeta[]; _2DChartTypes: ChartMeta[]; _NDChartTypes: ChartMeta[]; _mapChartTypes: ChartMeta[]; _anyChartTypes: ChartMeta[]; _allChartTypes: ChartMeta[]; _allMap; _allFamilies: string[]; _allChartTypesMap; _allChartTypesByClass; hideRowOnLegendClick(): boolean; hideRowOnLegendClick(_: boolean): this; chartType(): string; chartType(_: string): this; chart(): Widget; chart(_: Widget): this; chart_access(): Widget; chart_access(_: Widget): this; click(_row, _column, _selected): void; dblclick(_row, _column, _selected): void; vertex_click(row, column, selected, more): void; vertex_dblclick(row, column, selected, more): void; edge_click(row, column, selected, more): void; edge_dblclick(row, column, selected, more): void; } MultiChart.prototype._otherChartTypes = [ { id: "FORM", display: "Form", widgetClass: "form_FieldForm" } ].map(function (item: any) { item.family = "other"; return item; }); MultiChart.prototype._graphChartTypes = [ { id: "GRAPH", display: "Graph", widgetClass: "graph_Graph" }, { id: "ADJACENCY_GRAPH", display: "Graph", widgetClass: "graph_AdjacencyGraph" }, { id: "GRAPHC", display: "GraphC", widgetClass: "graph_GraphC" } ].map(function (item: any) { item.family = "GRAPH"; return item; }); MultiChart.prototype._1DChartTypes = [ ].map(function (item: any) { item.family = "1D"; return item; }); MultiChart.prototype._2DChartTypes = [ { id: "SUMMARY", display: "Summary", widgetClass: "chart_Summary" }, { id: "BUBBLE", display: "Bubble", widgetClass: "chart_Bubble" }, { id: "PIE", display: "Pie", widgetClass: "chart_Pie" }, { id: "WORD_CLOUD", display: "Word Cloud", widgetClass: "other_WordCloud" } ].map(function (item: any) { item.family = "2D"; return item; }); MultiChart.prototype._NDChartTypes = [ { id: "COLUMN", display: "Column", widgetClass: "chart_Column" }, { id: "BAR", display: "Bar", widgetClass: "chart_Bar" }, { id: "LINE", display: "Line", widgetClass: "chart_Line" }, { id: "AREA", display: "Area", widgetClass: "chart_Area" }, { id: "STEP", display: "Step", widgetClass: "chart_Step" }, { id: "SCATTER", display: "Scatter", widgetClass: "chart_Scatter" }, { id: "HEXBIN", display: "Hex Bin", widgetClass: "chart_HexBin" } ].map(function (item: any) { item.family = "ND"; return item; }); MultiChart.prototype._mapChartTypes = [ { id: "CHORO_USSTATES", display: "US State Choropleth", widgetClass: "map_ChoroplethStates" }, { id: "CHORO_USCOUNTIES", display: "US County Choropleth", widgetClass: "map_ChoroplethCounties" }, { id: "CHORO_COUNTRIES", display: "Country Choropleth", widgetClass: "map_ChoroplethCountries" }, { id: "GMAP_CHORO_USCOUNTIES", display: "Google Map US County Choropleth", widgetClass: "map_GMapCounties" }, { id: "GOOGLE_MAP", display: "Google Map", widgetClass: "map_GMapLayered" }, { id: "OPENSTREET", display: "Open Street Map", widgetClass: "map_OpenStreet" } ].map(function (item: any) { item.family = "map"; return item; }); MultiChart.prototype._anyChartTypes = [ { id: "TABLE", display: "Table", widgetClass: "dgrid_Table" }, { id: "TABLE_LEGACY", display: "Table (legacy)", widgetClass: "other_Table" }, { id: "TABLE_NESTED", display: "Nested Table", widgetClass: "other_NestedTable" }, { id: "TABLE_CALENDAR", display: "Table driven Calendar Heat Map", widgetClass: "other_CalendarHeatMap" }, { id: "TABLE_BULLET", display: "Table driven bullet chart", widgetClass: "chart_Bullet" }, { id: "TABLE_SELECT", display: "Table driven select", widgetClass: "other_Select" }, { id: "TABLE_AUTOCOMPLETE", display: "Table driven auto complete", widgetClass: "other_AutoCompleteText" }, { id: "TABLE_OPPORTUNITY", display: "Table driven opportunity widget", widgetClass: "graph_Opportunity" }, { id: "TABLE_TREE", display: "Table driven tree", widgetClass: "tree_Dendrogram" }, { id: "TABLE_TREEMAP", display: "Table driven Treemap", widgetClass: "tree_Treemap" }, { id: "TABLE_SANKEY", display: "Table driven Sankey", widgetClass: "graph_Sankey" }, { id: "TABLE_GMAP_PIN", display: "Table driven Google Map (pins)", widgetClass: "map_GMapPin" }, { id: "TABLE_GMAP_PINLINE", display: "Table driven Google Map (pins/lines)", widgetClass: "map_GMapPinLine" }, { id: "TABLE_XML_TREE", display: "Table driven XML Tree", widgetClass: "tree_Indented" } ].map(function (item: any) { item.family = "any"; return item; }); MultiChart.prototype._allChartTypes = MultiChart.prototype._otherChartTypes.concat( MultiChart.prototype._graphChartTypes.concat( MultiChart.prototype._1DChartTypes.concat( MultiChart.prototype._2DChartTypes.concat( MultiChart.prototype._NDChartTypes.concat( MultiChart.prototype._mapChartTypes.concat( MultiChart.prototype._anyChartTypes )))))); MultiChart.prototype._allMap = d3Map(MultiChart.prototype._allChartTypes, function (item: any) { return item.family; }); MultiChart.prototype._allFamilies = MultiChart.prototype._allMap.keys(); MultiChart.prototype._allChartTypesMap = {}; MultiChart.prototype._allChartTypesByClass = {}; MultiChart.prototype._allChartTypes.forEach(function (item) { item.widgetPath = Utility.widgetPath(item.widgetClass); MultiChart.prototype._allChartTypesMap[item.id] = item; MultiChart.prototype._allChartTypesByClass[item.widgetClass] = item; }); MultiChart.prototype.publishReset(); MultiChart.prototype.publish("hideRowOnLegendClick", false, "boolean", "Enable/Disable hiding row on legend clicks", null, { tags: ["Basic"] }); MultiChart.prototype.publish("chartType", "BUBBLE", "set", "Chart Type", MultiChart.prototype._allChartTypes.map(function (item) { return item.id; }), { tags: ["Basic"] }); MultiChart.prototype.publish("chart", null, "widget", "Chart", null, { tags: ["Basic"] }); const _origChart = MultiChart.prototype.chart; MultiChart.prototype.chart = function (_?) { const retVal = _origChart.apply(this, arguments); if (arguments.length) { const context = this; if (this._allChartTypesByClass[_.classID()]) { this.chartType(this._allChartTypesByClass[_.classID()].id); } else { console.warn("Unknown Class ID: " + _.classID()); } _.click = function (_row, _column, _selected) { context.click.apply(context, arguments); }; _.dblclick = function (_row, _column, _selected) { context.dblclick.apply(context, arguments); }; _.vertex_click = function (row, column, selected, more) { context.vertex_click.apply(context, arguments); }; _.vertex_dblclick = function (row, column, selected, more) { context.vertex_dblclick.apply(context, arguments); }; _.edge_click = function (row, column, selected, more) { context.edge_click.apply(context, arguments); }; _.edge_dblclick = function (row, column, selected, more) { context.edge_dblclick.apply(context, arguments); }; if (this._chartMonitor) { this._chartMonitor.remove(); delete this._chartMonitor; } this._chartMonitor = _.monitor(function (key, newVal, oldVal) { context.broadcast(key, newVal, oldVal, _); }); } return retVal; };