diff --git a/bsconfig.json b/bsconfig.json
index 7bef0766..c2566368 100644
--- a/bsconfig.json
+++ b/bsconfig.json
@@ -42,9 +42,7 @@
"bs-css",
"rationale",
"bs-moment",
- "reschema",
- "bs-webapi",
- "bs-fetch"
+ "reschema"
],
"refmt": 3,
"ppx-flags": [
diff --git a/package.json b/package.json
index 8f5fdc19..3ad539cd 100644
--- a/package.json
+++ b/package.json
@@ -34,10 +34,8 @@
"binary-search-tree": "0.2.6",
"bs-ant-design-alt": "2.0.0-alpha.33",
"bs-css": "11.0.0",
- "bs-fetch": "^0.5.2",
"bs-moment": "0.4.5",
"bs-reform": "9.7.1",
- "bs-webapi": "^0.15.9",
"bsb-js": "1.1.7",
"d3": "5.15.0",
"gh-pages": "2.2.0",
diff --git a/src/App.re b/src/App.re
index c4fcd888..7439e6b6 100644
--- a/src/App.re
+++ b/src/App.re
@@ -1,7 +1,6 @@
type route =
| Model(string)
| DistBuilder
- | Drawer
| Home
| NotFound;
@@ -9,7 +8,6 @@ let routeToPath = route =>
switch (route) {
| Model(modelId) => "/m/" ++ modelId
| DistBuilder => "/dist-builder"
- | Drawer => "/drawer"
| Home => "/"
| _ => "/"
};
@@ -71,10 +69,6 @@ module Menu = {
-
{"Dist Builder" |> R.ste}
- -
- {"Drawer" |> R.ste}
-
-
;
};
};
@@ -87,7 +81,6 @@ let make = () => {
switch (url.path) {
| ["m", modelId] => Model(modelId)
| ["dist-builder"] => DistBuilder
- | ["drawer"] => Drawer
| [] => Home
| _ => NotFound
};
@@ -101,7 +94,6 @@ let make = () => {
| None =>
{"Page is not found" |> R.ste}
}
| DistBuilder =>
- | Drawer =>
| Home =>
| _ => {"Page is not found" |> R.ste}
}}
diff --git a/src/components/Drawer.re b/src/components/Drawer.re
deleted file mode 100644
index 7b9be5e7..00000000
--- a/src/components/Drawer.re
+++ /dev/null
@@ -1,992 +0,0 @@
-module Types = {
- type rectangle = {
- // Ref: https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
- left: int,
- top: int,
- right: int,
- bottom: int,
- x: int,
- y: int,
- width: int,
- height: int,
- };
-
- type webapi = Webapi.Canvas.Canvas2d.t;
-
- type xyShape = DistTypes.xyShape; /* {
- xs: array(float),
- ys: array(float),
- };*/
-
- type continuousShape = DistTypes.continuousShape; /*{
- xyShape,
- interpolation: [ | `Stepwise | `Linear],
- };*/
-
- type canvasPoint = {
- w: float,
- h: float,
- };
-
- type canvasShape = {
- ws: array(float),
- hs: array(float),
- xValues: array(float),
- };
-
- type foretoldFormElements = {
- measurableId: string,
- token: string,
- comment: string,
- };
-
- type distributionLimits = {
- lower: float,
- upper: float,
- };
-
- type canvasState = {
- canvasShape: option(canvasShape),
- lastMousePosition: option(canvasPoint),
- isMouseDown: bool,
- readyToRender: bool,
- hasJustBeenSentToForetold: bool,
- limitsHaveJustBeenUpdated: bool,
- foretoldFormElements,
- distributionLimits,
- };
-};
-
-module CanvasContext = {
- type t = Types.webapi;
-
- /* Externals */
- [@bs.send]
- external getBoundingClientRect: Dom.element => Types.rectangle =
- "getBoundingClientRect";
- [@bs.send] external setLineDash: (t, array(int)) => unit = "setLineDash";
-
- /* Webapi functions */
- // Ref: https://github.com/reasonml-community/bs-webapi-incubator/blob/master/src/Webapi/Webapi__Canvas/Webapi__Canvas__Canvas2d.re
- let getContext2d: Dom.element => t = Webapi.Canvas.CanvasElement.getContext2d;
- module Canvas2d = Webapi.Canvas.Canvas2d;
- let clearRect = Canvas2d.clearRect;
- let setFillStyle = Canvas2d.setFillStyle;
- let fillRect = Canvas2d.fillRect;
- let beginPath = Canvas2d.beginPath;
- let closePath = Canvas2d.closePath;
- let setStrokeStyle = Canvas2d.setStrokeStyle;
- let lineWidth = Canvas2d.lineWidth;
- let moveTo = Canvas2d.moveTo;
- let lineTo = Canvas2d.lineTo;
- let stroke = Canvas2d.stroke;
- let font = Canvas2d.font;
- let textAlign = Canvas2d.textAlign;
- let strokeText = Canvas2d.strokeText;
- let fillText = Canvas2d.fillText;
-
- /* Padding */
- let paddingRatioX = 0.9;
- let paddingRatioY = 0.9;
-
- let paddingFactorX = (rectangleWidth: int) =>
- (1. -. paddingRatioX) *. float_of_int(rectangleWidth) /. 2.0;
- let paddingFactorY = (rectangleHeight: int) =>
- (1. -. paddingRatioY) *. float_of_int(rectangleHeight) /. 2.0;
-
- let translatePointToInside = (canvasElement: Dom.element) => {
- let rectangle: Types.rectangle = getBoundingClientRect(canvasElement);
- let translate = (p: Types.canvasPoint): Types.canvasPoint => {
- let w = p.w -. float_of_int(rectangle.x);
- let h = p.h -. float_of_int(rectangle.y);
- {w, h};
- };
- translate;
- };
-};
-
-module Convert = {
- /*
- - In this module, the fundamental unit for the canvas shape is the distance vector from the (0,0) point at the upper leftmost corner of the screen.
- - For some drawing functions, this is instead from the (0,0) point at the upper leftmost corner of the canvas element. This is irrelevant in this module.
- - The fundamental unit for a probability distribution is an x coordinate and its corresponding y probability density
- */
-
- let xyShapeToCanvasShape =
- (~xyShape: Types.xyShape, ~canvasElement: Dom.element) => {
- let xs = xyShape.xs;
- let ys = xyShape.ys;
- let rectangle: Types.rectangle =
- CanvasContext.getBoundingClientRect(canvasElement);
- let lengthX = E.A.length(xs);
-
- let minX = xs[0];
- let maxX = xs[lengthX - 1];
- let ratioXs =
- float_of_int(rectangle.width)
- *. CanvasContext.paddingRatioX
- /. (maxX -. minX);
- let ws =
- E.A.fmap(
- x =>
- (x -. minX)
- *. ratioXs
- +. float_of_int(rectangle.left)
- +. (1. -. CanvasContext.paddingRatioX)
- *. float_of_int(rectangle.width)
- /. 2.0,
- xs,
- );
-
- let minY = 0.;
- let maxY = E.A.reduce(ys, 0., (x, y) => x > y ? x : y);
- let ratioYs =
- float_of_int(rectangle.height)
- *. CanvasContext.paddingRatioY
- /. (maxY -. minY);
- let hs =
- E.A.fmap(
- y =>
- float_of_int(rectangle.bottom)
- -. y
- *. ratioYs
- -. CanvasContext.paddingFactorY(rectangle.height),
- ys,
- );
-
- let canvasShape: Types.canvasShape = {ws, hs, xValues: xs};
- canvasShape;
- };
-
- let canvasShapeToContinuousShape =
- (~canvasShape: Types.canvasShape, ~canvasElement: Dom.element)
- : Types.continuousShape => {
- let xs = canvasShape.xValues;
- let hs = canvasShape.hs;
- let rectangle: Types.rectangle =
- CanvasContext.getBoundingClientRect(canvasElement);
- let bottom = float_of_int(rectangle.bottom);
- let paddingFactorY = CanvasContext.paddingFactorX(rectangle.height);
- let windowScrollY: float = [%raw "window.scrollY"];
-
- let y0Line = bottom +. windowScrollY -. paddingFactorY;
- let ys = E.A.fmap(h => y0Line -. h, hs);
-
- let xyShape: Types.xyShape = {xs, ys};
- let continuousShape: Types.continuousShape = {
- xyShape,
- interpolation: `Linear,
- integralSumCache: None,
- integralCache: None,
- };
-
- let integral = XYShape.Analysis.integrateContinuousShape(continuousShape);
- let ys = E.A.fmap(y => y /. integral, ys);
-
- let continuousShape: Types.continuousShape = {
- xyShape: {
- xs,
- ys,
- },
- interpolation: `Linear,
- integralSumCache: Some(1.0),
- integralCache: None,
- };
- continuousShape;
- };
-
- /* Misc helper functions */
- let log2 = x => log(x) /. log(2.0);
- let findClosestInOrderedArrayDangerously = (x: float, xs: array(float)) => {
- let l = Array.length(xs);
- let a = ref(0);
- let b = ref(l - 1);
- let numSteps = int_of_float(log2(float_of_int(l))) + 1;
- for (_ in 0 to numSteps) {
- let c = (a^ + b^) / 2;
- xs[c] > x ? b := c : a := c;
- };
- b^;
- };
- let getPoint = (canvasShape: Types.canvasShape, n: int): Types.canvasPoint => {
- let point: Types.canvasPoint = {
- w: canvasShape.ws[n],
- h: canvasShape.hs[n],
- };
- point;
- };
-};
-
-module Draw = {
- let line =
- (
- canvasElement: Dom.element,
- ~point0: Types.canvasPoint,
- ~point1: Types.canvasPoint,
- )
- : unit => {
- let translator = CanvasContext.translatePointToInside(canvasElement);
- let point0 = translator(point0);
- let point1 = translator(point1);
-
- let context = CanvasContext.getContext2d(canvasElement);
- CanvasContext.beginPath(context);
- CanvasContext.moveTo(context, ~x=point0.w, ~y=point0.h);
- CanvasContext.lineTo(context, ~x=point1.w, ~y=point1.h);
- CanvasContext.stroke(context);
- };
-
- let canvasPlot =
- (canvasElement: Dom.element, canvasShape: Types.canvasShape) => {
- let context = CanvasContext.getContext2d(canvasElement);
- let rectangle: Types.rectangle =
- CanvasContext.getBoundingClientRect(canvasElement);
-
- /* Some useful reference points */
- let paddingFactorX = CanvasContext.paddingFactorX(rectangle.width);
- let paddingFactorY = CanvasContext.paddingFactorX(rectangle.height);
-
- let p00: Types.canvasPoint = {
- w: float_of_int(rectangle.left) +. paddingFactorX,
- h: float_of_int(rectangle.bottom) -. paddingFactorY,
- };
- let p01: Types.canvasPoint = {
- w: float_of_int(rectangle.left) +. paddingFactorX,
- h: float_of_int(rectangle.top) +. paddingFactorY,
- };
- let p10: Types.canvasPoint = {
- w: float_of_int(rectangle.right) -. paddingFactorX,
- h: float_of_int(rectangle.bottom) -. paddingFactorY,
- };
- let p11: Types.canvasPoint = {
- w: float_of_int(rectangle.right) -. paddingFactorX,
- h: float_of_int(rectangle.top) +. paddingFactorY,
- };
-
- /* Clear the canvas with new white sheet */
- CanvasContext.clearRect(
- context,
- ~x=0.,
- ~y=0.,
- ~w=float_of_int(rectangle.width),
- ~h=float_of_int(rectangle.height),
- );
-
- /* Draw a line between every two adjacent points */
- let length = Array.length(canvasShape.ws);
- let windowScrollY: float = [%raw "window.scrollY"];
- CanvasContext.setStrokeStyle(context, String, "#5680cc");
- CanvasContext.lineWidth(context, 4.);
-
- for (i in 1 to length - 1) {
- let point0 = Convert.getPoint(canvasShape, i - 1);
- let point1 = Convert.getPoint(canvasShape, i);
-
- let point0 = {...point0, h: point0.h -. windowScrollY};
- let point1 = {...point1, h: point1.h -. windowScrollY};
- line(canvasElement, ~point0, ~point1);
- };
-
- /* Draws the expected value line */
- // Removed on the grounds that it didn't play nice with changes in limits.
- /*
- let continuousShape =
- Convert.canvasShapeToContinuousShape(~canvasShape, ~canvasElement);
- let mean = Continuous.T.mean(continuousShape);
- let variance = Continuous.T.variance(continuousShape);
- let meanLocation =
- Convert.findClosestInOrderedArrayDangerously(mean, canvasShape.xValues);
- let meanLocationCanvasX = canvasShape.ws[meanLocation];
- let meanLocationCanvasY = canvasShape.hs[meanLocation];
- CanvasContext.beginPath(context);
- CanvasContext.setStrokeStyle(context, String, "#5680cc");
- CanvasContext.setLineDash(context, [|5, 10|]);
-
- line(
- canvasElement,
- ~point0={w: meanLocationCanvasX, h: p00.h},
- ~point1={
- w: meanLocationCanvasX,
- h: meanLocationCanvasY -. windowScrollY,
- },
- );
- CanvasContext.stroke(context);
- CanvasContext.setLineDash(context, [||]);
- */
- /* draws lines parallel to x axis + factors to help w/ precise drawing. */
- CanvasContext.beginPath(context);
- CanvasContext.setStrokeStyle(context, String, "#CCC");
- CanvasContext.lineWidth(context, 2.);
- CanvasContext.font(context, "18px Roboto");
- CanvasContext.textAlign(context, "center");
-
- let numLines = 8;
- let height =
- float_of_int(rectangle.height)
- *. CanvasContext.paddingRatioX
- /. float_of_int(numLines);
-
- for (i in 0 to numLines - 1) {
- let pLeft = {...p00, h: p00.h -. height *. float_of_int(i)};
- let pRight = {...p10, h: p10.h -. height *. float_of_int(i)};
- line(canvasElement, ~point0=pLeft, ~point1=pRight);
- CanvasContext.fillText(
- string_of_int(i) ++ "x",
- ~x=pLeft.w -. float_of_int(rectangle.left) +. 15.0,
- ~y=pLeft.h -. float_of_int(rectangle.top) -. 5.0,
- context,
- );
- };
-
- /* Draw a frame around the drawable area */
- CanvasContext.lineWidth(context, 2.0);
- CanvasContext.setStrokeStyle(context, String, "#000");
- line(canvasElement, ~point0=p00, ~point1=p01);
- line(canvasElement, ~point0=p01, ~point1=p11);
- line(canvasElement, ~point0=p11, ~point1=p10);
- line(canvasElement, ~point0=p10, ~point1=p00);
-
- /* draw units along the x axis */
- CanvasContext.font(context, "16px Roboto");
- CanvasContext.lineWidth(context, 2.0);
-
- let numIntervals = 10;
- let width = float_of_int(rectangle.width);
- let height = float_of_int(rectangle.height);
- let xMin = canvasShape.xValues[0];
- let xMax = canvasShape.xValues[length - 1];
- let xSpan = (xMax -. xMin) /. float_of_int(numIntervals - 1);
-
- for (i in 0 to numIntervals - 1) {
- let x =
- float_of_int(rectangle.left)
- +. width
- *. float_of_int(i)
- /. float_of_int(numIntervals);
- let dashValue = xMin +. xSpan *. float_of_int(i);
- CanvasContext.fillText(
- Js.Float.toFixedWithPrecision(dashValue, ~digits=2),
- ~x,
- ~y=height,
- context,
- );
- line(
- canvasElement,
- ~point0={
- w: x +. CanvasContext.paddingFactorX(rectangle.width),
- h: p00.h,
- },
- ~point1={
- w: x +. CanvasContext.paddingFactorX(rectangle.width),
- h: p00.h +. 10.0,
- },
- );
- };
- };
-
- let initialDistribution = (canvasElement: Dom.element, setState) => {
- let mean = 100.0;
- let stdev = 15.0;
- let numSamples = 3000;
-
- let normal: SymbolicTypes.symbolicDist = `Normal({mean, stdev});
- let normalShape =
- ExpressionTree.toShape(
- {sampleCount: 10000, outputXYPoints: 10000, kernelWidth: None, shapeLength:numSamples},
- ExpressionTypes.ExpressionTree.Environment.empty,
- `SymbolicDist(normal),
- ) |> E.R.toExn;
- let xyShape: Types.xyShape =
- switch (normalShape) {
- | Mixed(_) => {xs: [||], ys: [||]}
- | Discrete(_) => {xs: [||], ys: [||]}
- | Continuous(m) => Continuous.getShape(m)
- };
-
- /* // To use a lognormal instead:
- let lognormal = SymbolicTypes.Lognormal.fromMeanAndStdev(mean, stdev);
- let lognormalShape =
- SymbolicTypes.GenericSimple.toShape(lognormal, numSamples);
- let lognormalXYShape: Types.xyShape =
- switch (lognormalShape) {
- | Mixed(_) => {xs: [||], ys: [||]}
- | Discrete(_) => {xs: [||], ys: [||]}
- | Continuous(m) => Continuous.getShape(m)
- };
- */
-
- let canvasShape = Convert.xyShapeToCanvasShape(~xyShape, ~canvasElement);
- /* let continuousShapeBack =
- Convert.canvasShapeToContinuousShape(~canvasShape, ~canvasElement);
- */
-
- let windowScrollY: float = [%raw "window.scrollY"];
- let canvasShape = {
- ...canvasShape,
- hs: E.A.fmap(h => h +. windowScrollY, canvasShape.hs),
- };
- setState((state: Types.canvasState) => {
- {...state, canvasShape: Some(canvasShape)}
- });
-
- canvasPlot(canvasElement, canvasShape);
- };
-};
-
-module ForetoldAPI = {
- let predict = (~measurableId, ~token, ~xs, ~ys, ~comment) => {
- let payload = Js.Dict.empty();
- let xsString = Js.Array.toString(xs);
- let ysString = Js.Array.toString(ys);
-
- let query = {j|mutation {
- measurementCreate(input: {
- value: {
- floatCdf: {
- xs: [$xsString]
- ys: [$ysString]
- }
- }
- valueText: "Drawn by hand."
- description: "$comment"
- competitorType: COMPETITIVE
- measurableId: "$measurableId"
- }) {
- id
- }
- }|j};
- Js.Dict.set(payload, "query", Js.Json.string(query));
-
- Js.Promise.(
- Fetch.fetchWithInit(
- "https://api.foretold.io/graphql?token=" ++ token,
- Fetch.RequestInit.make(
- ~method_=Post,
- ~body=
- Fetch.BodyInit.make(
- Js.Json.stringify(Js.Json.object_(payload)),
- ),
- ~headers=
- Fetch.HeadersInit.make({
- "Accept-Encoding": "gzip, deflate, br",
- "Content-Type": "application/json",
- "Accept": "application/json",
- "Connection": "keep-alive",
- "DNT": "1",
- "Origin": "https://api.foretold.io",
- }),
- (),
- ),
- )
- |> then_(Fetch.Response.json)
- );
- };
-};
-
-module State = {
- type t = Types.canvasState;
-
- let initialState: t = {
- canvasShape: None,
- lastMousePosition: None,
- isMouseDown: false,
- readyToRender: false,
- hasJustBeenSentToForetold: false,
- limitsHaveJustBeenUpdated: false,
- foretoldFormElements: {
- measurableId: "",
- token: "",
- comment: "",
- },
- distributionLimits: {
- lower: 0.0,
- upper: 1000.0,
- },
- };
-
- let updateMousePosition = (~point: Types.canvasPoint, ~setState) => {
- setState((state: t) => {...state, lastMousePosition: Some(point)});
- };
-
- let onMouseMovement =
- (
- ~event: ReactEvent.Mouse.t,
- ~potentialCanvas: option(Dom.element),
- ~state: t,
- ~setState,
- ) => {
- /* Helper functions and objects*/
- let x = ReactEvent.Mouse.clientX(event);
- let y = ReactEvent.Mouse.clientY(event);
-
- let windowScrollY: float = [%raw "window.scrollY"];
-
- let point1: Types.canvasPoint = {
- w: float_of_int(x),
- h: float_of_int(y) +. windowScrollY,
- };
-
- let pointIsInBetween =
- (a: Types.canvasPoint, b: Types.canvasPoint, c: Types.canvasPoint)
- : bool => {
- let x0 = a.w;
- let x1 = b.w;
- let x2 = c.w;
- x0 < x2 && x2 < x1 || x1 < x2 && x2 < x0;
- };
-
- /* If all conditions are met, update the distribution */
- let updateDistWithMouseMovement =
- (
- ~point0: Types.canvasPoint,
- ~point1: Types.canvasPoint,
- ~canvasShape: Types.canvasShape,
- ) => {
- /*
- The mouse moves across the screen, and we get a series of (x,y) positions.
- We know where the mouse last was
- we update everything between the last (x,y) position and the new (x,y), using linear interpolation
- Note that we only want to update & iterate over the parts of the canvas which are changed by the mouse movement
- (otherwise, things might be too slow)
- */
-
- let slope = (point1.h -. point0.h) /. (point1.w -. point0.w);
- let pos0 =
- Convert.findClosestInOrderedArrayDangerously(
- point0.w,
- canvasShape.ws,
- );
- let pos1 =
- Convert.findClosestInOrderedArrayDangerously(
- point1.w,
- canvasShape.ws,
- );
-
- // Mouse is moving to the right
- for (i in pos0 to pos1) {
- let pointN = Convert.getPoint(canvasShape, i);
- switch (pointIsInBetween(point0, point1, pointN)) {
- | false => ()
- | true =>
- canvasShape.hs[i] = point0.h +. slope *. (pointN.w -. point0.w)
- };
- };
-
- // Mouse is moving to the left
- for (i in pos0 downto pos1) {
- let pointN = Convert.getPoint(canvasShape, i);
- switch (pointIsInBetween(point0, point1, pointN)) {
- | false => ()
- | true =>
- canvasShape.hs[i] = point0.h +. slope *. (pointN.w -. point0.w)
- };
- };
- canvasShape;
- };
-
- /* Check that the mouse movement was within the paddding box. */
- let validateYCoordinates =
- (~point: Types.canvasPoint, ~rectangle: Types.rectangle) => {
- switch (
- /*
- - If we also validate the xs, this produces a jaded user experience around the edges.
- - Instead, we will also update the first and last points in the updateDistWithMouseMovement, with the findClosestInOrderedArrayDangerously function, even when the x is outside the padding zone
- - When we send the distribution to foretold, we'll get rid of the first and last points.
- */
- /*
- point.w >= float_of_int(rectangle.left)
- +. CanvasContext.paddingFactorX(rectangle.width),
- point.w <= float_of_int(rectangle.right)
- -. CanvasContext.paddingFactorX(rectangle.width),
- */
- point.h
- -. windowScrollY >= float_of_int(rectangle.top)
- +. CanvasContext.paddingFactorY(rectangle.height),
- point.h
- -. windowScrollY <= float_of_int(rectangle.bottom)
- -. CanvasContext.paddingFactorY(rectangle.height),
- ) {
- | (true, true) => true
- | _ => false
- };
- };
-
- let decideWithCanvas = (~canvasElement, ~canvasShape, ~point0) => {
- let rectangle = CanvasContext.getBoundingClientRect(canvasElement);
- switch (
- validateYCoordinates(~point=point0, ~rectangle),
- validateYCoordinates(~point=point1, ~rectangle),
- ) {
- | (true, true) =>
- let newCanvasShape =
- updateDistWithMouseMovement(~point0, ~point1, ~canvasShape);
- setState((state: t) => {
- {
- ...state,
- lastMousePosition: Some(point1),
- canvasShape: Some(newCanvasShape),
- readyToRender: false,
- }
- });
- state.readyToRender
- ? Draw.canvasPlot(canvasElement, newCanvasShape) : ();
-
- | (false, true) => updateMousePosition(~point=point1, ~setState)
- | (_, false) => ()
- };
- };
-
- switch (
- potentialCanvas,
- state.canvasShape,
- state.isMouseDown,
- state.lastMousePosition,
- ) {
- | (Some(canvasElement), Some(canvasShape), true, Some(point0)) =>
- decideWithCanvas(~canvasElement, ~canvasShape, ~point0)
- | (Some(canvasElement), _, true, None) =>
- let rectangle = CanvasContext.getBoundingClientRect(canvasElement);
- validateYCoordinates(~point=point1, ~rectangle)
- ? updateMousePosition(~point=point1, ~setState) : ();
- | _ => ()
- };
- };
-
- let onMouseClick = (~setState, ~state) => {
- setState((state: t) => {
- {...state, isMouseDown: !state.isMouseDown, lastMousePosition: None}
- });
- };
-
- let onSubmitForetoldForm =
- (
- ~state: Types.canvasState,
- ~potentialCanvasElement: option(Dom.element),
- ~setState,
- ) => {
- let potentialCanvasShape = state.canvasShape;
-
- switch (potentialCanvasShape, potentialCanvasElement) {
- | (None, _) => ()
- | (_, None) => ()
- | (Some(canvasShape), Some(canvasElement)) =>
- let pdf =
- Convert.canvasShapeToContinuousShape(~canvasShape, ~canvasElement);
-
- /* create a cdf from a pdf */
- let _pdf = Continuous.T.normalize(pdf);
-
- let cdf = Continuous.T.integral(_pdf);
- let xs = [||];
- let ys = [||];
- for (i in 1 to 999) {
- /*
- - see comment in validateYCoordinates as to why this starts at 1.
- - foretold accepts distributions with up to 1000 points.
- */
- let j = i * 3;
- Js.Array.push(cdf.xyShape.xs[j], xs);
- Js.Array.push(cdf.xyShape.ys[j], ys);
-
- ();
- };
-
- ForetoldAPI.predict(
- ~measurableId=state.foretoldFormElements.measurableId,
- ~token=state.foretoldFormElements.token,
- ~comment=state.foretoldFormElements.comment,
- ~xs,
- ~ys,
- );
-
- setState((state: t) => {...state, hasJustBeenSentToForetold: true});
- Js.Global.setTimeout(
- () => {
- setState((state: t) =>
- {...state, hasJustBeenSentToForetold: false}
- )
- },
- 5000,
- );
-
- ();
- };
- ();
- };
-
- let onSubmitLimitsForm =
- (
- ~state: Types.canvasState,
- ~potentialCanvasElement: option(Dom.element),
- ~setState,
- ) => {
- let potentialCanvasShape = state.canvasShape;
-
- switch (potentialCanvasShape, potentialCanvasElement) {
- | (None, _) => ()
- | (_, None) => ()
- | (Some(canvasShape), Some(canvasElement)) =>
- let xValues = canvasShape.xValues;
- let length = Array.length(xValues);
- let xMin = xValues[0];
- let xMax = xValues[length - 1];
- let lower = state.distributionLimits.lower;
- let upper = state.distributionLimits.upper;
-
- let slope = (upper -. lower) /. (xMax -. xMin);
- let delta = lower -. slope *. xMin;
-
- let xValues = E.A.fmap(x => delta +. x *. slope, xValues);
- let newCanvasShape = {...canvasShape, xValues};
- setState((state: t) =>
- {
- ...state,
- canvasShape: Some(newCanvasShape),
- limitsHaveJustBeenUpdated: true,
- }
- );
- Draw.canvasPlot(canvasElement, newCanvasShape);
-
- Js.Global.setTimeout(
- () => {
- setState((state: t) =>
- {...state, limitsHaveJustBeenUpdated: false}
- )
- },
- 5000,
- );
-
- ();
- };
- ();
- };
-};
-
-module Styles = {
- open Css;
- let dist = style([padding(em(1.))]);
- let spacer = style([marginTop(em(1.))]);
-};
-
-[@react.component]
-let make = () => {
- let canvasRef: React.Ref.t(option(Dom.element)) = React.useRef(None); // should morally live inside the state, but this is tricky.
- let (state, setState) = React.useState(() => State.initialState);
-
- /* Draw the initial distribution */
- React.useEffect0(() => {
- let potentialCanvas = React.Ref.current(canvasRef);
- (
- switch (potentialCanvas) {
- | Some(canvasElement) =>
- Draw.initialDistribution(canvasElement, setState)
- | None => ()
- }
- )
- |> ignore;
- None;
- });
-
- /* Render the current distribution every 30ms, while the mouse is moving and changing it */
- React.useEffect0(() => {
- let runningInterval =
- Js.Global.setInterval(
- () => {
- setState((state: Types.canvasState) => {
- {...state, readyToRender: true}
- })
- },
- 30,
- );
- Some(() => Js.Global.clearInterval(runningInterval));
- });
-
- R.ste}>
-
- {"Click to begin drawing, click to stop drawing" |> R.ste}
- ;
-};
diff --git a/yarn.lock b/yarn.lock
index eb9cd5ab..14609a5c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2499,11 +2499,6 @@ bs-css@11.0.0:
dependencies:
emotion "^10.0.7"
-bs-fetch@^0.5.2:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/bs-fetch/-/bs-fetch-0.5.2.tgz#a9f4582ddb1414d3467b900305c738813481988c"
- integrity sha512-CYweTJcgLeLOqzR3vNsB+NmyEFhWThnPNdZmmF28nkFmo0CQEf+20eSHZJDO6EuAhhoRqJ0qp2VgxtH6zBB5xA==
-
bs-moment@0.4.5, bs-moment@^0.4.4:
version "0.4.5"
resolved "https://registry.yarnpkg.com/bs-moment/-/bs-moment-0.4.5.tgz#3f84fed55c2a70d25b0b6025e4e8d821fcdd4dc8"
@@ -2528,11 +2523,6 @@ bs-reform@9.7.1:
reason-react-update "^1.0.0"
reschema "^1.3.0"
-bs-webapi@^0.15.9:
- version "0.15.9"
- resolved "https://registry.yarnpkg.com/bs-webapi/-/bs-webapi-0.15.9.tgz#d1dcfbd40499a3b0914daacc4ceef47a0f3c906f"
- integrity sha512-bmzO6na2HmK01a34qB7afMwfVSrPxkP3EGzUslWObuxbHIlLC0PAMDu4lA8ZL5NasBUctlwnA1QZxox+1aNWWw==
-
bsb-js@1.1.7:
version "1.1.7"
resolved "https://registry.yarnpkg.com/bsb-js/-/bsb-js-1.1.7.tgz#12cc91e974f5896b3a2aa8358419d24e56f552c3"