1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
import functionPlot from 'function-plot';
import { action, computed, makeObservable, override, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast } from '../../../fields/Doc';
import { documentSchema } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
import { List } from '../../../fields/List';
import { createSchema, listSpec, makeInterface } from '../../../fields/Schema';
import { Cast, StrCast } from '../../../fields/Types';
import { TraceMobx } from '../../../fields/util';
import { copyProps } from '../../../Utils';
import { Docs } from '../../documents/Documents';
import { DragManager } from '../../util/DragManager';
import { undoBatch } from '../../util/UndoManager';
import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { FieldView, FieldViewProps } from './FieldView';
import { PinProps, PresBox } from './trails';
@observer
export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(FunctionPlotBox, fieldKey);
}
public static GraphCount = 0;
_plot: any;
_plotId = '';
_plotEle: any;
_prevProps: React.PropsWithChildren<FieldViewProps>;
@override _props: React.PropsWithChildren<FieldViewProps>;
constructor(props: React.PropsWithChildren<FieldViewProps>) {
super(props);
this._props = this._prevProps = props;
makeObservable(this);
this._plotId = 'graph' + FunctionPlotBox.GraphCount++;
}
componentDidUpdate() {
copyProps(this);
}
componentDidMount() {
this._props.setContentView?.(this);
reaction(
() => [DocListCast(this.dataDoc[this.fieldKey]).map(doc => doc?.text), this.layoutDoc.width, this.layoutDoc.height, this.layoutDoc.xRange, this.layoutDoc.yRange],
() => this.createGraph()
);
}
getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
const anchor = Docs.Create.ConfigDocument({ annotationOn: this.Document });
PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), datarange: true } }, this.Document);
anchor.config_xRange = new List<number>(Array.from(this._plot.options.xAxis.domain));
anchor.config_yRange = new List<number>(Array.from(this._plot.options.yAxis.domain));
if (addAsAnnotation) this.addDocument(anchor);
return anchor;
};
createGraph = (ele?: HTMLDivElement) => {
this._plotEle = ele || this._plotEle;
const width = this._props.PanelWidth();
const height = this._props.PanelHeight();
const fns = DocListCast(this.dataDoc.data).map(doc => StrCast(doc.text, 'x^2').replace(/\\frac\{(.*)\}\{(.*)\}/, '($1/$2)'));
try {
this._plotEle.children.length && this._plotEle.removeChild(this._plotEle.children[0]);
this._plot = functionPlot({
target: '#' + this._plotEle.id,
width,
height,
xAxis: { domain: Cast(this.layoutDoc.xRange, listSpec('number'), [-10, 10]) },
yAxis: { domain: Cast(this.layoutDoc.yRange, listSpec('number'), [-1, 9]) },
grid: true,
data: fns.map(fn => ({
fn,
// derivative: { fn: "2 * x", updateOnMouseMove: true }
})),
});
} catch (e) {
console.log(e);
}
};
@undoBatch
drop = (e: Event, de: DragManager.DropEvent) => {
if (de.complete.docDragData?.droppedDocuments.length) {
const added = de.complete.docDragData.droppedDocuments.reduce((res, doc) => res && Doc.AddDocToList(this.dataDoc, this._props.fieldKey, doc), true);
!added && e.preventDefault();
e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
return added;
}
return false;
};
_dropDisposer: any;
protected createDropTarget = (ele: HTMLDivElement) => {
this._dropDisposer?.();
if (ele) {
this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc);
}
// if (this.layout_autoHeight) this.tryUpdateScrollHeight();
};
@computed get theGraph() {
return <div id={`${this._plotId}`} ref={r => r && this.createGraph(r)} style={{ position: 'absolute', width: '100%', height: '100%' }} onPointerDown={e => e.stopPropagation()} />;
}
render() {
TraceMobx();
return (
<div
ref={this.createDropTarget}
style={{
pointerEvents: !this._props.isContentActive() ? 'all' : undefined,
width: this._props.PanelWidth(),
height: this._props.PanelHeight(),
}}>
{this.theGraph}
<div
style={{
display: this._props.isSelected() ? 'none' : undefined,
position: 'absolute',
width: '100%',
height: '100%',
pointerEvents: 'all',
}}
/>
</div>
);
}
}
|