import functionPlot from 'function-plot'; import { action, computed, 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 { Docs } from '../../documents/Documents'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { DocFocusOptions, DocumentView } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { PinProps, PresBox } from './trails'; const EquationSchema = createSchema({}); type EquationDocument = makeInterface<[typeof EquationSchema, typeof documentSchema]>; const EquationDocument = makeInterface(EquationSchema, documentSchema); @observer export class FunctionPlotBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FunctionPlotBox, fieldKey); } public static GraphCount = 0; _plot: any; _plotId = ''; _plotEle: any; constructor(props: any) { super(props); this._plotId = 'graph' + FunctionPlotBox.GraphCount++; } componentDidMount() { this.props.setContentView?.(this); reaction( () => [DocListCast(this.dataDoc[this.fieldKey]).map(doc => doc?.text), this.layoutDoc.width, this.layoutDoc.height, this.rootDoc.xRange, this.rootDoc.yRange], () => this.createGraph() ); } getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { const anchor = Docs.Create.TextanchorDocument({ annotationOn: this.rootDoc, unrendered: true }); PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), datarange: true } }, this.rootDoc); anchor.presXRange = new List(Array.from(this._plot.options.xAxis.domain)); anchor.presYRange = new List(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.rootDoc.xRange, listSpec('number'), [-10, 10]) }, yAxis: { domain: Cast(this.rootDoc.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) { e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place de.complete.docDragData.droppedDocuments.map(doc => Doc.AddDocToList(this.dataDoc, this.props.fieldKey, doc)); return false; } 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.autoHeight) this.tryUpdateScrollHeight(); }; @computed get theGraph() { return
r && this.createGraph(r)} style={{ position: 'absolute', width: '100%', height: '100%' }} onPointerDown={e => e.stopPropagation()} />; } render() { TraceMobx(); return (
{this.theGraph}
); } }