diff options
-rw-r--r-- | package-lock.json | 225 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | src/client/documents/DocumentTypes.ts | 3 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 10 | ||||
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackingView.tsx | 39 | ||||
-rw-r--r-- | src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentContentsView.tsx | 3 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 17 | ||||
-rw-r--r-- | src/client/views/nodes/EquationBox.tsx | 39 | ||||
-rw-r--r-- | src/client/views/nodes/FunctionPlotBox.scss | 0 | ||||
-rw-r--r-- | src/client/views/nodes/FunctionPlotBox.tsx | 76 |
13 files changed, 373 insertions, 46 deletions
diff --git a/package-lock.json b/package-lock.json index 47aa1f0ea..3cbdb7a74 100644 --- a/package-lock.json +++ b/package-lock.json @@ -550,6 +550,11 @@ "@types/glob": "*" } }, + "@types/assert": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.5.4.tgz", + "integrity": "sha512-CaFVW21Ulu0J9sUaEWJjwmhkDkeoxa4fniVSERzZC13sU9v8NNM2lMlkfZZv60j47D+qDt0Lyo8skVP3CTXUdA==" + }, "@types/async": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@types/async/-/async-2.4.2.tgz", @@ -2862,6 +2867,14 @@ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", "dev": true }, + "built-in-math-eval": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/built-in-math-eval/-/built-in-math-eval-0.3.0.tgz", + "integrity": "sha1-JA3CHLOJQ5WIxhxGDrAHZJfvxBw=", + "requires": { + "math-codegen": "^0.3.5" + } + }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -3685,6 +3698,11 @@ "safe-buffer": "^5.0.1" } }, + "clamp": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz", + "integrity": "sha1-ZqDmQBGBbjcZaCj9yMjBRzEshjQ=" + }, "class-transformer": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.2.3.tgz", @@ -4639,6 +4657,130 @@ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" }, + "d3-axis": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-2.0.0.tgz", + "integrity": "sha512-9nzB0uePtb+u9+dWir+HTuEAKJOEUYJoEwbJPsZ1B4K3iZUgzJcSENQ05Nj7S4CIfbZZ8/jQGoUzGKFznBhiiQ==" + }, + "d3-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", + "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" + }, + "d3-dispatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", + "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==" + }, + "d3-drag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz", + "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==", + "requires": { + "d3-dispatch": "1 - 2", + "d3-selection": "2" + } + }, + "d3-ease": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", + "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==" + }, + "d3-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-2.0.0.tgz", + "integrity": "sha512-Ab3S6XuE/Q+flY96HXT0jOXcM4EAClYFnRGY5zsjRGNy6qCYrQsMffs7cV5Q9xejb35zxW5hf/guKw34kvIKsA==" + }, + "d3-interpolate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", + "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", + "requires": { + "d3-color": "1 - 2" + } + }, + "d3-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-2.0.0.tgz", + "integrity": "sha512-ZwZQxKhBnv9yHaiWd6ZU4x5BtCQ7pXszEV9CU6kRgwIQVQGLMv1oiL4M+MK/n79sYzsj+gcgpPQSctJUsLN7fA==" + }, + "d3-scale": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-3.2.3.tgz", + "integrity": "sha512-8E37oWEmEzj57bHcnjPVOBS3n4jqakOeuv1EDdQSiSrYnMCBdMd3nc4HtKk7uia8DUHcY/CGuJ42xxgtEYrX0g==", + "requires": { + "d3-array": "^2.3.0", + "d3-format": "1 - 2", + "d3-interpolate": "1.2.0 - 2", + "d3-time": "1 - 2", + "d3-time-format": "2 - 3" + }, + "dependencies": { + "d3-array": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.11.0.tgz", + "integrity": "sha512-26clcwmHQEdsLv34oNKq5Ia9tQ26Y/4HqS3dQzF42QBUqymZJ+9PORcN1G52bt37NsL2ABoX4lvyYZc+A9Y0zw==", + "requires": { + "internmap": "^1.0.0" + } + } + } + }, + "d3-selection": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", + "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" + }, + "d3-shape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-2.0.0.tgz", + "integrity": "sha512-djpGlA779ua+rImicYyyjnOjeubyhql1Jyn1HK0bTyawuH76UQRWXd+pftr67H6Fa8hSwetkgb/0id3agKWykw==", + "requires": { + "d3-path": "1 - 2" + } + }, + "d3-time": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.0.0.tgz", + "integrity": "sha512-2mvhstTFcMvwStWd9Tj3e6CEqtOivtD8AUiHT8ido/xmzrI9ijrUUihZ6nHuf/vsScRBonagOdj0Vv+SEL5G3Q==" + }, + "d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "requires": { + "d3-time": "1 - 2" + } + }, + "d3-timer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", + "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" + }, + "d3-transition": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", + "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", + "requires": { + "d3-color": "1 - 2", + "d3-dispatch": "1 - 2", + "d3-ease": "1 - 2", + "d3-interpolate": "1 - 2", + "d3-timer": "1 - 2" + } + }, + "d3-zoom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", + "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", + "requires": { + "d3-dispatch": "1 - 2", + "d3-drag": "2", + "d3-interpolate": "1 - 2", + "d3-selection": "2", + "d3-transition": "2" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -5309,6 +5451,11 @@ "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", "dev": true }, + "double-bits": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/double-bits/-/double-bits-1.1.1.tgz", + "integrity": "sha1-WKu6RUlNpND6Nrc60RoobJGEscY=" + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -6574,6 +6721,24 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "function-plot": { + "version": "1.22.7", + "resolved": "https://registry.npmjs.org/function-plot/-/function-plot-1.22.7.tgz", + "integrity": "sha512-rB6FeVqvgNECmt5PhIvFFEOyEjM9AWLIpMkj9Nzbzq9f81Irgn3ZrXAuv5+qnuzM99jPL7ZM4kK3+ImiKXcSHA==", + "requires": { + "built-in-math-eval": "^0.3.0", + "clamp": "^1.0.1", + "d3-axis": "^2.0.0", + "d3-color": "^2.0.0", + "d3-format": "^2.0.0", + "d3-interpolate": "^2.0.1", + "d3-scale": "^3.2.2", + "d3-selection": "^2.0.0", + "d3-shape": "^2.0.0", + "d3-zoom": "^2.0.0", + "interval-arithmetic-eval": "^0.4.7" + } + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -7652,11 +7817,36 @@ "ipaddr.js": "^1.9.0" } }, + "internmap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.0.tgz", + "integrity": "sha512-SdoDWwNOTE2n4JWUsLn4KXZGuZPjPF9yyOGc8bnfWnBQh7BD/l80rzSznKc/r4Y0aQ7z3RTk9X+tV4tHBpu+dA==" + }, "interpret": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==" }, + "interval-arithmetic": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/interval-arithmetic/-/interval-arithmetic-1.0.6.tgz", + "integrity": "sha512-eVotDGYPNiEaJ63oa4CeEHgOczZJ3gNHqG5wfVQ2o8sN2CEczQyR82Sjey/Bp36x8e7PtBcBvitcMnw6VUpjgQ==", + "requires": { + "@types/assert": "^1.4.6", + "is-safe-integer": "^2.0.0", + "nextafter": "^1.0.0", + "typedarray": "0.0.6" + } + }, + "interval-arithmetic-eval": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/interval-arithmetic-eval/-/interval-arithmetic-eval-0.4.7.tgz", + "integrity": "sha512-ClK+N4efbsgjlZR8h0qd0LQbyzUzJ9IkrjmTnD5MVb4Ytebd0lesoVP4AxLclcsEI+nIieskQ8cepHIWUPaRhQ==", + "requires": { + "interval-arithmetic": "^1.0.6", + "math-codegen": "^0.3.5" + } + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -7948,6 +8138,14 @@ "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" }, + "is-safe-integer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-safe-integer/-/is-safe-integer-2.0.0.tgz", + "integrity": "sha512-eDaA39/1+3SNtYTRP28lRYOHMwiB1gfqXQaXcf/+f4mLwKgm8TTDkwJldsdtbgrK1R5CoDbf6AQ0KqP7BKoGtQ==", + "requires": { + "max-safe-integer": "^1.0.0" + } + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -8822,6 +9020,15 @@ } } }, + "math-codegen": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/math-codegen/-/math-codegen-0.3.5.tgz", + "integrity": "sha1-R5nuRnfe0Ud2bQA8ykt4ee3UDMo=", + "requires": { + "extend": "^3.0.0", + "mr-parser": "^0.2.1" + } + }, "mathquill": { "version": "0.10.1-a", "resolved": "https://registry.npmjs.org/mathquill/-/mathquill-0.10.1-a.tgz", @@ -8837,6 +9044,11 @@ } } }, + "max-safe-integer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/max-safe-integer/-/max-safe-integer-1.0.1.tgz", + "integrity": "sha1-84BgvixWPYwC5tSK85Ei/YO29BA=" + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -9343,6 +9555,11 @@ } } }, + "mr-parser": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/mr-parser/-/mr-parser-0.2.1.tgz", + "integrity": "sha1-hhi5ukF+KOn0OaQcaVtVTq/u2Sc=" + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -9428,6 +9645,14 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, + "nextafter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nextafter/-/nextafter-1.0.0.tgz", + "integrity": "sha1-t9d7U1MQ4+CX5gJauwqQNHfsGjo=", + "requires": { + "double-bits": "^1.1.0" + } + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", diff --git a/package.json b/package.json index 1f27b1ae6..aae4fdfff 100644 --- a/package.json +++ b/package.json @@ -165,6 +165,7 @@ "fit-curve": "^0.1.7", "flexlayout-react": "^0.3.11", "formidable": "^1.2.1", + "function-plot": "^1.22.7", "golden-layout": "^1.5.9", "google-auth-library": "^4.2.4", "google-maps-react": "^2.0.6", diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 20dbc6f25..58b120e7d 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -21,7 +21,8 @@ export enum DocumentType { PDFANNO = "pdfanno", // pdf text selection (could be just a collection?) DATE = "date", // calendar view of a date SCRIPTING = "script", // script editor - EQUATION = "equation", // equation edtior + EQUATION = "equation", // equation editor + FUNCPLOT = "funcplot", // function plotter // special purpose wrappers that either take no data or are compositions of lower level types LINK = "link", // link (view of a document that acts as a link) diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index f87c7185c..ca5ee9cbd 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -58,6 +58,7 @@ import { SearchBox } from "../views/search/SearchBox"; import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo"; import { DocumentType } from "./DocumentTypes"; import { EquationBox } from "../views/nodes/EquationBox"; +import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox"; const path = require('path'); const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", "")); @@ -379,6 +380,9 @@ export namespace Docs { [DocumentType.EQUATION, { layout: { view: EquationBox, dataField: defaultDataKey }, }], + [DocumentType.FUNCPLOT, { + layout: { view: FunctionPlotBox, dataField: defaultDataKey }, + }], [DocumentType.BUTTON, { layout: { view: LabelBox, dataField: "onClick" }, }], @@ -899,6 +903,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.EQUATION), undefined, { ...(options || {}) }); } + export function FunctionPlotDocument(documents: Array<Doc>, options?: DocumentOptions) { + return InstanceFromProto(Prototypes.get(DocumentType.FUNCPLOT), new List(documents), { ...(options || {}) }); + } + export function ButtonDocument(options?: DocumentOptions) { // const btn = InstanceFromProto(Prototypes.get(DocumentType.BUTTON), undefined, { ...(options || {}), "onClick-rawScript": "-script-" }); // btn.layoutKey = "layout_onClick"; @@ -1229,7 +1237,7 @@ export namespace DocUtils { icon: "eye" }); ContextMenu.Instance.addItem({ - description: ":math", event: () => { + description: ":=math", event: () => { const created = Docs.Create.EquationDocument(); if (created) { created.author = Doc.CurrentUserEmail; diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 79a493dc9..a2f59e48f 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -793,7 +793,7 @@ export class CurrentUserUtils { // setup Recently Closed library item if (doc.myRecentlyClosedDocs === undefined) { doc.myRecentlyClosedDocs = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "Recently Closed", _height: 500, + title: "Recently Closed", treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, _forceActive: true, childDropAction: "alias", treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false, ignoreClick: true, _lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 7152f4272..95a95b10d 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -30,6 +30,7 @@ import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewField import { CollectionSubView } from "./CollectionSubView"; import { CollectionViewType } from "./CollectionView"; import { LightboxView } from "../LightboxView"; +import { DocumentType } from "../../documents/DocumentTypes"; const _global = (window /* browser */ || global /* node */) as any; type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>; @@ -220,8 +221,8 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument, LayoutTemplate={this.props.childLayoutTemplate} LayoutTemplateString={this.props.childLayoutString} freezeDimensions={this.props.childFreezeDimensions} - NativeWidth={this.props.childIgnoreNativeSize ? returnZero : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox - NativeHeight={this.props.childIgnoreNativeSize ? returnZero : undefined} + NativeWidth={this.props.childIgnoreNativeSize ? returnZero : doc._fitWidth && !Doc.NativeWidth(doc) ? width : undefined} // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox + NativeHeight={this.props.childIgnoreNativeSize ? returnZero : doc._fitWidth && !Doc.NativeHeight(doc) ? height : undefined} dontCenter={this.props.childIgnoreNativeSize ? "xy" : undefined} dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.dontRegisterChildViews, this.props.dontRegisterView)} rootSelected={this.rootSelected} @@ -257,27 +258,29 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument, getDocWidth(d?: Doc) { if (!d) return 0; const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.()); - const nw = Doc.NativeWidth(childLayoutDoc) || (childLayoutDoc._fitWidth ? 0 : d[WidthSym]()); - return Math.min(nw && !this.layoutDoc._columnsFill ? (this.props.scaling?.() || 1) * d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); + const maxWidth = this.columnWidth / this.numGroupColumns; + if (!this.layoutDoc._columnsFill && !childLayoutDoc._fitWidth) { + return Math.min(d[WidthSym]() * (this.props.scaling?.() || 1), maxWidth); + } + return maxWidth; } getDocHeight(d?: Doc) { if (!d) return 0; - const childDataDoc = (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc; const childLayoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.()); - const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (childLayoutDoc._fitWidth ? 0 : d[WidthSym]()); - const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (childLayoutDoc._fitWidth ? 0 : d[HeightSym]()); - let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); - if (!this.layoutDoc._columnsFill) wid = Math.min(wid, childLayoutDoc[WidthSym]()); - const hllimit = NumCast(this.layoutDoc.childLimitHeight, -1); - if (!childLayoutDoc._fitWidth && nw && nh) { - const aspect = nw && nh ? nh / nw : 1; - if (!(this.layoutDoc._columnsFill)) wid = Math.min(this.getDocWidth(d), wid); - return Math.min(hllimit === 0 ? this.props.PanelWidth() : hllimit === -1 ? 10000 : hllimit, wid * aspect); + const childDataDoc = (!d.isTemplateDoc && !d.isTemplateForField && !d.PARAMS) ? undefined : this.props.DataDoc; + const maxHeight = (lim => lim === 0 ? this.props.PanelWidth() : lim === -1 ? 10000 : lim)(NumCast(this.layoutDoc.childLimitHeight, -1)); + const nw = Doc.NativeWidth(childLayoutDoc, childDataDoc) || (!childLayoutDoc._fitWidth || this.layoutDoc._columnsFill ? d[WidthSym]() : 0); + const nh = Doc.NativeHeight(childLayoutDoc, childDataDoc) || (!childLayoutDoc._fitWidth || this.layoutDoc._columnsFill ? d[HeightSym]() : 0); + if (nw && nh) { + const colWid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1); + const docWid = this.layoutDoc._columnsFill ? colWid : Math.min(this.getDocWidth(d), colWid); + return Math.min( + maxHeight, + docWid * nh / nw); } - return childLayoutDoc._fitWidth ? - (!nh ? Math.min(NumCast(childLayoutDoc.height, 10000) * (this.props.scaling?.() || 1), this.props.PanelHeight() - 2 * this.yMargin) : - Math.min(wid * nh / (nw || 1), this.layoutDoc._autoHeight ? 100000 : this.props.PanelHeight() - 2 * this.yMargin)) : - Math.min(hllimit === 0 ? this.props.PanelWidth() : hllimit === -1 ? 10000 : hllimit, Math.max(20, childLayoutDoc[HeightSym]())); + const childHeight = NumCast(childLayoutDoc._height); + const panelHeight = this.props.PanelHeight() - 2 * this.yMargin; + return Math.min(childHeight, maxHeight, panelHeight); } columnDividerDown = (e: React.PointerEvent) => { diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index d23f3309e..0c0dbef9f 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -182,7 +182,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu let offset = 0; for (const { layout: candidate } of this.childLayoutPairs) { if (candidate === layout) { - return this.props.ScreenToLocalTransform().translate(-offset, 0); + return this.props.ScreenToLocalTransform().translate(-offset / (this.props.scaling?.() || 1), 0); } offset += this.lookupPixels(candidate) + resizerWidth; } diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 641ae6ce1..0a1000a20 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -182,7 +182,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) let offset = 0; for (const { layout: candidate } of this.childLayoutPairs) { if (candidate === layout) { - return this.props.ScreenToLocalTransform().translate(0, -offset); + return this.props.ScreenToLocalTransform().translate(0, -offset / (this.props.scaling?.() || 1)); } offset += this.lookupPixels(candidate) + resizerHeight; } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 02c112745..32542d056 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -12,6 +12,7 @@ import { YoutubeBox } from "./../../apis/youtube/YoutubeBox"; import { AudioBox } from "./AudioBox"; import { LabelBox } from "./LabelBox"; import { EquationBox } from "./EquationBox"; +import { FunctionPlotBox } from "./FunctionPlotBox"; import { SliderBox } from "./SliderBox"; import { LinkBox } from "./LinkBox"; import { ScriptingBox } from "./ScriptingBox"; @@ -223,7 +224,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo components={{ FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, EquationBox, SliderBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox, - PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, SearchBox, FilterBox, + PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, SearchBox, FilterBox, FunctionPlotBox, ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox, ScreenshotBox, HTMLtag, ComparisonBox }} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cd61d20b1..d4f6c076a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1013,25 +1013,22 @@ export class DocumentView extends React.Component<DocumentViewProps> { return this.docView?._componentView?.reverseNativeScaling?.() ? 0 : returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); } - shouldNotScale = () => this.layoutDoc._fitWidth || [CollectionViewType.Docking, CollectionViewType.Tree].includes(this.Document._viewType as any); - @computed get effectiveNativeWidth() { return this.nativeWidth || (this.shouldNotScale() ? 0 : NumCast(this.layoutDoc.width)); } - @computed get effectiveNativeHeight() { return this.nativeHeight || (this.shouldNotScale() ? 0 : NumCast(this.layoutDoc.height)); } + shouldNotScale = () => (this.layoutDoc._fitWidth && !this.nativeWidth) || [CollectionViewType.Docking, CollectionViewType.Tree].includes(this.Document._viewType as any); + @computed get effectiveNativeWidth() { return this.shouldNotScale() ? 0 : (this.nativeWidth || NumCast(this.layoutDoc.width)); } + @computed get effectiveNativeHeight() { return this.shouldNotScale() ? 0 : (this.nativeHeight || NumCast(this.layoutDoc.height)); } @computed get nativeScaling() { + if (this.shouldNotScale()) return 1; const minTextScale = this.Document.type === DocumentType.RTF ? 0.1 : 0; - if (this.effectiveNativeWidth && (this.layoutDoc?._fitWidth || this.props.PanelHeight() / this.effectiveNativeHeight > this.props.PanelWidth() / this.effectiveNativeWidth)) { + if (this.props.PanelHeight() / this.effectiveNativeHeight > this.props.PanelWidth() / this.effectiveNativeWidth) { return Math.max(minTextScale, this.props.PanelWidth() / this.effectiveNativeWidth); // width-limited or fitWidth } - return this.effectiveNativeWidth && this.effectiveNativeHeight ? Math.max(minTextScale, this.props.PanelHeight() / this.effectiveNativeHeight) : 1; // height-limited or unscaled + return Math.max(minTextScale, this.props.PanelHeight() / this.effectiveNativeHeight); // height-limited or unscaled } @computed get panelWidth() { return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth(); } @computed get panelHeight() { if (this.effectiveNativeHeight) { - return Math.min(this.props.PanelHeight(), - this.props.Document._fitWidth ? - Math.max(NumCast(this.props.Document._height), NumCast(((this.props.Document.scrollHeight || 0) as number) * this.props.PanelWidth() / this.effectiveNativeWidth, this.props.PanelHeight())) : - this.effectiveNativeHeight * this.nativeScaling - ); + return Math.min(this.props.PanelHeight(), Math.max(NumCast(this.layoutDoc.scrollHeight), this.effectiveNativeHeight) * this.nativeScaling); } return this.props.PanelHeight(); } diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx index 5bc73d5d9..5bb904f91 100644 --- a/src/client/views/nodes/EquationBox.tsx +++ b/src/client/views/nodes/EquationBox.tsx @@ -1,18 +1,22 @@ import EquationEditor from 'equation-editor-react'; +import { action, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { documentSchema } from '../../../fields/documentSchemas'; -import { createSchema, makeInterface } from '../../../fields/Schema'; -import { StrCast, NumCast } from '../../../fields/Types'; -import { ViewBoxBaseComponent } from '../DocComponent'; -import { FieldView, FieldViewProps } from './FieldView'; -import './LabelBox.scss'; import { Id } from '../../../fields/FieldSymbols'; -import { simulateMouseClick } from '../../../Utils'; +import { createSchema, makeInterface } from '../../../fields/Schema'; +import { NumCast, StrCast } from '../../../fields/Types'; import { TraceMobx } from '../../../fields/util'; -import { reaction, action } from 'mobx'; import { Docs } from '../../documents/Documents'; +import { ViewBoxBaseComponent } from '../DocComponent'; import { LightboxView } from '../LightboxView'; +import { FieldView, FieldViewProps } from './FieldView'; +import './LabelBox.scss'; +import functionPlot from "function-plot"; +import { DocumentManager } from '../../util/DocumentManager'; +import { Utils } from '../../../Utils'; +import { HeightSym, WidthSym } from '../../../fields/Doc'; + const EquationSchema = createSchema({}); @@ -39,18 +43,29 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps, EquationDo } }, { fireImmediately: true }); } + plot: any; @action keyPressed = (e: KeyboardEvent) => { const _height = Number(getComputedStyle(this._ref.current!.element.current).height.replace("px", "")); const _width = Number(getComputedStyle(this._ref.current!.element.current).width.replace("px", "")); - if (e.key === "Enter" || e.key === "Tab") { + if (e.key === "Enter") { const nextEq = Docs.Create.EquationDocument({ title: "# math", text: StrCast(this.dataDoc.text), _width, _height: 25, - x: NumCast(this.layoutDoc.x) + (e.key === "Tab" ? _width + 10 : 0), y: NumCast(this.layoutDoc.y) + (e.key === "Enter" ? _height + 10 : 0) + x: NumCast(this.layoutDoc.x), y: NumCast(this.layoutDoc.y) + _height + 10 }); EquationBox.SelectOnLoad = nextEq[Id]; this.props.addDocument?.(nextEq); e.stopPropagation(); + + } + if (e.key === "Tab") { + const graph = Docs.Create.FunctionPlotDocument([this.rootDoc], { + x: NumCast(this.layoutDoc.x) + this.layoutDoc[WidthSym](), + y: NumCast(this.layoutDoc.y), + _width: 400, _height: 300, _backgroundColor: "white" + }); + this.props.addDocument?.(graph); + e.stopPropagation(); } if (e.key === "Backspace" && !this.dataDoc.text) this.props.removeDocument?.(this.rootDoc); } @@ -72,11 +87,11 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps, EquationDo }} > <EquationEditor ref={this._ref} - value={this.dataDoc.text || "y"} + value={this.dataDoc.text || "x"} spaceBehavesLikeTab={true} onChange={this.onChange} autoCommands="pi theta sqrt sum prod alpha beta gamma rho" - autoOperatorNames="sin cos tan" /></div> - ); + autoOperatorNames="sin cos tan" /> + </div>); } }
\ No newline at end of file diff --git a/src/client/views/nodes/FunctionPlotBox.scss b/src/client/views/nodes/FunctionPlotBox.scss new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/client/views/nodes/FunctionPlotBox.scss diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx new file mode 100644 index 000000000..dba08b506 --- /dev/null +++ b/src/client/views/nodes/FunctionPlotBox.tsx @@ -0,0 +1,76 @@ +import EquationEditor from 'equation-editor-react'; +import functionPlot from "function-plot"; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { documentSchema } from '../../../fields/documentSchemas'; +import { createSchema, makeInterface } from '../../../fields/Schema'; +import { StrCast } from '../../../fields/Types'; +import { TraceMobx } from '../../../fields/util'; +import { ViewBoxBaseComponent } from '../DocComponent'; +import { FieldView, FieldViewProps } from './FieldView'; +import './LabelBox.scss'; +import { DocListCast } from '../../../fields/Doc'; +import { computed } from 'mobx'; + + +const EquationSchema = createSchema({}); + +type EquationDocument = makeInterface<[typeof EquationSchema, typeof documentSchema]>; +const EquationDocument = makeInterface(EquationSchema, documentSchema); + +@observer +export class FunctionPlotBox extends ViewBoxBaseComponent<FieldViewProps, EquationDocument>(EquationDocument) { + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(FunctionPlotBox, fieldKey); } + public static GraphCount = 0; + _ref: React.RefObject<EquationEditor> = React.createRef(); + _plot: any; + _plotId = ""; + constructor(props: any) { + super(props); + this._plotId = "graph" + FunctionPlotBox.GraphCount++; + } + createGraph = (ele: HTMLDivElement) => { + let width = this.props.PanelWidth(); + let height = this.props.PanelHeight(); + const fn = StrCast(DocListCast(this.dataDoc.data).lastElement()?.text, "x^2").replace(/\\frac\{(.*)\}\{(.*)\}/, "($1/$2)"); + console.log("Graphing:" + fn); + try { + this._plot = functionPlot({ + target: "#" + ele.id, + width, + height, + yAxis: { domain: [-1, 9] }, + grid: true, + data: [ + { + fn, + // derivative: { fn: "2 * x", updateOnMouseMove: true } + } + ] + }); + } catch (e) { + console.log(e); + } + } + @computed get theGraph() { + const fn = StrCast(DocListCast(this.dataDoc.data).lastElement()?.text, "x^2"); + 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 + style={{ + pointerEvents: !this.active() ? "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>); + } +}
\ No newline at end of file |