aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.scss28
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx160
-rw-r--r--src/client/views/nodes/DataVizBox/components/Chart.scss1
-rw-r--r--src/client/views/nodes/DataVizBox/components/Histogram.tsx2
-rw-r--r--src/client/views/nodes/DataVizBox/components/LineChart.tsx16
-rw-r--r--src/client/views/nodes/DataVizBox/components/PieChart.tsx2
-rw-r--r--src/client/views/nodes/DataVizBox/components/TableBox.tsx3
7 files changed, 199 insertions, 13 deletions
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss
index 430446c06..84d4b21a6 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.scss
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss
@@ -7,6 +7,34 @@
display: flex;
flex-direction: row;
}
+
+ .dataviz-overlayButton-sidebar {
+ background: #121721;
+ height: 25px;
+ width: 25px;
+ right: 5px;
+ display: flex;
+ position: absolute;
+ align-items: center;
+ justify-content: center;
+ border-radius: 3px;
+ pointer-events: all;
+ z-index: 1; // so it appears on top of the document's title, if shown
+
+ // box-shadow: $standard-box-shadow;
+ // transition: 0.2s;
+
+ &:hover {
+ filter: brightness(0.85);
+ }
+ }
+
+ .dataviz-sidebar {
+ position: absolute;
+ right: 0;
+ top: 0;
+ height: 100%;
+ }
.button-container {
pointer-events: unset;
}
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 299494c83..9692345a6 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -1,12 +1,12 @@
-import { Toggle, ToggleType, Type } from 'browndash-components';
-import { action, computed, ObservableMap } from 'mobx';
+import { Colors, Toggle, ToggleType, Type } from 'browndash-components';
+import { action, computed, observable, ObservableMap, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
-import { Doc, Field, StrListCast } from '../../../../fields/Doc';
+import { Doc, Field, Opt, StrListCast } from '../../../../fields/Doc';
import { List } from '../../../../fields/List';
-import { Cast, CsvCast, StrCast } from '../../../../fields/Types';
+import { Cast, CsvCast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
import { CsvField } from '../../../../fields/URLField';
-import { Docs } from '../../../documents/Documents';
+import { DocUtils, Docs } from '../../../documents/Documents';
import { ViewBoxAnnotatableComponent } from '../../DocComponent';
import { FieldView, FieldViewProps } from '../FieldView';
import { PinProps } from '../trails';
@@ -15,6 +15,14 @@ import { LineChart } from './components/LineChart';
import { PieChart } from './components/PieChart';
import { TableBox } from './components/TableBox';
import './DataVizBox.scss';
+import { UndoManager, undoable } from '../../../util/UndoManager';
+import { SidebarAnnos } from '../../SidebarAnnos';
+import { PDFBox } from '../PDFBox';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { emptyFunction, setupMoveUpEvents } from '../../../../Utils';
+import { LinkManager } from '../../../util/LinkManager';
+import { DocumentView } from '../DocumentView';
+import { DocumentManager } from '../../../util/DocumentManager';
export enum DataVizView {
TABLE = 'table',
@@ -32,6 +40,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
// all datasets that have been retrieved from the server stored as a map from the dataset url to an array of records
static dataset = new ObservableMap<string, { [key: string]: string }[]>();
private _vizRenderer: LineChart | Histogram | PieChart | undefined;
+ private _sidebarRef = React.createRef<SidebarAnnos>();
// all CSV records in the dataset (that aren't an empty row)
@computed.struct get records() {
@@ -97,6 +106,124 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return anchor;
};
+ createNoteAnnotation = () => {
+ const createFunc = undoable(
+ action(() => {
+ const note = this._sidebarRef.current?.anchorMenuClick(this.getAnchor(false), ['latitude', 'longitude', '-linkedTo']);
+ // if (note && this.selectedPin) {
+ // note.latitude = this.selectedPin.latitude;
+ // note.longitude = this.selectedPin.longitude;
+ // note.map = this.selectedPin.map;
+ // }
+ }),
+ 'create note annotation'
+ );
+ if (!this.layoutDoc.layout_showSidebar) {
+ this.toggleSidebar();
+ setTimeout(createFunc);
+ } else createFunc();
+ };
+
+ @observable _showSidebar = false;
+ @observable _previewNativeWidth: Opt<number> = undefined;
+ @observable _previewWidth: Opt<number> = undefined;
+ @action
+ toggleSidebar = () => {
+ const prevWidth = this.sidebarWidth();
+ this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(100 * 0.2) / 1.2}%` : '0%') !== '0%';
+ this.layoutDoc._width = this.layoutDoc._layout_showSidebar ? NumCast(this.layoutDoc._width) * 1.2 : Math.max(20, NumCast(this.layoutDoc._width) - prevWidth);
+ };
+ @computed get SidebarShown() {
+ return this.layoutDoc._layout_showSidebar ? true : false;
+ }
+ @computed get sidebarHandle() {
+ return (
+ <div
+ className="dataviz-overlayButton-sidebar"
+ key="sidebar"
+ title="Toggle Sidebar"
+ style={{
+ display: !this.props.isContentActive() ? 'none' : undefined,
+ top: StrCast(this.rootDoc._layout_showTitle) === 'title' ? 20 : 5,
+ backgroundColor: this.SidebarShown ? Colors.MEDIUM_BLUE : Colors.BLACK,
+ }}
+ onPointerDown={this.sidebarBtnDown}>
+ <FontAwesomeIcon style={{ color: Colors.WHITE }} icon={'comment-alt'} size="sm" />
+ </div>
+ );
+ }
+ /**
+ * Toggle sidebar onclick the tiny comment button on the top right corner
+ * @param e
+ */
+ sidebarBtnDown = (e: React.PointerEvent) => {
+ setupMoveUpEvents(
+ this,
+ e,
+ (e, down, delta) =>
+ runInAction(() => {
+ const localDelta = this.props
+ .ScreenToLocalTransform()
+ .scale(this.props.NativeDimScaling?.() || 1)
+ .transformDirection(delta[0], delta[1]);
+ const fullWidth = this.props.width;
+ const mapWidth = fullWidth! - this.sidebarWidth();
+ if (this.sidebarWidth() + localDelta[0] > 0) {
+ this.layoutDoc._layout_showSidebar = true;
+ this.layoutDoc._width = fullWidth! + localDelta[0];
+ this.layoutDoc._layout_sidebarWidthPercent = ((100 * (this.sidebarWidth() + localDelta[0])) / (fullWidth! + localDelta[0])).toString() + '%';
+ } else {
+ this.layoutDoc._layout_showSidebar = false;
+ this.layoutDoc._width = mapWidth;
+ this.layoutDoc._layout_sidebarWidthPercent = '0%';
+ }
+ return false;
+ }),
+ emptyFunction,
+ () => UndoManager.RunInBatch(this.toggleSidebar, 'toggle sidebar')
+ );
+ };
+ getView = async (doc: Doc) => {
+ if (this._sidebarRef?.current?.makeDocUnfiltered(doc) && !this.SidebarShown) this.toggleSidebar();
+ return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv)));
+ };
+ @computed get sidebarWidthPercent() {
+ return StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%');
+ }
+ @computed get sidebarColor() {
+ return StrCast(this.layoutDoc.sidebar_color, StrCast(this.layoutDoc[this.props.fieldKey + '_backgroundColor'], '#e4e4e4'));
+ }
+ sidebarWidth = () => (Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100) * this.props.PanelWidth();
+ sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => {
+ console.log('sideBarAddDoc')
+ if (!this.SidebarShown) this.toggleSidebar();
+ return this.addDocument(doc, sidebarKey);
+ // if (!this.layoutDoc._layout_showSidebar) this.toggleSidebar();
+ // const docs = doc instanceof Doc ? [doc] : doc;
+ // docs.forEach(doc => {
+ // let existingPin = Docs.Create.TextDocument("test");
+ // //let existingPin = this.allPushpins.find(pin => pin.latitude === doc.latitude && pin.longitude === doc.longitude) ?? this.selectedPin;
+ // // if (doc.latitude !== undefined && doc.longitude !== undefined && !existingPin) {
+ // // existingPin = this.createPushpin(NumCast(doc.latitude), NumCast(doc.longitude), StrCast(doc.map));
+ // // }
+ // if (existingPin) {
+ // setTimeout(() => {
+ // // we use a timeout in case this is called from the sidebar which may have just added a link that hasn't made its way into th elink manager yet
+ // if (!LinkManager.Instance.getAllRelatedLinks(doc).some(link => DocCast(link.link_anchor_1)?.mapPin === existingPin || DocCast(link.link_anchor_2)?.mapPin === existingPin)) {
+ // // const anchor = this.getAnchor(true, undefined, existingPin);
+ // const anchor = this.getAnchor(true, undefined);
+ // anchor && DocUtils.MakeLink(anchor, doc, { link_relationship: 'link to datapoint' });
+ // // doc.latitude = existingPin?.latitude;
+ // // doc.longitude = existingPin?.longitude;
+ // }
+ // });
+ // }
+ // }); //add to annotation list
+
+ // return this.addDocument(doc, sidebarKey); // add to sidebar list
+ };
+ sidebarRemoveDocument = (doc: Doc | Doc[], sidebarKey?: string) => this.removeDocument(doc, sidebarKey);
+
componentDidMount() {
this.props.setContentView?.(this);
if (!DataVizBox.dataset.has(CsvCast(this.rootDoc[this.fieldKey]).url.href)) this.fetchData();
@@ -116,7 +243,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
records: this.records,
axes: this.axes,
height: (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9,
- width: this.props.PanelWidth() * 0.9,
+ width: this.SidebarShown? this.props.PanelWidth()*.9/1.2: this.props.PanelWidth() * 0.9,
margin: { top: 10, right: 25, bottom: 75, left: 45 },
};
if (!this.records.length) return 'no data/visualization';
@@ -124,7 +251,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
case DataVizView.TABLE:
return <TableBox {...sharedProps} docView={this.props.DocumentView} selectAxes={this.selectAxes} />;
case DataVizView.LINECHART:
- return <LineChart {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
+ return <LineChart vizBox={this} {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
case DataVizView.HISTOGRAM:
return <Histogram {...sharedProps} dataDoc={this.dataDoc} fieldKey={this.fieldKey} ref={r => (this._vizRenderer = r ?? undefined)} />;
case DataVizView.PIECHART:
@@ -160,6 +287,25 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
<Toggle text={'PIE CHART'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.PIECHART)} toggleStatus={this.layoutDoc._dataViz == DataVizView.PIECHART} />
</div>
{this.renderVizView()}
+ <div className="dataviz-sidebar" style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+ <SidebarAnnos
+ ref={this._sidebarRef}
+ {...this.props}
+ fieldKey={this.fieldKey}
+ rootDoc={this.rootDoc}
+ layoutDoc={this.layoutDoc}
+ dataDoc={this.dataDoc}
+ usePanelWidth={true}
+ showSidebar={this.SidebarShown}
+ nativeWidth={NumCast(this.layoutDoc._nativeWidth)}
+ whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+ PanelWidth={this.sidebarWidth}
+ sidebarAddDocument={this.sidebarAddDocument}
+ moveDocument={this.moveDocument}
+ removeDocument={this.sidebarRemoveDocument}
+ />
+ </div>
+ {this.sidebarHandle}
</div>
);
}
diff --git a/src/client/views/nodes/DataVizBox/components/Chart.scss b/src/client/views/nodes/DataVizBox/components/Chart.scss
index c788a64c2..c8ea88d63 100644
--- a/src/client/views/nodes/DataVizBox/components/Chart.scss
+++ b/src/client/views/nodes/DataVizBox/components/Chart.scss
@@ -111,6 +111,7 @@
white-space: pre;
max-width: 150;
overflow: hidden;
+ margin-left: 2px;
}
}
}
diff --git a/src/client/views/nodes/DataVizBox/components/Histogram.tsx b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
index e67e2bf31..eca77f0f3 100644
--- a/src/client/views/nodes/DataVizBox/components/Histogram.tsx
+++ b/src/client/views/nodes/DataVizBox/components/Histogram.tsx
@@ -456,7 +456,7 @@ export class Histogram extends React.Component<HistogramProps> {
if (this._histogramData.length > 0 || !this.parentViz) {
return this.props.axes.length >= 1 ? (
- <div className="chart-container">
+ <div className="chart-container" style={{width: this.props.width+this.props.margin.right}}>
<div className="graph-title">
<EditableText
val={StrCast(this.props.layoutDoc[titleAccessor])}
diff --git a/src/client/views/nodes/DataVizBox/components/LineChart.tsx b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
index 3de7a0c4a..007d0259c 100644
--- a/src/client/views/nodes/DataVizBox/components/LineChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/LineChart.tsx
@@ -1,4 +1,4 @@
-import { EditableText, Size } from 'browndash-components';
+import { Button, EditableText, Size } from 'browndash-components';
import * as d3 from 'd3';
import { action, computed, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
@@ -23,6 +23,7 @@ export interface SelectedDataPoint extends DataPoint {
elem?: d3.Selection<d3.BaseType, unknown, SVGGElement, unknown>;
}
export interface LineChartProps {
+ vizBox: DataVizBox;
rootDoc: Doc;
layoutDoc: Doc;
axes: string[];
@@ -352,7 +353,7 @@ export class LineChart extends React.Component<LineChartProps> {
const selectedPt = this._currSelected ? `{ ${this.props.axes[0]}: ${this._currSelected.x} ${this.props.axes[1]}: ${this._currSelected.y} }` : 'none';
if (this._lineChartData.length > 0 || !this.parentViz || this.parentViz.length == 0) {
return this.props.axes.length >= 2 && /\d/.test(this.props.records[0][this.props.axes[0]]) && /\d/.test(this.props.records[0][this.props.axes[1]]) ? (
- <div className="chart-container">
+ <div className="chart-container" style={{width: this.props.width+this.props.margin.right}}>
<div className="graph-title">
<EditableText
val={StrCast(this.props.layoutDoc[titleAccessor])}
@@ -366,7 +367,16 @@ export class LineChart extends React.Component<LineChartProps> {
/>
</div>
<div ref={this._lineChartRef} />
- {selectedPt != 'none' ? <div className={'selected-data'}> {`Selected: ${selectedPt}`}</div> : null}
+ {selectedPt != 'none' ?
+ <div className={'selected-data'}>
+ {`Selected: ${selectedPt}`}
+ <Button onClick={e=>{
+ console.log("test plzz")
+ this.props.vizBox.sidebarBtnDown;
+ this.props.vizBox.sidebarAddDocument;}
+ }></Button>
+ </div>
+ : null}
</div>
) : (
<span className="chart-container"> {'first use table view to select two numerical axes to plot'}</span>
diff --git a/src/client/views/nodes/DataVizBox/components/PieChart.tsx b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
index 561f39141..df65810b5 100644
--- a/src/client/views/nodes/DataVizBox/components/PieChart.tsx
+++ b/src/client/views/nodes/DataVizBox/components/PieChart.tsx
@@ -353,7 +353,7 @@ export class PieChart extends React.Component<PieChartProps> {
if (this._pieChartData.length > 0 || !this.parentViz) {
return this.props.axes.length >= 1 ? (
- <div className="chart-container">
+ <div className="chart-container" style={{width: this.props.width+this.props.margin.right}}>
<div className="graph-title">
<EditableText
val={StrCast(this.props.layoutDoc[titleAccessor])}
diff --git a/src/client/views/nodes/DataVizBox/components/TableBox.tsx b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
index b88389de6..3685a198e 100644
--- a/src/client/views/nodes/DataVizBox/components/TableBox.tsx
+++ b/src/client/views/nodes/DataVizBox/components/TableBox.tsx
@@ -82,7 +82,7 @@ export class TableBox extends React.Component<TableBoxProps> {
return (this.viewScale * this._tableHeight) / this._tableDataIds.length;
}
@computed get startID() {
- return this.rowHeight ? Math.floor(this._scrollTop / this.rowHeight) : 0;
+ return this.rowHeight ? Math.max(Math.floor(this._scrollTop / this.rowHeight)-1, 0) : 0;
}
@computed get endID() {
return Math.ceil(this.startID + (this._tableContainerHeight * this.viewScale) / (this.rowHeight || 1));
@@ -163,6 +163,7 @@ export class TableBox extends React.Component<TableBoxProps> {
return (
<div
className="tableBox"
+ style={{width: this.props.width+this.props.margin.right}}
tabIndex={0}
onKeyDown={e => {
if (this.props.layoutDoc && e.key === 'a' && (e.ctrlKey || e.metaKey)) {