aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.scss11
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx183
2 files changed, 148 insertions, 46 deletions
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.scss b/src/client/views/nodes/DataVizBox/DataVizBox.scss
index 84d4b21a6..a3132dc6e 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.scss
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.scss
@@ -1,4 +1,4 @@
-.dataviz {
+.dataViz-box {
overflow: auto;
height: 100%;
width: 100%;
@@ -38,6 +38,15 @@
.button-container {
pointer-events: unset;
}
+
+ .dataVizBox-annotationLayer{
+ position: absolute;
+ transform-origin: left top;
+ top: 0;
+ width: 100%;
+ pointer-events: none;
+ mix-blend-mode: multiply;
+ }
}
.start-message {
margin: 10px;
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 9692345a6..f3670622a 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -6,7 +6,7 @@ import { Doc, Field, Opt, StrListCast } from '../../../../fields/Doc';
import { List } from '../../../../fields/List';
import { Cast, CsvCast, DocCast, NumCast, StrCast } from '../../../../fields/Types';
import { CsvField } from '../../../../fields/URLField';
-import { DocUtils, Docs } from '../../../documents/Documents';
+import { Docs } from '../../../documents/Documents';
import { ViewBoxAnnotatableComponent } from '../../DocComponent';
import { FieldView, FieldViewProps } from '../FieldView';
import { PinProps } from '../trails';
@@ -17,12 +17,16 @@ 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 { emptyFunction, returnEmptyString, returnFalse, setupMoveUpEvents } from '../../../../Utils';
import { DocumentView } from '../DocumentView';
import { DocumentManager } from '../../../util/DocumentManager';
+import { TraceMobx } from '../../../../fields/util';
+import { MarqueeAnnotator } from '../../MarqueeAnnotator';
+import { InkTool } from '../../../../fields/InkField';
+import { AnchorMenu } from '../../pdf/AnchorMenu';
+import { GPTPopup } from '../../pdf/GPTPopup/GPTPopup';
+import { CollectionFreeFormView } from '../../collections/collectionFreeForm';
export enum DataVizView {
TABLE = 'table',
@@ -33,6 +37,41 @@ export enum DataVizView {
@observer
export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
+ private _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
+ private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
+ private _ffref = React.createRef<CollectionFreeFormView>();
+ private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
+ @observable _marqueeing: number[] | undefined;
+ @observable _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
+ @computed get annotationLayer() {
+ TraceMobx();
+ return <div className="dataVizBox-annotationLayer" style={{ height: this.props.PanelHeight(), width: this.props.PanelWidth() }} ref={this._annotationLayer} />;
+ }
+ marqueeDown = (e: React.PointerEvent) => {
+ if (!e.altKey && e.button === 0 && NumCast(this.rootDoc._freeform_scale, 1) <= NumCast(this.rootDoc.freeform_scaleMin, 1) && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ setupMoveUpEvents(
+ this,
+ e,
+ action(e => {
+ MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
+ //this._marqueeing = [e.pageX, e.pageY];
+ this._marqueeing = [e.clientX, e.clientY];
+ return true;
+ }),
+ returnFalse,
+ () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations),
+ false
+ );
+ }
+ };
+ @action
+ finishMarquee = () => {
+ this._getAnchor = AnchorMenu.Instance?.GetAnchor;
+ this._marqueeing = undefined;
+ this.props.select(false);
+ };
+ savedAnnotations = () => this._savedAnnotations;
+
public static LayoutString(fieldStr: string) {
return FieldView.LayoutString(DataVizBox, fieldStr);
}
@@ -83,10 +122,17 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return func() ?? false;
};
getAnchor = (addAsAnnotation?: boolean, pinProps?: PinProps) => {
+ const visibleAnchor = this._getAnchor?.(this._savedAnnotations, false); // use marquee anchor, otherwise, save zoom/pan as anchor
const anchor = !pinProps
? this.rootDoc
: this._vizRenderer?.getAnchor(pinProps) ??
+ visibleAnchor ??
Docs.Create.ConfigDocument({
+ title: 'ImgAnchor:' + this.rootDoc.title,
+ config_panX: NumCast(this.layoutDoc._freeform_panX),
+ config_panY: NumCast(this.layoutDoc._freeform_panY),
+ config_viewScale: Cast(this.layoutDoc._freeform_scale, 'number', null),
+ annotationOn: this.rootDoc,
// when we clear selection -> we should have it so chartBox getAnchor returns undefined
// this is for when we want the whole doc (so when the chartBox getAnchor returns without a marker)
/*put in some options*/
@@ -102,7 +148,9 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
anchor[key] = this.layoutDoc[key];
}
});
+
this.addDocument(anchor);
+ //addAsAnnotation && this.addDocument(anchor);
return anchor;
};
@@ -110,11 +158,6 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
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'
);
@@ -195,32 +238,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
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);
@@ -259,35 +278,91 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
};
+ @action
+ onPointerDown = (e: React.PointerEvent): void => {
+ if ((this.props.Document._freeform_scale || 1) !== 1) return;
+ if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
+ this.props.select(false);
+ MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
+ this._marqueeing = [e.clientX, e.clientY];
+ const target = e.target as any;
+ if (e.target && (target.className.includes('endOfContent') || (target.parentElement.className !== 'textLayer' && target.parentElement.parentElement?.className !== 'textLayer'))) {
+ } else {
+ // if textLayer is hit, then we select text instead of using a marquee so clear out the marquee.
+ setTimeout(
+ action(() => (this._marqueeing = undefined)),
+ 100
+ ); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it.
+
+ document.addEventListener('pointerup', this.onSelectEnd);
+ }
+ }
+ };
+
+ @action
+ onSelectEnd = (e: PointerEvent): void => {
+ this.props.select(false);
+ document.removeEventListener('pointerup', this.onSelectEnd);
+
+ const sel = window.getSelection();
+ if (sel) {
+ AnchorMenu.Instance.setSelectedText(sel.toString());
+ }
+
+ if (sel?.type === 'Range') {
+ AnchorMenu.Instance.jumpTo(e.clientX, e.clientY);
+ }
+
+ // Changing which document to add the annotation to (the currently selected PDF)
+ GPTPopup.Instance.setSidebarId('data_sidebar');
+ GPTPopup.Instance.addDoc = this.sidebarAddDocument;
+ };
+
render() {
return !this.records.length ? (
// displays how to get data into the DataVizBox if its empty
<div className="start-message">To create a DataViz box, either import / drag a CSV file into your canvas or copy a data table and use the command 'ctrl + p' to bring the data table to your canvas.</div>
) : (
<div
- className="dataViz"
+ className="dataViz-box"
+ onPointerDown={this.marqueeDown}
style={{
pointerEvents: this.props.isContentActive() === true ? 'all' : 'none',
}}
onWheel={e => e.stopPropagation()}
- ref={r =>
- r?.addEventListener(
- 'wheel', // if scrollTop is 0, then don't let wheel trigger scroll on any container (which it would since onScroll won't be triggered on this)
- (e: WheelEvent) => {
- if (!r.scrollTop && e.deltaY <= 0) e.preventDefault();
- e.stopPropagation();
- },
- { passive: false }
- )
- }>
+ ref={this._mainCont}
+ >
<div className={'datatype-button'}>
<Toggle text={'TABLE'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.TABLE)} toggleStatus={this.layoutDoc._dataViz == DataVizView.TABLE} />
<Toggle text={'LINECHART'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.LINECHART)} toggleStatus={this.layoutDoc._dataViz == DataVizView.LINECHART} />
<Toggle text={'HISTOGRAM'} toggleType={ToggleType.BUTTON} type={Type.SEC} color={'black'} onClick={e => (this.layoutDoc._dataViz = DataVizView.HISTOGRAM)} toggleStatus={this.layoutDoc._dataViz == DataVizView.HISTOGRAM} />
<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>
+
+ <CollectionFreeFormView
+ ref={this._ffref}
+ {...this.props}
+ setContentView={emptyFunction}
+ renderDepth={this.props.renderDepth + 1}
+ fieldKey={this.annotationKey}
+ styleProvider={this.props.styleProvider}
+ isAnnotationOverlay={true}
+ annotationLayerHostsContent={true}
+ PanelWidth={this.props.PanelWidth}
+ PanelHeight={this.props.PanelHeight}
+ select={emptyFunction}
+ isAnyChildContentActive={returnFalse}
+ whenChildContentsActiveChanged={this.whenChildContentsActiveChanged}
+ removeDocument={this.removeDocument}
+ moveDocument={this.moveDocument}
+ addDocument={this.addDocument}>
+ </CollectionFreeFormView>
+
{this.renderVizView()}
- <div className="dataviz-sidebar" style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
+ <div className="dataviz-sidebar"
+ style={{ width: `${this.sidebarWidthPercent}`,
+ backgroundColor: `${this.sidebarColor}` }}
+ onPointerDown={this.onPointerDown}>
<SidebarAnnos
ref={this._sidebarRef}
{...this.props}
@@ -306,6 +381,24 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
/>
</div>
{this.sidebarHandle}
+ {this.annotationLayer}
+ {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : (
+ <MarqueeAnnotator
+ rootDoc={this.rootDoc}
+ scrollTop={0}
+ down={this._marqueeing}
+ scaling={this.props.NativeDimScaling}
+ docView={this.props.docViewPath().slice(-1)[0]}
+ addDocument={this.sidebarAddDocument}
+ finishMarquee={this.finishMarquee}
+ savedAnnotations={this.savedAnnotations}
+ selectionText={returnEmptyString}
+ annotationLayer={this._annotationLayer.current}
+ mainCont={this._mainCont.current}
+ highlightDragSrcColor={''}
+ />
+
+ )}
</div>
);
}