import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Doc, Field, StrListCast } from '../../../../../fields/Doc'; import { List } from '../../../../../fields/List'; import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../../Utils'; import { DragManager } from '../../../../util/DragManager'; import { DocumentView } from '../../DocumentView'; import { DataVizView } from '../DataVizBox'; import { LinkManager } from '../../../../util/LinkManager'; import { Cast, DocCast } from '../../../../../fields/Types'; import './Chart.scss'; import { listSpec } from '../../../../../fields/Schema'; interface TableBoxProps { rootDoc: Doc; layoutDoc: Doc; pairs: { [key: string]: any }[]; selectAxes: (axes: string[]) => void; axes: string[]; width: number; height: number; margin: { top: number; right: number; bottom: number; left: number; }; docView?: () => DocumentView | undefined; } @observer export class TableBox extends React.Component { // filters all data to just display selected data if brushed (created from an incoming link) @computed get _tableData() { if (this.incomingLinks.length! <= 0) return this.props.pairs; var guids = StrListCast(this.props.layoutDoc.dataViz_rowGuids); return this.props.pairs?.filter(pair => this.incomingLinks[0]!.dataViz_selectedRows && StrListCast(this.incomingLinks[0].dataViz_selectedRows).includes(guids[this.props.pairs.indexOf(pair)])); } @computed get incomingLinks() { return LinkManager.Instance.getAllRelatedLinks(this.props.rootDoc) // out of all links .filter(link => { return link.link_anchor_1 == this.props.rootDoc.draggedFrom; }) // get links where this chart doc is the target of the link .map(link => DocCast(link.link_anchor_1)); // then return the source of the link } @computed get columns() { if (!this.props.layoutDoc.dataViz_rowGuids) this.props.layoutDoc.dataViz_rowGuids = new List(); const guids = Cast(this.props.layoutDoc.dataViz_rowGuids, listSpec('string'), null); if (guids.length == 0) this.props.pairs.map(row => guids.push(Utils.GenerateGuid())); return this._tableData.length ? Array.from(Object.keys(this._tableData[0])).filter(header => header != '' && header != undefined) : []; } // updates the 'selected' field to no longer include rows that aren't in the table filterSelectedRowsDown() { if (!this.props.layoutDoc.dataViz_selectedRows) this.props.layoutDoc.dataViz_selectedRows = new List(); const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('string'), null); const incomingSelected = this.incomingLinks.length ? StrListCast(this.incomingLinks[0].dataViz_selectedRows) : undefined; if (incomingSelected) { selected.map(guid => { if (!incomingSelected.includes(guid)) selected.splice(selected.indexOf(guid), 1); }); // filters through selected to remove guids that were removed in the incoming data } } render() { this.filterSelectedRowsDown(); if (this._tableData.length > 0) { return (
{this.columns .filter(col => !col.startsWith('select')) .map(col => { const header = React.createRef(); return ( ); })} {this._tableData?.map((p, i) => { var containsData = false; var guid = StrListCast(this.props.layoutDoc.dataViz_rowGuids)![this.props.pairs.indexOf(p)]; this.columns.map(col => { if (p[col] != '' && p[col] != null && p[col] != undefined) containsData = true; }); if (containsData) { return ( { // selecting a row const selected = Cast(this.props.layoutDoc.dataViz_selectedRows, listSpec('string'), null); if (selected.includes(guid)) selected.splice(selected.indexOf(guid), 1); else { selected.push(guid); } })} style={{ background: StrListCast(this.props.layoutDoc.dataViz_selectedRows).includes(guid) ? 'lightgrey' : '', width: '110%' }}> {this.columns.map(col => { // each cell var colSelected = this.props.axes.length > 1 ? this.props.axes[0] == col || this.props.axes[1] == col : this.props.axes.length > 0 ? this.props.axes[0] == col : false; return ( ); })} ); } })}
{ const downX = e.clientX; const downY = e.clientY; setupMoveUpEvents( {}, e, e => { // dragging off a column to create a brushed DataVizBox const sourceAnchorCreator = () => this.props.docView?.()!.rootDoc!; const targetCreator = (annotationOn: Doc | undefined) => { const embedding = Doc.MakeEmbedding(this.props.docView?.()!.rootDoc!); embedding._dataViz = DataVizView.TABLE; embedding._dataViz_axes = new List([col, col]); embedding._draggedFrom = this.props.docView?.()!.rootDoc!; embedding.annotationOn = annotationOn; //this.props.docView?.()!.rootDoc!; embedding.histogramBarColors = Field.Copy(this.props.layoutDoc.histogramBarColors); embedding.defaultHistogramColor = this.props.layoutDoc.defaultHistogramColor; embedding.pieSliceColors = Field.Copy(this.props.layoutDoc.pieSliceColors); return embedding; }; if (this.props.docView?.() && !Utils.isClick(e.clientX, e.clientY, downX, downY, Date.now())) { DragManager.StartAnchorAnnoDrag([header.current!], new DragManager.AnchorAnnoDragData(this.props.docView()!, sourceAnchorCreator, targetCreator), downX, downY, { dragComplete: e => { if (!e.aborted && e.annoDragData && e.annoDragData.linkSourceDoc && e.annoDragData.dropDocument && e.linkDocument) { e.linkDocument.link_displayLine = true; e.linkDocument.link_matchEmbeddings = true; // e.annoDragData.linkSourceDoc.followLinkToggle = e.annoDragData.dropDocument.annotationOn === this.props.rootDoc; // e.annoDragData.linkSourceDoc.followLinkZoom = false; } }, }); return true; } return false; }, emptyFunction, action(e => { const newAxes = this.props.axes; if (newAxes.includes(col)) { newAxes.splice(newAxes.indexOf(col), 1); } else if (newAxes.length > 1) { newAxes[1] = col; } else { newAxes.push(col); } this.props.selectAxes(newAxes); }) ); }}> {col}
{p[col]}
); } else return ( // when it is a brushed table and the incoming table doesn't have any rows selected
Selected rows of data from the incoming DataVizBox to display.
); } }