+ Added the ability to change the upper and lower boundaries.
+ Made the drawings relative to the canvas, not to the screen. - Removed the mean line, as it didn't play nice with the ability to change upper and lower boundaries.
This commit is contained in:
		
							parent
							
								
									ff5b26d865
								
							
						
					
					
						commit
						23952af460
					
				| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
module Types = {
 | 
			
		||||
 | 
			
		||||
  type rectangle = {
 | 
			
		||||
    // Ref: https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
 | 
			
		||||
    left: int,
 | 
			
		||||
| 
						 | 
				
			
			@ -35,19 +34,26 @@ module Types = {
 | 
			
		|||
    xValues: array(float),
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  type formElements = {
 | 
			
		||||
  type foretoldFormElements = {
 | 
			
		||||
    measurableId: string,
 | 
			
		||||
    token: string,
 | 
			
		||||
    comment: string,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  type distributionLimits = {
 | 
			
		||||
    lower: float,
 | 
			
		||||
    upper: float,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  type canvasState = {
 | 
			
		||||
    isMouseDown: bool,
 | 
			
		||||
    lastMousePosition: option(canvasPoint),
 | 
			
		||||
    canvasShape: option(canvasShape),
 | 
			
		||||
    lastMousePosition: option(canvasPoint),
 | 
			
		||||
    isMouseDown: bool,
 | 
			
		||||
    readyToRender: bool,
 | 
			
		||||
    formElements,
 | 
			
		||||
    hasJustBeenSent: bool,
 | 
			
		||||
    hasJustBeenSentToForetold: bool,
 | 
			
		||||
    limitsHaveJustBeenUpdated: bool,
 | 
			
		||||
    foretoldFormElements,
 | 
			
		||||
    distributionLimits,
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -110,13 +116,16 @@ module Convert = {
 | 
			
		|||
      (~xyShape: Types.xyShape, ~canvasElement: Dom.element) => {
 | 
			
		||||
    let xs = xyShape.xs;
 | 
			
		||||
    let ys = xyShape.ys;
 | 
			
		||||
    let rectangle: Types.rectangle = CanvasContext.getBoundingClientRect(canvasElement);
 | 
			
		||||
    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);
 | 
			
		||||
      float_of_int(rectangle.width)
 | 
			
		||||
      *. CanvasContext.paddingRatioX
 | 
			
		||||
      /. (maxX -. minX);
 | 
			
		||||
    let ws =
 | 
			
		||||
      E.A.fmap(
 | 
			
		||||
        x =>
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +140,10 @@ module Convert = {
 | 
			
		|||
 | 
			
		||||
    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 ratioYs =
 | 
			
		||||
      float_of_int(rectangle.height)
 | 
			
		||||
      *. CanvasContext.paddingRatioY
 | 
			
		||||
      /. (maxY -. minY);
 | 
			
		||||
    let hs =
 | 
			
		||||
      E.A.fmap(
 | 
			
		||||
        y =>
 | 
			
		||||
| 
						 | 
				
			
			@ -151,11 +163,15 @@ module Convert = {
 | 
			
		|||
      : Types.continuousShape => {
 | 
			
		||||
    let xs = canvasShape.xValues;
 | 
			
		||||
    let hs = canvasShape.hs;
 | 
			
		||||
    let rectangle: Types.rectangle = CanvasContext.getBoundingClientRect(canvasElement);
 | 
			
		||||
    let rectangle: Types.rectangle =
 | 
			
		||||
      CanvasContext.getBoundingClientRect(canvasElement);
 | 
			
		||||
    let bottom = float_of_int(rectangle.bottom);
 | 
			
		||||
 | 
			
		||||
    let ysRelative =
 | 
			
		||||
      E.A.fmap(h => bottom -. h +. CanvasContext.paddingFactorY(rectangle.height), hs);
 | 
			
		||||
      E.A.fmap(
 | 
			
		||||
        h => bottom -. h +. CanvasContext.paddingFactorY(rectangle.height),
 | 
			
		||||
        hs,
 | 
			
		||||
      );
 | 
			
		||||
    let xyShape: Types.xyShape = {xs, ys: ysRelative};
 | 
			
		||||
    let continuousShape: Types.continuousShape = {
 | 
			
		||||
      xyShape,
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +212,6 @@ module Convert = {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
module Draw = {
 | 
			
		||||
 | 
			
		||||
  let line =
 | 
			
		||||
      (
 | 
			
		||||
        canvasElement: Dom.element,
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +233,8 @@ module Draw = {
 | 
			
		|||
  let canvasPlot =
 | 
			
		||||
      (canvasElement: Dom.element, canvasShape: Types.canvasShape) => {
 | 
			
		||||
    let context = CanvasContext.getContext2d(canvasElement);
 | 
			
		||||
    let rectangle: Types.rectangle = CanvasContext.getBoundingClientRect(canvasElement);
 | 
			
		||||
    let rectangle: Types.rectangle =
 | 
			
		||||
      CanvasContext.getBoundingClientRect(canvasElement);
 | 
			
		||||
 | 
			
		||||
    /* Some useful reference points */
 | 
			
		||||
    let paddingFactorX = CanvasContext.paddingFactorX(rectangle.width);
 | 
			
		||||
| 
						 | 
				
			
			@ -252,16 +268,22 @@ module Draw = {
 | 
			
		|||
 | 
			
		||||
    /* 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 = Distributions.Continuous.T.mean(continuousShape);
 | 
			
		||||
| 
						 | 
				
			
			@ -277,11 +299,14 @@ module Draw = {
 | 
			
		|||
          line(
 | 
			
		||||
            canvasElement,
 | 
			
		||||
            ~point0={w: meanLocationCanvasX, h: p00.h},
 | 
			
		||||
      ~point1={w: meanLocationCanvasX, h: meanLocationCanvasY},
 | 
			
		||||
            ~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");
 | 
			
		||||
| 
						 | 
				
			
			@ -318,19 +343,19 @@ module Draw = {
 | 
			
		|||
    /* draw units along the x axis */
 | 
			
		||||
    CanvasContext.font(context, "16px Roboto");
 | 
			
		||||
    CanvasContext.lineWidth(context, 2.0);
 | 
			
		||||
    let numUnits = 10;
 | 
			
		||||
    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(numUnits);
 | 
			
		||||
    let xSpan = (xMax -. xMin) /. float_of_int(numIntervals - 1);
 | 
			
		||||
 | 
			
		||||
    for (i in 0 to numUnits - 1) {
 | 
			
		||||
    for (i in 0 to numIntervals - 1) {
 | 
			
		||||
      let x =
 | 
			
		||||
        float_of_int(rectangle.left)
 | 
			
		||||
        +. width
 | 
			
		||||
        *. float_of_int(i)
 | 
			
		||||
        /. float_of_int(numUnits);
 | 
			
		||||
        /. float_of_int(numIntervals);
 | 
			
		||||
      let dashValue = xMin +. xSpan *. float_of_int(i);
 | 
			
		||||
      CanvasContext.fillText(
 | 
			
		||||
        Js.Float.toFixedWithPrecision(dashValue, ~digits=2),
 | 
			
		||||
| 
						 | 
				
			
			@ -340,7 +365,10 @@ module Draw = {
 | 
			
		|||
      );
 | 
			
		||||
      line(
 | 
			
		||||
        canvasElement,
 | 
			
		||||
        ~point0={w: x +. CanvasContext.paddingFactorX(rectangle.width), h: p00.h},
 | 
			
		||||
        ~point0={
 | 
			
		||||
          w: x +. CanvasContext.paddingFactorX(rectangle.width),
 | 
			
		||||
          h: p00.h,
 | 
			
		||||
        },
 | 
			
		||||
        ~point1={
 | 
			
		||||
          w: x +. CanvasContext.paddingFactorX(rectangle.width),
 | 
			
		||||
          h: p00.h +. 10.0,
 | 
			
		||||
| 
						 | 
				
			
			@ -350,9 +378,8 @@ module Draw = {
 | 
			
		|||
  };
 | 
			
		||||
 | 
			
		||||
  let initialDistribution = (canvasElement: Dom.element, setState) => {
 | 
			
		||||
 | 
			
		||||
    let mean = 10.0;
 | 
			
		||||
    let stdev = 4.0;
 | 
			
		||||
    let mean = 50.0;
 | 
			
		||||
    let stdev = 20.0;
 | 
			
		||||
    let numSamples = 3000;
 | 
			
		||||
 | 
			
		||||
    let normal: SymbolicDist.dist = `Normal({mean, stdev});
 | 
			
		||||
| 
						 | 
				
			
			@ -381,6 +408,11 @@ module Draw = {
 | 
			
		|||
         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)}
 | 
			
		||||
    });
 | 
			
		||||
| 
						 | 
				
			
			@ -443,20 +475,25 @@ module State = {
 | 
			
		|||
  type t = Types.canvasState;
 | 
			
		||||
 | 
			
		||||
  let initialState: t = {
 | 
			
		||||
    isMouseDown: false,
 | 
			
		||||
    lastMousePosition: None,
 | 
			
		||||
    canvasShape: None,
 | 
			
		||||
    lastMousePosition: None,
 | 
			
		||||
    isMouseDown: false,
 | 
			
		||||
    readyToRender: false,
 | 
			
		||||
    hasJustBeenSent: false,
 | 
			
		||||
    formElements: {
 | 
			
		||||
    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 updateMousePosition = (~point: Types.canvasPoint, ~setState) => {
 | 
			
		||||
    setState((state: t) => {...state, lastMousePosition: Some(point)});
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let onMouseMovement =
 | 
			
		||||
| 
						 | 
				
			
			@ -466,14 +503,15 @@ module State = {
 | 
			
		|||
        ~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),
 | 
			
		||||
      h: float_of_int(y) +. windowScrollY,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let pointIsInBetween =
 | 
			
		||||
| 
						 | 
				
			
			@ -485,7 +523,6 @@ module State = {
 | 
			
		|||
      x0 < x2 && x2 < x1 || x1 < x2 && x2 < x0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /* If all conditions are met, update the distribution */
 | 
			
		||||
    let updateDistWithMouseMovement =
 | 
			
		||||
        (
 | 
			
		||||
| 
						 | 
				
			
			@ -550,9 +587,11 @@ module State = {
 | 
			
		|||
         point.w <= float_of_int(rectangle.right)
 | 
			
		||||
         -. CanvasContext.paddingFactorX(rectangle.width),
 | 
			
		||||
         */
 | 
			
		||||
        point.h >= float_of_int(rectangle.top)
 | 
			
		||||
        point.h
 | 
			
		||||
        -. windowScrollY >= float_of_int(rectangle.top)
 | 
			
		||||
        +. CanvasContext.paddingFactorY(rectangle.height),
 | 
			
		||||
        point.h <= float_of_int(rectangle.bottom)
 | 
			
		||||
        point.h
 | 
			
		||||
        -. windowScrollY <= float_of_int(rectangle.bottom)
 | 
			
		||||
        -. CanvasContext.paddingFactorY(rectangle.height),
 | 
			
		||||
      ) {
 | 
			
		||||
      | (true, true) => true
 | 
			
		||||
| 
						 | 
				
			
			@ -567,8 +606,8 @@ module State = {
 | 
			
		|||
        validateYCoordinates(~point=point1, ~rectangle),
 | 
			
		||||
      ) {
 | 
			
		||||
      | (true, true) =>
 | 
			
		||||
        let newCanvasShape = updateDistWithMouseMovement(~point0, ~point1, ~canvasShape);
 | 
			
		||||
        state.readyToRender ? Draw.canvasPlot(canvasElement, newCanvasShape) : ();
 | 
			
		||||
        let newCanvasShape =
 | 
			
		||||
          updateDistWithMouseMovement(~point0, ~point1, ~canvasShape);
 | 
			
		||||
        setState((state: t) => {
 | 
			
		||||
          {
 | 
			
		||||
            ...state,
 | 
			
		||||
| 
						 | 
				
			
			@ -577,10 +616,13 @@ module State = {
 | 
			
		|||
            readyToRender: false,
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
        state.readyToRender
 | 
			
		||||
          ? Draw.canvasPlot(canvasElement, newCanvasShape) : ();
 | 
			
		||||
 | 
			
		||||
      | (false, true) => updateMousePosition(~point=point1, ~setState)
 | 
			
		||||
      | (_, false) => ()
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    switch (
 | 
			
		||||
      potentialCanvas,
 | 
			
		||||
| 
						 | 
				
			
			@ -589,10 +631,11 @@ module State = {
 | 
			
		|||
      state.lastMousePosition,
 | 
			
		||||
    ) {
 | 
			
		||||
    | (Some(canvasElement), Some(canvasShape), true, Some(point0)) =>
 | 
			
		||||
      decideWithCanvas(~canvasElement, ~canvasShape, ~point0);
 | 
			
		||||
      decideWithCanvas(~canvasElement, ~canvasShape, ~point0)
 | 
			
		||||
    | (Some(canvasElement), _, true, None) =>
 | 
			
		||||
      let rectangle = CanvasContext.getBoundingClientRect(canvasElement);
 | 
			
		||||
      validateYCoordinates(~point=point1, ~rectangle) ? updateMousePosition(~point=point1, ~setState) : ();
 | 
			
		||||
      validateYCoordinates(~point=point1, ~rectangle)
 | 
			
		||||
        ? updateMousePosition(~point=point1, ~setState) : ();
 | 
			
		||||
    | _ => ()
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
| 
						 | 
				
			
			@ -603,7 +646,7 @@ module State = {
 | 
			
		|||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  let onSubmitForm =
 | 
			
		||||
  let onSubmitForetoldForm =
 | 
			
		||||
      (
 | 
			
		||||
        ~state: Types.canvasState,
 | 
			
		||||
        ~potentialCanvasElement: option(Dom.element),
 | 
			
		||||
| 
						 | 
				
			
			@ -615,7 +658,6 @@ module State = {
 | 
			
		|||
    | (None, _) => ()
 | 
			
		||||
    | (_, None) => ()
 | 
			
		||||
    | (Some(canvasShape), Some(canvasElement)) =>
 | 
			
		||||
    
 | 
			
		||||
      let pdf =
 | 
			
		||||
        Convert.canvasShapeToContinuousShape(~canvasShape, ~canvasElement);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -637,21 +679,75 @@ module State = {
 | 
			
		|||
        let j = i * 3;
 | 
			
		||||
        Js.Array.push(cdf.xyShape.xs[j], xs);
 | 
			
		||||
        Js.Array.push(cdf.xyShape.ys[j], ys);
 | 
			
		||||
 | 
			
		||||
        ();
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      ForetoldAPI.predict(
 | 
			
		||||
        ~measurableId=state.formElements.measurableId,
 | 
			
		||||
        ~token=state.formElements.token,
 | 
			
		||||
        ~comment=state.formElements.comment,
 | 
			
		||||
        ~measurableId=state.foretoldFormElements.measurableId,
 | 
			
		||||
        ~token=state.foretoldFormElements.token,
 | 
			
		||||
        ~comment=state.foretoldFormElements.comment,
 | 
			
		||||
        ~xs,
 | 
			
		||||
        ~ys,
 | 
			
		||||
      );
 | 
			
		||||
      setState((state: t) => {...state, hasJustBeenSent: true});
 | 
			
		||||
 | 
			
		||||
      setState((state: t) => {...state, hasJustBeenSentToForetold: true});
 | 
			
		||||
      Js.Global.setTimeout(
 | 
			
		||||
        () => {
 | 
			
		||||
          setState((state: t) => {...state, hasJustBeenSent: false});
 | 
			
		||||
          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,
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      ();
 | 
			
		||||
    };
 | 
			
		||||
    ();
 | 
			
		||||
| 
						 | 
				
			
			@ -666,7 +762,6 @@ module Styles = {
 | 
			
		|||
 | 
			
		||||
[@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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -684,7 +779,7 @@ let make = () => {
 | 
			
		|||
    None;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /* Render the current distribution every 40ms, while the mouse is moving and changing it */
 | 
			
		||||
  /* Render the current distribution every 30ms, while the mouse is moving and changing it */
 | 
			
		||||
  React.useEffect0(() => {
 | 
			
		||||
    let runningInterval =
 | 
			
		||||
      Js.Global.setInterval(
 | 
			
		||||
| 
						 | 
				
			
			@ -693,14 +788,14 @@ let make = () => {
 | 
			
		|||
            {...state, readyToRender: true}
 | 
			
		||||
          })
 | 
			
		||||
        },
 | 
			
		||||
        40,
 | 
			
		||||
        30,
 | 
			
		||||
      );
 | 
			
		||||
    Some(() => Js.Global.clearInterval(runningInterval));
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  <Antd.Card title={"Distribution Drawer" |> R.ste}>
 | 
			
		||||
    <div className=Styles.spacer />
 | 
			
		||||
    <p>{"Click to begin drawing, click to stop drawing" |> R.ste}</p>
 | 
			
		||||
    <p> {"Click to begin drawing, click to stop drawing" |> R.ste} </p>
 | 
			
		||||
    <canvas
 | 
			
		||||
      width="1000"
 | 
			
		||||
      height="700"
 | 
			
		||||
| 
						 | 
				
			
			@ -722,13 +817,88 @@ let make = () => {
 | 
			
		|||
    <br />
 | 
			
		||||
    <br />
 | 
			
		||||
    <br />
 | 
			
		||||
    <Antd.Card title={"Update upper and lower limits" |> R.ste}>
 | 
			
		||||
      <form
 | 
			
		||||
        id="update-limits"
 | 
			
		||||
        onSubmit={(e: ReactEvent.Form.t): unit => {
 | 
			
		||||
          ReactEvent.Form.preventDefault(e);
 | 
			
		||||
          /* code to run on submit */
 | 
			
		||||
          State.onSubmitLimitsForm(
 | 
			
		||||
            ~state,
 | 
			
		||||
            ~potentialCanvasElement=React.Ref.current(canvasRef),
 | 
			
		||||
            ~setState,
 | 
			
		||||
          );
 | 
			
		||||
          ();
 | 
			
		||||
        }}>
 | 
			
		||||
        <div>
 | 
			
		||||
          <label> {"Lower:  " |> R.ste} </label>
 | 
			
		||||
          <input
 | 
			
		||||
            type_="number"
 | 
			
		||||
            id="lowerlimit"
 | 
			
		||||
            name="lowerlimit"
 | 
			
		||||
            value={Js.Float.toString(state.distributionLimits.lower)}
 | 
			
		||||
            placeholder="a number. f.ex., 0"
 | 
			
		||||
            required=true
 | 
			
		||||
            step=0.001
 | 
			
		||||
            onChange={event => {
 | 
			
		||||
              let value = ReactEvent.Form.target(event)##value;
 | 
			
		||||
              setState((state: Types.canvasState) => {
 | 
			
		||||
                {
 | 
			
		||||
                  ...state,
 | 
			
		||||
                  distributionLimits: {
 | 
			
		||||
                    ...state.distributionLimits,
 | 
			
		||||
                    lower: value,
 | 
			
		||||
                  },
 | 
			
		||||
                }
 | 
			
		||||
              });
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
        <br />
 | 
			
		||||
        <div>
 | 
			
		||||
          <label> {"Upper:  " |> R.ste} </label>
 | 
			
		||||
          <input
 | 
			
		||||
            type_="number"
 | 
			
		||||
            id="upperlimit"
 | 
			
		||||
            name="upperlimit"
 | 
			
		||||
            value={Js.Float.toString(state.distributionLimits.upper)}
 | 
			
		||||
            placeholder="a number. f.ex., 100"
 | 
			
		||||
            required=true
 | 
			
		||||
            step=0.001
 | 
			
		||||
            onChange={event => {
 | 
			
		||||
              let value = ReactEvent.Form.target(event)##value;
 | 
			
		||||
              setState((state: Types.canvasState) => {
 | 
			
		||||
                {
 | 
			
		||||
                  ...state,
 | 
			
		||||
                  distributionLimits: {
 | 
			
		||||
                    ...state.distributionLimits,
 | 
			
		||||
                    upper: value,
 | 
			
		||||
                  },
 | 
			
		||||
                }
 | 
			
		||||
              });
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
        <br />
 | 
			
		||||
        <button type_="submit" id="updatelimits">
 | 
			
		||||
          {"Update limits" |> R.ste}
 | 
			
		||||
        </button>
 | 
			
		||||
        <br />
 | 
			
		||||
        <p hidden={!state.limitsHaveJustBeenUpdated}>
 | 
			
		||||
          {"Updated!" |> R.ste}
 | 
			
		||||
        </p>
 | 
			
		||||
      </form>
 | 
			
		||||
    </Antd.Card>
 | 
			
		||||
    <br />
 | 
			
		||||
    <br />
 | 
			
		||||
    <br />
 | 
			
		||||
    <Antd.Card title={"Send to foretold" |> R.ste}>
 | 
			
		||||
      <form
 | 
			
		||||
        id="send-to-foretold"
 | 
			
		||||
        onSubmit={(e: ReactEvent.Form.t): unit => {
 | 
			
		||||
          ReactEvent.Form.preventDefault(e);
 | 
			
		||||
          /* code to run on submit */
 | 
			
		||||
          State.onSubmitForm(
 | 
			
		||||
          State.onSubmitForetoldForm(
 | 
			
		||||
            ~state,
 | 
			
		||||
            ~potentialCanvasElement=React.Ref.current(canvasRef),
 | 
			
		||||
            ~setState,
 | 
			
		||||
| 
						 | 
				
			
			@ -741,7 +911,7 @@ let make = () => {
 | 
			
		|||
            type_="text"
 | 
			
		||||
            id="measurableId"
 | 
			
		||||
            name="measurableId"
 | 
			
		||||
            value={state.formElements.measurableId}
 | 
			
		||||
            value={state.foretoldFormElements.measurableId}
 | 
			
		||||
            placeholder="The last bit in the url, after the m"
 | 
			
		||||
            required=true
 | 
			
		||||
            onChange={event => {
 | 
			
		||||
| 
						 | 
				
			
			@ -749,8 +919,8 @@ let make = () => {
 | 
			
		|||
              setState((state: Types.canvasState) => {
 | 
			
		||||
                {
 | 
			
		||||
                  ...state,
 | 
			
		||||
                  formElements: {
 | 
			
		||||
                    ...state.formElements,
 | 
			
		||||
                  foretoldFormElements: {
 | 
			
		||||
                    ...state.foretoldFormElements,
 | 
			
		||||
                    measurableId: value,
 | 
			
		||||
                  },
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -765,7 +935,7 @@ let make = () => {
 | 
			
		|||
            type_="text"
 | 
			
		||||
            id="foretoldToken"
 | 
			
		||||
            name="foretoldToken"
 | 
			
		||||
            value={state.formElements.token}
 | 
			
		||||
            value={state.foretoldFormElements.token}
 | 
			
		||||
            placeholder="Profile -> Bots -> (New Bot) -> Token"
 | 
			
		||||
            required=true
 | 
			
		||||
            onChange={event => {
 | 
			
		||||
| 
						 | 
				
			
			@ -773,8 +943,8 @@ let make = () => {
 | 
			
		|||
              setState((state: Types.canvasState) => {
 | 
			
		||||
                {
 | 
			
		||||
                  ...state,
 | 
			
		||||
                  formElements: {
 | 
			
		||||
                    ...state.formElements,
 | 
			
		||||
                  foretoldFormElements: {
 | 
			
		||||
                    ...state.foretoldFormElements,
 | 
			
		||||
                    token: value,
 | 
			
		||||
                  },
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -794,8 +964,8 @@ let make = () => {
 | 
			
		|||
            setState((state: Types.canvasState) => {
 | 
			
		||||
              {
 | 
			
		||||
                ...state,
 | 
			
		||||
                formElements: {
 | 
			
		||||
                  ...state.formElements,
 | 
			
		||||
                foretoldFormElements: {
 | 
			
		||||
                  ...state.foretoldFormElements,
 | 
			
		||||
                  comment: value,
 | 
			
		||||
                },
 | 
			
		||||
              }
 | 
			
		||||
| 
						 | 
				
			
			@ -807,7 +977,7 @@ let make = () => {
 | 
			
		|||
          {"Send to foretold" |> R.ste}
 | 
			
		||||
        </button>
 | 
			
		||||
        <br />
 | 
			
		||||
        <p hidden={!state.hasJustBeenSent}> {"Sent!" |> R.ste} </p>
 | 
			
		||||
        <p hidden={!state.hasJustBeenSentToForetold}> {"Sent!" |> R.ste} </p>
 | 
			
		||||
      </form>
 | 
			
		||||
    </Antd.Card>
 | 
			
		||||
  </Antd.Card>;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user