From e9d5dbeef2bf1dab9dfb863d970b70b3074e3d0a Mon Sep 17 00:00:00 2001 From: Michael Foiani Date: Wed, 2 Nov 2022 14:56:20 -0400 Subject: add basic heartbeat functinality througha ping/pong api cycle --- src/client/util/PingManager.ts | 31 +++++++ src/client/views/Main.tsx | 2 + src/client/views/MainView.tsx | 158 ++++++++++++++++++-------------- src/client/views/topbar/TopBar.tsx | 19 +++- src/server/ApiManagers/UploadManager.ts | 10 ++ 5 files changed, 152 insertions(+), 68 deletions(-) create mode 100644 src/client/util/PingManager.ts (limited to 'src') diff --git a/src/client/util/PingManager.ts b/src/client/util/PingManager.ts new file mode 100644 index 000000000..7562faf03 --- /dev/null +++ b/src/client/util/PingManager.ts @@ -0,0 +1,31 @@ +import { action, IReactionDisposer, observable, observe, reaction } from "mobx"; +import { Networking } from "../Network"; +export class PingManager { + // create static instance and getter for global use + @observable static _instance: PingManager; + static get Instance(): PingManager { + return PingManager._instance; + } + + @observable isBeating: boolean = true; + private setIsBeating = action((status: boolean) => this.isBeating = status); + + ping = async (): Promise => { + try { + const response = await Networking.PostToServer('/ping', { date: new Date() }); + // console.log('ping response', response, this.interval); + !this.isBeating && this.setIsBeating(true); + } catch { + console.error('ping error'); + this.isBeating && this.setIsBeating(false); + } + } + + // not used now, but may need to clear interval + private interval: NodeJS.Timeout | null = null; + INTERVAL_SECONDS = 1; + constructor() { + PingManager._instance = this; + this.interval = setInterval(this.ping, this.INTERVAL_SECONDS * 1000); + } +} diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index f327f3184..a1d221af2 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -14,6 +14,7 @@ import { TrackMovements } from '../util/TrackMovements'; import { CollectionView } from './collections/CollectionView'; import { MainView } from './MainView'; import * as dotenv from 'dotenv'; // see https://github.com/motdotla/dotenv#how-do-i-use-dotenv-with-import +import { PingManager } from '../util/PingManager'; dotenv.config(); AssignAllExtensions(); @@ -44,6 +45,7 @@ AssignAllExtensions(); new LinkManager(); new TrackMovements(); new ReplayMovements(); + new PingManager(); ReactDOM.createRoot(document.getElementById('root')!).render(); }, 0); })(); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 9648a7807..5be5c3588 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -66,6 +66,7 @@ import { PropertiesView } from './PropertiesView'; import { DashboardStyleProvider, DefaultStyleProvider } from './StyleProvider'; import { TopBar } from './topbar/TopBar'; import 'browndash-components/dist/styles/global.min.css'; +import { PingManager } from '../util/PingManager'; const _global = (window /* browser */ || global) /* node */ as any; @observer @@ -143,75 +144,96 @@ export class MainView extends React.Component { componentDidMount() { document.getElementById('root')?.addEventListener('scroll', e => (ele => (ele.scrollLeft = ele.scrollTop = 0))(document.getElementById('root')!)); const ele = document.getElementById('loader'); - const prog = document.getElementById('dash-progress'); - if (ele && prog) { - // remove from DOM - setTimeout(() => { - clearTimeout(); - prog.style.transition = '1s'; - prog.style.width = '100%'; - }, 0); - setTimeout(() => (ele.outerHTML = ''), 1000); - } - this._sidebarContent.proto = undefined; - if (!MainView.Live) { - DocServer.setPlaygroundFields([ - 'dataTransition', - 'viewTransition', - 'treeViewOpen', - 'showSidebar', - 'itemIndex', // for changing slides in presentations - 'sidebarWidthPercent', - 'currentTimecode', - 'timelineHeightPercent', - 'presStatus', - 'panX', - 'panY', - 'overlayX', - 'overlayY', - 'fitWidth', - 'nativeWidth', - 'nativeHeight', - 'text-scrollHeight', - 'text-height', - 'hideMinimap', - 'viewScale', - 'scrollTop', - 'hidden', - 'curPage', - 'viewType', - 'chromeHidden', - 'currentFrame', - 'width', - 'height', - 'nativeWidth', - ]); // can play with these fields on someone else's + console.log(PingManager.Instance); + + const wrapper = () => { + const prog = document.getElementById('dash-progress'); + if (ele && prog) { + // remove from DOM + setTimeout(() => { + clearTimeout(); + prog.style.transition = '1s'; + prog.style.width = '100%'; + }, 0); + setTimeout(() => (ele.outerHTML = ''), 1000); + } + this._sidebarContent.proto = undefined; + if (!MainView.Live) { + DocServer.setPlaygroundFields([ + 'dataTransition', + 'viewTransition', + 'treeViewOpen', + 'showSidebar', + 'itemIndex', // for changing slides in presentations + 'sidebarWidthPercent', + 'currentTimecode', + 'timelineHeightPercent', + 'presStatus', + 'panX', + 'panY', + 'overlayX', + 'overlayY', + 'fitWidth', + 'nativeWidth', + 'nativeHeight', + 'text-scrollHeight', + 'text-height', + 'hideMinimap', + 'viewScale', + 'scrollTop', + 'hidden', + 'curPage', + 'viewType', + 'chromeHidden', + 'currentFrame', + 'width', + 'height', + 'nativeWidth', + ]); // can play with these fields on someone else's + } + DocServer.GetRefField('rtfProto').then( + proto => + proto instanceof Doc && + reaction( + () => StrCast(proto.BROADCAST_MESSAGE), + msg => msg && alert(msg) + ) + ); + + const tag = document.createElement('script'); + tag.src = 'https://www.youtube.com/iframe_api'; + const firstScriptTag = document.getElementsByTagName('script')[0]; + firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag); + window.removeEventListener('keydown', KeyManager.Instance.handle); + window.addEventListener('keydown', KeyManager.Instance.handle); + window.removeEventListener('keyup', KeyManager.Instance.unhandle); + window.addEventListener('keyup', KeyManager.Instance.unhandle); + window.addEventListener('paste', KeyManager.Instance.paste as any); + document.addEventListener('dash', (e: any) => { + // event used by chrome plugin to tell Dash which document to focus on + const id = FormattedTextBox.GetDocFromUrl(e.detail); + DocServer.GetRefField(id).then(doc => (doc instanceof Doc ? DocumentManager.Instance.jumpToDocument(doc, false, undefined, []) : null)); + }); + document.addEventListener('linkAnnotationToDash', Hypothesis.linkListener); + this.initEventListeners(); } - DocServer.GetRefField('rtfProto').then( - proto => - proto instanceof Doc && - reaction( - () => StrCast(proto.BROADCAST_MESSAGE), - msg => msg && alert(msg) - ) - ); - const tag = document.createElement('script'); - tag.src = 'https://www.youtube.com/iframe_api'; - const firstScriptTag = document.getElementsByTagName('script')[0]; - firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag); - window.removeEventListener('keydown', KeyManager.Instance.handle); - window.addEventListener('keydown', KeyManager.Instance.handle); - window.removeEventListener('keyup', KeyManager.Instance.unhandle); - window.addEventListener('keyup', KeyManager.Instance.unhandle); - window.addEventListener('paste', KeyManager.Instance.paste as any); - document.addEventListener('dash', (e: any) => { - // event used by chrome plugin to tell Dash which document to focus on - const id = FormattedTextBox.GetDocFromUrl(e.detail); - DocServer.GetRefField(id).then(doc => (doc instanceof Doc ? DocumentManager.Instance.jumpToDocument(doc, false, undefined, []) : null)); - }); - document.addEventListener('linkAnnotationToDash', Hypothesis.linkListener); - this.initEventListeners(); + if (PingManager.Instance.isBeating) { + wrapper(); + } else { + console.error('PingManager is not beating', new Date()); + const dispose = reaction( + () => PingManager.Instance.isBeating, + isBeating => { + if (isBeating) { + console.log('PingManager is beating', new Date()); + wrapper(); + dispose(); + } + } + ); + } + } componentWillUnMount() { @@ -478,6 +500,8 @@ export class MainView extends React.Component { fa.faSquareRootAlt, fa.faVolumeMute, fa.faUserCircle, + fa.faHeart, + fa.faHeartBroken, ] ); this.initAuthenticationRouters(); diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx index 7e728306c..50a93ee92 100644 --- a/src/client/views/topbar/TopBar.tsx +++ b/src/client/views/topbar/TopBar.tsx @@ -1,6 +1,6 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Button, FontSize, IconButton, Size } from 'browndash-components'; -import { action, computed, observable } from 'mobx'; +import { action, computed, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { FaBug, FaCamera } from 'react-icons/fa'; @@ -8,6 +8,7 @@ import { AclAdmin, Doc, DocListCast } from '../../../fields/Doc'; import { StrCast } from '../../../fields/Types'; import { GetEffectiveAcl } from '../../../fields/util'; import { DocumentManager } from '../../util/DocumentManager'; +import { PingManager } from '../../util/PingManager'; import { ReportManager } from '../../util/ReportManager'; import { SettingsManager } from '../../util/SettingsManager'; import { SharingManager } from '../../util/SharingManager'; @@ -35,6 +36,12 @@ export class TopBar extends React.Component { @observable textColor: string = Colors.LIGHT_GRAY; @observable backgroundColor: string = Colors.DARK_GRAY; + @observable happyHeart: boolean = PingManager.Instance.isBeating; + setHappyHeart = action((status: boolean) => this.happyHeart = status); + dispose = reaction(() => PingManager.Instance.isBeating, isBeating => this.setHappyHeart(isBeating)); + + + /** * Returns the left hand side of the topbar. * This side of the topbar contains the different modes. @@ -176,6 +183,16 @@ export class TopBar extends React.Component { onClick={() => SettingsManager.Instance.open()} icon={} /> + SettingsManager.Instance.open()} + icon={} + /> {/* + + +
+
+

{questionPartOne}

+

{questionPartTwo}

+
+
{answerInputFields}
+
+ + )} + {mode == "Tutorial" && ( +
+
+

Problem

+

{selectedTutorial.question}

+
+
+ { + let step = stepNumber - 1; + step = Math.max(step, 0); + step = Math.min(step, selectedTutorial.steps.length - 1); + setStepNumber(step); + setStartForces( + getForceFromJSON(selectedTutorial.steps[step].forces) + ); + setUpdatedForces( + getForceFromJSON(selectedTutorial.steps[step].forces) + ); + setShowForceMagnitudes( + selectedTutorial.steps[step].showMagnitude + ); + }} + disabled={stepNumber == 0} + > + + +
+

+ Step {stepNumber + 1}:{" "} + {selectedTutorial.steps[stepNumber].description} +

+

{selectedTutorial.steps[stepNumber].content}

+
+ { + let step = stepNumber + 1; + step = Math.max(step, 0); + step = Math.min(step, selectedTutorial.steps.length - 1); + setStepNumber(step); + setStartForces( + getForceFromJSON(selectedTutorial.steps[step].forces) + ); + setUpdatedForces( + getForceFromJSON(selectedTutorial.steps[step].forces) + ); + setShowForceMagnitudes( + selectedTutorial.steps[step].showMagnitude + ); + }} + disabled={stepNumber == selectedTutorial.steps.length - 1} + > + + +
+
+

Resources

+ {simulationType == "One Weight" && ( + + )} + {simulationType == "Inclined Plane" && ( + + )} + {simulationType == "Pendulum" && ( + + )} +
+
+ )} + {mode == "Review" && ( +
+

setMode("Tutorial")} + > + {" "} + Go to walkthrough{" "} +

+
+ + +
+
+ )} + + {mode == "Freeform" && ( +
+ + + {!wedge && !pendulum && ( + + setElasticCollisions(!elasticCollisions) + } + /> + } + label="Make collisions elastic" + labelPlacement="start" + /> + )} + {!wedge && !pendulum && } + setShowForces(!showForces)} + defaultChecked + /> + } + label="Show force vectors" + labelPlacement="start" + /> + setShowAcceleration(!showAcceleration)} + /> + } + label="Show acceleration vector" + labelPlacement="start" + /> + setShowVelocity(!showVelocity)} + /> + } + label="Show velocity vector" + labelPlacement="start" + /> + + + {wedge && simulationPaused && ( +
+ + θ + Angle of incline plane from the ground, 0-49 + + } + followCursor + > + θ + + } + lowerBound={0} + changeValue={setWedgeAngle} + step={1} + unit={"°"} + upperBound={49} + value={wedgeAngle} + effect={changeWedgeBasedOnNewAngle} + radianEquivalent={true} + mode={"Freeform"} + /> + + + μs + + Coefficient of static friction, between 0 and 1 + + } + followCursor + > + + μs + + + } + lowerBound={0} + changeValue={setCoefficientOfStaticFriction} + step={0.1} + unit={""} + upperBound={1} + value={coefficientOfStaticFriction} + effect={updateForcesWithFriction} + mode={"Freeform"} + /> + + + μk + + Coefficient of kinetic friction, between 0 and + coefficient of static friction + + } + followCursor + > + + μk + + + } + lowerBound={0} + changeValue={setCoefficientOfKineticFriction} + step={0.1} + unit={""} + upperBound={Number(coefficientOfStaticFriction)} + value={coefficientOfKineticFriction} + mode={"Freeform"} + /> +
+ )} + {wedge && !simulationPaused && ( + + θ: {Math.round(Number(wedgeAngle) * 100) / 100}° ≈{" "} + {Math.round(((Number(wedgeAngle) * Math.PI) / 180) * 100) / + 100}{" "} + rad +
+ μ s: {coefficientOfStaticFriction} +
+ μ k: {coefficientOfKineticFriction} +
+ )} + {pendulum && !simulationPaused && ( + + θ: {Math.round(pendulumAngle * 100) / 100}° ≈{" "} + {Math.round(((pendulumAngle * Math.PI) / 180) * 100) / 100}{" "} + rad + + )} + {pendulum && simulationPaused && ( +
+ + θ + Pendulum angle offest from equilibrium + + } + followCursor + > + θ + + } + lowerBound={0} + changeValue={setPendulumAngle} + step={1} + unit={"°"} + upperBound={59} + value={pendulumAngle} + effect={(value) => { + if (pendulum) { + const mag = + 1 * 9.81 * Math.cos((value * Math.PI) / 180); + + const forceOfTension: IForce = { + description: "Tension", + magnitude: mag, + directionInDegrees: 90 - value, + }; + setUpdatedForces([forceOfGravity, forceOfTension]); + setAdjustPendulumAngle({ + angle: value, + length: pendulumLength, + }); + } + }} + radianEquivalent={true} + mode={"Freeform"} + /> + + Length + Pendulum rod length + + } + followCursor + > + Length + + } + lowerBound={0} + changeValue={setPendulumLength} + step={1} + unit={"m"} + upperBound={400} + value={pendulumLength} + effect={(value) => { + if (pendulum) { + setAdjustPendulumAngle({ + angle: pendulumAngle, + length: value, + }); + } + }} + radianEquivalent={false} + mode={"Freeform"} + /> +
+ )} +
+ )} +
+ {mode == "Freeform" && twoWeights &&

Red Weight

} + {mode == "Freeform" && weight && ( + + + + + + + + + + + + + + + + + + + + + + + +
 XY
{ + window.open( + "https://www.khanacademy.org/science/physics/two-dimensional-motion" + ); + }} + > + + Position + Equation: x1 + =x + 0 + +v + 0 + t+0.5at + 2 +
+ Units: m + + } + followCursor + > + Position +
+
+ {(!simulationPaused || wedge) && ( +

+ {positionXDisplay} m +

+ )}{" "} + {simulationPaused && !wedge && ( + { + setDisplayChange({ + xDisplay: value, + yDisplay: positionYDisplay, + }); + }} + small={true} + mode={"Freeform"} + /> + )}{" "} +
+ {(!simulationPaused || wedge) && ( +

+ {positionYDisplay} m +

+ )}{" "} + {simulationPaused && !wedge && ( + { + setDisplayChange({ + xDisplay: positionXDisplay, + yDisplay: value, + }); + }} + small={true} + mode={"Freeform"} + /> + )}{" "} +
{ + window.open( + "https://www.khanacademy.org/science/physics/two-dimensional-motion" + ); + }} + > + + Velocity + Equation: v1 + =v + 0 + +at +
+ Units: m/s + + } + followCursor + > + Velocity +
+
+ {(!simulationPaused || pendulum || wedge) && ( +

+ {velocityXDisplay} m/s +

+ )}{" "} + {simulationPaused && !pendulum && !wedge && ( + + setDisplayChange({ + xDisplay: positionXDisplay, + yDisplay: positionYDisplay, + }) + } + small={true} + mode={"Freeform"} + /> + )}{" "} +
+ {(!simulationPaused || pendulum || wedge) && ( +

+ {velocityYDisplay} m/s +

+ )}{" "} + {simulationPaused && !pendulum && !wedge && ( + + setDisplayChange({ + xDisplay: positionXDisplay, + yDisplay: positionYDisplay, + }) + } + small={true} + mode={"Freeform"} + /> + )}{" "} +
{ + window.open( + "https://www.khanacademy.org/science/physics/two-dimensional-motion" + ); + }} + > + + + Acceleration + + Equation: a=F/m +
+ Units: m/s + 2 + + } + followCursor + > + Acceleration +
+
+ {accelerationXDisplay} m/s2 + + {accelerationYDisplay} m/s2 +
+ )} +
+ {/* {mode == "Freeform" && + simulationElements.length > 0 && + simulationElements[0].pendulum && ( +
+ + + + + + + + + + + + + + + + + + + +
 Value
Potential Energy + {Math.round( + pendulumLength * + (1 - Math.cos(pendulumAngle)) * + 9.81 * + 10 + ) / 10}{" "} + J +
Kinetic Energy + {Math.round( + (Math.round( + pendulumLength * + (1 - Math.cos(startPendulumAngle)) * + 9.81 * + 10 + ) / + 10 - + Math.round( + pendulumLength * + (1 - Math.cos(pendulumAngle)) * + 9.81 * + 10 + ) / + 10) * + 10 + ) / 10}{" "} + J +
+ Total Energy + + {Math.round( + pendulumLength * + (1 - Math.cos(startPendulumAngle)) * + 9.81 * + 10 + ) / 10}{" "} + J +
+
+ )}*/} + + + + + ); +} + +export default App; diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss index 2eb6e6ff0..f756d59fc 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.scss +++ b/src/client/views/nodes/PhysicsSimulationBox.scss @@ -1,3 +1,69 @@ -.physicsSimulationContainer { - -} \ No newline at end of file +* { + box-sizing: border-box; + font-size: 14px; +} + +.mechanicsSimulationContainer { + height: 100vh; + width: 100vw; + display: flex; + + .mechanicsSimulationContentContainer { + width: 70%; + + .mechanicsSimulationButtons { + display: flex; + justify-content: space-between; + } + } + + .mechanicsSimulationEquationContainer { + width: 30%; + padding: 1em; + display: flex; + flex-direction: column; + + .mechanicsSimulationControls { + display: flex; + justify-content: space-between; + } + + .slider { + margin-top: 0.5em; + } + } +} + +.coordinateSystem { + z-index: -100; +} + +th, +td { + border-collapse: collapse; + padding: 1em; +} + +table { + min-width: 300px; +} + +tr:nth-child(even) { + background-color: #d6eeee; +} + +button { + z-index: 5000; +} + +.wordProblemBox { + border-style: solid; + border-color: black; + border-width: 1px; + margin-top: 10px; + padding: 10px; +} + +.answer-inactive { + pointer-events: none; +} diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index b16bccdde..4a68ba5aa 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -3,6 +3,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import React = require('react'); import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { observer } from 'mobx-react'; +import App from './PhysicsSimulationApp'; export interface IForce { description: string; @@ -18,65 +19,17 @@ export interface IWallProps { @observer export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() { - forceOfGravity: IForce = { - description: "Gravity", - magnitude: 9.81, - directionInDegrees: 270, -}; - - // Logic for Dash integration public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); } constructor(props: any) { super(props); - this.state = { - timer: 0, - weight: true, - pendulum: false, - wedge: false, - startPosX: 0, - startPosY: 0, - showVelocity: false, - showAcceleration: false, - showForces: false, - elasticCollisions: false, - updatedForces: [this.forceOfGravity], - wallPositions: [] - } } - // Add one weight to the simulation - addWeight = () => { - this.setState({weight: true}); - this.setState({wedge: false}); - this.setState({pendulum: false}); - }; - -// Remove floor and walls from simulation -removeWalls = () => { - this.setState({wallPositions: []}); -}; - -// Add floor and walls to simulation -addWalls = () => { - const walls: IWallProps[] = []; - walls.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 }); - walls.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 }); - walls.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 }); - this.setState({wallPositions: walls}); -}; - - // Timer for animating the simulation - // setInterval(() => { - // const time = this.timer ?? 0 - // this.setState({timer: time+1}); - // }, 60); - render () { return (
- -
+ + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx new file mode 100644 index 000000000..c63538cc0 --- /dev/null +++ b/src/client/views/nodes/PhysicsSimulationWall.tsx @@ -0,0 +1,35 @@ +import { useState, useEffect } from "react"; +import "./Weight.scss"; + +export interface Force { + magnitude: number; + directionInDegrees: number; +} +export interface IWallProps { + length: number; + xPos: number; + yPos: number; + angleInDegrees: number; +} + +export const Wall = (props: IWallProps) => { + const { length, xPos, yPos, angleInDegrees } = props; + + let wallStyle = { + width: length + "%", + height: 0.5 + "vw", + position: "absolute" as "absolute", + left: xPos + "%", + top: yPos + "%", + backgroundColor: "#6c7b8b", + zIndex: -1000, + margin: 0, + padding: 0, + }; + if (angleInDegrees != 0) { + wallStyle.width = 0.5 + "vw"; + wallStyle.height = length + "%"; + } + + return
; +}; diff --git a/src/client/views/nodes/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsSimulationWedge.tsx new file mode 100644 index 000000000..af01c1c51 --- /dev/null +++ b/src/client/views/nodes/PhysicsSimulationWedge.tsx @@ -0,0 +1,64 @@ +import { useState, useEffect, useCallback } from "react"; +import "./Wedge.scss"; + +export interface IWedgeProps { + startHeight: number; + startWidth: number; + startLeft: number; +} + +export const Wedge = (props: IWedgeProps) => { + const { startHeight, startWidth, startLeft } = props; + + const [angleInRadians, setAngleInRadians] = useState( + Math.atan(startHeight / startWidth) + ); + const [left, setLeft] = useState(startLeft); + const [coordinates, setCoordinates] = useState(""); + + const color = "#deb887"; + + useEffect(() => { + const coordinatePair1 = + Math.round(left) + "," + Math.round(window.innerHeight * 0.8) + " "; + const coordinatePair2 = + Math.round(left + startWidth) + + "," + + Math.round(window.innerHeight * 0.8) + + " "; + const coordinatePair3 = + Math.round(left) + + "," + + Math.round(window.innerHeight * 0.8 - startHeight); + const coord = coordinatePair1 + coordinatePair2 + coordinatePair3; + setCoordinates(coord); + }, [left, startWidth, startHeight]); + + useEffect(() => { + setAngleInRadians(Math.atan(startHeight / startWidth)); + }, [startWidth, startHeight]); + + return ( +
+
+ + + +
+ +

+ {Math.round(((angleInRadians * 180) / Math.PI) * 100) / 100}° +

+
+ ); +}; diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx new file mode 100644 index 000000000..227f20901 --- /dev/null +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -0,0 +1,913 @@ +import { InputAdornment, TextField } from "@mui/material"; +import { useEffect, useState } from "react"; +import { IWallProps } from "./PhysicsSimulationWall"; +import { Wedge } from "./PhysicsSimulationWedge"; + +export interface IForce { + description: string; + magnitude: number; + directionInDegrees: number; +} +export interface IWeightProps { + adjustPendulumAngle: { angle: number; length: number }; + color: string; + displayXPosition: number; + displayYPosition: number; + displayXVelocity: number; + displayYVelocity: number; + elasticCollisions: boolean; + startForces: IForce[]; + incrementTime: number; + mass: number; + paused: boolean; + pendulum: boolean; + pendulumLength: number; + wedge: boolean; + radius: number; + reset: boolean; + setDisplayXAcceleration: (val: number) => any; + setDisplayXPosition: (val: number) => any; + setDisplayXVelocity: (val: number) => any; + setDisplayYAcceleration: (val: number) => any; + setDisplayYPosition: (val: number) => any; + setDisplayYVelocity: (val: number) => any; + setPaused: (bool: boolean) => any; + setPendulumAngle: (val: number) => any; + setPendulumLength: (val: number) => any; + setStartPendulumAngle: (val: number) => any; + showAcceleration: boolean; + mode: string; + noMovement: boolean; + pendulumAngle: number; + setSketching: (val: boolean) => any; + showForces: boolean; + showForceMagnitudes: boolean; + showVelocity: boolean; + startPosX: number; + startPosY: number; + startVelX?: number; + startVelY?: number; + timestepSize: number; + updateDisplay: { xDisplay: number; yDisplay: number }; + updatedForces: IForce[]; + setUpdatedForces: (val: IForce[]) => any; + walls: IWallProps[]; + coefficientOfKineticFriction: number; + wedgeWidth: number; + wedgeHeight: number; +} + +export const Weight = (props: IWeightProps) => { + const { + adjustPendulumAngle, + color, + displayXPosition, + displayYPosition, + displayXVelocity, + displayYVelocity, + elasticCollisions, + startForces, + incrementTime, + mass, + paused, + pendulum, + pendulumLength, + wedge, + radius, + mode, + noMovement, + pendulumAngle, + reset, + setSketching, + setDisplayXAcceleration, + setDisplayXPosition, + setDisplayXVelocity, + setDisplayYAcceleration, + setDisplayYPosition, + setDisplayYVelocity, + setPaused, + setPendulumAngle, + setPendulumLength, + setStartPendulumAngle, + showAcceleration, + showForces, + showForceMagnitudes, + showVelocity, + startPosX, + startPosY, + startVelX, + startVelY, + timestepSize, + updateDisplay, + updatedForces, + setUpdatedForces, + walls, + coefficientOfKineticFriction, + wedgeWidth, + wedgeHeight, + } = props; + + // Constants + const draggable = !wedge && mode == "Freeform"; + const epsilon = 0.0001; + + const forceOfGravity: IForce = { + description: "Gravity", + magnitude: mass * 9.81, + directionInDegrees: 270, + }; + const xMax = window.innerWidth * 0.7; + const xMin = 0; + const yMax = window.innerHeight * 0.8; + const yMin = 0; + + // State hooks + const [dragging, setDragging] = useState(false); + const [kineticFriction, setKineticFriction] = useState(false); + const [updatedStartPosX, setUpdatedStartPosX] = useState(startPosX); + const [updatedStartPosY, setUpdatedStartPosY] = useState(startPosY); + const [xPosition, setXPosition] = useState(startPosX); + const [xVelocity, setXVelocity] = useState(startVelX ?? 0); + const [yPosition, setYPosition] = useState(startPosY); + const [yVelocity, setYVelocity] = useState(startVelY ?? 0); + + // Helper function to go between display and real values + const getDisplayYPos = (yPos: number) => { + return yMax - yPos - 2 * radius + 5; + }; + const getYPosFromDisplay = (yDisplay: number) => { + return yMax - yDisplay - 2 * radius + 5; + }; + + // Set display values based on real values + const setYPosDisplay = (yPos: number) => { + const displayPos = getDisplayYPos(yPos); + setDisplayYPosition(Math.round(displayPos * 100) / 100); + }; + const setXPosDisplay = (xPos: number) => { + setDisplayXPosition(Math.round(xPos * 100) / 100); + }; + const setYVelDisplay = (yVel: number) => { + setDisplayYVelocity((-1 * Math.round(yVel * 100)) / 100); + }; + const setXVelDisplay = (xVel: number) => { + setDisplayXVelocity(Math.round(xVel * 100) / 100); + }; + + const setDisplayValues = ( + xPos: number = xPosition, + yPos: number = yPosition, + xVel: number = xVelocity, + yVel: number = yVelocity + ) => { + setYPosDisplay(yPos); + setXPosDisplay(xPos); + setYVelDisplay(yVel); + setXVelDisplay(xVel); + setDisplayYAcceleration( + (-1 * Math.round(getNewAccelerationY(updatedForces) * 100)) / 100 + ); + setDisplayXAcceleration( + Math.round(getNewAccelerationX(updatedForces) * 100) / 100 + ); + }; + + // When display values updated by user, update real values + useEffect(() => { + if (updateDisplay.xDisplay != xPosition) { + let x = updateDisplay.xDisplay; + x = Math.max(0, x); + x = Math.min(x, xMax - 2 * radius); + setUpdatedStartPosX(x); + setXPosition(x); + setDisplayXPosition(x); + } + + if (updateDisplay.yDisplay != getDisplayYPos(yPosition)) { + let y = updateDisplay.yDisplay; + y = Math.max(0, y); + y = Math.min(y, yMax - 2 * radius); + setDisplayYPosition(y); + let coordinatePosition = getYPosFromDisplay(y); + setUpdatedStartPosY(coordinatePosition); + setYPosition(coordinatePosition); + } + + if (displayXVelocity != xVelocity) { + let x = displayXVelocity; + setXVelocity(x); + setDisplayXVelocity(x); + } + + if (displayYVelocity != -yVelocity) { + let y = displayYVelocity; + setYVelocity(-y); + setDisplayYVelocity(y); + } + }, [updateDisplay]); + + // Check for collisions and update + useEffect(() => { + if (!paused && !noMovement) { + let collisions = false; + if (!pendulum) { + const collisionsWithGround = checkForCollisionsWithGround(); + const collisionsWithWalls = checkForCollisionsWithWall(); + collisions = collisionsWithGround || collisionsWithWalls; + } + if (!collisions) { + update(); + } + setDisplayValues(); + } + }, [incrementTime]); + + useEffect(() => { + resetEverything(); + }, [reset]); + + useEffect(() => { + setXVelocity(startVelX ?? 0); + setYVelocity(startVelY ?? 0); + setDisplayValues(); + }, [startForces]); + + const resetEverything = () => { + setKineticFriction(false); + setXPosition(updatedStartPosX); + setYPosition(updatedStartPosY); + setXVelocity(startVelX ?? 0); + setYVelocity(startVelY ?? 0); + setUpdatedForces(startForces); + setDisplayValues(); + }; + + // Change pendulum angle based on input field + useEffect(() => { + let length = adjustPendulumAngle.length; + const x = + length * Math.cos(((90 - adjustPendulumAngle.angle) * Math.PI) / 180); + const y = + length * Math.sin(((90 - adjustPendulumAngle.angle) * Math.PI) / 180); + const xPos = xMax / 2 - x - radius; + const yPos = y - radius - 5; + setXPosition(xPos); + setYPosition(yPos); + setUpdatedStartPosX(xPos); + setUpdatedStartPosY(yPos); + setPendulumAngle(adjustPendulumAngle.angle); + setPendulumLength(adjustPendulumAngle.length); + }, [adjustPendulumAngle]); + + const getNewAccelerationX = (forceList: IForce[]) => { + let newXAcc = 0; + forceList.forEach((force) => { + newXAcc += + (force.magnitude * + Math.cos((force.directionInDegrees * Math.PI) / 180)) / + mass; + }); + return newXAcc; + }; + + const getNewAccelerationY = (forceList: IForce[]) => { + let newYAcc = 0; + forceList.forEach((force) => { + newYAcc += + (-1 * + (force.magnitude * + Math.sin((force.directionInDegrees * Math.PI) / 180))) / + mass; + }); + return newYAcc; + }; + + const getNewForces = ( + xPos: number, + yPos: number, + xVel: number, + yVel: number + ) => { + if (!pendulum) { + return updatedForces; + } + const x = xMax / 2 - xPos - radius; + const y = yPos + radius + 5; + let angle = (Math.atan(y / x) * 180) / Math.PI; + if (angle < 0) { + angle += 180; + } + let oppositeAngle = 90 - angle; + if (oppositeAngle < 0) { + oppositeAngle = 90 - (180 - angle); + } + + const pendulumLength = Math.sqrt(x * x + y * y); + setPendulumAngle(oppositeAngle); + setPendulumLength(Math.sqrt(x * x + y * y)); + + const mag = + mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) + + (mass * (xVel * xVel + yVel * yVel)) / pendulumLength; + + const forceOfTension: IForce = { + description: "Tension", + magnitude: mag, + directionInDegrees: angle, + }; + + return [forceOfGravity, forceOfTension]; + }; + + const getNewPosition = (pos: number, vel: number) => { + return pos + vel * timestepSize; + }; + + const getNewVelocity = (vel: number, acc: number) => { + return vel + acc * timestepSize; + }; + + const checkForCollisionsWithWall = () => { + let collision = false; + const minX = xPosition; + const maxX = xPosition + 2 * radius; + const containerWidth = window.innerWidth; + if (xVelocity != 0) { + walls.forEach((wall) => { + if (wall.angleInDegrees == 90) { + const wallX = (wall.xPos / 100) * window.innerWidth; + if (wall.xPos < 0.35) { + if (minX <= wallX) { + if (elasticCollisions) { + setXVelocity(-xVelocity); + } else { + setXVelocity(0); + setXPosition(wallX + 5); + } + collision = true; + } + } else { + if (maxX >= wallX) { + if (elasticCollisions) { + setXVelocity(-xVelocity); + } else { + setXVelocity(0); + setXPosition(wallX - 2 * radius + 5); + } + collision = true; + } + } + } + }); + } + return collision; + }; + + const checkForCollisionsWithGround = () => { + let collision = false; + const maxY = yPosition + 2 * radius; + if (yVelocity > 0) { + walls.forEach((wall) => { + if (wall.angleInDegrees == 0) { + const groundY = (wall.yPos / 100) * window.innerHeight; + if (maxY >= groundY) { + if (elasticCollisions) { + setYVelocity(-yVelocity); + } else { + setYVelocity(0); + setYPosition(groundY - 2 * radius + 5); + const forceOfGravity: IForce = { + description: "Gravity", + magnitude: 9.81 * mass, + directionInDegrees: 270, + }; + const normalForce: IForce = { + description: "Normal force", + magnitude: 9.81 * mass, + directionInDegrees: wall.angleInDegrees + 90, + }; + setUpdatedForces([forceOfGravity, normalForce]); + } + collision = true; + } + } + }); + } + return collision; + }; + + useEffect(() => { + if (wedge && xVelocity != 0 && mode != "Review" && !kineticFriction) { + setKineticFriction(true); + //switch from static to kinetic friction + const normalForce: IForce = { + description: "Normal Force", + magnitude: + forceOfGravity.magnitude * + Math.cos(Math.atan(wedgeHeight / wedgeWidth)), + directionInDegrees: + 180 - 90 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI, + }; + let frictionForce: IForce = { + description: "Kinetic Friction Force", + magnitude: + coefficientOfKineticFriction * + forceOfGravity.magnitude * + Math.cos(Math.atan(wedgeHeight / wedgeWidth)), + directionInDegrees: + 180 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI, + }; + // reduce magnitude of friction force if necessary such that block cannot slide up plane + let yForce = -forceOfGravity.magnitude; + yForce += + normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180); + yForce += + frictionForce.magnitude * + Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + if (yForce > 0) { + frictionForce.magnitude = + (-normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + + forceOfGravity.magnitude) / + Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + } + if (coefficientOfKineticFriction != 0) { + setUpdatedForces([forceOfGravity, normalForce, frictionForce]); + } else { + setUpdatedForces([forceOfGravity, normalForce]); + } + } + }, [xVelocity]); + + const update = () => { + // RK4 update + let xPos = xPosition; + let yPos = yPosition; + let xVel = xVelocity; + let yVel = yVelocity; + for (let i = 0; i < 60; i++) { + let forces1 = getNewForces(xPos, yPos, xVel, yVel); + const xAcc1 = getNewAccelerationX(forces1); + const yAcc1 = getNewAccelerationY(forces1); + const xVel1 = getNewVelocity(xVel, xAcc1); + const yVel1 = getNewVelocity(yVel, yAcc1); + + let xVel2 = getNewVelocity(xVel, xAcc1 / 2); + let yVel2 = getNewVelocity(yVel, yAcc1 / 2); + let xPos2 = getNewPosition(xPos, xVel1 / 2); + let yPos2 = getNewPosition(yPos, yVel1 / 2); + const forces2 = getNewForces(xPos2, yPos2, xVel2, yVel2); + const xAcc2 = getNewAccelerationX(forces2); + const yAcc2 = getNewAccelerationY(forces2); + xVel2 = getNewVelocity(xVel2, xAcc2); + yVel2 = getNewVelocity(yVel2, yAcc2); + xPos2 = getNewPosition(xPos2, xVel2); + yPos2 = getNewPosition(yPos2, yVel2); + + let xVel3 = getNewVelocity(xVel, xAcc2 / 2); + let yVel3 = getNewVelocity(yVel, yAcc2 / 2); + let xPos3 = getNewPosition(xPos, xVel2 / 2); + let yPos3 = getNewPosition(yPos, yVel2 / 2); + const forces3 = getNewForces(xPos3, yPos3, xVel3, yVel3); + const xAcc3 = getNewAccelerationX(forces3); + const yAcc3 = getNewAccelerationY(forces3); + xVel3 = getNewVelocity(xVel3, xAcc3); + yVel3 = getNewVelocity(yVel3, yAcc3); + xPos3 = getNewPosition(xPos3, xVel3); + yPos3 = getNewPosition(yPos3, yVel3); + + let xVel4 = getNewVelocity(xVel, xAcc3); + let yVel4 = getNewVelocity(yVel, yAcc3); + let xPos4 = getNewPosition(xPos, xVel3); + let yPos4 = getNewPosition(yPos, yVel3); + const forces4 = getNewForces(xPos4, yPos4, xVel4, yVel4); + const xAcc4 = getNewAccelerationX(forces4); + const yAcc4 = getNewAccelerationY(forces4); + xVel4 = getNewVelocity(xVel4, xAcc4); + yVel4 = getNewVelocity(yVel4, yAcc4); + xPos4 = getNewPosition(xPos4, xVel4); + yPos4 = getNewPosition(yPos4, yVel4); + + xVel += + timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0); + yVel += + timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0); + xPos += + timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0); + yPos += + timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0); + } + + setXVelocity(xVel); + setYVelocity(yVel); + setXPosition(xPos); + setYPosition(yPos); + setUpdatedForces(getNewForces(xPos, yPos, xVel, yVel)); + }; + + let weightStyle = { + backgroundColor: color, + borderStyle: "solid", + borderColor: "black", + position: "absolute" as "absolute", + left: xPosition + "px", + top: yPosition + "px", + width: 2 * radius + "px", + height: 2 * radius + "px", + borderRadius: 50 + "%", + display: "flex", + justifyContent: "center", + alignItems: "center", + touchAction: "none", + }; + if (dragging) { + weightStyle.borderColor = "lightblue"; + } + + const [clickPositionX, setClickPositionX] = useState(0); + const [clickPositionY, setClickPositionY] = useState(0); + const labelBackgroundColor = `rgba(255,255,255,0.5)`; + + // Update x start position + useEffect(() => { + setUpdatedStartPosX(startPosX); + setXPosition(startPosX); + setXPosDisplay(startPosX); + }, [startPosX]); + + // Update y start position + useEffect(() => { + setUpdatedStartPosY(startPosY); + setYPosition(startPosY); + setYPosDisplay(startPosY); + }, [startPosY]); + + return ( +
+
{ + if (draggable) { + e.preventDefault(); + setPaused(true); + setDragging(true); + setClickPositionX(e.clientX); + setClickPositionY(e.clientY); + } else if (mode == "Review") { + setSketching(true); + } + }} + onPointerMove={(e) => { + e.preventDefault(); + if (dragging) { + let newY = yPosition + e.clientY - clickPositionY; + if (newY > yMax - 2 * radius) { + newY = yMax - 2 * radius; + } + + let newX = xPosition + e.clientX - clickPositionX; + if (newX > xMax - 2 * radius) { + newX = xMax - 2 * radius; + } else if (newX < 0) { + newX = 0; + } + + setXPosition(newX); + setYPosition(newY); + setUpdatedStartPosX(newX); + setUpdatedStartPosY(newY); + setDisplayYPosition( + Math.round((yMax - 2 * radius - newY + 5) * 100) / 100 + ); + setClickPositionX(e.clientX); + setClickPositionY(e.clientY); + setDisplayValues(); + } + }} + onPointerUp={(e) => { + if (dragging) { + e.preventDefault(); + if (!pendulum) { + resetEverything(); + } + setDragging(false); + let newY = yPosition + e.clientY - clickPositionY; + if (newY > yMax - 2 * radius) { + newY = yMax - 2 * radius; + } + + let newX = xPosition + e.clientX - clickPositionX; + if (newX > xMax - 2 * radius) { + newX = xMax - 2 * radius; + } else if (newX < 0) { + newX = 0; + } + if (pendulum) { + const x = xMax / 2 - newX - radius; + const y = newY + radius + 5; + let angle = (Math.atan(y / x) * 180) / Math.PI; + if (angle < 0) { + angle += 180; + } + let oppositeAngle = 90 - angle; + if (oppositeAngle < 0) { + oppositeAngle = 90 - (180 - angle); + } + + const pendulumLength = Math.sqrt(x * x + y * y); + setPendulumAngle(oppositeAngle); + setPendulumLength(Math.sqrt(x * x + y * y)); + const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180); + const forceOfTension: IForce = { + description: "Tension", + magnitude: mag, + directionInDegrees: angle, + }; + + setKineticFriction(false); + setXVelocity(startVelX ?? 0); + setYVelocity(startVelY ?? 0); + setDisplayValues(); + setUpdatedForces([forceOfGravity, forceOfTension]); + } + } + }} + > +
+

{mass} kg

+
+
+ {pendulum && ( +
+ + + + {!dragging && ( +
+

+ {Math.round(pendulumLength)} m +

+

+ {Math.round(pendulumAngle * 100) / 100}° +

+
+ )} +
+ )} + {!dragging && showAcceleration && ( +
+
+ + + + + + + + +
+

+ {Math.round( + 100 * + Math.sqrt( + Math.pow(getNewAccelerationX(updatedForces) * 3, 2) + + Math.pow(getNewAccelerationY(updatedForces) * 3, 2) + ) + ) / 100}{" "} + m/s2 +

+
+
+
+ )} + {!dragging && showVelocity && ( +
+
+ + + + + + + + +
+

+ {Math.round( + 100 * Math.sqrt(xVelocity * xVelocity + yVelocity * yVelocity) + ) / 100}{" "} + m/s +

+
+
+
+ )} + {!dragging && + showForces && + updatedForces.map((force, index) => { + if (force.magnitude < epsilon) { + return; + } + let arrowStartY: number = yPosition + radius; + const arrowStartX: number = xPosition + radius; + let arrowEndY: number = + arrowStartY - + Math.abs(force.magnitude) * + 20 * + Math.sin((force.directionInDegrees * Math.PI) / 180); + const arrowEndX: number = + arrowStartX + + Math.abs(force.magnitude) * + 20 * + Math.cos((force.directionInDegrees * Math.PI) / 180); + + let color = "#0d0d0d"; + + let labelTop = arrowEndY; + let labelLeft = arrowEndX; + if (force.directionInDegrees > 90 && force.directionInDegrees < 270) { + labelLeft -= 120; + } else { + labelLeft += 30; + } + if (force.directionInDegrees >= 0 && force.directionInDegrees < 180) { + labelTop += 40; + } else { + labelTop -= 40; + } + labelTop = Math.min(labelTop, yMax + 50); + labelTop = Math.max(labelTop, yMin); + labelLeft = Math.min(labelLeft, xMax - 60); + labelLeft = Math.max(labelLeft, xMin); + + return ( +
+
+ + + + + + + + +
+
+ {force.description &&

{force.description}

} + {!force.description &&

Force

} + {showForceMagnitudes && ( +

{Math.round(100 * force.magnitude) / 100} N

+ )} +
+
+ ); + })} +
+ ); +}; -- cgit v1.2.3-70-g09d2 From 136d946b88ff817c2dd738553ddb2aea0a11f0e7 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Mon, 30 Jan 2023 14:29:43 -0500 Subject: remove extraneous code --- src/client/views/nodes/PhysicsSimulationApp.tsx | 1353 +------------------- src/client/views/nodes/PhysicsSimulationBox.scss | 7 + src/client/views/nodes/PhysicsSimulationWall.tsx | 1 - src/client/views/nodes/PhysicsSimulationWedge.tsx | 2 +- src/client/views/nodes/PhysicsSimulationWeight.tsx | 1 - 5 files changed, 27 insertions(+), 1337 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx index 7486aa88d..0a39b3291 100644 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ b/src/client/views/nodes/PhysicsSimulationApp.tsx @@ -1,51 +1,8 @@ -import AddIcon from "@mui/icons-material/Add"; -import AddCircleIcon from "@mui/icons-material/AddCircle"; -import ClearIcon from "@mui/icons-material/Clear"; -import PauseIcon from "@mui/icons-material/Pause"; -import PlayArrowIcon from "@mui/icons-material/PlayArrow"; -import ReplayIcon from "@mui/icons-material/Replay"; -import QuestionMarkIcon from "@mui/icons-material/QuestionMark"; -import ArrowLeftIcon from "@mui/icons-material/ArrowLeft"; -import ArrowRightIcon from "@mui/icons-material/ArrowRight"; -import { SelectChangeEvent } from "@mui/material/Select"; -import { - Alert, - Box, - Button, - Checkbox, - CircularProgress, - Dialog, - DialogTitle, - DialogContent, - DialogContentText, - DialogActions, - Divider, - FormControl, - FormControlLabel, - FormGroup, - IconButton, - InputAdornment, - InputLabel, - LinearProgress, - List, - ListItem, - ListItemButton, - ListItemIcon, - ListItemText, - MenuItem, - Popover, - Select, - Stack, - TextField, - Tooltip, -} from "@mui/material"; -import { styled } from "@mui/material/styles"; -import { tooltipClasses, TooltipProps } from "@mui/material/Tooltip"; -import Typography from "@mui/material/Typography"; import React, { useEffect, useState } from "react"; import "./PhysicsSimulationBox.scss"; import { IForce, Weight } from "./PhysicsSimulationWeight"; -import { Description } from "@mui/icons-material"; +import {Wall, IWallProps } from "./PhysicsSimulationWall" +import {Wedge} from "./PhysicsSimulationWedge" interface VectorTemplate { top: number; @@ -91,17 +48,6 @@ function App() { magnitude: gravityMagnitude, directionInDegrees: 270, }; - const HtmlTooltip = styled(({ className, ...props }: TooltipProps) => ( - - ))(({ theme }) => ({ - [`& .${tooltipClasses.tooltip}`]: { - backgroundColor: "#f5f5f9", - color: "rgba(0, 0, 0, 0.87)", - maxWidth: 220, - fontSize: theme.typography.pxToRem(12), - border: "1px solid #dadde9", - }, - })); const xMin = 0; const yMin = 0; const xMax = window.innerWidth * 0.7; @@ -165,12 +111,6 @@ function App() { const [reviewNormalMagnitude, setReviewNormalMagnitude] = useState(0); const [reviewStaticAngle, setReviewStaticAngle] = useState(0); const [reviewStaticMagnitude, setReviewStaticMagnitude] = useState(0); - const [selectedQuestion, setSelectedQuestion] = useState( - questions.inclinePlane[0] - ); - const [selectedTutorial, setSelectedTutorial] = useState( - tutorials.inclinePlane - ); const [questionPartTwo, setQuestionPartTwo] = useState(""); const [selectedSolutions, setSelectedSolutions] = useState([]); const [showAcceleration, setShowAcceleration] = useState(false); @@ -333,244 +273,7 @@ function App() { const getDisplayYPos = (yPos: number) => { return yMax - yPos - 2 * 50 + 5; }; - - // In review mode, update forces when coefficient of static friction changed - const updateReviewForcesBasedOnCoefficient = (coefficient: number) => { - let theta: number = Number(wedgeAngle); - let index = - selectedQuestion.variablesForQuestionSetup.indexOf("theta - max 45"); - if (index >= 0) { - theta = questionVariables[index]; - } - if (isNaN(theta)) { - return; - } - setReviewGravityMagnitude(forceOfGravity.magnitude); - setReviewGravityAngle(270); - setReviewNormalMagnitude( - forceOfGravity.magnitude * Math.cos((theta * Math.PI) / 180) - ); - setReviewNormalAngle(90 - theta); - let yForce = -forceOfGravity.magnitude; - yForce += - 9.81 * - Math.cos((theta * Math.PI) / 180) * - Math.sin(((90 - theta) * Math.PI) / 180); - yForce += - coefficient * - 9.81 * - Math.cos((theta * Math.PI) / 180) * - Math.sin(((180 - theta) * Math.PI) / 180); - let friction = coefficient * 9.81 * Math.cos((theta * Math.PI) / 180); - if (yForce > 0) { - friction = - (-(forceOfGravity.magnitude * Math.cos((theta * Math.PI) / 180)) * - Math.sin(((90 - theta) * Math.PI) / 180) + - forceOfGravity.magnitude) / - Math.sin(((180 - theta) * Math.PI) / 180); - } - setReviewStaticMagnitude(friction); - setReviewStaticAngle(180 - theta); - }; - - // In review mode, update forces when wedge angle changed - const updateReviewForcesBasedOnAngle = (angle: number) => { - setReviewGravityMagnitude(9.81); - setReviewGravityAngle(270); - setReviewNormalMagnitude(9.81 * Math.cos((Number(angle) * Math.PI) / 180)); - setReviewNormalAngle(90 - angle); - let yForce = -forceOfGravity.magnitude; - yForce += - 9.81 * - Math.cos((Number(angle) * Math.PI) / 180) * - Math.sin(((90 - Number(angle)) * Math.PI) / 180); - yForce += - reviewCoefficient * - 9.81 * - Math.cos((Number(angle) * Math.PI) / 180) * - Math.sin(((180 - Number(angle)) * Math.PI) / 180); - let friction = - reviewCoefficient * 9.81 * Math.cos((Number(angle) * Math.PI) / 180); - if (yForce > 0) { - friction = - (-(9.81 * Math.cos((Number(angle) * Math.PI) / 180)) * - Math.sin(((90 - Number(angle)) * Math.PI) / 180) + - forceOfGravity.magnitude) / - Math.sin(((180 - Number(angle)) * Math.PI) / 180); - } - setReviewStaticMagnitude(friction); - setReviewStaticAngle(180 - angle); - }; - - // Solve for the correct answers to the generated problem - const getAnswersToQuestion = ( - question: QuestionTemplate, - questionVars: number[] - ) => { - const solutions: number[] = []; - - let theta: number = Number(wedgeAngle); - let index = question.variablesForQuestionSetup.indexOf("theta - max 45"); - if (index >= 0) { - theta = questionVars[index]; - } - let muS: number = Number(coefficientOfStaticFriction); - index = question.variablesForQuestionSetup.indexOf( - "coefficient of static friction" - ); - if (index >= 0) { - muS = questionVars[index]; - } - - for (let i = 0; i < question.answerSolutionDescriptions.length; i++) { - const description = question.answerSolutionDescriptions[i]; - if (!isNaN(Number(description))) { - solutions.push(Number(description)); - } else if (description == "solve normal force angle from wedge angle") { - solutions.push(90 - theta); - } else if ( - description == "solve normal force magnitude from wedge angle" - ) { - solutions.push( - forceOfGravity.magnitude * Math.cos((theta / 180) * Math.PI) - ); - } else if ( - description == - "solve static force magnitude from wedge angle given equilibrium" - ) { - let normalForceMagnitude = - forceOfGravity.magnitude * Math.cos((theta / 180) * Math.PI); - let normalForceAngle = 90 - theta; - let frictionForceAngle = 180 - theta; - let frictionForceMagnitude = - (-normalForceMagnitude * - Math.sin((normalForceAngle * Math.PI) / 180) + - 9.81) / - Math.sin((frictionForceAngle * Math.PI) / 180); - solutions.push(frictionForceMagnitude); - } else if ( - description == - "solve static force angle from wedge angle given equilibrium" - ) { - solutions.push(180 - theta); - } else if ( - description == - "solve minimum static coefficient from wedge angle given equilibrium" - ) { - let normalForceMagnitude = - forceOfGravity.magnitude * Math.cos((theta / 180) * Math.PI); - let normalForceAngle = 90 - theta; - let frictionForceAngle = 180 - theta; - let frictionForceMagnitude = - (-normalForceMagnitude * - Math.sin((normalForceAngle * Math.PI) / 180) + - 9.81) / - Math.sin((frictionForceAngle * Math.PI) / 180); - let frictionCoefficient = frictionForceMagnitude / normalForceMagnitude; - solutions.push(frictionCoefficient); - } else if ( - description == - "solve maximum wedge angle from coefficient of static friction given equilibrium" - ) { - solutions.push((Math.atan(muS) * 180) / Math.PI); - } - } - setSelectedSolutions(solutions); - return solutions; - }; - - // In review mode, check if input answers match correct answers and optionally generate alert - const checkAnswers = (showAlert: boolean = true) => { - let error: boolean = false; - let epsilon: number = 0.01; - if (selectedQuestion) { - for (let i = 0; i < selectedQuestion.answerParts.length; i++) { - if (selectedQuestion.answerParts[i] == "force of gravity") { - if ( - Math.abs(reviewGravityMagnitude - selectedSolutions[i]) > epsilon - ) { - error = true; - } - } else if (selectedQuestion.answerParts[i] == "angle of gravity") { - if (Math.abs(reviewGravityAngle - selectedSolutions[i]) > epsilon) { - error = true; - } - } else if (selectedQuestion.answerParts[i] == "normal force") { - if ( - Math.abs(reviewNormalMagnitude - selectedSolutions[i]) > epsilon - ) { - error = true; - } - } else if (selectedQuestion.answerParts[i] == "angle of normal force") { - if (Math.abs(reviewNormalAngle - selectedSolutions[i]) > epsilon) { - error = true; - } - } else if ( - selectedQuestion.answerParts[i] == "force of static friction" - ) { - if ( - Math.abs(reviewStaticMagnitude - selectedSolutions[i]) > epsilon - ) { - error = true; - } - } else if ( - selectedQuestion.answerParts[i] == "angle of static friction" - ) { - if (Math.abs(reviewStaticAngle - selectedSolutions[i]) > epsilon) { - error = true; - } - } else if ( - selectedQuestion.answerParts[i] == "coefficient of static friction" - ) { - if ( - Math.abs( - Number(coefficientOfStaticFriction) - selectedSolutions[i] - ) > epsilon - ) { - error = true; - } - } else if (selectedQuestion.answerParts[i] == "wedge angle") { - if (Math.abs(Number(wedgeAngle) - selectedSolutions[i]) > epsilon) { - error = true; - } - } - } - } - if (showAlert) { - if (!error) { - setSimulationPaused(false); - setTimeout(() => { - setSimulationPaused(true); - }, 3000); - } else { - setSimulationPaused(false); - setTimeout(() => { - setSimulationPaused(true); - }, 3000); - } - } - if (selectedQuestion.goal == "noMovement") { - if (!error) { - setNoMovement(true); - } else { - setNoMovement(false); - } - } - }; - - const resetReviewValuesToDefault = () => { - // Reset all values to default - setReviewGravityMagnitude(0); - setReviewGravityAngle(0); - setReviewNormalMagnitude(0); - setReviewNormalAngle(0); - setReviewStaticMagnitude(0); - setReviewStaticAngle(0); - setCoefficientOfKineticFriction(0); - setSimulationPaused(true); - setAnswerInputFields(
); - }; - + // In review mode, edit force arrow sketch on mouse movement const editForce = (element: VectorTemplate) => { if (!sketching) { @@ -589,288 +292,6 @@ function App() { } }; - // In review mode, reset problem variables and generate a new question - const generateNewQuestion = () => { - resetReviewValuesToDefault(); - - const vars: number[] = []; - let question: QuestionTemplate = questions.inclinePlane[0]; - - if (simulationType == "Inclined Plane") { - if (questionNumber == questions.inclinePlane.length - 1) { - setQuestionNumber(0); - } else { - setQuestionNumber(questionNumber + 1); - } - question = questions.inclinePlane[questionNumber]; - - let coefficient = 0; - let wedge = 0; - - for (let i = 0; i < question.variablesForQuestionSetup.length; i++) { - if (question.variablesForQuestionSetup[i] == "theta - max 45") { - let randValue = Math.floor(Math.random() * 44 + 1); - vars.push(randValue); - wedge = randValue; - } else if ( - question.variablesForQuestionSetup[i] == - "coefficient of static friction" - ) { - let randValue = Math.round(Math.random() * 1000) / 1000; - vars.push(randValue); - coefficient = randValue; - } - } - setWedgeAngle(wedge); - changeWedgeBasedOnNewAngle(wedge); - setCoefficientOfStaticFriction(coefficient); - reviewCoefficient = coefficient; - } - let q = ""; - for (let i = 0; i < question.questionSetup.length; i++) { - q += question.questionSetup[i]; - if (i != question.questionSetup.length - 1) { - q += vars[i]; - if (question.variablesForQuestionSetup[i].includes("theta")) { - q += - " degree (≈" + - Math.round((1000 * (vars[i] * Math.PI)) / 180) / 1000 + - " rad)"; - } - } - } - questionVariables = vars; - setSelectedQuestion(question); - setQuestionPartOne(q); - setQuestionPartTwo(question.question); - const answers = getAnswersToQuestion(question, vars); - generateInputFieldsForQuestion(false, question, answers); - }; - - // Generate answerInputFields for new review question - const generateInputFieldsForQuestion = ( - showIcon: boolean = false, - question: QuestionTemplate = selectedQuestion, - answers: number[] = selectedSolutions - ) => { - let answerInput = []; - const d = new Date(); - for (let i = 0; i < question.answerParts.length; i++) { - if (question.answerParts[i] == "force of gravity") { - setReviewGravityMagnitude(0); - answerInput.push( -
- - FG -

- } - lowerBound={0} - changeValue={setReviewGravityMagnitude} - step={0.1} - unit={"N"} - upperBound={50} - value={reviewGravityMagnitude} - showIcon={showIcon} - correctValue={answers[i]} - /> -
- ); - } else if (question.answerParts[i] == "angle of gravity") { - setReviewGravityAngle(0); - answerInput.push( -
- - θG -

- } - lowerBound={0} - changeValue={setReviewGravityAngle} - step={1} - unit={"°"} - upperBound={360} - value={reviewGravityAngle} - radianEquivalent={true} - showIcon={showIcon} - correctValue={answers[i]} - /> -
- ); - } else if (question.answerParts[i] == "normal force") { - setReviewNormalMagnitude(0); - answerInput.push( -
- - FN -

- } - lowerBound={0} - changeValue={setReviewNormalMagnitude} - step={0.1} - unit={"N"} - upperBound={50} - value={reviewNormalMagnitude} - showIcon={showIcon} - correctValue={answers[i]} - /> -
- ); - } else if (question.answerParts[i] == "angle of normal force") { - setReviewNormalAngle(0); - answerInput.push( -
- - θN -

- } - lowerBound={0} - changeValue={setReviewNormalAngle} - step={1} - unit={"°"} - upperBound={360} - value={reviewNormalAngle} - radianEquivalent={true} - showIcon={showIcon} - correctValue={answers[i]} - /> -
- ); - } else if (question.answerParts[i] == "force of static friction") { - setReviewStaticMagnitude(0); - answerInput.push( -
- - F - - Fs - -

- } - lowerBound={0} - changeValue={setReviewStaticMagnitude} - step={0.1} - unit={"N"} - upperBound={50} - value={reviewStaticMagnitude} - showIcon={showIcon} - correctValue={answers[i]} - /> -
- ); - } else if (question.answerParts[i] == "angle of static friction") { - setReviewStaticAngle(0); - answerInput.push( -
- - θ - - Fs - -

- } - lowerBound={0} - changeValue={setReviewStaticAngle} - step={1} - unit={"°"} - upperBound={360} - value={reviewStaticAngle} - radianEquivalent={true} - showIcon={showIcon} - correctValue={answers[i]} - /> -
- ); - } else if (question.answerParts[i] == "coefficient of static friction") { - updateReviewForcesBasedOnCoefficient(0); - answerInput.push( -
- - - μs - - Coefficient of static friction; between 0 and 1 - - } - followCursor - > - - μs - - - } - lowerBound={0} - changeValue={setCoefficientOfStaticFriction} - step={0.1} - unit={""} - upperBound={1} - value={coefficientOfStaticFriction} - effect={updateReviewForcesBasedOnCoefficient} - showIcon={showIcon} - correctValue={answers[i]} - /> -
- ); - } else if (question.answerParts[i] == "wedge angle") { - updateReviewForcesBasedOnAngle(0); - answerInput.push( -
- - θ - Angle of incline plane from the ground, 0-49 - - } - followCursor - > - θ - - } - lowerBound={0} - changeValue={setWedgeAngle} - step={1} - unit={"°"} - upperBound={49} - value={wedgeAngle} - effect={(val: number) => { - changeWedgeBasedOnNewAngle(val); - updateReviewForcesBasedOnAngle(val); - }} - radianEquivalent={true} - showIcon={showIcon} - correctValue={answers[i]} - /> -
- ); - } - } - - setAnswerInputFields( -
- {answerInput} -
- ); - }; - // Remove floor and walls from simulation const removeWalls = () => { setWallPositions([]); @@ -939,62 +360,6 @@ function App() { setAdjustPendulumAngle({ angle: 50, length: 300 }); removeWalls(); } - } else if (mode == "Review") { - setShowForceMagnitudes(true); - if (simulationType == "Two Weights") { - // TODO - } else if (simulationType == "Inclined Plane") { - addWedge(); - setUpdatedForces([]); - setStartForces([]); - addWalls(); - } - setShowAcceleration(false); - setShowVelocity(false); - setShowForces(true); - generateNewQuestion(); - } else if (mode == "Tutorial") { - setStepNumber(0); - if (simulationType == "One Weight") { - addWeight(); - setStartPosY(yMin + 50); - setStartPosX((xMax + xMin - 50) / 2); - setSelectedTutorial(tutorials.freeWeight); - setSelectedTutorial(tutorials.freeWeight); - setStartForces(getForceFromJSON(tutorials.freeWeight.steps[0].forces)); - setShowForceMagnitudes(tutorials.freeWeight.steps[0].showMagnitude); - addWalls(); - } else if (simulationType == "Two Weights") { - // TODO - } else if (simulationType == "Pendulum") { - const length = 300; - const angle = 30; - const x = length * Math.cos(((90 - angle) * Math.PI) / 180); - const y = length * Math.sin(((90 - angle) * Math.PI) / 180); - const xPos = xMax / 2 - x - 50; - const yPos = y - 50 - 5; - addPendulum(); - setStartPosX(xPos); - setStartPosY(yPos); - setSelectedTutorial(tutorials.pendulum); - setStartForces(getForceFromJSON(tutorials.pendulum.steps[0].forces)); - setShowForceMagnitudes(tutorials.pendulum.steps[0].showMagnitude); - setPendulumAngle(50); - setPendulumLength(300); - setAdjustPendulumAngle({ angle: 30, length: 300 }); - removeWalls(); - } else if (simulationType == "Inclined Plane") { - addWedge(); - setWedgeAngle(26); - changeWedgeBasedOnNewAngle(26); - setSelectedTutorial(tutorials.inclinePlane); - setStartForces( - getForceFromJSON(tutorials.inclinePlane.steps[0].forces) - ); - setShowForceMagnitudes(tutorials.inclinePlane.steps[0].showMagnitude); - addWalls(); - } - setSimulationReset(!simulationReset); } }, [simulationType, mode]); @@ -1130,7 +495,7 @@ function App() { width: "50vw", }} > - +

SIMULATION IN PROGRESS

)}
- - {simulationPaused && mode != "Tutorial" && ( - - { - setSimulationPaused(false); - }} - > - - - +
+ {simulationPaused && ( + )} - {!simulationPaused && mode != "Tutorial" && ( - - { - setSimulationPaused(true); - }} - > - - - + {!simulationPaused && ( + )} - {simulationPaused && mode != "Tutorial" && ( - - { - setSimulationReset(!simulationReset); - }} - > - - - + {simulationPaused && ( + )} - +
{ - setSimulationType(event.target.value); - }} - style={{ height: "2em", width: "100%", fontSize: "16px" }} - > - - - - - -
-
-
-
- {showForces && currentForceSketch && simulationPaused && ( -
- - - - - - - - -
- )} - {showForces && - forceSketches.length > 0 && - simulationPaused && - forceSketches.map((element: VectorTemplate, index) => { - return ( -
- - - - - - - { - if (deleteMode) { - deleteForce(element); - } else { - editForce(element); - } - }} - /> - -
- ); - })} - {weight && ( - - )} - {twoWeights && ( - - )} - {wedge && ( - - )} -
-
- {wallPositions.map((element, index) => { - return ( - - ); - })} -
-
- -
-
-
- {simulationPaused && ( - - )} - {!simulationPaused && ( - - )} - {simulationPaused && ( - - )} -
-
- -
-
- {/* {mode == "Freeform" && - simulationElements.length > 0 && - simulationElements[0].pendulum && ( -
- - - - - - - - - - - - - - - - - - - -
 Value
Potential Energy - {Math.round( - pendulumLength * - (1 - Math.cos(pendulumAngle)) * - 9.81 * - 10 - ) / 10}{" "} - J -
Kinetic Energy - {Math.round( - (Math.round( - pendulumLength * - (1 - Math.cos(startPendulumAngle)) * - 9.81 * - 10 - ) / - 10 - - Math.round( - pendulumLength * - (1 - Math.cos(pendulumAngle)) * - 9.81 * - 10 - ) / - 10) * - 10 - ) / 10}{" "} - J -
- Total Energy - - {Math.round( - pendulumLength * - (1 - Math.cos(startPendulumAngle)) * - 9.81 * - 10 - ) / 10}{" "} - J -
-
- )}*/} -
- - {/* */} - - ); + render () { + return ( +

Hello world!

+ ); + } + //
+ //
+ //
{ + // // if (sketching) { + // // x1 = positionXDisplay + 50; + // // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50; + // // x2 = e.clientX; + // // y2 = e.clientY; + // // height = Math.abs(y1 - y2) + 120; + // // width = Math.abs(x1 - x2) + 120; + // // top = Math.min(y1, y2) - 60; + // // left = Math.min(x1, x2) - 60; + // // x1Updated = x1 - left; + // // x2Updated = x2 - left; + // // y1Updated = y1 - top; + // // y2Updated = y2 - top; + // // setCurrentForceSketch({ + // // top: top, + // // left: left, + // // width: width, + // // height: height, + // // x1: x1Updated, + // // y1: y1Updated, + // // x2: x2Updated, + // // y2: y2Updated, + // // weightX: positionXDisplay, + // // weightY: positionYDisplay, + // // }); + // // } + // }} + // onPointerDown={(e) => { + // // if (sketching && currentForceSketch) { + // // setSketching(false); + // // sketches = forceSketches; + // // sketches.push(currentForceSketch); + // // setForceSketches(sketches); + // // setCurrentForceSketch(null); + // // } + // }} + // > + //
+ //
+ // {/* {showForces && currentForceSketch && simulationPaused && ( + //
+ // + // + // + // + // + // + // + // + //
+ // )} */} + // {/* {showForces && + // forceSketches.length > 0 && + // simulationPaused && + // forceSketches.map((element: PhysicsVectorTemplate, index) => { + // return ( + //
+ // + // + // + // + // + // + // { + // if (deleteMode) { + // deleteForce(element); + // } else { + // editForce(element); + // } + // }} + // /> + // + //
+ // ); + // })} */} + // {weight && ( + // + // )} + // {wedge && ( + // + // )} + //
+ //
+ // {wallPositions.map((element, index) => { + // return ( + // + // ); + // })} + //
+ //
+ //
+ //
+ //
+ //
+ // {simulationPaused && ( + // + // )} + // {!simulationPaused && ( + // + // )} + // {simulationPaused && ( + // + // )} + //
+ //
+ //
+ //
+ //
} - -export default App; -- cgit v1.2.3-70-g09d2 From 6fba3c7fdaaed12d94dee359f520591e55cb76d8 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Tue, 31 Jan 2023 12:42:45 -0500 Subject: convert from functional to class components --- src/client/views/nodes/PhysicsSimulationApp.tsx | 6 +- src/client/views/nodes/PhysicsSimulationWall.tsx | 26 +++--- src/client/views/nodes/PhysicsSimulationWedge.tsx | 96 ++++++++++++++--------- 3 files changed, 74 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx index 2a314a723..414d61809 100644 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ b/src/client/views/nodes/PhysicsSimulationApp.tsx @@ -329,9 +329,7 @@ export default class App extends React.Component<{}, IState> { render () { return ( -

Hello world!

- ); - } +

Hello world!

//
//
//
{ //
//
//
+ ); + } } diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx index c2d3567f1..a31704d2f 100644 --- a/src/client/views/nodes/PhysicsSimulationWall.tsx +++ b/src/client/views/nodes/PhysicsSimulationWall.tsx @@ -1,3 +1,4 @@ +import React from "react"; import { useState, useEffect } from "react"; export interface Force { @@ -11,24 +12,25 @@ export interface IWallProps { angleInDegrees: number; } -export const Wall = (props: IWallProps) => { - const { length, xPos, yPos, angleInDegrees } = props; +export default class App extends React.Component { - let wallStyle = { - width: length + "%", - height: 0.5 + "vw", + constructor(props: any) { + super(props) + } + + wallStyle = { + width: this.props.angleInDegrees == 0 ? this.props.length + "%" : 0.5 + "vw", + height: this.props.angleInDegrees == 0 ? 0.5 + "vw" : this.props.length + "%", position: "absolute" as "absolute", - left: xPos + "%", - top: yPos + "%", + left: this.props.xPos + "%", + top: this.props.yPos + "%", backgroundColor: "#6c7b8b", zIndex: -1000, margin: 0, padding: 0, }; - if (angleInDegrees != 0) { - wallStyle.width = 0.5 + "vw"; - wallStyle.height = length + "%"; - } - return
; + render () { + return (
); + } }; diff --git a/src/client/views/nodes/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsSimulationWedge.tsx index 0dc7751f3..bf0cadce2 100644 --- a/src/client/views/nodes/PhysicsSimulationWedge.tsx +++ b/src/client/views/nodes/PhysicsSimulationWedge.tsx @@ -1,3 +1,4 @@ +import React from "react"; import { useState, useEffect, useCallback } from "react"; import "./PhysicsSimulationBox.scss"; @@ -7,58 +8,75 @@ export interface IWedgeProps { startLeft: number; } -export const Wedge = (props: IWedgeProps) => { - const { startHeight, startWidth, startLeft } = props; +interface IState { + angleInRadians: number, + left: number, + coordinates: string, +} + +export default class Wedge extends React.Component { - const [angleInRadians, setAngleInRadians] = useState( - Math.atan(startHeight / startWidth) - ); - const [left, setLeft] = useState(startLeft); - const [coordinates, setCoordinates] = useState(""); + constructor(props: any) { + super(props) + this.state = { + angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth), + left: this.props.startLeft, + coordinates: "", + } + } - const color = "#deb887"; + color = "#deb887"; - useEffect(() => { + updateCoordinates() { const coordinatePair1 = - Math.round(left) + "," + Math.round(window.innerHeight * 0.8) + " "; + Math.round(this.state.left) + "," + Math.round(window.innerHeight * 0.8) + " "; const coordinatePair2 = - Math.round(left + startWidth) + + Math.round(this.state.left + this.props.startWidth) + "," + Math.round(window.innerHeight * 0.8) + " "; const coordinatePair3 = - Math.round(left) + + Math.round(this.state.left) + "," + - Math.round(window.innerHeight * 0.8 - startHeight); + Math.round(window.innerHeight * 0.8 - this.props.startHeight); const coord = coordinatePair1 + coordinatePair2 + coordinatePair3; - setCoordinates(coord); - }, [left, startWidth, startHeight]); + this.setState({coordinates: coord}); + } - useEffect(() => { - setAngleInRadians(Math.atan(startHeight / startWidth)); - }, [startWidth, startHeight]); + componentDidMount() { + this.updateCoordinates() + } - return ( -
-
- , prevState: Readonly, snapshot?: any): void { + this.updateCoordinates(); + if (prevProps.startHeight != this.props.startHeight || prevProps.startWidth != this.props.startWidth) { + this.setState({angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth)}); + } + } + + render() { + return ( +
+
+ + + +
+ +

- - + {Math.round(((this.state.angleInRadians * 180) / Math.PI) * 100) / 100}° +

- -

- {Math.round(((angleInRadians * 180) / Math.PI) * 100) / 100}° -

-
- ); + ); + } }; -- cgit v1.2.3-70-g09d2 From 60ed47bf843704f2f4a4ccd152e15fb96a5c375e Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Tue, 31 Jan 2023 13:11:44 -0500 Subject: start converting weight file to class --- src/client/views/nodes/PhysicsSimulationApp.tsx | 461 ++++++++++----------- src/client/views/nodes/PhysicsSimulationWeight.tsx | 397 ++++++++---------- 2 files changed, 409 insertions(+), 449 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx index 414d61809..2277c7875 100644 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ b/src/client/views/nodes/PhysicsSimulationApp.tsx @@ -1,8 +1,8 @@ import React = require('react'); import "./PhysicsSimulationBox.scss"; -import { IForce, Weight } from "./PhysicsSimulationWeight"; -import {Wall, IWallProps } from "./PhysicsSimulationWall" -import {Wedge} from "./PhysicsSimulationWedge" +import Weight from "./PhysicsSimulationWeight"; +import Wall from "./PhysicsSimulationWall" +import Wedge from "./PhysicsSimulationWedge" import { props, any } from 'bluebird'; import { render } from 'react-dom'; @@ -329,235 +329,232 @@ export default class App extends React.Component<{}, IState> { render () { return ( -

Hello world!

- //
- //
- //
{ - // // if (sketching) { - // // x1 = positionXDisplay + 50; - // // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50; - // // x2 = e.clientX; - // // y2 = e.clientY; - // // height = Math.abs(y1 - y2) + 120; - // // width = Math.abs(x1 - x2) + 120; - // // top = Math.min(y1, y2) - 60; - // // left = Math.min(x1, x2) - 60; - // // x1Updated = x1 - left; - // // x2Updated = x2 - left; - // // y1Updated = y1 - top; - // // y2Updated = y2 - top; - // // setCurrentForceSketch({ - // // top: top, - // // left: left, - // // width: width, - // // height: height, - // // x1: x1Updated, - // // y1: y1Updated, - // // x2: x2Updated, - // // y2: y2Updated, - // // weightX: positionXDisplay, - // // weightY: positionYDisplay, - // // }); - // // } - // }} - // onPointerDown={(e) => { - // // if (sketching && currentForceSketch) { - // // setSketching(false); - // // sketches = forceSketches; - // // sketches.push(currentForceSketch); - // // setForceSketches(sketches); - // // setCurrentForceSketch(null); - // // } - // }} - // > - //
- //
- // {/* {showForces && currentForceSketch && simulationPaused && ( - //
- // - // - // - // - // - // - // - // - //
- // )} */} - // {/* {showForces && - // forceSketches.length > 0 && - // simulationPaused && - // forceSketches.map((element: PhysicsVectorTemplate, index) => { - // return ( - //
- // - // - // - // - // - // - // { - // if (deleteMode) { - // deleteForce(element); - // } else { - // editForce(element); - // } - // }} - // /> - // - //
- // ); - // })} */} - // {weight && ( - // - // )} - // {wedge && ( - // - // )} - //
- //
- // {wallPositions.map((element, index) => { - // return ( - // - // ); - // })} - //
- //
- //
- //
- //
- //
- // {simulationPaused && ( - // - // )} - // {!simulationPaused && ( - // - // )} - // {simulationPaused && ( - // - // )} - //
- //
- //
- //
- //
+
+
+
{ + // if (sketching) { + // x1 = positionXDisplay + 50; + // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50; + // x2 = e.clientX; + // y2 = e.clientY; + // height = Math.abs(y1 - y2) + 120; + // width = Math.abs(x1 - x2) + 120; + // top = Math.min(y1, y2) - 60; + // left = Math.min(x1, x2) - 60; + // x1Updated = x1 - left; + // x2Updated = x2 - left; + // y1Updated = y1 - top; + // y2Updated = y2 - top; + // setCurrentForceSketch({ + // top: top, + // left: left, + // width: width, + // height: height, + // x1: x1Updated, + // y1: y1Updated, + // x2: x2Updated, + // y2: y2Updated, + // weightX: positionXDisplay, + // weightY: positionYDisplay, + // }); + // } + }} + onPointerDown={(e) => { + // if (sketching && currentForceSketch) { + // setSketching(false); + // sketches = forceSketches; + // sketches.push(currentForceSketch); + // setForceSketches(sketches); + // setCurrentForceSketch(null); + // } + }} + > +
+
+ {/* {showForces && currentForceSketch && simulationPaused && ( +
+ + + + + + + + +
+ )} */} + {/* {showForces && + forceSketches.length > 0 && + simulationPaused && + forceSketches.map((element: PhysicsVectorTemplate, index) => { + return ( +
+ + + + + + + { + if (deleteMode) { + deleteForce(element); + } else { + editForce(element); + } + }} + /> + +
+ ); + })} */} + {/* {weight && ( + + )} */} + {this.state.wedge && ( + + )} +
+
+ {this.state.wallPositions.map((element, index) => { + return ( + + ); + })} +
+
+
+
+
+
+ {this.state.simulationPaused && ( + + )} + {!this.state.simulationPaused && ( + + )} + {this.state.simulationPaused && ( + + )} +
+
+
+
+
); } } diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index cc024f29a..d234c1395 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -1,6 +1,8 @@ +import React from "react"; import { useEffect, useState } from "react"; +import { render } from "react-dom"; import { IWallProps } from "./PhysicsSimulationWall"; -import { Wedge } from "./PhysicsSimulationWedge"; +import Wedge from "./PhysicsSimulationWedge"; export interface IForce { description: string; @@ -35,8 +37,6 @@ export interface IWeightProps { setPendulumLength: (val: number) => any; setStartPendulumAngle: (val: number) => any; showAcceleration: boolean; - mode: string; - noMovement: boolean; pendulumAngle: number; setSketching: (val: boolean) => any; showForces: boolean; @@ -56,154 +56,121 @@ export interface IWeightProps { wedgeHeight: number; } -export const Weight = (props: IWeightProps) => { - const { - adjustPendulumAngle, - color, - displayXPosition, - displayYPosition, - displayXVelocity, - displayYVelocity, - elasticCollisions, - startForces, - incrementTime, - mass, - paused, - pendulum, - pendulumLength, - wedge, - radius, - mode, - noMovement, - pendulumAngle, - reset, - setSketching, - setDisplayXAcceleration, - setDisplayXPosition, - setDisplayXVelocity, - setDisplayYAcceleration, - setDisplayYPosition, - setDisplayYVelocity, - setPaused, - setPendulumAngle, - setPendulumLength, - setStartPendulumAngle, - showAcceleration, - showForces, - showForceMagnitudes, - showVelocity, - startPosX, - startPosY, - startVelX, - startVelY, - timestepSize, - updateDisplay, - updatedForces, - setUpdatedForces, - walls, - coefficientOfKineticFriction, - wedgeWidth, - wedgeHeight, - } = props; +interface IState { + dragging: boolean, + kineticFriction: boolean, + updatedStartPosX: number, + updatedStartPosY: number, + xPosition: number, + yPosition: number, + xVelocity: number, + yVelocity: number, +} +export default class Weight extends React.Component { + + constructor(props: any) { + super(props) + this.state = { + dragging: false, + kineticFriction: false, + updatedStartPosX: this.props.startPosX, + updatedStartPosY: this.props.startPosY, + xPosition: this.props.startPosX, + yPosition: this.props.startPosY, + xVelocity: this.props.startVelX ? this.props.startVelX: 0, + yVelocity: this.props.startVelY ? this.props.startVelY: 0, + } + } // Constants - const draggable = !wedge && mode == "Freeform"; - const epsilon = 0.0001; - - const forceOfGravity: IForce = { + draggable = !this.props.wedge; + epsilon = 0.0001; + forceOfGravity: IForce = { description: "Gravity", - magnitude: mass * 9.81, + magnitude: this.props.mass * 9.81, directionInDegrees: 270, }; - const xMax = window.innerWidth * 0.7; - const xMin = 0; - const yMax = window.innerHeight * 0.8; - const yMin = 0; - - // State hooks - const [dragging, setDragging] = useState(false); - const [kineticFriction, setKineticFriction] = useState(false); - const [updatedStartPosX, setUpdatedStartPosX] = useState(startPosX); - const [updatedStartPosY, setUpdatedStartPosY] = useState(startPosY); - const [xPosition, setXPosition] = useState(startPosX); - const [xVelocity, setXVelocity] = useState(startVelX ?? 0); - const [yPosition, setYPosition] = useState(startPosY); - const [yVelocity, setYVelocity] = useState(startVelY ?? 0); + xMax = window.innerWidth * 0.7; + xMin = 0; + yMax = window.innerHeight * 0.8; + yMin = 0; // Helper function to go between display and real values const getDisplayYPos = (yPos: number) => { - return yMax - yPos - 2 * radius + 5; + return this.yMax - yPos - 2 * this.props.radius + 5; }; const getYPosFromDisplay = (yDisplay: number) => { - return yMax - yDisplay - 2 * radius + 5; + return this.yMax - yDisplay - 2 * this.props.radius + 5; }; // Set display values based on real values const setYPosDisplay = (yPos: number) => { - const displayPos = getDisplayYPos(yPos); - setDisplayYPosition(Math.round(displayPos * 100) / 100); + const displayPos = this.getDisplayYPos(yPos); + this.props.setDisplayYPosition(Math.round(displayPos * 100) / 100) }; const setXPosDisplay = (xPos: number) => { - setDisplayXPosition(Math.round(xPos * 100) / 100); + this.props.setDisplayXPosition(Math.round(xPos * 100) / 100); }; const setYVelDisplay = (yVel: number) => { - setDisplayYVelocity((-1 * Math.round(yVel * 100)) / 100); + this.props.setDisplayYVelocity((-1 * Math.round(yVel * 100)) / 100); }; const setXVelDisplay = (xVel: number) => { - setDisplayXVelocity(Math.round(xVel * 100) / 100); + this.props.setDisplayXVelocity(Math.round(xVel * 100) / 100); }; const setDisplayValues = ( - xPos: number = xPosition, - yPos: number = yPosition, - xVel: number = xVelocity, - yVel: number = yVelocity + xPos: number = this.state.xPosition, + yPos: number = this.state.yPosition, + xVel: number = this.state.xVelocity, + yVel: number = this.state.yVelocity ) => { - setYPosDisplay(yPos); - setXPosDisplay(xPos); - setYVelDisplay(yVel); - setXVelDisplay(xVel); - setDisplayYAcceleration( - (-1 * Math.round(getNewAccelerationY(updatedForces) * 100)) / 100 + this.setYPosDisplay(yPos); + this.setXPosDisplay(xPos); + this.setYVelDisplay(yVel); + this.setXVelDisplay(xVel); + this.props.setDisplayYAcceleration( + (-1 * Math.round(getNewAccelerationY(this.props.updatedForces) * 100)) / 100 ); - setDisplayXAcceleration( - Math.round(getNewAccelerationX(updatedForces) * 100) / 100 + this.props.setDisplayXAcceleration( + Math.round(getNewAccelerationX(this.props.updatedForces) * 100) / 100 ); }; // When display values updated by user, update real values - useEffect(() => { - if (updateDisplay.xDisplay != xPosition) { - let x = updateDisplay.xDisplay; - x = Math.max(0, x); - x = Math.min(x, xMax - 2 * radius); - setUpdatedStartPosX(x); - setXPosition(x); - setDisplayXPosition(x); - } - - if (updateDisplay.yDisplay != getDisplayYPos(yPosition)) { - let y = updateDisplay.yDisplay; - y = Math.max(0, y); - y = Math.min(y, yMax - 2 * radius); - setDisplayYPosition(y); - let coordinatePosition = getYPosFromDisplay(y); - setUpdatedStartPosY(coordinatePosition); - setYPosition(coordinatePosition); - } - - if (displayXVelocity != xVelocity) { - let x = displayXVelocity; - setXVelocity(x); - setDisplayXVelocity(x); - } - - if (displayYVelocity != -yVelocity) { - let y = displayYVelocity; - setYVelocity(-y); - setDisplayYVelocity(y); + componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { + if (this.props.updateDisplay != prevProps.updateDisplay) { + if (this.props.updateDisplay.xDisplay != this.state.xPosition) { + let x = this.props.updateDisplay.xDisplay; + x = Math.max(0, x); + x = Math.min(x, this.xMax - 2 * this.props.radius); + this.setState({updatedStartPosX: x}) + this.setState({xPosition: x}) + this.props.setDisplayXPosition(x); + } + + if (this.props.updateDisplay.yDisplay != this.getDisplayYPos(this.state.yPosition)) { + let y = this.props.updateDisplay.yDisplay; + y = Math.max(0, y); + y = Math.min(y, this.yMax - 2 * this.props.radius); + this.props.setDisplayYPosition(y); + let coordinatePosition = this.getYPosFromDisplay(y); + this.setState({updatedStartPosY: coordinatePosition}) + this.setState({yPosition: coordinatePosition}) + } + + if (this.props.displayXVelocity != this.state.xVelocity) { + let x = this.props.displayXVelocity; + this.setState({xVelocity: x}) + this.props.setDisplayXVelocity(x); + } + + if (this.props.displayYVelocity != this.state.yVelocity) { + let y = this.props.displayYVelocity; + this.setState({yVelocity: -y}) + this.props.setDisplayXVelocity(y); + } } - }, [updateDisplay]); + } // Check for collisions and update useEffect(() => { @@ -264,7 +231,7 @@ export const Weight = (props: IWeightProps) => { newXAcc += (force.magnitude * Math.cos((force.directionInDegrees * Math.PI) / 180)) / - mass; + this.props.mass; }); return newXAcc; }; @@ -276,7 +243,7 @@ export const Weight = (props: IWeightProps) => { (-1 * (force.magnitude * Math.sin((force.directionInDegrees * Math.PI) / 180))) / - mass; + this.props.mass; }); return newYAcc; }; @@ -287,11 +254,11 @@ export const Weight = (props: IWeightProps) => { xVel: number, yVel: number ) => { - if (!pendulum) { - return updatedForces; + if (!this.props.pendulum) { + return this.state.updatedForces; } - const x = xMax / 2 - xPos - radius; - const y = yPos + radius + 5; + const x = this.xMax / 2 - xPos - this.props.radius; + const y = yPos + this.props.radius + 5; let angle = (Math.atan(y / x) * 180) / Math.PI; if (angle < 0) { angle += 180; @@ -306,8 +273,8 @@ export const Weight = (props: IWeightProps) => { setPendulumLength(Math.sqrt(x * x + y * y)); const mag = - mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) + - (mass * (xVel * xVel + yVel * yVel)) / pendulumLength; + this.props.mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) + + (this.props.mass * (xVel * xVel + yVel * yVel)) / pendulumLength; const forceOfTension: IForce = { description: "Tension", @@ -315,24 +282,24 @@ export const Weight = (props: IWeightProps) => { directionInDegrees: angle, }; - return [forceOfGravity, forceOfTension]; + return [this.forceOfGravity, forceOfTension]; }; const getNewPosition = (pos: number, vel: number) => { - return pos + vel * timestepSize; + return pos + vel * this.props.timestepSize; }; const getNewVelocity = (vel: number, acc: number) => { - return vel + acc * timestepSize; + return vel + acc * this.props.timestepSize; }; const checkForCollisionsWithWall = () => { let collision = false; - const minX = xPosition; - const maxX = xPosition + 2 * radius; + const minX = this.state.xPosition; + const maxX = this.state.xPosition + 2 * this.props.radius; const containerWidth = window.innerWidth; - if (xVelocity != 0) { - walls.forEach((wall) => { + if (this.state.xVelocity != 0) { + this.props.walls.forEach((wall) => { if (wall.angleInDegrees == 90) { const wallX = (wall.xPos / 100) * window.innerWidth; if (wall.xPos < 0.35) { @@ -542,43 +509,39 @@ export const Weight = (props: IWeightProps) => { setYPosDisplay(startPosY); }, [startPosY]); - return ( + render () { + return (
{ - if (draggable) { + if (this.props.draggable) { e.preventDefault(); - setPaused(true); - setDragging(true); + this.props.setPaused(true); + this.setState({dragging: true}); setClickPositionX(e.clientX); setClickPositionY(e.clientY); - } else if (mode == "Review") { - setSketching(true); } }} onPointerMove={(e) => { e.preventDefault(); - if (dragging) { - let newY = yPosition + e.clientY - clickPositionY; - if (newY > yMax - 2 * radius) { - newY = yMax - 2 * radius; + if (this.state.dragging) { + let newY = this.state.yPosition + e.clientY - clickPositionY; + if (newY > this.yMax - 2 * this.props.radius) { + newY = this.yMax - 2 * this.props.radius; } - let newX = xPosition + e.clientX - clickPositionX; - if (newX > xMax - 2 * radius) { - newX = xMax - 2 * radius; + let newX = this.state.xPosition + e.clientX - clickPositionX; + if (newX > this.xMax - 2 * this.props.radius) { + newX = this.xMax - 2 * this.props.radius; } else if (newX < 0) { newX = 0; } - - setXPosition(newX); - setYPosition(newY); - setUpdatedStartPosX(newX); - setUpdatedStartPosY(newY); - setDisplayYPosition( - Math.round((yMax - 2 * radius - newY + 5) * 100) / 100 - ); + this.setState({xPosition: newX}) + this.setState({yPosition: newY}) + this.setState({updatedStartPosX: newX}) + this.setState({updatedStartPosY: newY}) + this.setState({displayYPosition: Math.round((yMax - 2 * radius - newY + 5) * 100) / 100}) setClickPositionX(e.clientX); setClickPositionY(e.clientY); setDisplayValues(); @@ -591,20 +554,20 @@ export const Weight = (props: IWeightProps) => { resetEverything(); } setDragging(false); - let newY = yPosition + e.clientY - clickPositionY; - if (newY > yMax - 2 * radius) { - newY = yMax - 2 * radius; + let newY = this.state.yPosition + e.clientY - clickPositionY; + if (newY > this.yMax - 2 * this.props.radius) { + newY = this.yMax - 2 * this.props.radius; } let newX = xPosition + e.clientX - clickPositionX; - if (newX > xMax - 2 * radius) { - newX = xMax - 2 * radius; + if (newX > this.xMax - 2 * this.props.radius) { + newX = this.xMax - 2 * this.props.radius; } else if (newX < 0) { newX = 0; } - if (pendulum) { - const x = xMax / 2 - newX - radius; - const y = newY + radius + 5; + if (this.state.pendulum) { + const x = this.xMax / 2 - newX - this.props.radius; + const y = newY + this.props.radius + 5; let angle = (Math.atan(y / x) * 180) / Math.PI; if (angle < 0) { angle += 180; @@ -615,20 +578,19 @@ export const Weight = (props: IWeightProps) => { } const pendulumLength = Math.sqrt(x * x + y * y); - setPendulumAngle(oppositeAngle); - setPendulumLength(Math.sqrt(x * x + y * y)); + this.props.setPendulumAngle(oppositeAngle); + this.props.setPendulumLength(Math.sqrt(x * x + y * y)); const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180); const forceOfTension: IForce = { description: "Tension", magnitude: mag, directionInDegrees: angle, }; - - setKineticFriction(false); - setXVelocity(startVelX ?? 0); - setYVelocity(startVelY ?? 0); + this.setState({kineticFriction: false}) + this.setState({xVelocity: startVelX ?? 0}) + this.setState({yVelocity: startVelY ?? 0}) setDisplayValues(); - setUpdatedForces([forceOfGravity, forceOfTension]); + this.setState({updatedForces :[forceOfGravity, forceOfTension]}); } } }} @@ -637,7 +599,7 @@ export const Weight = (props: IWeightProps) => {

{mass} kg

- {pendulum && ( + {this.state.pendulum && (
{ zIndex: -2, }} > - + - {!dragging && ( + {!this.state.dragging && (

- {Math.round(pendulumLength)} m + {Math.round(this.props.pendulumLength)} m

- {Math.round(pendulumAngle * 100) / 100}° + {Math.round(this.props.pendulumAngle * 100) / 100}°

)}
)} - {!dragging && showAcceleration && ( + {!this.state.dragging && this.props.showAcceleration && (
{ top: 0, }} > - + { { pointerEvents: "none", position: "absolute", left: - xPosition + - radius + - getNewAccelerationX(updatedForces) * 5 + + this.state.xPosition + + this.props.radius + + getNewAccelerationX(this.state.updatedForces) * 5 + 25 + "px", top: - yPosition + - radius + - getNewAccelerationY(updatedForces) * 5 + + this.state.yPosition + + this.props.radius + + getNewAccelerationY(this.state.updatedForces) * 5 + 25 + "px", zIndex: -1, @@ -745,8 +707,8 @@ export const Weight = (props: IWeightProps) => { {Math.round( 100 * Math.sqrt( - Math.pow(getNewAccelerationX(updatedForces) * 3, 2) + - Math.pow(getNewAccelerationY(updatedForces) * 3, 2) + Math.pow(getNewAccelerationX(this.state.updatedForces) * 3, 2) + + Math.pow(getNewAccelerationY(this.state.updatedForces) * 3, 2) ) ) / 100}{" "} m/s2 @@ -755,7 +717,7 @@ export const Weight = (props: IWeightProps) => {
)} - {!dragging && showVelocity && ( + {!this.state.dragging && this.props.showVelocity && (
{ top: 0, }} > - + { { style={{ pointerEvents: "none", position: "absolute", - left: xPosition + radius + xVelocity * 3 + 25 + "px", - top: yPosition + radius + yVelocity * 3 + "px", + left: this.state.xPosition + this.props.radius + this.state.xVelocity * 3 + 25 + "px", + top: this.state.yPosition + this.props.radius + this.state.yVelocity * 3 + "px", zIndex: -1, lineHeight: 0.5, }} >

{Math.round( - 100 * Math.sqrt(xVelocity * xVelocity + yVelocity * yVelocity) + 100 * Math.sqrt(this.state.xVelocity**2 + this.state.yVelocity**2) ) / 100}{" "} m/s

@@ -810,14 +772,14 @@ export const Weight = (props: IWeightProps) => {
)} - {!dragging && - showForces && - updatedForces.map((force, index) => { - if (force.magnitude < epsilon) { + {!this.state.dragging && + this.props.showForces && + this.props.updatedForces.map((force, index) => { + if (force.magnitude < this.epsilon) { return; } - let arrowStartY: number = yPosition + radius; - const arrowStartX: number = xPosition + radius; + let arrowStartY: number = this.state.yPosition + this.props.radius; + const arrowStartX: number = this.state.xPosition + this.props.radius; let arrowEndY: number = arrowStartY - Math.abs(force.magnitude) * @@ -843,10 +805,10 @@ export const Weight = (props: IWeightProps) => { } else { labelTop -= 40; } - labelTop = Math.min(labelTop, yMax + 50); - labelTop = Math.max(labelTop, yMin); - labelLeft = Math.min(labelLeft, xMax - 60); - labelLeft = Math.max(labelLeft, xMin); + labelTop = Math.min(labelTop, this.yMax + 50); + labelTop = Math.max(labelTop, this.yMin); + labelLeft = Math.min(labelLeft, this.xMax - 60); + labelLeft = Math.max(labelLeft, this.xMin); return (
@@ -908,5 +870,6 @@ export const Weight = (props: IWeightProps) => { ); })}
- ); + ); + } }; -- cgit v1.2.3-70-g09d2 From 6000ce6b65e6bd4c87fadc9c41f3508037854470 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Wed, 1 Feb 2023 14:43:25 -0500 Subject: keep switching to class components --- src/client/views/nodes/PhysicsSimulationApp.tsx | 2 +- src/client/views/nodes/PhysicsSimulationWeight.tsx | 566 ++++++++++----------- 2 files changed, 282 insertions(+), 286 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx index 2277c7875..bd218f63b 100644 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ b/src/client/views/nodes/PhysicsSimulationApp.tsx @@ -1,6 +1,6 @@ import React = require('react'); import "./PhysicsSimulationBox.scss"; -import Weight from "./PhysicsSimulationWeight"; +import Weight, { IForce } from "./PhysicsSimulationWeight"; import Wall from "./PhysicsSimulationWall" import Wedge from "./PhysicsSimulationWedge" import { props, any } from 'bluebird'; diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index d234c1395..fb040c850 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -57,6 +57,8 @@ export interface IWeightProps { } interface IState { + clickPositionX: number, + clickPositionY: number, dragging: boolean, kineticFriction: boolean, updatedStartPosX: number, @@ -71,6 +73,8 @@ export default class Weight extends React.Component { constructor(props: any) { super(props) this.state = { + clickPositionX: 0, + clickPositionY: 0, dragging: false, kineticFriction: false, updatedStartPosX: this.props.startPosX, @@ -96,29 +100,29 @@ export default class Weight extends React.Component { yMin = 0; // Helper function to go between display and real values - const getDisplayYPos = (yPos: number) => { + getDisplayYPos = (yPos: number) => { return this.yMax - yPos - 2 * this.props.radius + 5; }; - const getYPosFromDisplay = (yDisplay: number) => { + getYPosFromDisplay = (yDisplay: number) => { return this.yMax - yDisplay - 2 * this.props.radius + 5; }; // Set display values based on real values - const setYPosDisplay = (yPos: number) => { + setYPosDisplay = (yPos: number) => { const displayPos = this.getDisplayYPos(yPos); this.props.setDisplayYPosition(Math.round(displayPos * 100) / 100) }; - const setXPosDisplay = (xPos: number) => { + setXPosDisplay = (xPos: number) => { this.props.setDisplayXPosition(Math.round(xPos * 100) / 100); }; - const setYVelDisplay = (yVel: number) => { + setYVelDisplay = (yVel: number) => { this.props.setDisplayYVelocity((-1 * Math.round(yVel * 100)) / 100); }; - const setXVelDisplay = (xVel: number) => { + setXVelDisplay = (xVel: number) => { this.props.setDisplayXVelocity(Math.round(xVel * 100) / 100); }; - const setDisplayValues = ( + setDisplayValues = ( xPos: number = this.state.xPosition, yPos: number = this.state.yPosition, xVel: number = this.state.xVelocity, @@ -129,10 +133,10 @@ export default class Weight extends React.Component { this.setYVelDisplay(yVel); this.setXVelDisplay(xVel); this.props.setDisplayYAcceleration( - (-1 * Math.round(getNewAccelerationY(this.props.updatedForces) * 100)) / 100 + (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100 ); this.props.setDisplayXAcceleration( - Math.round(getNewAccelerationX(this.props.updatedForces) * 100) / 100 + Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100 ); }; @@ -170,62 +174,59 @@ export default class Weight extends React.Component { this.props.setDisplayXVelocity(y); } } - } - - // Check for collisions and update - useEffect(() => { - if (!paused && !noMovement) { - let collisions = false; - if (!pendulum) { - const collisionsWithGround = checkForCollisionsWithGround(); - const collisionsWithWalls = checkForCollisionsWithWall(); - collisions = collisionsWithGround || collisionsWithWalls; - } - if (!collisions) { - update(); + // Update sim + if (this.props.incrementTime != prevProps.incrementTime) { + if (!this.props.paused) { + let collisions = false; + if (!this.props.pendulum) { + const collisionsWithGround = this.checkForCollisionsWithGround(); + const collisionsWithWalls = this.checkForCollisionsWithWall(); + collisions = collisionsWithGround || collisionsWithWalls; + } + if (!collisions) { + this.update(); + } + this.setDisplayValues(); } - setDisplayValues(); } - }, [incrementTime]); - - useEffect(() => { - resetEverything(); - }, [reset]); - - useEffect(() => { - setXVelocity(startVelX ?? 0); - setYVelocity(startVelY ?? 0); - setDisplayValues(); - }, [startForces]); - - const resetEverything = () => { - setKineticFriction(false); - setXPosition(updatedStartPosX); - setYPosition(updatedStartPosY); - setXVelocity(startVelX ?? 0); - setYVelocity(startVelY ?? 0); - setUpdatedForces(startForces); - setDisplayValues(); + if (this.props.reset != prevProps.reset) { + this.resetEverything(); + } + if (this.props.startForces != prevProps.startForces) { + this.setState({xVelocity: this.props.startVelX ?? 0}) + this.setState({yVelocity: this.props.startVelY ?? 0}) + this.setDisplayValues(); + } + } + + resetEverything = () => { + this.setState({kineticFriction: false}) + this.setState({xPosition: this.state.updatedStartPosX}) + this.setState({yPosition: this.state.updatedStartPosY}) + this.setState({xVelocity: this.props.startVelX ?? 0}) + this.setState({yVelocity: this.props.startVelY ?? 0}) + this.props.setUpdatedForces(this.props.startForces) + this.setDisplayValues(); }; - // Change pendulum angle based on input field - useEffect(() => { - let length = adjustPendulumAngle.length; - const x = - length * Math.cos(((90 - adjustPendulumAngle.angle) * Math.PI) / 180); - const y = - length * Math.sin(((90 - adjustPendulumAngle.angle) * Math.PI) / 180); - const xPos = xMax / 2 - x - radius; - const yPos = y - radius - 5; - setXPosition(xPos); - setYPosition(yPos); - setUpdatedStartPosX(xPos); - setUpdatedStartPosY(yPos); - setPendulumAngle(adjustPendulumAngle.angle); - setPendulumLength(adjustPendulumAngle.length); - }, [adjustPendulumAngle]); - - const getNewAccelerationX = (forceList: IForce[]) => { + // // Change pendulum angle based on input field + // useEffect(() => { + // let length = adjustPendulumAngle.length; + // const x = + // length * Math.cos(((90 - adjustPendulumAngle.angle) * Math.PI) / 180); + // const y = + // length * Math.sin(((90 - adjustPendulumAngle.angle) * Math.PI) / 180); + // const xPos = xMax / 2 - x - radius; + // const yPos = y - radius - 5; + // setXPosition(xPos); + // setYPosition(yPos); + // setUpdatedStartPosX(xPos); + // setUpdatedStartPosY(yPos); + // setPendulumAngle(adjustPendulumAngle.angle); + // setPendulumLength(adjustPendulumAngle.length); + // }, [adjustPendulumAngle]); + + getNewAccelerationX = (forceList: IForce[]) => { let newXAcc = 0; forceList.forEach((force) => { newXAcc += @@ -236,7 +237,7 @@ export default class Weight extends React.Component { return newXAcc; }; - const getNewAccelerationY = (forceList: IForce[]) => { + getNewAccelerationY = (forceList: IForce[]) => { let newYAcc = 0; forceList.forEach((force) => { newYAcc += @@ -248,14 +249,14 @@ export default class Weight extends React.Component { return newYAcc; }; - const getNewForces = ( + getNewForces = ( xPos: number, yPos: number, xVel: number, yVel: number ) => { if (!this.props.pendulum) { - return this.state.updatedForces; + return this.props.updatedForces; } const x = this.xMax / 2 - xPos - this.props.radius; const y = yPos + this.props.radius + 5; @@ -269,8 +270,8 @@ export default class Weight extends React.Component { } const pendulumLength = Math.sqrt(x * x + y * y); - setPendulumAngle(oppositeAngle); - setPendulumLength(Math.sqrt(x * x + y * y)); + this.props.setPendulumAngle(oppositeAngle); + this.props.setPendulumLength(Math.sqrt(x * x + y * y)); const mag = this.props.mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) + @@ -285,74 +286,74 @@ export default class Weight extends React.Component { return [this.forceOfGravity, forceOfTension]; }; - const getNewPosition = (pos: number, vel: number) => { + getNewPosition = (pos: number, vel: number) => { return pos + vel * this.props.timestepSize; }; - const getNewVelocity = (vel: number, acc: number) => { + getNewVelocity = (vel: number, acc: number) => { return vel + acc * this.props.timestepSize; }; - const checkForCollisionsWithWall = () => { + // const checkForCollisionsWithWall = () => { + // let collision = false; + // const minX = this.state.xPosition; + // const maxX = this.state.xPosition + 2 * this.props.radius; + // const containerWidth = window.innerWidth; + // if (this.state.xVelocity != 0) { + // this.props.walls.forEach((wall) => { + // if (wall.angleInDegrees == 90) { + // const wallX = (wall.xPos / 100) * window.innerWidth; + // if (wall.xPos < 0.35) { + // if (minX <= wallX) { + // if (elasticCollisions) { + // setXVelocity(-xVelocity); + // } else { + // setXVelocity(0); + // setXPosition(wallX + 5); + // } + // collision = true; + // } + // } else { + // if (maxX >= wallX) { + // if (elasticCollisions) { + // setXVelocity(-xVelocity); + // } else { + // setXVelocity(0); + // setXPosition(wallX - 2 * radius + 5); + // } + // collision = true; + // } + // } + // } + // }); + // } + // return collision; + // }; + + checkForCollisionsWithGround = () => { let collision = false; - const minX = this.state.xPosition; - const maxX = this.state.xPosition + 2 * this.props.radius; - const containerWidth = window.innerWidth; - if (this.state.xVelocity != 0) { + const maxY = this.state.yPosition + 2 * this.props.radius; + if (this.state.yVelocity > 0) { this.props.walls.forEach((wall) => { - if (wall.angleInDegrees == 90) { - const wallX = (wall.xPos / 100) * window.innerWidth; - if (wall.xPos < 0.35) { - if (minX <= wallX) { - if (elasticCollisions) { - setXVelocity(-xVelocity); - } else { - setXVelocity(0); - setXPosition(wallX + 5); - } - collision = true; - } - } else { - if (maxX >= wallX) { - if (elasticCollisions) { - setXVelocity(-xVelocity); - } else { - setXVelocity(0); - setXPosition(wallX - 2 * radius + 5); - } - collision = true; - } - } - } - }); - } - return collision; - }; - - const checkForCollisionsWithGround = () => { - let collision = false; - const maxY = yPosition + 2 * radius; - if (yVelocity > 0) { - walls.forEach((wall) => { if (wall.angleInDegrees == 0) { const groundY = (wall.yPos / 100) * window.innerHeight; if (maxY >= groundY) { - if (elasticCollisions) { - setYVelocity(-yVelocity); + if (this.props.elasticCollisions) { + this.setState({yVelocity: -this.state.yVelocity}) } else { - setYVelocity(0); - setYPosition(groundY - 2 * radius + 5); + this.setState({yVelocity: 0}) + this.setState({yPosition: groundY - 2 * this.props.radius + 5}) const forceOfGravity: IForce = { description: "Gravity", - magnitude: 9.81 * mass, + magnitude: 9.81 * this.props.mass, directionInDegrees: 270, }; const normalForce: IForce = { description: "Normal force", - magnitude: 9.81 * mass, + magnitude: 9.81 * this.props.mass, directionInDegrees: wall.angleInDegrees + 90, }; - setUpdatedForces([forceOfGravity, normalForce]); + this.props.setUpdatedForces([forceOfGravity, normalForce]); } collision = true; } @@ -362,152 +363,147 @@ export default class Weight extends React.Component { return collision; }; - useEffect(() => { - if (wedge && xVelocity != 0 && mode != "Review" && !kineticFriction) { - setKineticFriction(true); - //switch from static to kinetic friction - const normalForce: IForce = { - description: "Normal Force", - magnitude: - forceOfGravity.magnitude * - Math.cos(Math.atan(wedgeHeight / wedgeWidth)), - directionInDegrees: - 180 - 90 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI, - }; - let frictionForce: IForce = { - description: "Kinetic Friction Force", - magnitude: - coefficientOfKineticFriction * - forceOfGravity.magnitude * - Math.cos(Math.atan(wedgeHeight / wedgeWidth)), - directionInDegrees: - 180 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI, - }; - // reduce magnitude of friction force if necessary such that block cannot slide up plane - let yForce = -forceOfGravity.magnitude; - yForce += - normalForce.magnitude * - Math.sin((normalForce.directionInDegrees * Math.PI) / 180); - yForce += - frictionForce.magnitude * - Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - if (yForce > 0) { - frictionForce.magnitude = - (-normalForce.magnitude * - Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + - forceOfGravity.magnitude) / - Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - } - if (coefficientOfKineticFriction != 0) { - setUpdatedForces([forceOfGravity, normalForce, frictionForce]); - } else { - setUpdatedForces([forceOfGravity, normalForce]); - } - } - }, [xVelocity]); - - const update = () => { - // RK4 update - let xPos = xPosition; - let yPos = yPosition; - let xVel = xVelocity; - let yVel = yVelocity; - for (let i = 0; i < 60; i++) { - let forces1 = getNewForces(xPos, yPos, xVel, yVel); - const xAcc1 = getNewAccelerationX(forces1); - const yAcc1 = getNewAccelerationY(forces1); - const xVel1 = getNewVelocity(xVel, xAcc1); - const yVel1 = getNewVelocity(yVel, yAcc1); - - let xVel2 = getNewVelocity(xVel, xAcc1 / 2); - let yVel2 = getNewVelocity(yVel, yAcc1 / 2); - let xPos2 = getNewPosition(xPos, xVel1 / 2); - let yPos2 = getNewPosition(yPos, yVel1 / 2); - const forces2 = getNewForces(xPos2, yPos2, xVel2, yVel2); - const xAcc2 = getNewAccelerationX(forces2); - const yAcc2 = getNewAccelerationY(forces2); - xVel2 = getNewVelocity(xVel2, xAcc2); - yVel2 = getNewVelocity(yVel2, yAcc2); - xPos2 = getNewPosition(xPos2, xVel2); - yPos2 = getNewPosition(yPos2, yVel2); - - let xVel3 = getNewVelocity(xVel, xAcc2 / 2); - let yVel3 = getNewVelocity(yVel, yAcc2 / 2); - let xPos3 = getNewPosition(xPos, xVel2 / 2); - let yPos3 = getNewPosition(yPos, yVel2 / 2); - const forces3 = getNewForces(xPos3, yPos3, xVel3, yVel3); - const xAcc3 = getNewAccelerationX(forces3); - const yAcc3 = getNewAccelerationY(forces3); - xVel3 = getNewVelocity(xVel3, xAcc3); - yVel3 = getNewVelocity(yVel3, yAcc3); - xPos3 = getNewPosition(xPos3, xVel3); - yPos3 = getNewPosition(yPos3, yVel3); - - let xVel4 = getNewVelocity(xVel, xAcc3); - let yVel4 = getNewVelocity(yVel, yAcc3); - let xPos4 = getNewPosition(xPos, xVel3); - let yPos4 = getNewPosition(yPos, yVel3); - const forces4 = getNewForces(xPos4, yPos4, xVel4, yVel4); - const xAcc4 = getNewAccelerationX(forces4); - const yAcc4 = getNewAccelerationY(forces4); - xVel4 = getNewVelocity(xVel4, xAcc4); - yVel4 = getNewVelocity(yVel4, yAcc4); - xPos4 = getNewPosition(xPos4, xVel4); - yPos4 = getNewPosition(yPos4, yVel4); - - xVel += - timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0); - yVel += - timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0); - xPos += - timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0); - yPos += - timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0); - } - - setXVelocity(xVel); - setYVelocity(yVel); - setXPosition(xPos); - setYPosition(yPos); - setUpdatedForces(getNewForces(xPos, yPos, xVel, yVel)); - }; - - let weightStyle = { - backgroundColor: color, + // useEffect(() => { + // if (wedge && xVelocity != 0 && mode != "Review" && !kineticFriction) { + // setKineticFriction(true); + // //switch from static to kinetic friction + // const normalForce: IForce = { + // description: "Normal Force", + // magnitude: + // forceOfGravity.magnitude * + // Math.cos(Math.atan(wedgeHeight / wedgeWidth)), + // directionInDegrees: + // 180 - 90 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI, + // }; + // let frictionForce: IForce = { + // description: "Kinetic Friction Force", + // magnitude: + // coefficientOfKineticFriction * + // forceOfGravity.magnitude * + // Math.cos(Math.atan(wedgeHeight / wedgeWidth)), + // directionInDegrees: + // 180 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI, + // }; + // // reduce magnitude of friction force if necessary such that block cannot slide up plane + // let yForce = -forceOfGravity.magnitude; + // yForce += + // normalForce.magnitude * + // Math.sin((normalForce.directionInDegrees * Math.PI) / 180); + // yForce += + // frictionForce.magnitude * + // Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + // if (yForce > 0) { + // frictionForce.magnitude = + // (-normalForce.magnitude * + // Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + + // forceOfGravity.magnitude) / + // Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + // } + // if (coefficientOfKineticFriction != 0) { + // this.props.setUpdatedForces([forceOfGravity, normalForce, frictionForce]); + // } else { + // this.props.setUpdatedForces([forceOfGravity, normalForce]); + // } + // } + // }, [xVelocity]); + + // const update = () => { + // // RK4 update + // let xPos = xPosition; + // let yPos = yPosition; + // let xVel = xVelocity; + // let yVel = yVelocity; + // for (let i = 0; i < 60; i++) { + // let forces1 = this.getNewForces(xPos, yPos, xVel, yVel); + // const xAcc1 = this.getNewAccelerationX(forces1); + // const yAcc1 = this.getNewAccelerationY(forces1); + // const xVel1 = this.getNewVelocity(xVel, xAcc1); + // const yVel1 = this.getNewVelocity(yVel, yAcc1); + + // let xVel2 = getNewVelocity(xVel, xAcc1 / 2); + // let yVel2 = getNewVelocity(yVel, yAcc1 / 2); + // let xPos2 = getNewPosition(xPos, xVel1 / 2); + // let yPos2 = getNewPosition(yPos, yVel1 / 2); + // const forces2 = this.getNewForces(xPos2, yPos2, xVel2, yVel2); + // const xAcc2 = this.getNewAccelerationX(forces2); + // const yAcc2 = this.getNewAccelerationY(forces2); + // xVel2 = this.getNewVelocity(xVel2, xAcc2); + // yVel2 = this.getNewVelocity(yVel2, yAcc2); + // xPos2 = this.getNewPosition(xPos2, xVel2); + // yPos2 = this.getNewPosition(yPos2, yVel2); + + // let xVel3 = this.getNewVelocity(xVel, xAcc2 / 2); + // let yVel3 = this.getNewVelocity(yVel, yAcc2 / 2); + // let xPos3 = this.getNewPosition(xPos, xVel2 / 2); + // let yPos3 = this.getNewPosition(yPos, yVel2 / 2); + // const forces3 = this.getNewForces(xPos3, yPos3, xVel3, yVel3); + // const xAcc3 = this.getNewAccelerationX(forces3); + // const yAcc3 = this.getNewAccelerationY(forces3); + // xVel3 = this.getNewVelocity(xVel3, xAcc3); + // yVel3 = this.getNewVelocity(yVel3, yAcc3); + // xPos3 = this.getNewPosition(xPos3, xVel3); + // yPos3 = this.getNewPosition(yPos3, yVel3); + + // let xVel4 = this.getNewVelocity(xVel, xAcc3); + // let yVel4 = this.getNewVelocity(yVel, yAcc3); + // let xPos4 = this.getNewPosition(xPos, xVel3); + // let yPos4 = this.getNewPosition(yPos, yVel3); + // const forces4 = this.getNewForces(xPos4, yPos4, xVel4, yVel4); + // const xAcc4 = this.getNewAccelerationX(forces4); + // const yAcc4 = this.getNewAccelerationY(forces4); + // xVel4 = this.getNewVelocity(xVel4, xAcc4); + // yVel4 = this.getNewVelocity(yVel4, yAcc4); + // xPos4 = this.getNewPosition(xPos4, xVel4); + // yPos4 = this.getNewPosition(yPos4, yVel4); + + // xVel += + // timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0); + // yVel += + // timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0); + // xPos += + // timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0); + // yPos += + // timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0); + // } + + // setXVelocity(xVel); + // setYVelocity(yVel); + // setXPosition(xPos); + // setYPosition(yPos); + // this.props.setUpdatedForces(getNewForces(xPos, yPos, xVel, yVel)); + // }; + + weightStyle = { + backgroundColor: this.props.color, borderStyle: "solid", - borderColor: "black", + borderColor: this.state.dragging ? "lightblue" : "black", position: "absolute" as "absolute", - left: xPosition + "px", - top: yPosition + "px", - width: 2 * radius + "px", - height: 2 * radius + "px", + left: this.state.xPosition + "px", + top: this.state.yPosition + "px", + width: 2 * this.props.radius + "px", + height: 2 * this.props.radius + "px", borderRadius: 50 + "%", display: "flex", justifyContent: "center", alignItems: "center", touchAction: "none", }; - if (dragging) { - weightStyle.borderColor = "lightblue"; - } - const [clickPositionX, setClickPositionX] = useState(0); - const [clickPositionY, setClickPositionY] = useState(0); - const labelBackgroundColor = `rgba(255,255,255,0.5)`; + labelBackgroundColor = `rgba(255,255,255,0.5)`; - // Update x start position - useEffect(() => { - setUpdatedStartPosX(startPosX); - setXPosition(startPosX); - setXPosDisplay(startPosX); - }, [startPosX]); + // // Update x start position + // useEffect(() => { + // setUpdatedStartPosX(startPosX); + // setXPosition(startPosX); + // setXPosDisplay(startPosX); + // }, [startPosX]); - // Update y start position - useEffect(() => { - setUpdatedStartPosY(startPosY); - setYPosition(startPosY); - setYPosDisplay(startPosY); - }, [startPosY]); + // // Update y start position + // useEffect(() => { + // setUpdatedStartPosY(startPosY); + // setYPosition(startPosY); + // setYPosDisplay(startPosY); + // }, [startPosY]); render () { return ( @@ -515,23 +511,23 @@ export default class Weight extends React.Component {
{ - if (this.props.draggable) { + if (this.draggable) { e.preventDefault(); this.props.setPaused(true); this.setState({dragging: true}); - setClickPositionX(e.clientX); - setClickPositionY(e.clientY); + this.setState({clickPositionX: e.clientX}) + this.setState({clickPositionY: e.clientY}) } }} onPointerMove={(e) => { e.preventDefault(); if (this.state.dragging) { - let newY = this.state.yPosition + e.clientY - clickPositionY; + let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; if (newY > this.yMax - 2 * this.props.radius) { newY = this.yMax - 2 * this.props.radius; } - let newX = this.state.xPosition + e.clientX - clickPositionX; + let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; if (newX > this.xMax - 2 * this.props.radius) { newX = this.xMax - 2 * this.props.radius; } else if (newX < 0) { @@ -541,31 +537,31 @@ export default class Weight extends React.Component { this.setState({yPosition: newY}) this.setState({updatedStartPosX: newX}) this.setState({updatedStartPosY: newY}) - this.setState({displayYPosition: Math.round((yMax - 2 * radius - newY + 5) * 100) / 100}) - setClickPositionX(e.clientX); - setClickPositionY(e.clientY); - setDisplayValues(); + this.props.setDisplayYPosition(Math.round((this.yMax - 2 * this.props.radius - newY + 5) * 100) / 100) + this.setState({clickPositionX: e.clientX}) + this.setState({clickPositionY: e.clientY}) + this.setDisplayValues(); } }} onPointerUp={(e) => { - if (dragging) { + if (this.state.dragging) { e.preventDefault(); - if (!pendulum) { - resetEverything(); + if (!this.props.pendulum) { + this.resetEverything(); } - setDragging(false); - let newY = this.state.yPosition + e.clientY - clickPositionY; + this.setState({dragging: false}); + let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; if (newY > this.yMax - 2 * this.props.radius) { newY = this.yMax - 2 * this.props.radius; } - let newX = xPosition + e.clientX - clickPositionX; + let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; if (newX > this.xMax - 2 * this.props.radius) { newX = this.xMax - 2 * this.props.radius; } else if (newX < 0) { newX = 0; } - if (this.state.pendulum) { + if (this.props.pendulum) { const x = this.xMax / 2 - newX - this.props.radius; const y = newY + this.props.radius + 5; let angle = (Math.atan(y / x) * 180) / Math.PI; @@ -587,19 +583,19 @@ export default class Weight extends React.Component { directionInDegrees: angle, }; this.setState({kineticFriction: false}) - this.setState({xVelocity: startVelX ?? 0}) - this.setState({yVelocity: startVelY ?? 0}) - setDisplayValues(); - this.setState({updatedForces :[forceOfGravity, forceOfTension]}); + this.setState({xVelocity: this.props.startVelX ?? 0}) + this.setState({yVelocity: this.props.startVelY ?? 0}) + this.setDisplayValues(); + this.props.setUpdatedForces([this.forceOfGravity, forceOfTension]); } } }} > -
-

{mass} kg

+
+

{this.props.mass} kg

- {this.state.pendulum && ( + {this.props.pendulum && (
{ zIndex: 5, left: this.state.xPosition + "px", top: this.state.yPosition - 70 + "px", - backgroundColor: labelBackgroundColor, + backgroundColor: this.labelBackgroundColor, }} > {Math.round(this.props.pendulumLength)} m @@ -639,7 +635,7 @@ export default class Weight extends React.Component { zIndex: -1, left: this.xMax / 2 + "px", top: 30 + "px", - backgroundColor: labelBackgroundColor, + backgroundColor: this.labelBackgroundColor, }} > {Math.round(this.props.pendulumAngle * 100) / 100}° @@ -676,8 +672,8 @@ export default class Weight extends React.Component { { left: this.state.xPosition + this.props.radius + - getNewAccelerationX(this.state.updatedForces) * 5 + + this.getNewAccelerationX(this.props.updatedForces) * 5 + 25 + "px", top: this.state.yPosition + this.props.radius + - getNewAccelerationY(this.state.updatedForces) * 5 + + this.getNewAccelerationY(this.props.updatedForces) * 5 + 25 + "px", zIndex: -1, @@ -707,8 +703,8 @@ export default class Weight extends React.Component { {Math.round( 100 * Math.sqrt( - Math.pow(getNewAccelerationX(this.state.updatedForces) * 3, 2) + - Math.pow(getNewAccelerationY(this.state.updatedForces) * 3, 2) + Math.pow(this.getNewAccelerationX(this.props.updatedForces) * 3, 2) + + Math.pow(this.getNewAccelerationY(this.props.updatedForces) * 3, 2) ) ) / 100}{" "} m/s2 @@ -817,12 +813,12 @@ export default class Weight extends React.Component { pointerEvents: "none", position: "absolute", zIndex: -1, - left: xMin, - top: yMin, + left: this.xMin, + top: this.yMin, }} > @@ -857,12 +853,12 @@ export default class Weight extends React.Component { top: labelTop + "px", // zIndex: -1, lineHeight: 0.5, - backgroundColor: labelBackgroundColor, + backgroundColor: this.labelBackgroundColor, }} > {force.description &&

{force.description}

} {!force.description &&

Force

} - {showForceMagnitudes && ( + {this.props.showForceMagnitudes && (

{Math.round(100 * force.magnitude) / 100} N

)}
-- cgit v1.2.3-70-g09d2 From e73ee7676183bb91687130ba9147e74a5f55420c Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Fri, 3 Feb 2023 00:09:08 -0500 Subject: convert to class --- src/client/views/nodes/PhysicsSimulationApp.tsx | 99 +++--- src/client/views/nodes/PhysicsSimulationWall.tsx | 4 +- src/client/views/nodes/PhysicsSimulationWeight.tsx | 346 ++++++++++----------- 3 files changed, 222 insertions(+), 227 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx index bd218f63b..0536d0679 100644 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ b/src/client/views/nodes/PhysicsSimulationApp.tsx @@ -1,7 +1,7 @@ import React = require('react'); import "./PhysicsSimulationBox.scss"; import Weight, { IForce } from "./PhysicsSimulationWeight"; -import Wall from "./PhysicsSimulationWall" +import Wall, { IWallProps } from "./PhysicsSimulationWall" import Wedge from "./PhysicsSimulationWedge" import { props, any } from 'bluebird'; import { render } from 'react-dom'; @@ -153,7 +153,7 @@ export default class App extends React.Component<{}, IState> { let angle = 50; let x = length * Math.cos(((90 - angle) * Math.PI) / 180); let y = length * Math.sin(((90 - angle) * Math.PI) / 180); - let xPos = xMax / 2 - x - 50; + let xPos = this.xMax / 2 - x - 50; let yPos = y - 50 - 5; this.addPendulum(); this.setState({startPosX: xPos}) @@ -461,52 +461,50 @@ export default class App extends React.Component<{}, IState> {
); })} */} - {/* {weight && ( + {/* {this.state.weight && ( {this.setState({sketching: val})}} + setDisplayXAcceleration={(val: number) => {this.setState({accelerationXDisplay: val})}} + setDisplayXPosition={(val: number) => {this.setState({positionXDisplay: val})}} + setDisplayXVelocity={(val: number) => {this.setState({velocityXDisplay: val})}} + setDisplayYAcceleration={(val: number) => {this.setState({accelerationYDisplay: val})}} + setDisplayYPosition={(val: number) => {this.setState({positionYDisplay: val})}} + setDisplayYVelocity={(val: number) => {this.setState({velocityYDisplay: val})}} + setPaused={(val: boolean) => {this.setState({simulationPaused: val})}} + setPendulumAngle={(val: number) => {this.setState({pendulumAngle: val})}} + setPendulumLength={(val: number) => {this.setState({pendulumLength: val})}} + setStartPendulumAngle={(val: number) => {this.setState({startPendulumAngle: val})}} + setUpdatedForces={(val: IForce[]) => {this.setState({updatedForces: val})}} + showAcceleration={this.state.showAcceleration} + showForces={this.state.showForces} + showVelocity={this.state.showVelocity} + startForces={this.state.startForces} + startPosX={this.state.startPosX} + startPosY={this.state.startPosY} timestepSize={0.002} - updateDisplay={displayChange} - updatedForces={updatedForces} - walls={wallPositions} - wedge={wedge} - wedgeHeight={wedgeHeight} - wedgeWidth={wedgeWidth} - coefficientOfKineticFriction={Number( - coefficientOfKineticFriction - )} + updateDisplay={this.state.displayChange} + updatedForces={this.state.updatedForces} + walls={this.state.wallPositions} + wedge={this.state.wedge} + wedgeHeight={this.state.wedgeHeight} + wedgeWidth={this.state.wedgeWidth} + coefficientOfKineticFriction={this.state.coefficientOfKineticFriction} /> )} */} {this.state.wedge && ( @@ -520,13 +518,14 @@ export default class App extends React.Component<{}, IState> {
{this.state.wallPositions.map((element, index) => { return ( - +
+ +
); })}
diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx index a31704d2f..2608e4772 100644 --- a/src/client/views/nodes/PhysicsSimulationWall.tsx +++ b/src/client/views/nodes/PhysicsSimulationWall.tsx @@ -12,10 +12,10 @@ export interface IWallProps { angleInDegrees: number; } -export default class App extends React.Component { +export default class App extends React.Component { constructor(props: any) { - super(props) + super(props) } wallStyle = { diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index fb040c850..669aab67a 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -197,6 +197,77 @@ export default class Weight extends React.Component { this.setState({yVelocity: this.props.startVelY ?? 0}) this.setDisplayValues(); } + if (this.props.adjustPendulumAngle != prevProps.adjustPendulumAngle) { + // Change pendulum angle based on input field + let length = this.props.adjustPendulumAngle.length; + const x = + length * Math.cos(((90 - this.props.adjustPendulumAngle.angle) * Math.PI) / 180); + const y = + length * Math.sin(((90 - this.props.adjustPendulumAngle.angle) * Math.PI) / 180); + const xPos = this.xMax / 2 - x - this.props.radius; + const yPos = y - this.props.radius - 5; + this.setState({xPosition: xPos}) + this.setState({yPosition: yPos}) + this.setState({updatedStartPosX: xPos}) + this.setState({updatedStartPosY: yPos}) + this.props.setPendulumAngle(this.props.adjustPendulumAngle.angle); + this.props.setPendulumLength(this.props.adjustPendulumAngle.length); + } + // Update x start position + if (this.props.startPosX != prevProps.startPosX) { + this.setState({updatedStartPosX: this.props.startPosX}) + this.setState({xPosition: this.props.startPosX}) + this.setXPosDisplay(this.props.startPosX); + } + // Update y start position + if (this.props.startPosY != prevProps.startPosY) { + this.setState({updatedStartPosY: this.props.startPosY}) + this.setState({yPosition: this.props.startPosY}) + this.setYPosDisplay(this.props.startPosY); + } + if (this.state.xVelocity != prevState.xVelocity) { + if (this.props.wedge && this.state.xVelocity != 0 && !this.state.kineticFriction) { + this.setState({kineticFriction: true}); + //switch from static to kinetic friction + const normalForce: IForce = { + description: "Normal Force", + magnitude: + this.forceOfGravity.magnitude * + Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), + directionInDegrees: + 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI, + }; + let frictionForce: IForce = { + description: "Kinetic Friction Force", + magnitude: + this.props.coefficientOfKineticFriction * + this.forceOfGravity.magnitude * + Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), + directionInDegrees: + 180 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI, + }; + // reduce magnitude of friction force if necessary such that block cannot slide up plane + let yForce = -this.forceOfGravity.magnitude; + yForce += + normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180); + yForce += + frictionForce.magnitude * + Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + if (yForce > 0) { + frictionForce.magnitude = + (-normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + + this.forceOfGravity.magnitude) / + Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + } + if (this.props.coefficientOfKineticFriction != 0) { + this.props.setUpdatedForces([this.forceOfGravity, normalForce, frictionForce]); + } else { + this.props.setUpdatedForces([this.forceOfGravity, normalForce]); + } + } + } } resetEverything = () => { @@ -209,23 +280,6 @@ export default class Weight extends React.Component { this.setDisplayValues(); }; - // // Change pendulum angle based on input field - // useEffect(() => { - // let length = adjustPendulumAngle.length; - // const x = - // length * Math.cos(((90 - adjustPendulumAngle.angle) * Math.PI) / 180); - // const y = - // length * Math.sin(((90 - adjustPendulumAngle.angle) * Math.PI) / 180); - // const xPos = xMax / 2 - x - radius; - // const yPos = y - radius - 5; - // setXPosition(xPos); - // setYPosition(yPos); - // setUpdatedStartPosX(xPos); - // setUpdatedStartPosY(yPos); - // setPendulumAngle(adjustPendulumAngle.angle); - // setPendulumLength(adjustPendulumAngle.length); - // }, [adjustPendulumAngle]); - getNewAccelerationX = (forceList: IForce[]) => { let newXAcc = 0; forceList.forEach((force) => { @@ -294,41 +348,41 @@ export default class Weight extends React.Component { return vel + acc * this.props.timestepSize; }; - // const checkForCollisionsWithWall = () => { - // let collision = false; - // const minX = this.state.xPosition; - // const maxX = this.state.xPosition + 2 * this.props.radius; - // const containerWidth = window.innerWidth; - // if (this.state.xVelocity != 0) { - // this.props.walls.forEach((wall) => { - // if (wall.angleInDegrees == 90) { - // const wallX = (wall.xPos / 100) * window.innerWidth; - // if (wall.xPos < 0.35) { - // if (minX <= wallX) { - // if (elasticCollisions) { - // setXVelocity(-xVelocity); - // } else { - // setXVelocity(0); - // setXPosition(wallX + 5); - // } - // collision = true; - // } - // } else { - // if (maxX >= wallX) { - // if (elasticCollisions) { - // setXVelocity(-xVelocity); - // } else { - // setXVelocity(0); - // setXPosition(wallX - 2 * radius + 5); - // } - // collision = true; - // } - // } - // } - // }); - // } - // return collision; - // }; + checkForCollisionsWithWall = () => { + let collision = false; + const minX = this.state.xPosition; + const maxX = this.state.xPosition + 2 * this.props.radius; + const containerWidth = window.innerWidth; + if (this.state.xVelocity != 0) { + this.props.walls.forEach((wall) => { + if (wall.angleInDegrees == 90) { + const wallX = (wall.xPos / 100) * window.innerWidth; + if (wall.xPos < 0.35) { + if (minX <= wallX) { + if (this.props.elasticCollisions) { + this.setState({xVelocity: -this.state.xVelocity}); + } else { + this.setState({xVelocity: 0}); + this.setState({xPosition: wallX+5}); + } + collision = true; + } + } else { + if (maxX >= wallX) { + if (this.props.elasticCollisions) { + this.setState({xVelocity: -this.state.xVelocity}); + } else { + this.setState({xVelocity: 0}); + this.setState({xPosition: wallX - 2 * this.props.radius + 5}); + } + collision = true; + } + } + } + }); + } + return collision; + }; checkForCollisionsWithGround = () => { let collision = false; @@ -363,115 +417,71 @@ export default class Weight extends React.Component { return collision; }; - // useEffect(() => { - // if (wedge && xVelocity != 0 && mode != "Review" && !kineticFriction) { - // setKineticFriction(true); - // //switch from static to kinetic friction - // const normalForce: IForce = { - // description: "Normal Force", - // magnitude: - // forceOfGravity.magnitude * - // Math.cos(Math.atan(wedgeHeight / wedgeWidth)), - // directionInDegrees: - // 180 - 90 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI, - // }; - // let frictionForce: IForce = { - // description: "Kinetic Friction Force", - // magnitude: - // coefficientOfKineticFriction * - // forceOfGravity.magnitude * - // Math.cos(Math.atan(wedgeHeight / wedgeWidth)), - // directionInDegrees: - // 180 - (Math.atan(wedgeHeight / wedgeWidth) * 180) / Math.PI, - // }; - // // reduce magnitude of friction force if necessary such that block cannot slide up plane - // let yForce = -forceOfGravity.magnitude; - // yForce += - // normalForce.magnitude * - // Math.sin((normalForce.directionInDegrees * Math.PI) / 180); - // yForce += - // frictionForce.magnitude * - // Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - // if (yForce > 0) { - // frictionForce.magnitude = - // (-normalForce.magnitude * - // Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + - // forceOfGravity.magnitude) / - // Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - // } - // if (coefficientOfKineticFriction != 0) { - // this.props.setUpdatedForces([forceOfGravity, normalForce, frictionForce]); - // } else { - // this.props.setUpdatedForces([forceOfGravity, normalForce]); - // } - // } - // }, [xVelocity]); - - // const update = () => { - // // RK4 update - // let xPos = xPosition; - // let yPos = yPosition; - // let xVel = xVelocity; - // let yVel = yVelocity; - // for (let i = 0; i < 60; i++) { - // let forces1 = this.getNewForces(xPos, yPos, xVel, yVel); - // const xAcc1 = this.getNewAccelerationX(forces1); - // const yAcc1 = this.getNewAccelerationY(forces1); - // const xVel1 = this.getNewVelocity(xVel, xAcc1); - // const yVel1 = this.getNewVelocity(yVel, yAcc1); - - // let xVel2 = getNewVelocity(xVel, xAcc1 / 2); - // let yVel2 = getNewVelocity(yVel, yAcc1 / 2); - // let xPos2 = getNewPosition(xPos, xVel1 / 2); - // let yPos2 = getNewPosition(yPos, yVel1 / 2); - // const forces2 = this.getNewForces(xPos2, yPos2, xVel2, yVel2); - // const xAcc2 = this.getNewAccelerationX(forces2); - // const yAcc2 = this.getNewAccelerationY(forces2); - // xVel2 = this.getNewVelocity(xVel2, xAcc2); - // yVel2 = this.getNewVelocity(yVel2, yAcc2); - // xPos2 = this.getNewPosition(xPos2, xVel2); - // yPos2 = this.getNewPosition(yPos2, yVel2); - - // let xVel3 = this.getNewVelocity(xVel, xAcc2 / 2); - // let yVel3 = this.getNewVelocity(yVel, yAcc2 / 2); - // let xPos3 = this.getNewPosition(xPos, xVel2 / 2); - // let yPos3 = this.getNewPosition(yPos, yVel2 / 2); - // const forces3 = this.getNewForces(xPos3, yPos3, xVel3, yVel3); - // const xAcc3 = this.getNewAccelerationX(forces3); - // const yAcc3 = this.getNewAccelerationY(forces3); - // xVel3 = this.getNewVelocity(xVel3, xAcc3); - // yVel3 = this.getNewVelocity(yVel3, yAcc3); - // xPos3 = this.getNewPosition(xPos3, xVel3); - // yPos3 = this.getNewPosition(yPos3, yVel3); - - // let xVel4 = this.getNewVelocity(xVel, xAcc3); - // let yVel4 = this.getNewVelocity(yVel, yAcc3); - // let xPos4 = this.getNewPosition(xPos, xVel3); - // let yPos4 = this.getNewPosition(yPos, yVel3); - // const forces4 = this.getNewForces(xPos4, yPos4, xVel4, yVel4); - // const xAcc4 = this.getNewAccelerationX(forces4); - // const yAcc4 = this.getNewAccelerationY(forces4); - // xVel4 = this.getNewVelocity(xVel4, xAcc4); - // yVel4 = this.getNewVelocity(yVel4, yAcc4); - // xPos4 = this.getNewPosition(xPos4, xVel4); - // yPos4 = this.getNewPosition(yPos4, yVel4); - - // xVel += - // timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0); - // yVel += - // timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0); - // xPos += - // timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0); - // yPos += - // timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0); - // } - - // setXVelocity(xVel); - // setYVelocity(yVel); - // setXPosition(xPos); - // setYPosition(yPos); - // this.props.setUpdatedForces(getNewForces(xPos, yPos, xVel, yVel)); - // }; + update = () => { + // RK4 update + let xPos = this.state.xPosition; + let yPos = this.state.yPosition; + let xVel = this.state.xVelocity; + let yVel = this.state.yVelocity; + for (let i = 0; i < 60; i++) { + let forces1 = this.getNewForces(xPos, yPos, xVel, yVel); + const xAcc1 = this.getNewAccelerationX(forces1); + const yAcc1 = this.getNewAccelerationY(forces1); + const xVel1 = this.getNewVelocity(xVel, xAcc1); + const yVel1 = this.getNewVelocity(yVel, yAcc1); + + let xVel2 = this.getNewVelocity(xVel, xAcc1 / 2); + let yVel2 = this.getNewVelocity(yVel, yAcc1 / 2); + let xPos2 = this.getNewPosition(xPos, xVel1 / 2); + let yPos2 = this.getNewPosition(yPos, yVel1 / 2); + const forces2 = this.getNewForces(xPos2, yPos2, xVel2, yVel2); + const xAcc2 = this.getNewAccelerationX(forces2); + const yAcc2 = this.getNewAccelerationY(forces2); + xVel2 = this.getNewVelocity(xVel2, xAcc2); + yVel2 = this.getNewVelocity(yVel2, yAcc2); + xPos2 = this.getNewPosition(xPos2, xVel2); + yPos2 = this.getNewPosition(yPos2, yVel2); + + let xVel3 = this.getNewVelocity(xVel, xAcc2 / 2); + let yVel3 = this.getNewVelocity(yVel, yAcc2 / 2); + let xPos3 = this.getNewPosition(xPos, xVel2 / 2); + let yPos3 = this.getNewPosition(yPos, yVel2 / 2); + const forces3 = this.getNewForces(xPos3, yPos3, xVel3, yVel3); + const xAcc3 = this.getNewAccelerationX(forces3); + const yAcc3 = this.getNewAccelerationY(forces3); + xVel3 = this.getNewVelocity(xVel3, xAcc3); + yVel3 = this.getNewVelocity(yVel3, yAcc3); + xPos3 = this.getNewPosition(xPos3, xVel3); + yPos3 = this.getNewPosition(yPos3, yVel3); + + let xVel4 = this.getNewVelocity(xVel, xAcc3); + let yVel4 = this.getNewVelocity(yVel, yAcc3); + let xPos4 = this.getNewPosition(xPos, xVel3); + let yPos4 = this.getNewPosition(yPos, yVel3); + const forces4 = this.getNewForces(xPos4, yPos4, xVel4, yVel4); + const xAcc4 = this.getNewAccelerationX(forces4); + const yAcc4 = this.getNewAccelerationY(forces4); + xVel4 = this.getNewVelocity(xVel4, xAcc4); + yVel4 = this.getNewVelocity(yVel4, yAcc4); + xPos4 = this.getNewPosition(xPos4, xVel4); + yPos4 = this.getNewPosition(yPos4, yVel4); + + xVel += + this.props.timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0); + yVel += + this.props.timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0); + xPos += + this.props.timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0); + yPos += + this.props.timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0); + } + + this.setState({xVelocity: xVel}); + this.setState({yVelocity: yVel}); + this.setState({xPosition: xPos}); + this.setState({yPosition: yPos}); + this.props.setUpdatedForces(this.getNewForces(xPos, yPos, xVel, yVel)); + }; weightStyle = { backgroundColor: this.props.color, @@ -491,20 +501,6 @@ export default class Weight extends React.Component { labelBackgroundColor = `rgba(255,255,255,0.5)`; - // // Update x start position - // useEffect(() => { - // setUpdatedStartPosX(startPosX); - // setXPosition(startPosX); - // setXPosDisplay(startPosX); - // }, [startPosX]); - - // // Update y start position - // useEffect(() => { - // setUpdatedStartPosY(startPosY); - // setYPosition(startPosY); - // setYPosDisplay(startPosY); - // }, [startPosY]); - render () { return (
-- cgit v1.2.3-70-g09d2 From 728db020856e3ff5c11e7eabbb4fe48f10a9a490 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Mon, 6 Feb 2023 19:41:25 -0500 Subject: code compiles and runs --- src/client/views/nodes/PhysicsSimulationApp.tsx | 10 ++++------ src/client/views/nodes/PhysicsSimulationWall.tsx | 3 +-- src/client/views/nodes/PhysicsSimulationWedge.tsx | 15 +++++++-------- src/client/views/nodes/PhysicsSimulationWeight.tsx | 22 ++++++++++------------ 4 files changed, 22 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx index 0536d0679..1dfa04a31 100644 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ b/src/client/views/nodes/PhysicsSimulationApp.tsx @@ -3,8 +3,6 @@ import "./PhysicsSimulationBox.scss"; import Weight, { IForce } from "./PhysicsSimulationWeight"; import Wall, { IWallProps } from "./PhysicsSimulationWall" import Wedge from "./PhysicsSimulationWedge" -import { props, any } from 'bluebird'; -import { render } from 'react-dom'; interface PhysicsVectorTemplate { top: number; @@ -70,8 +68,8 @@ export default class App extends React.Component<{}, IState> { }; xMin = 0; yMin = 0; - xMax = window.innerWidth * 0.7; - yMax = window.innerHeight * 0.8; + xMax = 300; + yMax = 300; color = `rgba(0,0,0,0.5)`; radius = 50 @@ -461,7 +459,7 @@ export default class App extends React.Component<{}, IState> {
); })} */} - {/* {this.state.weight && ( + {this.state.weight && ( { wedgeWidth={this.state.wedgeWidth} coefficientOfKineticFriction={this.state.coefficientOfKineticFriction} /> - )} */} + )} {this.state.wedge && ( { updateCoordinates() { const coordinatePair1 = - Math.round(this.state.left) + "," + Math.round(window.innerHeight * 0.8) + " "; + Math.round(this.state.left) + "," + Math.round(300 * 0.8) + " "; const coordinatePair2 = Math.round(this.state.left + this.props.startWidth) + "," + - Math.round(window.innerHeight * 0.8) + + Math.round(300 * 0.8) + " "; const coordinatePair3 = Math.round(this.state.left) + "," + - Math.round(window.innerHeight * 0.8 - this.props.startHeight); + Math.round(300 * 0.8 - this.props.startHeight); const coord = coordinatePair1 + coordinatePair2 + coordinatePair3; this.setState({coordinates: coord}); } @@ -59,8 +58,8 @@ export default class Wedge extends React.Component {
@@ -71,7 +70,7 @@ export default class Wedge extends React.Component { position: "absolute", zIndex: 500, left: Math.round(this.state.left + this.props.startWidth - 80) + "px", - top: Math.round(window.innerHeight * 0.8 - 40) + "px", + top: Math.round(300 * 0.8 - 40) + "px", }} > {Math.round(((this.state.angleInRadians * 180) / Math.PI) * 100) / 100}° diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index 669aab67a..9ce740ae9 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -1,6 +1,4 @@ -import React from "react"; -import { useEffect, useState } from "react"; -import { render } from "react-dom"; +import React = require('react'); import { IWallProps } from "./PhysicsSimulationWall"; import Wedge from "./PhysicsSimulationWedge"; @@ -94,9 +92,9 @@ export default class Weight extends React.Component { magnitude: this.props.mass * 9.81, directionInDegrees: 270, }; - xMax = window.innerWidth * 0.7; + xMax = 300; xMin = 0; - yMax = window.innerHeight * 0.8; + yMax = 300; yMin = 0; // Helper function to go between display and real values @@ -352,11 +350,11 @@ export default class Weight extends React.Component { let collision = false; const minX = this.state.xPosition; const maxX = this.state.xPosition + 2 * this.props.radius; - const containerWidth = window.innerWidth; + const containerWidth = 300; if (this.state.xVelocity != 0) { this.props.walls.forEach((wall) => { if (wall.angleInDegrees == 90) { - const wallX = (wall.xPos / 100) * window.innerWidth; + const wallX = (wall.xPos / 100) * 300; if (wall.xPos < 0.35) { if (minX <= wallX) { if (this.props.elasticCollisions) { @@ -390,7 +388,7 @@ export default class Weight extends React.Component { if (this.state.yVelocity > 0) { this.props.walls.forEach((wall) => { if (wall.angleInDegrees == 0) { - const groundY = (wall.yPos / 100) * window.innerHeight; + const groundY = (wall.yPos / 100) * 300; if (maxY >= groundY) { if (this.props.elasticCollisions) { this.setState({yVelocity: -this.state.yVelocity}) @@ -602,7 +600,7 @@ export default class Weight extends React.Component { zIndex: -2, }} > - + { top: 0, }} > - + { top: 0, }} > - + { > Date: Mon, 6 Feb 2023 20:11:42 -0500 Subject: debugging and UI --- src/client/views/nodes/PhysicsSimulationApp.tsx | 5 ++- src/client/views/nodes/PhysicsSimulationBox.scss | 35 +++------------ src/client/views/nodes/PhysicsSimulationWall.tsx | 4 +- src/client/views/nodes/PhysicsSimulationWeight.tsx | 51 ++++++++++++++-------- 4 files changed, 45 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx index 1dfa04a31..608a38f1a 100644 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ b/src/client/views/nodes/PhysicsSimulationApp.tsx @@ -96,7 +96,7 @@ export default class App extends React.Component<{}, IState> { showForceMagnitudes: false, showForces: false, showVelocity: false, - simulationPaused: false, + simulationPaused: true, simulationReset: false, simulationType: "Inclined Plane", sketching: false, @@ -307,6 +307,9 @@ export default class App extends React.Component<{}, IState> { componentDidMount() { + // Add weight + this.addWeight() + // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click document.addEventListener("keydown", (e) => { if (e.shiftKey) { diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss index 1db758540..cfe2ee6ca 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.scss +++ b/src/client/views/nodes/PhysicsSimulationBox.scss @@ -4,33 +4,20 @@ } .mechanicsSimulationContainer { - height: 100vh; - width: 100vw; + background-color: white; + height: 100%; + width: 100%; display: flex; - .mechanicsSimulationContentContainer { - width: 70%; - - .mechanicsSimulationButtons { - display: flex; - justify-content: space-between; - } - } - .mechanicsSimulationEquationContainer { - width: 30%; + position: fixed; + left: 70%; padding: 1em; - display: flex; - flex-direction: column; .mechanicsSimulationControls { display: flex; justify-content: space-between; } - - .slider { - margin-top: 0.5em; - } } } @@ -56,18 +43,6 @@ button { z-index: 5000; } -.wordProblemBox { - border-style: solid; - border-color: black; - border-width: 1px; - margin-top: 10px; - padding: 10px; -} - -.answer-inactive { - pointer-events: none; -} - .angleLabel { font-weight: bold; font-size: 20px; diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx index e1f753179..d502c066a 100644 --- a/src/client/views/nodes/PhysicsSimulationWall.tsx +++ b/src/client/views/nodes/PhysicsSimulationWall.tsx @@ -18,8 +18,8 @@ export default class App extends React.Component { } wallStyle = { - width: this.props.angleInDegrees == 0 ? this.props.length + "%" : 0.5 + "vw", - height: this.props.angleInDegrees == 0 ? 0.5 + "vw" : this.props.length + "%", + width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "5px", + height: this.props.angleInDegrees == 0 ? "5px" : this.props.length + "%", position: "absolute" as "absolute", left: this.props.xPos + "%", top: this.props.yPos + "%", diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index 9ce740ae9..07ab84bd8 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -97,6 +97,23 @@ export default class Weight extends React.Component { yMax = 300; yMin = 0; + // Var + weightStyle = { + backgroundColor: this.props.color, + borderStyle: "solid", + borderColor: "black", + position: "absolute" as "absolute", + left: this.props.startPosX + "px", + top: this.props.startPosY + "px", + width: 2 * this.props.radius + "px", + height: 2 * this.props.radius + "px", + borderRadius: 50 + "%", + display: "flex", + justifyContent: "center", + alignItems: "center", + touchAction: "none", + }; + // Helper function to go between display and real values getDisplayYPos = (yPos: number) => { return this.yMax - yPos - 2 * this.props.radius + 5; @@ -138,8 +155,8 @@ export default class Weight extends React.Component { ); }; - // When display values updated by user, update real values componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { + // When display values updated by user, update real values if (this.props.updateDisplay != prevProps.updateDisplay) { if (this.props.updateDisplay.xDisplay != this.state.xPosition) { let x = this.props.updateDisplay.xDisplay; @@ -187,6 +204,22 @@ export default class Weight extends React.Component { this.setDisplayValues(); } } + this.weightStyle = { + backgroundColor: this.props.color, + borderStyle: "solid", + borderColor: this.state.dragging ? "lightblue" : "black", + position: "absolute" as "absolute", + left: this.state.xPosition + "px", + top: this.state.yPosition + "px", + width: 2 * this.props.radius + "px", + height: 2 * this.props.radius + "px", + borderRadius: 50 + "%", + display: "flex", + justifyContent: "center", + alignItems: "center", + touchAction: "none", + }; + if (this.props.reset != prevProps.reset) { this.resetEverything(); } @@ -481,22 +514,6 @@ export default class Weight extends React.Component { this.props.setUpdatedForces(this.getNewForces(xPos, yPos, xVel, yVel)); }; - weightStyle = { - backgroundColor: this.props.color, - borderStyle: "solid", - borderColor: this.state.dragging ? "lightblue" : "black", - position: "absolute" as "absolute", - left: this.state.xPosition + "px", - top: this.state.yPosition + "px", - width: 2 * this.props.radius + "px", - height: 2 * this.props.radius + "px", - borderRadius: 50 + "%", - display: "flex", - justifyContent: "center", - alignItems: "center", - touchAction: "none", - }; - labelBackgroundColor = `rgba(255,255,255,0.5)`; render () { -- cgit v1.2.3-70-g09d2 From 983ffa5e10abd89448e8b3f9be65894c7b775d84 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Tue, 7 Feb 2023 12:21:00 -0500 Subject: wall show --- src/client/views/nodes/PhysicsSimulationApp.tsx | 6 +++--- src/client/views/nodes/PhysicsSimulationWall.tsx | 5 ++--- src/client/views/nodes/PhysicsSimulationWeight.tsx | 7 +++++-- 3 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx index 608a38f1a..a2490cce8 100644 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ b/src/client/views/nodes/PhysicsSimulationApp.tsx @@ -298,9 +298,9 @@ export default class App extends React.Component<{}, IState> { addWalls = () => { if (this.state.wallPositions.length == 0) { let walls = []; - walls.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 }); - walls.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 }); - walls.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 }); + walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 }); + walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 }); + walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 }); this.setState({wallPositions: walls}) } }; diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx index d502c066a..f6396d6a7 100644 --- a/src/client/views/nodes/PhysicsSimulationWall.tsx +++ b/src/client/views/nodes/PhysicsSimulationWall.tsx @@ -18,13 +18,12 @@ export default class App extends React.Component { } wallStyle = { - width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "5px", - height: this.props.angleInDegrees == 0 ? "5px" : this.props.length + "%", + width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "3%", + height: this.props.angleInDegrees == 0 ? "3%" : this.props.length + "%", position: "absolute" as "absolute", left: this.props.xPos + "%", top: this.props.yPos + "%", backgroundColor: "#6c7b8b", - zIndex: -1000, margin: 0, padding: 0, }; diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index 07ab84bd8..92d65cf3d 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -93,8 +93,8 @@ export default class Weight extends React.Component { directionInDegrees: 270, }; xMax = 300; - xMin = 0; yMax = 300; + xMin = 0; yMin = 0; // Var @@ -397,6 +397,7 @@ export default class Weight extends React.Component { this.setState({xPosition: wallX+5}); } collision = true; + console.log('collision with wall') } } else { if (maxX >= wallX) { @@ -407,6 +408,7 @@ export default class Weight extends React.Component { this.setState({xPosition: wallX - 2 * this.props.radius + 5}); } collision = true; + console.log('collision with wall') } } } @@ -421,8 +423,9 @@ export default class Weight extends React.Component { if (this.state.yVelocity > 0) { this.props.walls.forEach((wall) => { if (wall.angleInDegrees == 0) { - const groundY = (wall.yPos / 100) * 300; + const groundY = (wall.yPos / 100) * this.yMax; if (maxY >= groundY) { + console.log('collision with ground ', wall, maxY) if (this.props.elasticCollisions) { this.setState({yVelocity: -this.state.yVelocity}) } else { -- cgit v1.2.3-70-g09d2 From 2387225f18bd63f70569df7039af445064738836 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Tue, 7 Feb 2023 12:58:32 -0500 Subject: free weight and wedge work --- src/client/views/nodes/PhysicsSimulationApp.tsx | 55 +++++++----------- src/client/views/nodes/PhysicsSimulationWall.tsx | 2 +- src/client/views/nodes/PhysicsSimulationWedge.tsx | 21 ++++--- src/client/views/nodes/PhysicsSimulationWeight.tsx | 66 +++++++++++----------- 4 files changed, 68 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx index a2490cce8..f31d92db2 100644 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ b/src/client/views/nodes/PhysicsSimulationApp.tsx @@ -71,8 +71,7 @@ export default class App extends React.Component<{}, IState> { xMax = 300; yMax = 300; color = `rgba(0,0,0,0.5)`; - radius = 50 - + radius = 0.1*this.yMax constructor(props: any) { super(props) @@ -112,8 +111,8 @@ export default class App extends React.Component<{}, IState> { wallPositions: [], wedge: false, wedgeAngle: 26, - wedgeHeight: Math.tan((26 * Math.PI) / 180) * 400, - wedgeWidth: 400, + wedgeHeight: Math.tan((26 * Math.PI) / 180) * this.xMax*0.6, + wedgeWidth: this.xMax*0.6, weight: false, } } @@ -219,45 +218,27 @@ export default class App extends React.Component<{}, IState> { let width = 0; let height = 0; if (angle < 50) { - width = 400; - height = Math.tan((angle * Math.PI) / 180) * 400; + width = this.xMax*0.6; + height = Math.tan((angle * Math.PI) / 180) * width; this.setState({wedgeWidth: width}) this.setState({wedgeHeight: height}) } else if (angle < 70) { - width = 200; - height = Math.tan((angle * Math.PI) / 180) * 200; + width = this.xMax*0.3; + height = Math.tan((angle * Math.PI) / 180) * width; this.setState({wedgeWidth: width}) this.setState({wedgeHeight: height}) } else { - width = 100; - height = Math.tan((angle * Math.PI) / 180) * 100; + width = this.xMax*0.15; + height = Math.tan((angle * Math.PI) / 180) * width; this.setState({wedgeWidth: width}) this.setState({wedgeHeight: height}) } // update weight position based on updated wedge width/height - let yPos = (width - 50) * Math.tan((angle * Math.PI) / 180); - if (angle < 40) { - yPos += Math.sqrt(angle); - } else if (angle < 58) { - yPos += angle / 2; - } else if (angle < 68) { - yPos += angle; - } else if (angle < 70) { - yPos += angle * 1.3; - } else if (angle < 75) { - yPos += angle * 1.5; - } else if (angle < 78) { - yPos += angle * 2; - } else if (angle < 79) { - yPos += angle * 2.25; - } else if (angle < 80) { - yPos += angle * 2.6; - } else { - yPos += angle * 3; - } + let xPos = (this.xMax * 0.2)-this.radius; + let yPos = width * Math.tan((angle * Math.PI) / 180) - this.radius; - this.setState({startPosX: Math.round((this.xMax * 0.5 - 200) * 10) / 10}); + this.setState({startPosX: xPos}); this.setState({startPosY: this.getDisplayYPos(yPos)}); this.updateForcesWithFriction( Number(this.state.coefficientOfStaticFriction), @@ -308,7 +289,7 @@ export default class App extends React.Component<{}, IState> { componentDidMount() { // Add weight - this.addWeight() + this.addWedge() // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click document.addEventListener("keydown", (e) => { @@ -477,7 +458,7 @@ export default class App extends React.Component<{}, IState> { pendulum={this.state.pendulum} pendulumAngle={this.state.pendulumAngle} pendulumLength={this.state.pendulumLength} - radius={50} + radius={this.radius} reset={this.state.simulationReset} showForceMagnitudes={this.state.showForceMagnitudes} setSketching={(val: boolean) => {this.setState({sketching: val})}} @@ -506,13 +487,19 @@ export default class App extends React.Component<{}, IState> { wedgeHeight={this.state.wedgeHeight} wedgeWidth={this.state.wedgeWidth} coefficientOfKineticFriction={this.state.coefficientOfKineticFriction} + xMax={this.xMax} + yMax={this.yMax} + xMin={this.xMin} + yMin={this.yMin} /> )} {this.state.wedge && ( )}
diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx index f6396d6a7..9283e8d46 100644 --- a/src/client/views/nodes/PhysicsSimulationWall.tsx +++ b/src/client/views/nodes/PhysicsSimulationWall.tsx @@ -18,7 +18,7 @@ export default class App extends React.Component { } wallStyle = { - width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "3%", + width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "3%", height: this.props.angleInDegrees == 0 ? "3%" : this.props.length + "%", position: "absolute" as "absolute", left: this.props.xPos + "%", diff --git a/src/client/views/nodes/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsSimulationWedge.tsx index b3988221c..43a4d69de 100644 --- a/src/client/views/nodes/PhysicsSimulationWedge.tsx +++ b/src/client/views/nodes/PhysicsSimulationWedge.tsx @@ -5,6 +5,8 @@ export interface IWedgeProps { startHeight: number; startWidth: number; startLeft: number; + xMax: number; + yMax: number; } interface IState { @@ -28,18 +30,19 @@ export default class Wedge extends React.Component { updateCoordinates() { const coordinatePair1 = - Math.round(this.state.left) + "," + Math.round(300 * 0.8) + " "; + Math.round(this.state.left) + "," + Math.round(this.props.yMax) + " "; const coordinatePair2 = Math.round(this.state.left + this.props.startWidth) + "," + - Math.round(300 * 0.8) + + Math.round(this.props.yMax) + " "; const coordinatePair3 = Math.round(this.state.left) + "," + - Math.round(300 * 0.8 - this.props.startHeight); + Math.round(this.props.yMax - this.props.startHeight); const coord = coordinatePair1 + coordinatePair2 + coordinatePair3; this.setState({coordinates: coord}); + console.log("coordinates: ", coord) } componentDidMount() { @@ -47,7 +50,9 @@ export default class Wedge extends React.Component { } componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { - this.updateCoordinates(); + if (prevState.coordinates != this.state.coordinates) { + this.updateCoordinates(); + } if (prevProps.startHeight != this.props.startHeight || prevProps.startWidth != this.props.startWidth) { this.setState({angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth)}); } @@ -56,10 +61,10 @@ export default class Wedge extends React.Component { render() { return (
-
+
@@ -70,7 +75,7 @@ export default class Wedge extends React.Component { position: "absolute", zIndex: 500, left: Math.round(this.state.left + this.props.startWidth - 80) + "px", - top: Math.round(300 * 0.8 - 40) + "px", + top: Math.round(this.props.yMax - 40) + "px", }} > {Math.round(((this.state.angleInRadians * 180) / Math.PI) * 100) / 100}° diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index 92d65cf3d..63f8c965f 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -52,6 +52,10 @@ export interface IWeightProps { coefficientOfKineticFriction: number; wedgeWidth: number; wedgeHeight: number; + xMax: number; + yMax: number; + xMin: number; + yMin: number; } interface IState { @@ -92,10 +96,6 @@ export default class Weight extends React.Component { magnitude: this.props.mass * 9.81, directionInDegrees: 270, }; - xMax = 300; - yMax = 300; - xMin = 0; - yMin = 0; // Var weightStyle = { @@ -116,10 +116,10 @@ export default class Weight extends React.Component { // Helper function to go between display and real values getDisplayYPos = (yPos: number) => { - return this.yMax - yPos - 2 * this.props.radius + 5; + return this.props.yMax - yPos - 2 * this.props.radius + 5; }; getYPosFromDisplay = (yDisplay: number) => { - return this.yMax - yDisplay - 2 * this.props.radius + 5; + return this.props.yMax - yDisplay - 2 * this.props.radius + 5; }; // Set display values based on real values @@ -161,7 +161,7 @@ export default class Weight extends React.Component { if (this.props.updateDisplay.xDisplay != this.state.xPosition) { let x = this.props.updateDisplay.xDisplay; x = Math.max(0, x); - x = Math.min(x, this.xMax - 2 * this.props.radius); + x = Math.min(x, this.props.xMax - 2 * this.props.radius); this.setState({updatedStartPosX: x}) this.setState({xPosition: x}) this.props.setDisplayXPosition(x); @@ -170,7 +170,7 @@ export default class Weight extends React.Component { if (this.props.updateDisplay.yDisplay != this.getDisplayYPos(this.state.yPosition)) { let y = this.props.updateDisplay.yDisplay; y = Math.max(0, y); - y = Math.min(y, this.yMax - 2 * this.props.radius); + y = Math.min(y, this.props.yMax - 2 * this.props.radius); this.props.setDisplayYPosition(y); let coordinatePosition = this.getYPosFromDisplay(y); this.setState({updatedStartPosY: coordinatePosition}) @@ -235,7 +235,7 @@ export default class Weight extends React.Component { length * Math.cos(((90 - this.props.adjustPendulumAngle.angle) * Math.PI) / 180); const y = length * Math.sin(((90 - this.props.adjustPendulumAngle.angle) * Math.PI) / 180); - const xPos = this.xMax / 2 - x - this.props.radius; + const xPos = this.props.xMax / 2 - x - this.props.radius; const yPos = y - this.props.radius - 5; this.setState({xPosition: xPos}) this.setState({yPosition: yPos}) @@ -343,7 +343,7 @@ export default class Weight extends React.Component { if (!this.props.pendulum) { return this.props.updatedForces; } - const x = this.xMax / 2 - xPos - this.props.radius; + const x = this.props.xMax / 2 - xPos - this.props.radius; const y = yPos + this.props.radius + 5; let angle = (Math.atan(y / x) * 180) / Math.PI; if (angle < 0) { @@ -423,7 +423,7 @@ export default class Weight extends React.Component { if (this.state.yVelocity > 0) { this.props.walls.forEach((wall) => { if (wall.angleInDegrees == 0) { - const groundY = (wall.yPos / 100) * this.yMax; + const groundY = (wall.yPos / 100) * this.props.yMax; if (maxY >= groundY) { console.log('collision with ground ', wall, maxY) if (this.props.elasticCollisions) { @@ -537,13 +537,13 @@ export default class Weight extends React.Component { e.preventDefault(); if (this.state.dragging) { let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; - if (newY > this.yMax - 2 * this.props.radius) { - newY = this.yMax - 2 * this.props.radius; + if (newY > this.props.yMax - 2 * this.props.radius) { + newY = this.props.yMax - 2 * this.props.radius; } let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; - if (newX > this.xMax - 2 * this.props.radius) { - newX = this.xMax - 2 * this.props.radius; + if (newX > this.props.xMax - 2 * this.props.radius) { + newX = this.props.xMax - 2 * this.props.radius; } else if (newX < 0) { newX = 0; } @@ -551,7 +551,7 @@ export default class Weight extends React.Component { this.setState({yPosition: newY}) this.setState({updatedStartPosX: newX}) this.setState({updatedStartPosY: newY}) - this.props.setDisplayYPosition(Math.round((this.yMax - 2 * this.props.radius - newY + 5) * 100) / 100) + this.props.setDisplayYPosition(Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100) this.setState({clickPositionX: e.clientX}) this.setState({clickPositionY: e.clientY}) this.setDisplayValues(); @@ -565,18 +565,18 @@ export default class Weight extends React.Component { } this.setState({dragging: false}); let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; - if (newY > this.yMax - 2 * this.props.radius) { - newY = this.yMax - 2 * this.props.radius; + if (newY > this.props.yMax - 2 * this.props.radius) { + newY = this.props.yMax - 2 * this.props.radius; } let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; - if (newX > this.xMax - 2 * this.props.radius) { - newX = this.xMax - 2 * this.props.radius; + if (newX > this.props.xMax - 2 * this.props.radius) { + newX = this.props.xMax - 2 * this.props.radius; } else if (newX < 0) { newX = 0; } if (this.props.pendulum) { - const x = this.xMax / 2 - newX - this.props.radius; + const x = this.props.xMax / 2 - newX - this.props.radius; const y = newY + this.props.radius + 5; let angle = (Math.atan(y / x) * 180) / Math.PI; if (angle < 0) { @@ -620,11 +620,11 @@ export default class Weight extends React.Component { zIndex: -2, }} > - + { style={{ position: "absolute", zIndex: -1, - left: this.xMax / 2 + "px", + left: this.props.xMax / 2 + "px", top: 30 + "px", backgroundColor: this.labelBackgroundColor, }} @@ -669,7 +669,7 @@ export default class Weight extends React.Component { top: 0, }} > - + { top: 0, }} > - + { } else { labelTop -= 40; } - labelTop = Math.min(labelTop, this.yMax + 50); - labelTop = Math.max(labelTop, this.yMin); - labelLeft = Math.min(labelLeft, this.xMax - 60); - labelLeft = Math.max(labelLeft, this.xMin); + labelTop = Math.min(labelTop, this.props.yMax + 50); + labelTop = Math.max(labelTop, this.props.yMin); + labelLeft = Math.min(labelLeft, this.props.xMax - 60); + labelLeft = Math.max(labelLeft, this.props.xMin); return (
@@ -827,12 +827,12 @@ export default class Weight extends React.Component { pointerEvents: "none", position: "absolute", zIndex: -1, - left: this.xMin, - top: this.yMin, + left: this.props.xMin, + top: this.props.yMin, }} > -- cgit v1.2.3-70-g09d2 From d757d90c4c5a5609c3c8bca874414e8a5171556c Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Tue, 7 Feb 2023 17:10:23 -0500 Subject: pendulum works --- src/client/util/CurrentUserUtils.ts | 2 +- src/client/views/nodes/PhysicsSimulationApp.tsx | 19 +++++++++---------- src/client/views/nodes/PhysicsSimulationWedge.tsx | 1 - src/client/views/nodes/PhysicsSimulationWeight.tsx | 19 +++++-------------- 4 files changed, 15 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 23e9a2bea..c8b36ff3a 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -287,7 +287,7 @@ export class CurrentUserUtils { { toolTip: "Tap or drag to create a note board", title: "Notes", icon: "folder", dragFactory: doc.emptyNoteboard as Doc, }, { toolTip: "Tap or drag to create a collection", title: "Col", icon: "folder", dragFactory: doc.emptyCollection as Doc, clickFactory: DocCast(doc.emptyTab), scripts: { onClick: 'openOnRight(copyDragFactory(this.clickFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, { toolTip: "Tap or drag to create an equation", title: "Math", icon: "calculator", dragFactory: doc.emptyEquation as Doc, }, - { toolTip: "Tap or drag to create a physics simulation", title: "Simulation", icon: "calculator", dragFactory: doc.emptySimulation as Doc, }, + { toolTip: "Tap or drag to create a physics simulation", title: "Simulation", icon: "atom", dragFactory: doc.emptySimulation as Doc, }, { toolTip: "Tap or drag to create a webpage", title: "Web", icon: "globe-asia", dragFactory: doc.emptyWebpage as Doc, }, { toolTip: "Tap or drag to create a comparison box", title: "Compare", icon: "columns", dragFactory: doc.emptyComparison as Doc, }, { toolTip: "Tap or drag to create an audio recorder", title: "Audio", icon: "microphone", dragFactory: doc.emptyAudio as Doc, scripts: { onClick: 'openInOverlay(copyDragFactory(this.dragFactory))', onDragStart: '{ return copyDragFactory(this.dragFactory);}'}, }, diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx index f31d92db2..6a3ab28a0 100644 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ b/src/client/views/nodes/PhysicsSimulationApp.tsx @@ -146,16 +146,15 @@ export default class App extends React.Component<{}, IState> { this.setState({weight: true}) this.setState({wedge: false}) this.setState({pendulum: true}) - let length = 300; - let angle = 50; + let length = this.xMax*0.7; + let angle = 40; let x = length * Math.cos(((90 - angle) * Math.PI) / 180); let y = length * Math.sin(((90 - angle) * Math.PI) / 180); - let xPos = this.xMax / 2 - x - 50; - let yPos = y - 50 - 5; - this.addPendulum(); + let xPos = this.xMax / 2 - x - this.radius; + let yPos = y - this.radius; this.setState({startPosX: xPos}) this.setState({startPosY: yPos}) - let mag = 9.81 * Math.cos((50 * Math.PI) / 180); + let mag = 9.81 * Math.cos((angle * Math.PI) / 180); let forceOfTension: IForce = { description: "Tension", magnitude: mag, @@ -163,9 +162,9 @@ export default class App extends React.Component<{}, IState> { }; this.setState({updatedForces: [this.forceOfGravity, forceOfTension]}) this.setState({startForces: [this.forceOfGravity, forceOfTension]}) - this.setState({pendulumAngle: 50}) - this.setState({pendulumLength: 300}) - this.setState({adjustPendulumAngle: {angle: 50, length: 300}}) + this.setState({pendulumAngle: 40}) + this.setState({pendulumLength: 100}) + this.setState({adjustPendulumAngle: {angle: 40, length: 100}}) this.removeWalls(); }; @@ -289,7 +288,7 @@ export default class App extends React.Component<{}, IState> { componentDidMount() { // Add weight - this.addWedge() + this.addPendulum() // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click document.addEventListener("keydown", (e) => { diff --git a/src/client/views/nodes/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsSimulationWedge.tsx index 43a4d69de..c5a186f18 100644 --- a/src/client/views/nodes/PhysicsSimulationWedge.tsx +++ b/src/client/views/nodes/PhysicsSimulationWedge.tsx @@ -42,7 +42,6 @@ export default class Wedge extends React.Component { Math.round(this.props.yMax - this.props.startHeight); const coord = coordinatePair1 + coordinatePair2 + coordinatePair3; this.setState({coordinates: coord}); - console.log("coordinates: ", coord) } componentDidMount() { diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index 63f8c965f..dfd463bbe 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -1,6 +1,5 @@ import React = require('react'); import { IWallProps } from "./PhysicsSimulationWall"; -import Wedge from "./PhysicsSimulationWedge"; export interface IForce { description: string; @@ -107,6 +106,7 @@ export default class Weight extends React.Component { top: this.props.startPosY + "px", width: 2 * this.props.radius + "px", height: 2 * this.props.radius + "px", + zIndex: 5, borderRadius: 50 + "%", display: "flex", justifyContent: "center", @@ -215,6 +215,7 @@ export default class Weight extends React.Component { height: 2 * this.props.radius + "px", borderRadius: 50 + "%", display: "flex", + zIndex: 5, justifyContent: "center", alignItems: "center", touchAction: "none", @@ -397,7 +398,6 @@ export default class Weight extends React.Component { this.setState({xPosition: wallX+5}); } collision = true; - console.log('collision with wall') } } else { if (maxX >= wallX) { @@ -408,7 +408,6 @@ export default class Weight extends React.Component { this.setState({xPosition: wallX - 2 * this.props.radius + 5}); } collision = true; - console.log('collision with wall') } } } @@ -425,7 +424,6 @@ export default class Weight extends React.Component { if (wall.angleInDegrees == 0) { const groundY = (wall.yPos / 100) * this.props.yMax; if (maxY >= groundY) { - console.log('collision with ground ', wall, maxY) if (this.props.elasticCollisions) { this.setState({yVelocity: -this.state.yVelocity}) } else { @@ -521,7 +519,7 @@ export default class Weight extends React.Component { render () { return ( -
+
{ @@ -617,7 +615,6 @@ export default class Weight extends React.Component { position: "absolute", left: 0, top: 0, - zIndex: -2, }} > @@ -632,7 +629,7 @@ export default class Weight extends React.Component { {!this.state.dragging && (
-

{ }} > {Math.round(this.props.pendulumLength)} m -

+

*/}

{ style={{ pointerEvents: "none", position: "absolute", - zIndex: -1, left: 0, top: 0, }} @@ -709,7 +704,6 @@ export default class Weight extends React.Component { this.getNewAccelerationY(this.props.updatedForces) * 5 + 25 + "px", - zIndex: -1, lineHeight: 0.5, }} > @@ -733,7 +727,6 @@ export default class Weight extends React.Component { style={{ pointerEvents: "none", position: "absolute", - zIndex: -1, left: 0, top: 0, }} @@ -768,7 +761,6 @@ export default class Weight extends React.Component { position: "absolute", left: this.state.xPosition + this.props.radius + this.state.xVelocity * 3 + 25 + "px", top: this.state.yPosition + this.props.radius + this.state.yVelocity * 3 + "px", - zIndex: -1, lineHeight: 0.5, }} > @@ -826,7 +818,6 @@ export default class Weight extends React.Component { style={{ pointerEvents: "none", position: "absolute", - zIndex: -1, left: this.props.xMin, top: this.props.yMin, }} -- cgit v1.2.3-70-g09d2 From 456d91f480ed96ac963c9f17164eb23e76fb4320 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Thu, 9 Feb 2023 10:29:04 -0500 Subject: switch between sim types --- src/client/views/nodes/PhysicsSimulationApp.tsx | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx index 6a3ab28a0..acca65b08 100644 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ b/src/client/views/nodes/PhysicsSimulationApp.tsx @@ -147,7 +147,7 @@ export default class App extends React.Component<{}, IState> { this.setState({wedge: false}) this.setState({pendulum: true}) let length = this.xMax*0.7; - let angle = 40; + let angle = 35; let x = length * Math.cos(((90 - angle) * Math.PI) / 180); let y = length * Math.sin(((90 - angle) * Math.PI) / 180); let xPos = this.xMax / 2 - x - this.radius; @@ -162,9 +162,9 @@ export default class App extends React.Component<{}, IState> { }; this.setState({updatedForces: [this.forceOfGravity, forceOfTension]}) this.setState({startForces: [this.forceOfGravity, forceOfTension]}) - this.setState({pendulumAngle: 40}) - this.setState({pendulumLength: 100}) - this.setState({adjustPendulumAngle: {angle: 40, length: 100}}) + this.setState({pendulumAngle: angle}) + this.setState({pendulumLength: length}) + this.setState({adjustPendulumAngle: {angle: angle, length: length}}) this.removeWalls(); }; @@ -536,6 +536,17 @@ export default class App extends React.Component<{}, IState> { this.setState({simulationReset: !this.state.simulationReset}); }} >RESET )} +

-- cgit v1.2.3-70-g09d2 From cb19032c67d810d3683e101896e20df7eecec77c Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Sun, 12 Feb 2023 15:34:16 -0500 Subject: start making everything persistent --- src/client/views/nodes/PhysicsSimulationBox.tsx | 573 +++++++++++++++++++++++- 1 file changed, 556 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index 4a68ba5aa..3ea4fba9f 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -3,33 +3,572 @@ import { FieldView, FieldViewProps } from './FieldView'; import React = require('react'); import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { observer } from 'mobx-react'; -import App from './PhysicsSimulationApp'; +import "./PhysicsSimulationBox.scss"; +import Weight from "./PhysicsSimulationWeight"; +import Wall from "./PhysicsSimulationWall" +import Wedge from "./PhysicsSimulationWedge" export interface IForce { - description: string; - magnitude: number; - directionInDegrees: number; + description: string; + magnitude: number; + directionInDegrees: number; } export interface IWallProps { - length: number; - xPos: number; - yPos: number; - angleInDegrees: number; + length: number; + xPos: number; + yPos: number; + angleInDegrees: number; +} + +interface PhysicsVectorTemplate { + top: number; + left: number; + width: number; + height: number; + x1: number; + y1: number; + x2: number; + y2: number; + weightX: number; + weightY: number; +} + +interface IState { + accelerationXDisplay: number, + accelerationYDisplay: number, + adjustPendulumAngle: {angle: number, length: number}, + coefficientOfKineticFriction: number, + coefficientOfStaticFriction: number, + currentForceSketch: PhysicsVectorTemplate | null, + deleteMode: boolean, + displayChange: {xDisplay: number, yDisplay: number}, + elasticCollisions: boolean, + forceSketches: PhysicsVectorTemplate[], + pendulum: boolean, + pendulumAngle: number, + pendulumLength: number, + positionXDisplay: number, + positionYDisplay: number, + showAcceleration: boolean, + showForceMagnitudes: boolean, + showForces: boolean, + showVelocity: boolean, + simulationPaused: boolean, + simulationReset: boolean, + simulationType: "Inclined Plane", + sketching: boolean, + startForces: IForce[], + startPendulumAngle: number, + startPosX: number, + startPosY: number, + stepNumber: number, + timer: number, + updatedForces: IForce[], + velocityXDisplay: number, + velocityYDisplay: number, + wallPositions: IWallProps[], + wedge: boolean, + wedgeAngle: number, + wedgeHeight: number, + wedgeWidth: number, + weight: boolean, } @observer export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() { - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); } + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); } + + // Constants + gravityMagnitude = 9.81; + forceOfGravity: IForce = { + description: "Gravity", + magnitude: this.gravityMagnitude, + directionInDegrees: 270, + }; + xMin = 0; + yMin = 0; + xMax = 300; + yMax = 300; + color = `rgba(0,0,0,0.5)`; + radius = 0.1*this.yMax + + constructor(props: any) { + super(props); + this.dataDoc.accelerationXDisplay = 0; + this.dataDoc.accelerationYDisplay = 0; + this.dataDoc.adjustPendulumAngle = {angle: 0, length: 0}; + this.dataDoc.coefficientOfKineticFriction = 0; + this.dataDoc.coefficientOfStaticFriction = 0; + this.dataDoc.currentForceSketch = []; + this.dataDoc.deleteMode = false; + this.dataDoc.displayChange = {xDisplay: 0, yDisplay: 0}; + this.dataDoc.elasticCollisions = false; + this.dataDoc.forceSketches = []; + this.dataDoc.pendulum = false; + this.dataDoc.pendulumAngle = 0; + this.dataDoc.pendulumLength = 300; + this.dataDoc.positionXDisplay = 0; + this.dataDoc.positionYDisplay = 0; + this.dataDoc.showAcceleration = false; + this.dataDoc.showForceMagnitudes = false; + this.dataDoc.showForces = false; + this.dataDoc.showVelocity = false; + this.dataDoc.simulationPaused = true; + this.dataDoc.simulationReset = false; + this.dataDoc.simulationType = "Inclined Plane"; + this.dataDoc.sketching = false; + this.dataDoc.startForces = [this.forceOfGravity]; + this.dataDoc.startPendulumAngle = 0; + this.dataDoc.startPosX = 0; + this.dataDoc.startPosY = 0; + this.dataDoc.stepNumber = 0; + this.dataDoc.timer = 0; + this.dataDoc.updatedForces = [this.forceOfGravity]; + this.dataDoc.velocityXDisplay = 0; + this.dataDoc.velocityYDisplay = 0; + this.dataDoc.wallPositions = []; + this.dataDoc.wedge = false; + this.dataDoc.wedgeAngle = 26; + this.dataDoc.wedgeHeight = Math.tan((26 * Math.PI) / 180) * this.xMax*0.6; + this.dataDoc.wedgeWidth = this.xMax*0.6; + this.dataDoc.weight = false; + } + + // Add one weight to the simulation + addWeight () { + this.dataDoc.weight = true; + this.dataDoc.wedge = false; + this.dataDoc.pendulum = false; + this.dataDoc.startPosY = this.yMin+this.radius; + this.dataDoc.startPosX = (this.xMax+this.xMin-this.radius)/2; + this.dataDoc.updatedForces = [this.forceOfGravity]; + this.dataDoc.startForces = [this.forceOfGravity]; + this.addWalls(); + this.dataDoc.simulationReset = !this.dataDoc.simulationReset; + }; + + // Add a wedge with a One Weight to the simulation + addWedge () { + this.dataDoc.weight = true; + this.dataDoc.wedge = true; + this.dataDoc.pendulum = false; + this.changeWedgeBasedOnNewAngle(26); + this.addWalls(); + this.dataDoc.startForces = [this.forceOfGravity]; + this.updateForcesWithFriction(this.dataDoc.coefficientOfStaticFriction); + }; + + // Add a simple pendulum to the simulation + addPendulum = () => { + this.dataDoc.weight = true; + this.dataDoc.wedge = false; + this.dataDoc.pendulum = true; + let length = this.xMax*0.7; + let angle = 35; + let x = length * Math.cos(((90 - angle) * Math.PI) / 180); + let y = length * Math.sin(((90 - angle) * Math.PI) / 180); + let xPos = this.xMax / 2 - x - this.radius; + let yPos = y - this.radius; + this.dataDoc.startPosX = xPos; + this.dataDoc.startPosY = yPos; + let mag = 9.81 * Math.cos((angle * Math.PI) / 180); + let forceOfTension: IForce = { + description: "Tension", + magnitude: mag, + directionInDegrees: 90 - angle, + }; + this.dataDoc.updatedForces = [this.forceOfGravity, forceOfTension]; + this.dataDoc.startForces = [this.forceOfGravity, forceOfTension]; + this.dataDoc.pendulumAngle = angle; + this.dataDoc.pendulumLength = length; + this.dataDoc.adjustPendulumAngle = {angle: angle, length: length}; + this.removeWalls(); + }; + + // Update forces when coefficient of static friction changes in freeform mode + updateForcesWithFriction ( + coefficient: number, + width: number = this.dataDoc.wedgeWidth, + height: number = this.dataDoc.wedgeHeight + ) { + let normalForce = { + description: "Normal Force", + magnitude: this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)), + directionInDegrees: + 180 - 90 - (Math.atan(height / width) * 180) / Math.PI, + }; + let frictionForce: IForce = { + description: "Static Friction Force", + magnitude: + coefficient * + this.forceOfGravity.magnitude * + Math.cos(Math.atan(height / width)), + directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI, + }; + // reduce magnitude of friction force if necessary such that block cannot slide up plane + let yForce = -this.forceOfGravity.magnitude; + yForce += + normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180); + yForce += + frictionForce.magnitude * + Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + if (yForce > 0) { + frictionForce.magnitude = + (-normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + + this.forceOfGravity.magnitude) / + Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + } + if (coefficient != 0) { + this.dataDoc.startForces = [this.forceOfGravity, normalForce, frictionForce]; + this.dataDoc.updatedForces = [this.forceOfGravity, normalForce, frictionForce]; + } else { + this.dataDoc.startForces = [this.forceOfGravity, normalForce]; + this.dataDoc.updatedForces = [this.forceOfGravity, normalForce]; + } + }; + + // Change wedge height and width and weight position to match new wedge angle + changeWedgeBasedOnNewAngle = (angle: number) => { + let width = 0; + let height = 0; + if (angle < 50) { + width = this.xMax*0.6; + height = Math.tan((angle * Math.PI) / 180) * width; + this.dataDoc.wedgeWidth = width; + this.dataDoc.wedgeHeight = height; + } else if (angle < 70) { + width = this.xMax*0.3; + height = Math.tan((angle * Math.PI) / 180) * width; + this.dataDoc.wedgeWidth = width; + this.dataDoc.wedgeHeight = height; + } else { + width = this.xMax*0.15; + height = Math.tan((angle * Math.PI) / 180) * width; + this.dataDoc.wedgeWidth = width; + this.dataDoc.wedgeHeight = height; + } + + // update weight position based on updated wedge width/height + let xPos = (this.xMax * 0.2)-this.radius; + let yPos = width * Math.tan((angle * Math.PI) / 180) - this.radius; + + this.dataDoc.startPosX = xPos; + this.dataDoc.startPosY = this.getDisplayYPos(yPos); + this.updateForcesWithFriction( + Number(this.dataDoc.coefficientOfStaticFriction), + width, + height + ); + }; + + // Helper function to go between display and real values + getDisplayYPos = (yPos: number) => { + return this.yMax - yPos - 2 * 50 + 5; + }; + + // In review mode, edit force arrow sketch on mouse movement + editForce = (element: PhysicsVectorTemplate) => { + if (!this.dataDoc.sketching) { + let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element); + this.dataDoc.forceSketches = sketches; + this.dataDoc.currentForceSketch = element; + this.dataDoc.sketching = true; + } + }; + + // In review mode, used to delete force arrow sketch on SHIFT+click + deleteForce = (element: PhysicsVectorTemplate) => { + if (!this.dataDoc.sketching) { + let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element); + this.dataDoc.forceSketches = sketches; + } + }; + + // Remove floor and walls from simulation + removeWalls = () => { + this.dataDoc.wallPositions = [] + }; + + // Add floor and walls to simulation + addWalls = () => { + if (this.dataDoc.wallPositions.length == 0) { + let walls = []; + walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 }); + walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 }); + walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 }); + this.dataDoc.wallPositions = walls + } + }; + + + componentDidMount() { + // Add weight + this.addPendulum() + + // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click + document.addEventListener("keydown", (e) => { + if (e.shiftKey) { + this.dataDoc.deleteMode = true; + } + }); + document.addEventListener("keyup", (e) => { + if (e.shiftKey) { + this.dataDoc.deleteMode = false; + } + }); - constructor(props: any) { - super(props); - } + // Timer for animating the simulation + setInterval(() => { + this.dataDoc.timer = this.dataDoc.timer+1; + }, 60); + } render () { return ( -
- -
- ); - } +
+
+
{ + // if (sketching) { + // x1 = positionXDisplay + 50; + // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50; + // x2 = e.clientX; + // y2 = e.clientY; + // height = Math.abs(y1 - y2) + 120; + // width = Math.abs(x1 - x2) + 120; + // top = Math.min(y1, y2) - 60; + // left = Math.min(x1, x2) - 60; + // x1Updated = x1 - left; + // x2Updated = x2 - left; + // y1Updated = y1 - top; + // y2Updated = y2 - top; + // setCurrentForceSketch({ + // top: top, + // left: left, + // width: width, + // height: height, + // x1: x1Updated, + // y1: y1Updated, + // x2: x2Updated, + // y2: y2Updated, + // weightX: positionXDisplay, + // weightY: positionYDisplay, + // }); + // } + }} + onPointerDown={(e) => { + // if (sketching && currentForceSketch) { + // setSketching(false); + // sketches = forceSketches; + // sketches.push(currentForceSketch); + // setForceSketches(sketches); + // setCurrentForceSketch(null); + // } + }} + > +
+
+ {/* {showForces && currentForceSketch && simulationPaused && ( +
+ + + + + + + + +
+ )} */} + {/* {showForces && + forceSketches.length > 0 && + simulationPaused && + forceSketches.map((element: PhysicsVectorTemplate, index) => { + return ( +
+ + + + + + + { + if (deleteMode) { + deleteForce(element); + } else { + editForce(element); + } + }} + /> + +
+ ); + })} */} + {this.dataDoc.weight && ( + {this.dataDoc.sketching = val}} + setDisplayXAcceleration={(val: number) => {this.dataDoc.accelerationXDisplay = val}} + setDisplayXPosition={(val: number) => {this.dataDoc.positionXDisplay = val}} + setDisplayXVelocity={(val: number) => {this.dataDoc.velocityXDisplay = val}} + setDisplayYAcceleration={(val: number) => {this.dataDoc.accelerationYDisplay = val}} + setDisplayYPosition={(val: number) => {this.dataDoc.positionYDisplay = val}} + setDisplayYVelocity={(val: number) => {this.dataDoc.velocityYDisplay = val}} + setPaused={(val: boolean) => {this.dataDoc.simulationPaused = val}} + setPendulumAngle={(val: number) => {this.dataDoc.pendulumAngle = val}} + setPendulumLength={(val: number) => {this.dataDoc.pendulumLength = val}} + setStartPendulumAngle={(val: number) => {this.dataDoc.startPendulumAngle = val}} + setUpdatedForces={(val: IForce[]) => {this.dataDoc.updatedForces = val}} + showAcceleration={this.dataDoc.showAcceleration} + showForces={this.dataDoc.showForces} + showVelocity={this.dataDoc.showVelocity} + startForces={this.dataDoc.startForces} + startPosX={this.dataDoc.startPosX} + startPosY={this.dataDoc.startPosY} + timestepSize={0.002} + updateDisplay={this.dataDoc.displayChange} + updatedForces={this.dataDoc.updatedForces} + walls={this.dataDoc.wallPositions} + wedge={this.dataDoc.wedge} + wedgeHeight={this.dataDoc.wedgeHeight} + wedgeWidth={this.dataDoc.wedgeWidth} + coefficientOfKineticFriction={this.dataDoc.coefficientOfKineticFriction} + xMax={this.xMax} + yMax={this.yMax} + xMin={this.xMin} + yMin={this.yMin} + /> + )} + {this.dataDoc.wedge && ( + + )} +
+
+ {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { + return ( +
+ +
+ ); + })} +
+
+
+
+
+
+ {this.dataDoc.simulationPaused && ( + + )} + {!this.dataDoc.simulationPaused && ( + + )} + {this.dataDoc.simulationPaused && ( + + )} + +
+
+
+
+
+ ); + } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From ac98c1e9b6a2370569113e64514dd1240a2adf7e Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Mon, 13 Feb 2023 16:55:24 -0500 Subject: keep converting to persistent --- src/client/views/nodes/PhysicsSimulationApp.tsx | 557 --------------------- src/client/views/nodes/PhysicsSimulationBox.tsx | 194 +------ src/client/views/nodes/PhysicsSimulationWeight.tsx | 129 ++--- 3 files changed, 55 insertions(+), 825 deletions(-) delete mode 100644 src/client/views/nodes/PhysicsSimulationApp.tsx (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationApp.tsx b/src/client/views/nodes/PhysicsSimulationApp.tsx deleted file mode 100644 index acca65b08..000000000 --- a/src/client/views/nodes/PhysicsSimulationApp.tsx +++ /dev/null @@ -1,557 +0,0 @@ -import React = require('react'); -import "./PhysicsSimulationBox.scss"; -import Weight, { IForce } from "./PhysicsSimulationWeight"; -import Wall, { IWallProps } from "./PhysicsSimulationWall" -import Wedge from "./PhysicsSimulationWedge" - -interface PhysicsVectorTemplate { - top: number; - left: number; - width: number; - height: number; - x1: number; - y1: number; - x2: number; - y2: number; - weightX: number; - weightY: number; -} - -interface IState { - accelerationXDisplay: number, - accelerationYDisplay: number, - adjustPendulumAngle: {angle: number, length: number}, - coefficientOfKineticFriction: number, - coefficientOfStaticFriction: number, - currentForceSketch: PhysicsVectorTemplate | null, - deleteMode: boolean, - displayChange: {xDisplay: number, yDisplay: number}, - elasticCollisions: boolean, - forceSketches: PhysicsVectorTemplate[], - pendulum: boolean, - pendulumAngle: number, - pendulumLength: number, - positionXDisplay: number, - positionYDisplay: number, - showAcceleration: boolean, - showForceMagnitudes: boolean, - showForces: boolean, - showVelocity: boolean, - simulationPaused: boolean, - simulationReset: boolean, - simulationType: "Inclined Plane", - sketching: boolean, - startForces: IForce[], - startPendulumAngle: number, - startPosX: number, - startPosY: number, - stepNumber: number, - timer: number, - updatedForces: IForce[], - velocityXDisplay: number, - velocityYDisplay: number, - wallPositions: IWallProps[], - wedge: boolean, - wedgeAngle: number, - wedgeHeight: number, - wedgeWidth: number, - weight: boolean, -} -export default class App extends React.Component<{}, IState> { - - // Constants - gravityMagnitude = 9.81; - forceOfGravity: IForce = { - description: "Gravity", - magnitude: this.gravityMagnitude, - directionInDegrees: 270, - }; - xMin = 0; - yMin = 0; - xMax = 300; - yMax = 300; - color = `rgba(0,0,0,0.5)`; - radius = 0.1*this.yMax - - constructor(props: any) { - super(props) - this.state = { - accelerationXDisplay: 0, - accelerationYDisplay: 0, - adjustPendulumAngle: {angle: 0, length: 0}, - coefficientOfKineticFriction: 0, - coefficientOfStaticFriction: 0, - currentForceSketch: null, - deleteMode: false, - displayChange: {xDisplay: 0, yDisplay: 0}, - elasticCollisions: false, - forceSketches: [], - pendulum: false, - pendulumAngle: 0, - pendulumLength: 300, - positionXDisplay: 0, - positionYDisplay: 0, - showAcceleration: false, - showForceMagnitudes: false, - showForces: false, - showVelocity: false, - simulationPaused: true, - simulationReset: false, - simulationType: "Inclined Plane", - sketching: false, - startForces: [this.forceOfGravity], - startPendulumAngle: 0, - startPosX: 0, - startPosY: 0, - stepNumber: 0, - timer: 0, - updatedForces: [this.forceOfGravity], - velocityXDisplay: 0, - velocityYDisplay: 0, - wallPositions: [], - wedge: false, - wedgeAngle: 26, - wedgeHeight: Math.tan((26 * Math.PI) / 180) * this.xMax*0.6, - wedgeWidth: this.xMax*0.6, - weight: false, - } - } - - // Add one weight to the simulation - addWeight () { - this.setState({weight: true}) - this.setState({wedge: false}) - this.setState({pendulum: false}) - this.setState({startPosY: this.yMin+this.radius}) - this.setState({startPosX: (this.xMax+this.xMin-this.radius)/2}) - this.setState({updatedForces: [this.forceOfGravity]}) - this.setState({startForces: [this.forceOfGravity]}) - this.addWalls(); - this.setState({simulationReset: !this.state.simulationReset}) - }; - - // Add a wedge with a One Weight to the simulation - addWedge () { - this.setState({weight: true}) - this.setState({wedge: true}) - this.setState({pendulum: false}) - this.changeWedgeBasedOnNewAngle(26); - this.addWalls(); - this.setState({startForces: [this.forceOfGravity]}) - this.updateForcesWithFriction(this.state.coefficientOfStaticFriction); - }; - - // Add a simple pendulum to the simulation - addPendulum = () => { - this.setState({weight: true}) - this.setState({wedge: false}) - this.setState({pendulum: true}) - let length = this.xMax*0.7; - let angle = 35; - let x = length * Math.cos(((90 - angle) * Math.PI) / 180); - let y = length * Math.sin(((90 - angle) * Math.PI) / 180); - let xPos = this.xMax / 2 - x - this.radius; - let yPos = y - this.radius; - this.setState({startPosX: xPos}) - this.setState({startPosY: yPos}) - let mag = 9.81 * Math.cos((angle * Math.PI) / 180); - let forceOfTension: IForce = { - description: "Tension", - magnitude: mag, - directionInDegrees: 90 - angle, - }; - this.setState({updatedForces: [this.forceOfGravity, forceOfTension]}) - this.setState({startForces: [this.forceOfGravity, forceOfTension]}) - this.setState({pendulumAngle: angle}) - this.setState({pendulumLength: length}) - this.setState({adjustPendulumAngle: {angle: angle, length: length}}) - this.removeWalls(); - }; - - // Update forces when coefficient of static friction changes in freeform mode - updateForcesWithFriction ( - coefficient: number, - width: number = this.state.wedgeWidth, - height: number = this.state.wedgeHeight - ) { - let normalForce = { - description: "Normal Force", - magnitude: this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)), - directionInDegrees: - 180 - 90 - (Math.atan(height / width) * 180) / Math.PI, - }; - let frictionForce: IForce = { - description: "Static Friction Force", - magnitude: - coefficient * - this.forceOfGravity.magnitude * - Math.cos(Math.atan(height / width)), - directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI, - }; - // reduce magnitude of friction force if necessary such that block cannot slide up plane - let yForce = -this.forceOfGravity.magnitude; - yForce += - normalForce.magnitude * - Math.sin((normalForce.directionInDegrees * Math.PI) / 180); - yForce += - frictionForce.magnitude * - Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - if (yForce > 0) { - frictionForce.magnitude = - (-normalForce.magnitude * - Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + - this.forceOfGravity.magnitude) / - Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - } - if (coefficient != 0) { - this.setState({startForces: [this.forceOfGravity, normalForce, frictionForce]}) - this.setState({updatedForces: [this.forceOfGravity, normalForce, frictionForce]}); - } else { - this.setState({startForces: [this.forceOfGravity, normalForce]}) - this.setState({updatedForces: [this.forceOfGravity, normalForce]}); - } - }; - - // Change wedge height and width and weight position to match new wedge angle - changeWedgeBasedOnNewAngle = (angle: number) => { - let width = 0; - let height = 0; - if (angle < 50) { - width = this.xMax*0.6; - height = Math.tan((angle * Math.PI) / 180) * width; - this.setState({wedgeWidth: width}) - this.setState({wedgeHeight: height}) - } else if (angle < 70) { - width = this.xMax*0.3; - height = Math.tan((angle * Math.PI) / 180) * width; - this.setState({wedgeWidth: width}) - this.setState({wedgeHeight: height}) - } else { - width = this.xMax*0.15; - height = Math.tan((angle * Math.PI) / 180) * width; - this.setState({wedgeWidth: width}) - this.setState({wedgeHeight: height}) - } - - // update weight position based on updated wedge width/height - let xPos = (this.xMax * 0.2)-this.radius; - let yPos = width * Math.tan((angle * Math.PI) / 180) - this.radius; - - this.setState({startPosX: xPos}); - this.setState({startPosY: this.getDisplayYPos(yPos)}); - this.updateForcesWithFriction( - Number(this.state.coefficientOfStaticFriction), - width, - height - ); - }; - - // Helper function to go between display and real values - getDisplayYPos = (yPos: number) => { - return this.yMax - yPos - 2 * 50 + 5; - }; - - // In review mode, edit force arrow sketch on mouse movement - editForce = (element: PhysicsVectorTemplate) => { - if (!this.state.sketching) { - let sketches = this.state.forceSketches.filter((sketch) => sketch != element); - this.setState({forceSketches: sketches}) - this.setState({currentForceSketch: element}) - this.setState({sketching: true}) - } - }; - - // In review mode, used to delete force arrow sketch on SHIFT+click - deleteForce = (element: PhysicsVectorTemplate) => { - if (!this.state.sketching) { - let sketches = this.state.forceSketches.filter((sketch) => sketch != element); - this.setState({forceSketches: sketches}) - } - }; - - // Remove floor and walls from simulation - removeWalls = () => { - this.setState({wallPositions: []}) - }; - - // Add floor and walls to simulation - addWalls = () => { - if (this.state.wallPositions.length == 0) { - let walls = []; - walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 }); - walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 }); - walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 }); - this.setState({wallPositions: walls}) - } - }; - - - componentDidMount() { - // Add weight - this.addPendulum() - - // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click - document.addEventListener("keydown", (e) => { - if (e.shiftKey) { - this.setState({deleteMode: true}) - } - }); - document.addEventListener("keyup", (e) => { - if (e.shiftKey) { - this.setState({deleteMode: false}) - } - }); - - // Timer for animating the simulation - setInterval(() => { - this.setState({timer: this.state.timer+1}) - }, 60); - } - - render () { - return ( -
-
-
{ - // if (sketching) { - // x1 = positionXDisplay + 50; - // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50; - // x2 = e.clientX; - // y2 = e.clientY; - // height = Math.abs(y1 - y2) + 120; - // width = Math.abs(x1 - x2) + 120; - // top = Math.min(y1, y2) - 60; - // left = Math.min(x1, x2) - 60; - // x1Updated = x1 - left; - // x2Updated = x2 - left; - // y1Updated = y1 - top; - // y2Updated = y2 - top; - // setCurrentForceSketch({ - // top: top, - // left: left, - // width: width, - // height: height, - // x1: x1Updated, - // y1: y1Updated, - // x2: x2Updated, - // y2: y2Updated, - // weightX: positionXDisplay, - // weightY: positionYDisplay, - // }); - // } - }} - onPointerDown={(e) => { - // if (sketching && currentForceSketch) { - // setSketching(false); - // sketches = forceSketches; - // sketches.push(currentForceSketch); - // setForceSketches(sketches); - // setCurrentForceSketch(null); - // } - }} - > -
-
- {/* {showForces && currentForceSketch && simulationPaused && ( -
- - - - - - - - -
- )} */} - {/* {showForces && - forceSketches.length > 0 && - simulationPaused && - forceSketches.map((element: PhysicsVectorTemplate, index) => { - return ( -
- - - - - - - { - if (deleteMode) { - deleteForce(element); - } else { - editForce(element); - } - }} - /> - -
- ); - })} */} - {this.state.weight && ( - {this.setState({sketching: val})}} - setDisplayXAcceleration={(val: number) => {this.setState({accelerationXDisplay: val})}} - setDisplayXPosition={(val: number) => {this.setState({positionXDisplay: val})}} - setDisplayXVelocity={(val: number) => {this.setState({velocityXDisplay: val})}} - setDisplayYAcceleration={(val: number) => {this.setState({accelerationYDisplay: val})}} - setDisplayYPosition={(val: number) => {this.setState({positionYDisplay: val})}} - setDisplayYVelocity={(val: number) => {this.setState({velocityYDisplay: val})}} - setPaused={(val: boolean) => {this.setState({simulationPaused: val})}} - setPendulumAngle={(val: number) => {this.setState({pendulumAngle: val})}} - setPendulumLength={(val: number) => {this.setState({pendulumLength: val})}} - setStartPendulumAngle={(val: number) => {this.setState({startPendulumAngle: val})}} - setUpdatedForces={(val: IForce[]) => {this.setState({updatedForces: val})}} - showAcceleration={this.state.showAcceleration} - showForces={this.state.showForces} - showVelocity={this.state.showVelocity} - startForces={this.state.startForces} - startPosX={this.state.startPosX} - startPosY={this.state.startPosY} - timestepSize={0.002} - updateDisplay={this.state.displayChange} - updatedForces={this.state.updatedForces} - walls={this.state.wallPositions} - wedge={this.state.wedge} - wedgeHeight={this.state.wedgeHeight} - wedgeWidth={this.state.wedgeWidth} - coefficientOfKineticFriction={this.state.coefficientOfKineticFriction} - xMax={this.xMax} - yMax={this.yMax} - xMin={this.xMin} - yMin={this.yMin} - /> - )} - {this.state.wedge && ( - - )} -
-
- {this.state.wallPositions.map((element, index) => { - return ( -
- -
- ); - })} -
-
-
-
-
-
- {this.state.simulationPaused && ( - - )} - {!this.state.simulationPaused && ( - - )} - {this.state.simulationPaused && ( - - )} - -
-
-
-
-
- ); - } -} diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index 3ea4fba9f..9d91adefb 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -33,46 +33,6 @@ interface PhysicsVectorTemplate { weightY: number; } -interface IState { - accelerationXDisplay: number, - accelerationYDisplay: number, - adjustPendulumAngle: {angle: number, length: number}, - coefficientOfKineticFriction: number, - coefficientOfStaticFriction: number, - currentForceSketch: PhysicsVectorTemplate | null, - deleteMode: boolean, - displayChange: {xDisplay: number, yDisplay: number}, - elasticCollisions: boolean, - forceSketches: PhysicsVectorTemplate[], - pendulum: boolean, - pendulumAngle: number, - pendulumLength: number, - positionXDisplay: number, - positionYDisplay: number, - showAcceleration: boolean, - showForceMagnitudes: boolean, - showForces: boolean, - showVelocity: boolean, - simulationPaused: boolean, - simulationReset: boolean, - simulationType: "Inclined Plane", - sketching: boolean, - startForces: IForce[], - startPendulumAngle: number, - startPosX: number, - startPosY: number, - stepNumber: number, - timer: number, - updatedForces: IForce[], - velocityXDisplay: number, - velocityYDisplay: number, - wallPositions: IWallProps[], - wedge: boolean, - wedgeAngle: number, - wedgeHeight: number, - wedgeWidth: number, - weight: boolean, -} @observer export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() { @@ -96,7 +56,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
-
{ - // if (sketching) { - // x1 = positionXDisplay + 50; - // y1 = yMax - positionYDisplay - 2 * 50 + 5 + 50; - // x2 = e.clientX; - // y2 = e.clientY; - // height = Math.abs(y1 - y2) + 120; - // width = Math.abs(x1 - x2) + 120; - // top = Math.min(y1, y2) - 60; - // left = Math.min(x1, x2) - 60; - // x1Updated = x1 - left; - // x2Updated = x2 - left; - // y1Updated = y1 - top; - // y2Updated = y2 - top; - // setCurrentForceSketch({ - // top: top, - // left: left, - // width: width, - // height: height, - // x1: x1Updated, - // y1: y1Updated, - // x2: x2Updated, - // y2: y2Updated, - // weightX: positionXDisplay, - // weightY: positionYDisplay, - // }); - // } - }} - onPointerDown={(e) => { - // if (sketching && currentForceSketch) { - // setSketching(false); - // sketches = forceSketches; - // sketches.push(currentForceSketch); - // setForceSketches(sketches); - // setCurrentForceSketch(null); - // } - }} - > +
- {/* {showForces && currentForceSketch && simulationPaused && ( -
- - - - - - - - -
- )} */} - {/* {showForces && - forceSketches.length > 0 && - simulationPaused && - forceSketches.map((element: PhysicsVectorTemplate, index) => { - return ( -
- - - - - - - { - if (deleteMode) { - deleteForce(element); - } else { - editForce(element); - } - }} - /> - -
- ); - })} */} {this.dataDoc.weight && ( {this.dataDoc.sketching = val}} - setDisplayXAcceleration={(val: number) => {this.dataDoc.accelerationXDisplay = val}} - setDisplayXPosition={(val: number) => {this.dataDoc.positionXDisplay = val}} - setDisplayXVelocity={(val: number) => {this.dataDoc.velocityXDisplay = val}} - setDisplayYAcceleration={(val: number) => {this.dataDoc.accelerationYDisplay = val}} - setDisplayYPosition={(val: number) => {this.dataDoc.positionYDisplay = val}} - setDisplayYVelocity={(val: number) => {this.dataDoc.velocityYDisplay = val}} - setPaused={(val: boolean) => {this.dataDoc.simulationPaused = val}} - setPendulumAngle={(val: number) => {this.dataDoc.pendulumAngle = val}} - setPendulumLength={(val: number) => {this.dataDoc.pendulumLength = val}} - setStartPendulumAngle={(val: number) => {this.dataDoc.startPendulumAngle = val}} - setUpdatedForces={(val: IForce[]) => {this.dataDoc.updatedForces = val}} showAcceleration={this.dataDoc.showAcceleration} showForces={this.dataDoc.showForces} showVelocity={this.dataDoc.showVelocity} diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index dfd463bbe..fcfb149c9 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -1,4 +1,5 @@ import React = require('react'); +import { Doc } from '../../../fields/Doc'; import { IWallProps } from "./PhysicsSimulationWall"; export interface IForce { @@ -7,35 +8,17 @@ export interface IForce { directionInDegrees: number; } export interface IWeightProps { - adjustPendulumAngle: { angle: number; length: number }; + dataDoc: Doc; color: string; - displayXPosition: number; - displayYPosition: number; - displayXVelocity: number; - displayYVelocity: number; - elasticCollisions: boolean; startForces: IForce[]; - incrementTime: number; mass: number; - paused: boolean; pendulum: boolean; pendulumLength: number; wedge: boolean; radius: number; reset: boolean; - setDisplayXAcceleration: (val: number) => any; - setDisplayXPosition: (val: number) => any; - setDisplayXVelocity: (val: number) => any; - setDisplayYAcceleration: (val: number) => any; - setDisplayYPosition: (val: number) => any; - setDisplayYVelocity: (val: number) => any; - setPaused: (bool: boolean) => any; - setPendulumAngle: (val: number) => any; - setPendulumLength: (val: number) => any; - setStartPendulumAngle: (val: number) => any; showAcceleration: boolean; pendulumAngle: number; - setSketching: (val: boolean) => any; showForces: boolean; showForceMagnitudes: boolean; showVelocity: boolean; @@ -46,7 +29,6 @@ export interface IWeightProps { timestepSize: number; updateDisplay: { xDisplay: number; yDisplay: number }; updatedForces: IForce[]; - setUpdatedForces: (val: IForce[]) => any; walls: IWallProps[]; coefficientOfKineticFriction: number; wedgeWidth: number; @@ -125,16 +107,16 @@ export default class Weight extends React.Component { // Set display values based on real values setYPosDisplay = (yPos: number) => { const displayPos = this.getDisplayYPos(yPos); - this.props.setDisplayYPosition(Math.round(displayPos * 100) / 100) + this.props.dataDoc['positionYDisplay'] = Math.round(displayPos * 100) / 100 }; setXPosDisplay = (xPos: number) => { - this.props.setDisplayXPosition(Math.round(xPos * 100) / 100); + this.props.dataDoc['positionXDisplay'] = Math.round(xPos * 100) / 100; }; setYVelDisplay = (yVel: number) => { - this.props.setDisplayYVelocity((-1 * Math.round(yVel * 100)) / 100); + this.props.dataDoc['velocityYDisplay'] = (-1 * Math.round(yVel * 100)) / 100; }; setXVelDisplay = (xVel: number) => { - this.props.setDisplayXVelocity(Math.round(xVel * 100) / 100); + this.props.dataDoc['velocityXDisplay'] = Math.round(xVel * 100) / 100; }; setDisplayValues = ( @@ -147,12 +129,12 @@ export default class Weight extends React.Component { this.setXPosDisplay(xPos); this.setYVelDisplay(yVel); this.setXVelDisplay(xVel); - this.props.setDisplayYAcceleration( + this.props.dataDoc['accelerationYDisplay'] = (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100 - ); - this.props.setDisplayXAcceleration( + ; + this.props.dataDoc['accelerationXDisplay'] = Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100 - ); + ; }; componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { @@ -164,34 +146,34 @@ export default class Weight extends React.Component { x = Math.min(x, this.props.xMax - 2 * this.props.radius); this.setState({updatedStartPosX: x}) this.setState({xPosition: x}) - this.props.setDisplayXPosition(x); + this.props.dataDoc['positionXDisplay'] = x; } if (this.props.updateDisplay.yDisplay != this.getDisplayYPos(this.state.yPosition)) { let y = this.props.updateDisplay.yDisplay; y = Math.max(0, y); y = Math.min(y, this.props.yMax - 2 * this.props.radius); - this.props.setDisplayYPosition(y); + this.props.dataDoc['positionYDisplay'] = y; let coordinatePosition = this.getYPosFromDisplay(y); this.setState({updatedStartPosY: coordinatePosition}) this.setState({yPosition: coordinatePosition}) } - if (this.props.displayXVelocity != this.state.xVelocity) { - let x = this.props.displayXVelocity; + if (this.props.dataDoc['velocityXDisplay'] != this.state.xVelocity) { + let x = this.props.dataDoc['velocityXDisplay']; this.setState({xVelocity: x}) - this.props.setDisplayXVelocity(x); + this.props.dataDoc['velocityXDisplay'] = x; } - if (this.props.displayYVelocity != this.state.yVelocity) { - let y = this.props.displayYVelocity; + if (this.props.dataDoc['velocityYDisplay'] != this.state.yVelocity) { + let y = this.props.dataDoc['velocityYDisplay']; this.setState({yVelocity: -y}) - this.props.setDisplayXVelocity(y); + this.props.dataDoc['velocityYDisplay'] } } // Update sim - if (this.props.incrementTime != prevProps.incrementTime) { - if (!this.props.paused) { + if (this.props.dataDoc['incrementTime'] != prevProps.dataDoc['incrementTime']) { + if (!this.props.dataDoc['simulationPaused']) { let collisions = false; if (!this.props.pendulum) { const collisionsWithGround = this.checkForCollisionsWithGround(); @@ -229,21 +211,19 @@ export default class Weight extends React.Component { this.setState({yVelocity: this.props.startVelY ?? 0}) this.setDisplayValues(); } - if (this.props.adjustPendulumAngle != prevProps.adjustPendulumAngle) { + if (this.props.dataDoc['adjustPendulumAngle'] != prevProps.dataDoc['adjustPendulumAngle']) { // Change pendulum angle based on input field - let length = this.props.adjustPendulumAngle.length; + let length = this.props.dataDoc['pendulumLength'] ?? 0; const x = - length * Math.cos(((90 - this.props.adjustPendulumAngle.angle) * Math.PI) / 180); + length * Math.cos(((90 - this.props.dataDoc['pendulumAngle']) * Math.PI) / 180); const y = - length * Math.sin(((90 - this.props.adjustPendulumAngle.angle) * Math.PI) / 180); + length * Math.sin(((90 - this.props.dataDoc['pendulumAngle']) * Math.PI) / 180); const xPos = this.props.xMax / 2 - x - this.props.radius; const yPos = y - this.props.radius - 5; this.setState({xPosition: xPos}) this.setState({yPosition: yPos}) this.setState({updatedStartPosX: xPos}) this.setState({updatedStartPosY: yPos}) - this.props.setPendulumAngle(this.props.adjustPendulumAngle.angle); - this.props.setPendulumLength(this.props.adjustPendulumAngle.length); } // Update x start position if (this.props.startPosX != prevProps.startPosX) { @@ -314,24 +294,28 @@ export default class Weight extends React.Component { getNewAccelerationX = (forceList: IForce[]) => { let newXAcc = 0; - forceList.forEach((force) => { - newXAcc += - (force.magnitude * - Math.cos((force.directionInDegrees * Math.PI) / 180)) / - this.props.mass; - }); + if (forceList) { + forceList.forEach((force) => { + newXAcc += + (force.magnitude * + Math.cos((force.directionInDegrees * Math.PI) / 180)) / + this.props.mass; + }); + } return newXAcc; }; getNewAccelerationY = (forceList: IForce[]) => { let newYAcc = 0; - forceList.forEach((force) => { - newYAcc += - (-1 * - (force.magnitude * - Math.sin((force.directionInDegrees * Math.PI) / 180))) / - this.props.mass; - }); + if (forceList) { + forceList.forEach((force) => { + newYAcc += + (-1 * + (force.magnitude * + Math.sin((force.directionInDegrees * Math.PI) / 180))) / + this.props.mass; + }); + } return newYAcc; }; @@ -356,8 +340,8 @@ export default class Weight extends React.Component { } const pendulumLength = Math.sqrt(x * x + y * y); - this.props.setPendulumAngle(oppositeAngle); - this.props.setPendulumLength(Math.sqrt(x * x + y * y)); + this.props.dataDoc['pendulumAngle'] = oppositeAngle; + this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y); const mag = this.props.mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) + @@ -391,7 +375,7 @@ export default class Weight extends React.Component { const wallX = (wall.xPos / 100) * 300; if (wall.xPos < 0.35) { if (minX <= wallX) { - if (this.props.elasticCollisions) { + if (this.props.dataDoc['elasticCollisions']) { this.setState({xVelocity: -this.state.xVelocity}); } else { this.setState({xVelocity: 0}); @@ -401,7 +385,7 @@ export default class Weight extends React.Component { } } else { if (maxX >= wallX) { - if (this.props.elasticCollisions) { + if (this.props.dataDoc['elasticCollisions']) { this.setState({xVelocity: -this.state.xVelocity}); } else { this.setState({xVelocity: 0}); @@ -424,7 +408,7 @@ export default class Weight extends React.Component { if (wall.angleInDegrees == 0) { const groundY = (wall.yPos / 100) * this.props.yMax; if (maxY >= groundY) { - if (this.props.elasticCollisions) { + if (this.props.dataDoc['elasticCollisions']) { this.setState({yVelocity: -this.state.yVelocity}) } else { this.setState({yVelocity: 0}) @@ -525,7 +509,7 @@ export default class Weight extends React.Component { onPointerDown={(e) => { if (this.draggable) { e.preventDefault(); - this.props.setPaused(true); + this.props.dataDoc['simulationPaused'] = true; this.setState({dragging: true}); this.setState({clickPositionX: e.clientX}) this.setState({clickPositionY: e.clientY}) @@ -549,7 +533,7 @@ export default class Weight extends React.Component { this.setState({yPosition: newY}) this.setState({updatedStartPosX: newX}) this.setState({updatedStartPosY: newY}) - this.props.setDisplayYPosition(Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100) + this.props.dataDoc['positionYDisplay'] = Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100; this.setState({clickPositionX: e.clientX}) this.setState({clickPositionY: e.clientY}) this.setDisplayValues(); @@ -586,8 +570,8 @@ export default class Weight extends React.Component { } const pendulumLength = Math.sqrt(x * x + y * y); - this.props.setPendulumAngle(oppositeAngle); - this.props.setPendulumLength(Math.sqrt(x * x + y * y)); + this.props.dataDoc['pendulumAngle'] = oppositeAngle; + this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y); const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180); const forceOfTension: IForce = { description: "Tension", @@ -629,17 +613,6 @@ export default class Weight extends React.Component { {!this.state.dragging && (
- {/*

- {Math.round(this.props.pendulumLength)} m -

*/}

{ backgroundColor: this.labelBackgroundColor, }} > - {Math.round(this.props.pendulumAngle * 100) / 100}° + {Math.round(this.props.dataDoc['pendulumAngle'] * 100) / 100}°

)} -- cgit v1.2.3-70-g09d2 From 8cf1aed33306d633466ac78d3156e629b9dfe5e9 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Wed, 15 Feb 2023 20:51:59 -0500 Subject: simulation compiles and runs --- src/client/views/nodes/PhysicsSimulationBox.tsx | 56 +++----- src/client/views/nodes/PhysicsSimulationWeight.tsx | 142 ++++++++++----------- 2 files changed, 91 insertions(+), 107 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index 9d91adefb..13b4fe0b2 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -61,7 +61,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { - if (e.shiftKey) { - this.dataDoc.deleteMode = true; - } - }); - document.addEventListener("keyup", (e) => { - if (e.shiftKey) { - this.dataDoc.deleteMode = false; - } - }); + // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click + document.addEventListener("keydown", (e) => { + if (e.shiftKey) { + this.dataDoc.deleteMode = true; + } + }); + document.addEventListener("keyup", (e) => { + if (e.shiftKey) { + this.dataDoc.deleteMode = false; + } + }); - // Timer for animating the simulation - setInterval(() => { - this.dataDoc.timer = this.dataDoc.timer+1; - }, 60); + // // Timer for animating the simulation + // setInterval(() => { + // this.dataDoc.timer = this.dataDoc.timer+1; + // }, 60); } render () { @@ -297,26 +297,8 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent {this.dataDoc.simulationPaused && ( )} {!this.dataDoc.simulationPaused && ( )} diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index fcfb149c9..e7bd86915 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -10,27 +10,13 @@ export interface IForce { export interface IWeightProps { dataDoc: Doc; color: string; - startForces: IForce[]; mass: number; - pendulum: boolean; - pendulumLength: number; wedge: boolean; radius: number; - reset: boolean; - showAcceleration: boolean; - pendulumAngle: number; - showForces: boolean; - showForceMagnitudes: boolean; - showVelocity: boolean; - startPosX: number; - startPosY: number; startVelX?: number; startVelY?: number; timestepSize: number; - updateDisplay: { xDisplay: number; yDisplay: number }; - updatedForces: IForce[]; walls: IWallProps[]; - coefficientOfKineticFriction: number; wedgeWidth: number; wedgeHeight: number; xMax: number; @@ -46,6 +32,7 @@ interface IState { kineticFriction: boolean, updatedStartPosX: number, updatedStartPosY: number, + timer: number; xPosition: number, yPosition: number, xVelocity: number, @@ -60,17 +47,18 @@ export default class Weight extends React.Component { clickPositionY: 0, dragging: false, kineticFriction: false, - updatedStartPosX: this.props.startPosX, - updatedStartPosY: this.props.startPosY, - xPosition: this.props.startPosX, - yPosition: this.props.startPosY, + timer: 0, + updatedStartPosX: this.props.dataDoc['startPosX'], + updatedStartPosY: this.props.dataDoc['startPosY'], + xPosition: this.props.dataDoc['startPosX'], + yPosition: this.props.dataDoc['startPosY'], xVelocity: this.props.startVelX ? this.props.startVelX: 0, yVelocity: this.props.startVelY ? this.props.startVelY: 0, } } // Constants - draggable = !this.props.wedge; + draggable = !this.props.dataDoc['wedge'] ; epsilon = 0.0001; forceOfGravity: IForce = { description: "Gravity", @@ -84,8 +72,8 @@ export default class Weight extends React.Component { borderStyle: "solid", borderColor: "black", position: "absolute" as "absolute", - left: this.props.startPosX + "px", - top: this.props.startPosY + "px", + left: this.props.dataDoc['startPosX'] + "px", + top: this.props.dataDoc['startPosY'] + "px", width: 2 * this.props.radius + "px", height: 2 * this.props.radius + "px", zIndex: 5, @@ -130,18 +118,25 @@ export default class Weight extends React.Component { this.setYVelDisplay(yVel); this.setXVelDisplay(xVel); this.props.dataDoc['accelerationYDisplay'] = - (-1 * Math.round(this.getNewAccelerationY(this.props.updatedForces) * 100)) / 100 + (-1 * Math.round(this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 100)) / 100 ; this.props.dataDoc['accelerationXDisplay'] = - Math.round(this.getNewAccelerationX(this.props.updatedForces) * 100) / 100 + Math.round(this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 100) / 100 ; }; + componentDidMount() { + // Timer for animating the simulation + setInterval(() => { + this.setState({timer: this.state.timer + 1}); + }, 60); + } + componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { // When display values updated by user, update real values - if (this.props.updateDisplay != prevProps.updateDisplay) { - if (this.props.updateDisplay.xDisplay != this.state.xPosition) { - let x = this.props.updateDisplay.xDisplay; + if (this.props.dataDoc['updateDisplay'] != prevProps.dataDoc['updateDisplay']) { + if (this.props.dataDoc['positionXDisplay'] != this.state.xPosition) { + let x = this.props.dataDoc['positionXDisplay']; x = Math.max(0, x); x = Math.min(x, this.props.xMax - 2 * this.props.radius); this.setState({updatedStartPosX: x}) @@ -149,8 +144,8 @@ export default class Weight extends React.Component { this.props.dataDoc['positionXDisplay'] = x; } - if (this.props.updateDisplay.yDisplay != this.getDisplayYPos(this.state.yPosition)) { - let y = this.props.updateDisplay.yDisplay; + if (this.props.dataDoc['positionYDisplay'] != this.getDisplayYPos(this.state.yPosition)) { + let y = this.props.dataDoc['positionYDisplay']; y = Math.max(0, y); y = Math.min(y, this.props.yMax - 2 * this.props.radius); this.props.dataDoc['positionYDisplay'] = y; @@ -172,10 +167,11 @@ export default class Weight extends React.Component { } } // Update sim - if (this.props.dataDoc['incrementTime'] != prevProps.dataDoc['incrementTime']) { + if (this.state.timer != prevState.timer) { if (!this.props.dataDoc['simulationPaused']) { + console.log('update') let collisions = false; - if (!this.props.pendulum) { + if (!this.props.dataDoc['pendulum']) { const collisionsWithGround = this.checkForCollisionsWithGround(); const collisionsWithWalls = this.checkForCollisionsWithWall(); collisions = collisionsWithGround || collisionsWithWalls; @@ -203,10 +199,10 @@ export default class Weight extends React.Component { touchAction: "none", }; - if (this.props.reset != prevProps.reset) { + if (this.props.dataDoc['simulationReset'] != prevProps.dataDoc['simulationReset']) { this.resetEverything(); } - if (this.props.startForces != prevProps.startForces) { + if (this.props.dataDoc['startForces'] != prevProps.dataDoc['startForces']) { this.setState({xVelocity: this.props.startVelX ?? 0}) this.setState({yVelocity: this.props.startVelY ?? 0}) this.setDisplayValues(); @@ -226,37 +222,37 @@ export default class Weight extends React.Component { this.setState({updatedStartPosY: yPos}) } // Update x start position - if (this.props.startPosX != prevProps.startPosX) { - this.setState({updatedStartPosX: this.props.startPosX}) - this.setState({xPosition: this.props.startPosX}) - this.setXPosDisplay(this.props.startPosX); + if (this.props.dataDoc['startPosX'] != prevProps.dataDoc['startPosX']) { + this.setState({updatedStartPosX: this.props.dataDoc['startPosX']}) + this.setState({xPosition: this.props.dataDoc['startPosX']}) + this.setXPosDisplay(this.props.dataDoc['startPosX']); } // Update y start position - if (this.props.startPosY != prevProps.startPosY) { - this.setState({updatedStartPosY: this.props.startPosY}) - this.setState({yPosition: this.props.startPosY}) - this.setYPosDisplay(this.props.startPosY); + if (this.props.dataDoc['startPosY'] != prevProps.dataDoc['startPosY']) { + this.setState({updatedStartPosY: this.props.dataDoc['startPosY']}) + this.setState({yPosition: this.props.dataDoc['startPosY']}) + this.setYPosDisplay(this.props.dataDoc['startPosY']); } if (this.state.xVelocity != prevState.xVelocity) { - if (this.props.wedge && this.state.xVelocity != 0 && !this.state.kineticFriction) { + if (this.props.dataDoc['wedge'] && this.state.xVelocity != 0 && !this.state.kineticFriction) { this.setState({kineticFriction: true}); //switch from static to kinetic friction const normalForce: IForce = { description: "Normal Force", magnitude: this.forceOfGravity.magnitude * - Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), + Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), directionInDegrees: - 180 - 90 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI, + 180 - 90 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, }; let frictionForce: IForce = { description: "Kinetic Friction Force", magnitude: - this.props.coefficientOfKineticFriction * + this.props.dataDoc['coefficientOfKineticFriction'] * this.forceOfGravity.magnitude * - Math.cos(Math.atan(this.props.wedgeHeight / this.props.wedgeWidth)), + Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), directionInDegrees: - 180 - (Math.atan(this.props.wedgeHeight / this.props.wedgeWidth) * 180) / Math.PI, + 180 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, }; // reduce magnitude of friction force if necessary such that block cannot slide up plane let yForce = -this.forceOfGravity.magnitude; @@ -273,10 +269,10 @@ export default class Weight extends React.Component { this.forceOfGravity.magnitude) / Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); } - if (this.props.coefficientOfKineticFriction != 0) { - this.props.setUpdatedForces([this.forceOfGravity, normalForce, frictionForce]); + if (this.props.dataDoc['coefficientOfKineticFriction'] != 0) { + this.props.dataDoc['updatedForces'] = [this.forceOfGravity, normalForce, frictionForce]; } else { - this.props.setUpdatedForces([this.forceOfGravity, normalForce]); + this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, normalForce]); } } } @@ -288,7 +284,7 @@ export default class Weight extends React.Component { this.setState({yPosition: this.state.updatedStartPosY}) this.setState({xVelocity: this.props.startVelX ?? 0}) this.setState({yVelocity: this.props.startVelY ?? 0}) - this.props.setUpdatedForces(this.props.startForces) + this.props.dataDoc['updatedForces'] = (this.props.dataDoc['startForces']) this.setDisplayValues(); }; @@ -325,8 +321,8 @@ export default class Weight extends React.Component { xVel: number, yVel: number ) => { - if (!this.props.pendulum) { - return this.props.updatedForces; + if (!this.props.dataDoc['pendulum']) { + return this.props.dataDoc['updatedForces']; } const x = this.props.xMax / 2 - xPos - this.props.radius; const y = yPos + this.props.radius + 5; @@ -370,7 +366,7 @@ export default class Weight extends React.Component { const maxX = this.state.xPosition + 2 * this.props.radius; const containerWidth = 300; if (this.state.xVelocity != 0) { - this.props.walls.forEach((wall) => { + this.props.dataDoc['wallPositions'].forEach((wall) => { if (wall.angleInDegrees == 90) { const wallX = (wall.xPos / 100) * 300; if (wall.xPos < 0.35) { @@ -404,7 +400,7 @@ export default class Weight extends React.Component { let collision = false; const maxY = this.state.yPosition + 2 * this.props.radius; if (this.state.yVelocity > 0) { - this.props.walls.forEach((wall) => { + this.props.dataDoc['wallPositions'] .forEach((wall) => { if (wall.angleInDegrees == 0) { const groundY = (wall.yPos / 100) * this.props.yMax; if (maxY >= groundY) { @@ -423,7 +419,7 @@ export default class Weight extends React.Component { magnitude: 9.81 * this.props.mass, directionInDegrees: wall.angleInDegrees + 90, }; - this.props.setUpdatedForces([forceOfGravity, normalForce]); + this.props.dataDoc['updatedForces'] = ([forceOfGravity, normalForce]); } collision = true; } @@ -496,9 +492,13 @@ export default class Weight extends React.Component { this.setState({yVelocity: yVel}); this.setState({xPosition: xPos}); this.setState({yPosition: yPos}); - this.props.setUpdatedForces(this.getNewForces(xPos, yPos, xVel, yVel)); + this.props.dataDoc['updatedForces'] = (this.getNewForces(xPos, yPos, xVel, yVel)); }; + + + + labelBackgroundColor = `rgba(255,255,255,0.5)`; render () { @@ -542,7 +542,7 @@ export default class Weight extends React.Component { onPointerUp={(e) => { if (this.state.dragging) { e.preventDefault(); - if (!this.props.pendulum) { + if (!this.props.dataDoc['pendulum']) { this.resetEverything(); } this.setState({dragging: false}); @@ -557,7 +557,7 @@ export default class Weight extends React.Component { } else if (newX < 0) { newX = 0; } - if (this.props.pendulum) { + if (this.props.dataDoc['pendulum']) { const x = this.props.xMax / 2 - newX - this.props.radius; const y = newY + this.props.radius + 5; let angle = (Math.atan(y / x) * 180) / Math.PI; @@ -582,7 +582,7 @@ export default class Weight extends React.Component { this.setState({xVelocity: this.props.startVelX ?? 0}) this.setState({yVelocity: this.props.startVelY ?? 0}) this.setDisplayValues(); - this.props.setUpdatedForces([this.forceOfGravity, forceOfTension]); + this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, forceOfTension]); } } }} @@ -591,7 +591,7 @@ export default class Weight extends React.Component {

{this.props.mass} kg

- {this.props.pendulum && ( + {this.props.dataDoc['pendulum'] && (
{ )}
)} - {!this.state.dragging && this.props.showAcceleration && ( + {!this.state.dragging && this.props.dataDoc['showAcceleration'] && (
{ { left: this.state.xPosition + this.props.radius + - this.getNewAccelerationX(this.props.updatedForces) * 5 + + this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 5 + 25 + "px", top: this.state.yPosition + this.props.radius + - this.getNewAccelerationY(this.props.updatedForces) * 5 + + this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 5 + 25 + "px", lineHeight: 0.5, @@ -684,8 +684,8 @@ export default class Weight extends React.Component { {Math.round( 100 * Math.sqrt( - Math.pow(this.getNewAccelerationX(this.props.updatedForces) * 3, 2) + - Math.pow(this.getNewAccelerationY(this.props.updatedForces) * 3, 2) + Math.pow(this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 3, 2) + + Math.pow(this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 3, 2) ) ) / 100}{" "} m/s2 @@ -694,7 +694,7 @@ export default class Weight extends React.Component {
)} - {!this.state.dragging && this.props.showVelocity && ( + {!this.state.dragging && this.props.dataDoc['showVelocity'] && (
{
)} {!this.state.dragging && - this.props.showForces && - this.props.updatedForces.map((force, index) => { + this.props.dataDoc['showForces'] && + this.props.dataDoc['updatedForces'].map((force, index) => { if (force.magnitude < this.epsilon) { return; } @@ -836,7 +836,7 @@ export default class Weight extends React.Component { > {force.description &&

{force.description}

} {!force.description &&

Force

} - {this.props.showForceMagnitudes && ( + {this.props.dataDoc['showForceMagnitudes'] && (

{Math.round(100 * force.magnitude) / 100} N

)}
-- cgit v1.2.3-70-g09d2 From 15c5985f0f52a4ceed3532c95106a7e9c493b080 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Thu, 16 Feb 2023 13:38:53 -0500 Subject: debugging persistence --- src/client/views/nodes/PhysicsSimulationBox.tsx | 67 +++++++++++++++++-------- 1 file changed, 45 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index 13b4fe0b2..25777ce18 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -99,30 +99,52 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { this.dataDoc.weight = true; this.dataDoc.wedge = false; this.dataDoc.pendulum = true; + this.removeWalls(); + let angle = this.dataDoc.pendulumAngle; + let mag = 9.81 * Math.cos((angle * Math.PI) / 180); + let forceOfTension: IForce = { + description: "Tension", + magnitude: mag, + directionInDegrees: 90 - angle, + }; + this.dataDoc.updatedForces = [this.forceOfGravity, forceOfTension]; + this.dataDoc.startForces = [this.forceOfGravity, forceOfTension]; + }; + + // Set pendulum defaults + setToPendulumDefault () { let length = this.xMax*0.7; let angle = 35; let x = length * Math.cos(((90 - angle) * Math.PI) / 180); @@ -132,18 +154,10 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { @@ -279,10 +299,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { - // this.dataDoc.timer = this.dataDoc.timer+1; - // }, 60); + this.dataDoc['simulationPaused'] = true; } render () { @@ -351,17 +368,23 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentRESET )} - + }} >TYPE)}
-- cgit v1.2.3-70-g09d2 From 8428ad5be1d49c8985a59b442823ceaa33005aa6 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Fri, 17 Feb 2023 23:29:10 -0500 Subject: debugging datadoc not working --- src/client/views/nodes/PhysicsSimulationBox.tsx | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index 25777ce18..f9baac431 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -278,12 +278,19 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent {this.dataDoc.simulationPaused && ( )} {!this.dataDoc.simulationPaused && ( )} @@ -372,17 +377,17 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentTYPE)}
-- cgit v1.2.3-70-g09d2 From b206cc3e0f992d72010d8420a0e78b38a9840d2f Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Fri, 17 Feb 2023 23:49:56 -0500 Subject: sim type persists --- src/client/views/nodes/PhysicsSimulationBox.tsx | 112 +++++++++++------------- 1 file changed, 53 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index f9baac431..a78d899e0 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -54,44 +54,32 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { - if (this.dataDoc.wallPositions.length == 0) { - let walls = []; - walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 }); - walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 }); - walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 }); - this.dataDoc.wallPositions = walls - } + let walls = []; + walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 }); + walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 }); + walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 }); + this.dataDoc.wallPositions = walls }; @@ -289,7 +275,8 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
- {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { - return ( -
- -
- ); - })} + {/* {this.dataDoc.wallPositions && ( + {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { + return ( +
+ +
+ ); + })} + )} */}
-- cgit v1.2.3-70-g09d2 From 5a7019a97eb22b79fa15770badbfb265cb668208 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Sat, 18 Feb 2023 10:12:57 -0500 Subject: weight pos changes on type change --- src/client/views/nodes/PhysicsSimulationBox.tsx | 190 +++++++++++---------- src/client/views/nodes/PhysicsSimulationWeight.tsx | 95 ++++++----- 2 files changed, 152 insertions(+), 133 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index a78d899e0..e7d5e48f0 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -51,6 +51,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent -
-
-
-
- {this.dataDoc.weight && ( - - )} - {this.dataDoc.wedge && ( - - )} + componentDidUpdate() { + this.xMax = this.layoutDoc._width; + this.yMax = this.layoutDoc._height; + this.radius = 0.1*this.yMax + } + + render () { + return ( +
+
+
+
+
+ {this.dataDoc.weight && ( + + )} + {this.dataDoc.wedge && ( + + )} +
+
+ {/* {this.dataDoc.wallPositions && ( + {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { + return ( +
+ +
+ ); + })} + )} */} +
+
+
+
- {/* {this.dataDoc.wallPositions && ( - {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { - return ( -
- -
- ); - })} - )} */} + {this.dataDoc.simulationPaused && ( + + )} + {!this.dataDoc.simulationPaused && ( + + )} + {this.dataDoc.simulationPaused && ( + + )} + {this.dataDoc.simulationPaused && ( )} +
-
-
-
- {this.dataDoc.simulationPaused && ( - - )} - {!this.dataDoc.simulationPaused && ( - - )} - {this.dataDoc.simulationPaused && ( - - )} - {this.dataDoc.simulationPaused && ( )} -
-
-
-
- ); - } -} \ No newline at end of file + ); + } + } \ No newline at end of file diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index e7bd86915..fc75fa5aa 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -8,20 +8,25 @@ export interface IForce { directionInDegrees: number; } export interface IWeightProps { - dataDoc: Doc; + adjustPendulumAngle: boolean; color: string; + dataDoc: Doc; mass: number; - wedge: boolean; radius: number; + simulationReset: boolean; + startPosX: number; + startPosY: number; startVelX?: number; startVelY?: number; timestepSize: number; + updateDisplay: boolean, walls: IWallProps[]; - wedgeWidth: number; + wedge: boolean; wedgeHeight: number; + wedgeWidth: number; xMax: number; - yMax: number; xMin: number; + yMax: number; yMin: number; } @@ -37,6 +42,7 @@ interface IState { yPosition: number, xVelocity: number, yVelocity: number, + update: boolean, } export default class Weight extends React.Component { @@ -133,8 +139,9 @@ export default class Weight extends React.Component { } componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { + // When display values updated by user, update real values - if (this.props.dataDoc['updateDisplay'] != prevProps.dataDoc['updateDisplay']) { + if (this.props.updateDisplay != prevProps.updateDisplay) { if (this.props.dataDoc['positionXDisplay'] != this.state.xPosition) { let x = this.props.dataDoc['positionXDisplay']; x = Math.max(0, x); @@ -167,47 +174,29 @@ export default class Weight extends React.Component { } } // Update sim - if (this.state.timer != prevState.timer) { - if (!this.props.dataDoc['simulationPaused']) { - console.log('update') - let collisions = false; - if (!this.props.dataDoc['pendulum']) { - const collisionsWithGround = this.checkForCollisionsWithGround(); - const collisionsWithWalls = this.checkForCollisionsWithWall(); - collisions = collisionsWithGround || collisionsWithWalls; - } - if (!collisions) { - this.update(); - } - this.setDisplayValues(); + if (!this.props.dataDoc['simulationPaused']) { + if (this.state.timer != prevState.timer) { + console.log('update sim') + console.log('update') + let collisions = false; + if (!this.props.dataDoc['pendulum']) { + const collisionsWithGround = this.checkForCollisionsWithGround(); + const collisionsWithWalls = this.checkForCollisionsWithWall(); + collisions = collisionsWithGround || collisionsWithWalls; + } + if (!collisions) { + this.update(); + } + this.setDisplayValues(); } } - this.weightStyle = { - backgroundColor: this.props.color, - borderStyle: "solid", - borderColor: this.state.dragging ? "lightblue" : "black", - position: "absolute" as "absolute", - left: this.state.xPosition + "px", - top: this.state.yPosition + "px", - width: 2 * this.props.radius + "px", - height: 2 * this.props.radius + "px", - borderRadius: 50 + "%", - display: "flex", - zIndex: 5, - justifyContent: "center", - alignItems: "center", - touchAction: "none", - }; - if (this.props.dataDoc['simulationReset'] != prevProps.dataDoc['simulationReset']) { + if (this.props.simulationReset != prevProps.simulationReset) { + console.log('reset sim') this.resetEverything(); } - if (this.props.dataDoc['startForces'] != prevProps.dataDoc['startForces']) { - this.setState({xVelocity: this.props.startVelX ?? 0}) - this.setState({yVelocity: this.props.startVelY ?? 0}) - this.setDisplayValues(); - } - if (this.props.dataDoc['adjustPendulumAngle'] != prevProps.dataDoc['adjustPendulumAngle']) { + if (this.props.adjustPendulumAngle != prevProps.adjustPendulumAngle) { + console.log('update angle') // Change pendulum angle based on input field let length = this.props.dataDoc['pendulumLength'] ?? 0; const x = @@ -222,18 +211,21 @@ export default class Weight extends React.Component { this.setState({updatedStartPosY: yPos}) } // Update x start position - if (this.props.dataDoc['startPosX'] != prevProps.dataDoc['startPosX']) { + if (this.props.startPosX != prevProps.startPosX) { + console.log('update start x pos') this.setState({updatedStartPosX: this.props.dataDoc['startPosX']}) this.setState({xPosition: this.props.dataDoc['startPosX']}) this.setXPosDisplay(this.props.dataDoc['startPosX']); } // Update y start position - if (this.props.dataDoc['startPosY'] != prevProps.dataDoc['startPosY']) { + if (this.props.startPosY != prevProps.startPosY) { + console.log('update start y pos') this.setState({updatedStartPosY: this.props.dataDoc['startPosY']}) this.setState({yPosition: this.props.dataDoc['startPosY']}) this.setYPosDisplay(this.props.dataDoc['startPosY']); } if (this.state.xVelocity != prevState.xVelocity) { + console.log('check for kinetic friction') if (this.props.dataDoc['wedge'] && this.state.xVelocity != 0 && !this.state.kineticFriction) { this.setState({kineticFriction: true}); //switch from static to kinetic friction @@ -276,6 +268,23 @@ export default class Weight extends React.Component { } } } + + this.weightStyle = { + backgroundColor: this.props.color, + borderStyle: "solid", + borderColor: this.state.dragging ? "lightblue" : "black", + position: "absolute" as "absolute", + left: this.state.xPosition + "px", + top: this.state.yPosition + "px", + width: 2 * this.props.radius + "px", + height: 2 * this.props.radius + "px", + borderRadius: 50 + "%", + display: "flex", + zIndex: 5, + justifyContent: "center", + alignItems: "center", + touchAction: "none", + }; } resetEverything = () => { -- cgit v1.2.3-70-g09d2 From a9b9c26764cae849af16078796578db53a180be4 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Sat, 18 Feb 2023 10:20:58 -0500 Subject: debugging --- src/client/views/nodes/PhysicsSimulationWeight.tsx | 75 +++++++++++----------- 1 file changed, 37 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index fc75fa5aa..f7755dc5c 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -35,14 +35,14 @@ interface IState { clickPositionY: number, dragging: boolean, kineticFriction: boolean, + timer: number; + update: boolean, updatedStartPosX: number, updatedStartPosY: number, - timer: number; xPosition: number, - yPosition: number, xVelocity: number, + yPosition: number, yVelocity: number, - update: boolean, } export default class Weight extends React.Component { @@ -57,8 +57,8 @@ export default class Weight extends React.Component { updatedStartPosX: this.props.dataDoc['startPosX'], updatedStartPosY: this.props.dataDoc['startPosY'], xPosition: this.props.dataDoc['startPosX'], - yPosition: this.props.dataDoc['startPosY'], xVelocity: this.props.startVelX ? this.props.startVelX: 0, + yPosition: this.props.dataDoc['startPosY'], yVelocity: this.props.startVelY ? this.props.startVelY: 0, } } @@ -74,20 +74,20 @@ export default class Weight extends React.Component { // Var weightStyle = { + alignItems: "center", backgroundColor: this.props.color, - borderStyle: "solid", borderColor: "black", - position: "absolute" as "absolute", - left: this.props.dataDoc['startPosX'] + "px", - top: this.props.dataDoc['startPosY'] + "px", - width: 2 * this.props.radius + "px", - height: 2 * this.props.radius + "px", - zIndex: 5, borderRadius: 50 + "%", + borderStyle: "solid", display: "flex", + height: 2 * this.props.radius + "px", justifyContent: "center", - alignItems: "center", + left: this.props.dataDoc['startPosX'] + "px", + position: "absolute" as "absolute", + top: this.props.dataDoc['startPosY'] + "px", touchAction: "none", + width: 2 * this.props.radius + "px", + zIndex: 5, }; // Helper function to go between display and real values @@ -174,20 +174,18 @@ export default class Weight extends React.Component { } } // Update sim - if (!this.props.dataDoc['simulationPaused']) { - if (this.state.timer != prevState.timer) { - console.log('update sim') - console.log('update') - let collisions = false; - if (!this.props.dataDoc['pendulum']) { - const collisionsWithGround = this.checkForCollisionsWithGround(); - const collisionsWithWalls = this.checkForCollisionsWithWall(); - collisions = collisionsWithGround || collisionsWithWalls; - } - if (!collisions) { - this.update(); - } - this.setDisplayValues(); + if (this.state.timer != prevState.timer) { + if (!this.props.dataDoc['simulationPaused']) { + let collisions = false; + if (!this.props.dataDoc['pendulum']) { + const collisionsWithGround = this.checkForCollisionsWithGround(); + const collisionsWithWalls = this.checkForCollisionsWithWall(); + collisions = collisionsWithGround || collisionsWithWalls; + } + if (!collisions) { + this.update(); + } + this.setDisplayValues(); } } @@ -270,20 +268,20 @@ export default class Weight extends React.Component { } this.weightStyle = { + alignItems: "center", backgroundColor: this.props.color, - borderStyle: "solid", borderColor: this.state.dragging ? "lightblue" : "black", - position: "absolute" as "absolute", - left: this.state.xPosition + "px", - top: this.state.yPosition + "px", - width: 2 * this.props.radius + "px", - height: 2 * this.props.radius + "px", borderRadius: 50 + "%", + borderStyle: "solid", display: "flex", - zIndex: 5, + height: 2 * this.props.radius + "px", justifyContent: "center", - alignItems: "center", + left: this.state.xPosition + "px", + position: "absolute" as "absolute", + top: this.state.yPosition + "px", touchAction: "none", + width: 2 * this.props.radius + "px", + zIndex: 5, }; } @@ -375,6 +373,7 @@ export default class Weight extends React.Component { const maxX = this.state.xPosition + 2 * this.props.radius; const containerWidth = 300; if (this.state.xVelocity != 0) { + if (this.props.dataDoc.wallPositions) { this.props.dataDoc['wallPositions'].forEach((wall) => { if (wall.angleInDegrees == 90) { const wallX = (wall.xPos / 100) * 300; @@ -401,6 +400,7 @@ export default class Weight extends React.Component { } } }); + } } return collision; }; @@ -409,7 +409,8 @@ export default class Weight extends React.Component { let collision = false; const maxY = this.state.yPosition + 2 * this.props.radius; if (this.state.yVelocity > 0) { - this.props.dataDoc['wallPositions'] .forEach((wall) => { + if (this.props.dataDoc.wallPositions) { + this.props.dataDoc['wallPositions'].forEach((wall) => { if (wall.angleInDegrees == 0) { const groundY = (wall.yPos / 100) * this.props.yMax; if (maxY >= groundY) { @@ -434,6 +435,7 @@ export default class Weight extends React.Component { } } }); + } } return collision; }; @@ -505,9 +507,6 @@ export default class Weight extends React.Component { }; - - - labelBackgroundColor = `rgba(255,255,255,0.5)`; render () { -- cgit v1.2.3-70-g09d2 From 1bffa19d7b2c085a2f647a0269acdc05630d5146 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Sat, 18 Feb 2023 15:00:46 -0500 Subject: debugging --- src/client/views/nodes/PhysicsSimulationBox.tsx | 67 +++++++++-------- src/client/views/nodes/PhysicsSimulationWeight.tsx | 87 +++++++++++----------- 2 files changed, 78 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index e7d5e48f0..0f2bc43a0 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -7,6 +7,7 @@ import "./PhysicsSimulationBox.scss"; import Weight from "./PhysicsSimulationWeight"; import Wall from "./PhysicsSimulationWall" import Wedge from "./PhysicsSimulationWedge" +import { isUndefined } from "lodash"; export interface IForce { description: string; @@ -55,32 +56,6 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { @@ -292,12 +298,6 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentTYPE)}
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index f7755dc5c..e77cfa96a 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -190,7 +190,6 @@ export default class Weight extends React.Component { } if (this.props.simulationReset != prevProps.simulationReset) { - console.log('reset sim') this.resetEverything(); } if (this.props.adjustPendulumAngle != prevProps.adjustPendulumAngle) { @@ -210,59 +209,58 @@ export default class Weight extends React.Component { } // Update x start position if (this.props.startPosX != prevProps.startPosX) { - console.log('update start x pos') this.setState({updatedStartPosX: this.props.dataDoc['startPosX']}) this.setState({xPosition: this.props.dataDoc['startPosX']}) this.setXPosDisplay(this.props.dataDoc['startPosX']); } // Update y start position if (this.props.startPosY != prevProps.startPosY) { - console.log('update start y pos') this.setState({updatedStartPosY: this.props.dataDoc['startPosY']}) this.setState({yPosition: this.props.dataDoc['startPosY']}) this.setYPosDisplay(this.props.dataDoc['startPosY']); } - if (this.state.xVelocity != prevState.xVelocity) { - console.log('check for kinetic friction') - if (this.props.dataDoc['wedge'] && this.state.xVelocity != 0 && !this.state.kineticFriction) { - this.setState({kineticFriction: true}); - //switch from static to kinetic friction - const normalForce: IForce = { - description: "Normal Force", - magnitude: - this.forceOfGravity.magnitude * - Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), - directionInDegrees: - 180 - 90 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, - }; - let frictionForce: IForce = { - description: "Kinetic Friction Force", - magnitude: - this.props.dataDoc['coefficientOfKineticFriction'] * - this.forceOfGravity.magnitude * - Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), - directionInDegrees: - 180 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, - }; - // reduce magnitude of friction force if necessary such that block cannot slide up plane - let yForce = -this.forceOfGravity.magnitude; - yForce += - normalForce.magnitude * - Math.sin((normalForce.directionInDegrees * Math.PI) / 180); - yForce += - frictionForce.magnitude * - Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - if (yForce > 0) { - frictionForce.magnitude = - (-normalForce.magnitude * - Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + - this.forceOfGravity.magnitude) / + if (!this.props.dataDoc['simulationPaused']) { + if (this.state.xVelocity != prevState.xVelocity) { + if (this.props.dataDoc['wedge'] && this.state.xVelocity != 0 && !this.state.kineticFriction) { + this.setState({kineticFriction: true}); + //switch from static to kinetic friction + const normalForce: IForce = { + description: "Normal Force", + magnitude: + this.forceOfGravity.magnitude * + Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), + directionInDegrees: + 180 - 90 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, + }; + let frictionForce: IForce = { + description: "Kinetic Friction Force", + magnitude: + this.props.dataDoc['coefficientOfKineticFriction'] * + this.forceOfGravity.magnitude * + Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), + directionInDegrees: + 180 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, + }; + // reduce magnitude of friction force if necessary such that block cannot slide up plane + let yForce = -this.forceOfGravity.magnitude; + yForce += + normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180); + yForce += + frictionForce.magnitude * Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - } - if (this.props.dataDoc['coefficientOfKineticFriction'] != 0) { - this.props.dataDoc['updatedForces'] = [this.forceOfGravity, normalForce, frictionForce]; - } else { - this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, normalForce]); + if (yForce > 0) { + frictionForce.magnitude = + (-normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + + this.forceOfGravity.magnitude) / + Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + } + if (this.props.dataDoc['coefficientOfKineticFriction'] != 0) { + this.props.dataDoc['updatedForces'] = [this.forceOfGravity, normalForce, frictionForce]; + } else { + this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, normalForce]); + } } } } @@ -503,6 +501,9 @@ export default class Weight extends React.Component { this.setState({yVelocity: yVel}); this.setState({xPosition: xPos}); this.setState({yPosition: yPos}); + + console.log("start forces" this.props.dataDoc['startForces']) + console.log("updated forces" this.props.dataDoc['updatedForces']) this.props.dataDoc['updatedForces'] = (this.getNewForces(xPos, yPos, xVel, yVel)); }; -- cgit v1.2.3-70-g09d2 From 57be7b707694fcc3a2a7a6da6c8cd7782e4eb088 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Sat, 18 Feb 2023 19:17:12 -0500 Subject: debugging pendulum --- src/client/views/nodes/PhysicsSimulationWeight.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index e77cfa96a..7c26334bf 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -31,6 +31,7 @@ export interface IWeightProps { } interface IState { + angleLabel: number, clickPositionX: number, clickPositionY: number, dragging: boolean, @@ -54,6 +55,7 @@ export default class Weight extends React.Component { dragging: false, kineticFriction: false, timer: 0, + angleLabel: 0, updatedStartPosX: this.props.dataDoc['startPosX'], updatedStartPosY: this.props.dataDoc['startPosY'], xPosition: this.props.dataDoc['startPosX'], @@ -206,6 +208,7 @@ export default class Weight extends React.Component { this.setState({yPosition: yPos}) this.setState({updatedStartPosX: xPos}) this.setState({updatedStartPosY: yPos}) + this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle'] * 100) / 100}) } // Update x start position if (this.props.startPosX != prevProps.startPosX) { @@ -353,6 +356,7 @@ export default class Weight extends React.Component { magnitude: mag, directionInDegrees: angle, }; + this.setState({angleLabel: Math.round(oppositeAngle * 100) / 100}) return [this.forceOfGravity, forceOfTension]; }; @@ -502,8 +506,6 @@ export default class Weight extends React.Component { this.setState({xPosition: xPos}); this.setState({yPosition: yPos}); - console.log("start forces" this.props.dataDoc['startForces']) - console.log("updated forces" this.props.dataDoc['updatedForces']) this.props.dataDoc['updatedForces'] = (this.getNewForces(xPos, yPos, xVel, yVel)); }; @@ -630,7 +632,7 @@ export default class Weight extends React.Component { backgroundColor: this.labelBackgroundColor, }} > - {Math.round(this.props.dataDoc['pendulumAngle'] * 100) / 100}° + {this.state.angleLabel}°

)} -- cgit v1.2.3-70-g09d2 From b8762e80e3fd6b1c78b62f6bd50acb2029a68f58 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Mon, 20 Feb 2023 13:46:55 -0500 Subject: start sim settings menu --- src/client/views/nodes/PhysicsSimulationBox.scss | 16 +++++ src/client/views/nodes/PhysicsSimulationBox.tsx | 73 +++++++++++++++++++--- src/client/views/nodes/PhysicsSimulationWeight.tsx | 1 - 3 files changed, 80 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss index cfe2ee6ca..9efe835a3 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.scss +++ b/src/client/views/nodes/PhysicsSimulationBox.scss @@ -49,3 +49,19 @@ button { user-select: none; pointer-events: none; } + +.mechanicsSimulationSettingsMenu { + width: 100%; + height: 100%; + font-size: 12px; + background-color: purple; + border-radius: 2px; + border-color: black; + border-style: solid; + z-index: 20000; +} + +.mechanicsSimulationSettingsMenuRow { + display: flex; + z-index: 20000; +} \ No newline at end of file diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index 0f2bc43a0..b7f4ed0fb 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -7,8 +7,8 @@ import "./PhysicsSimulationBox.scss"; import Weight from "./PhysicsSimulationWeight"; import Wall from "./PhysicsSimulationWall" import Wedge from "./PhysicsSimulationWedge" -import { isUndefined } from "lodash"; - +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { CheckBox } from "../search/CheckBox"; export interface IForce { description: string; magnitude: number; @@ -53,6 +53,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent )}
-
- {/* {this.dataDoc.wallPositions && ( - {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { + {/*
+ {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { return (
); })} - )} */} -
+
*/}
+
+ {this.menuIsOpen && ( +
+
{this.menuIsOpen = false}}> + +
+

Simulation Settings

+ {this.dataDoc.simulationType == "Free Weight" && +
+

Elastic collisions

+ {this.dataDoc.elasticCollisions = val}} originalStatus={this.dataDoc.elasticCollisions} /> +
+ } + {/* {this.dataDoc.simulationType == "Inclined Plane" && +
+

Inclined plane angle

+

input field!

+
+ } + {this.dataDoc.simulationType == "Pendulum" && +
+

Pendulum angle

+

input field!

+
+ } +
+

Show forces

+ + this.dataDoc.showForces = !this.dataDoc.showForces + } + /> +
+
+

Show acceleration

+ + this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration + } + /> +
+
+

Show velocity

+ + this.dataDoc.showVelocity = !this.dataDoc.showVelocity + } + /> +
*/} +
+ )} +
@@ -395,6 +449,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentTYPE)} +
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index 7c26334bf..b9fa14df0 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -840,7 +840,6 @@ export default class Weight extends React.Component { position: "absolute", left: labelLeft + "px", top: labelTop + "px", - // zIndex: -1, lineHeight: 0.5, backgroundColor: this.labelBackgroundColor, }} -- cgit v1.2.3-70-g09d2 From 0fd4eb6a8bf80861345633aabe6d482c24cb4d70 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Tue, 21 Feb 2023 12:07:39 -0500 Subject: settings menu --- src/client/views/nodes/PhysicsSimulationBox.tsx | 45 ++++++++-------------- src/client/views/nodes/PhysicsSimulationWeight.tsx | 4 +- 2 files changed, 17 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index b7f4ed0fb..f0e009deb 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -361,14 +361,14 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent {this.menuIsOpen && (
-
{this.menuIsOpen = false}}> - +
{this.menuIsOpen = false; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}} style={{zIndex: 20000}}> +
-

Simulation Settings

+

Simulation Settings

{this.dataDoc.simulationType == "Free Weight" &&
-

Elastic collisions

- {this.dataDoc.elasticCollisions = val}} originalStatus={this.dataDoc.elasticCollisions} /> +

Elastic collisions

+ {this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/>
} {/* {this.dataDoc.simulationType == "Inclined Plane" && @@ -376,40 +376,25 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentInclined plane angle

input field!

- } - {this.dataDoc.simulationType == "Pendulum" && + } */} + {/* {this.dataDoc.simulationType == "Pendulum" &&

Pendulum angle

input field!

- } + } */}
-

Show forces

- - this.dataDoc.showForces = !this.dataDoc.showForces - } - /> +

Show forces

+ {this.dataDoc.showForces = !this.dataDoc.showForces}}/>
-

Show acceleration

- - this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration - } - /> +

Show acceleration

+ {this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/>
-

Show velocity

- - this.dataDoc.showVelocity = !this.dataDoc.showVelocity - } - /> -
*/} +

Show velocity

+ {this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/> +
)}
diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index b9fa14df0..66af645b5 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -769,12 +769,12 @@ export default class Weight extends React.Component { let arrowEndY: number = arrowStartY - Math.abs(force.magnitude) * - 20 * + 10 * Math.sin((force.directionInDegrees * Math.PI) / 180); const arrowEndX: number = arrowStartX + Math.abs(force.magnitude) * - 20 * + 10 * Math.cos((force.directionInDegrees * Math.PI) / 180); let color = "#0d0d0d"; -- cgit v1.2.3-70-g09d2 From 0f03110bab8d4636d33abf7568bf7c6cb14847b4 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Tue, 21 Feb 2023 16:10:23 -0500 Subject: settings menu --- src/client/views/nodes/PhysicsSimulationBox.scss | 17 +++++++---- src/client/views/nodes/PhysicsSimulationBox.tsx | 36 +++++++++++------------- 2 files changed, 28 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss index 9efe835a3..7573f1472 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.scss +++ b/src/client/views/nodes/PhysicsSimulationBox.scss @@ -40,7 +40,7 @@ tr:nth-child(even) { } button { - z-index: 5000; + z-index: 50; } .angleLabel { @@ -54,14 +54,21 @@ button { width: 100%; height: 100%; font-size: 12px; - background-color: purple; + background-color: rgb(224, 224, 224); border-radius: 2px; border-color: black; border-style: solid; - z-index: 20000; + padding: 10px; + position: fixed; + z-index: 1000; } -.mechanicsSimulationSettingsMenuRow { +.mechanicsSimulationSettingsMenuColumn { + display: flex; + flex-direction: column; + width: 50%; +} + +.mechanicsSimulationSettingsMenuContents { display: flex; - z-index: 20000; } \ No newline at end of file diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index f0e009deb..7eb9092bf 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -361,16 +361,24 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent {this.menuIsOpen && (
-
{this.menuIsOpen = false; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}} style={{zIndex: 20000}}> - +
{this.menuIsOpen = false; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}}> +
-

Simulation Settings

- {this.dataDoc.simulationType == "Free Weight" && -
-

Elastic collisions

- {this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/> +

Simulation Settings

+
+
+

Show forces

+

Show acceleration

+

Show velocity

+ {this.dataDoc.simulationType == "Free Weight" &&

Elastic collisions

} +
+
+
{this.dataDoc.showForces = !this.dataDoc.showForces}}/>
+
{this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/>
+
{this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/>
+ {this.dataDoc.simulationType == "Free Weight" &&
{this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/>
}
- } +
{/* {this.dataDoc.simulationType == "Inclined Plane" &&

Inclined plane angle

@@ -383,18 +391,6 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentinput field!

} */} -
-

Show forces

- {this.dataDoc.showForces = !this.dataDoc.showForces}}/> -
-
-

Show acceleration

- {this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/> -
-
-

Show velocity

- {this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/> -
)}
-- cgit v1.2.3-70-g09d2 From 9a5f2e9d098d0ad2db1be90818b6295390a60501 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Wed, 22 Feb 2023 14:29:44 -0500 Subject: pendulum angle --- src/client/views/nodes/PhysicsSimulationBox.scss | 8 +-- src/client/views/nodes/PhysicsSimulationBox.tsx | 76 ++++++++++++++++------ src/client/views/nodes/PhysicsSimulationWeight.tsx | 3 +- 3 files changed, 61 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss index 7573f1472..0f05010b4 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.scss +++ b/src/client/views/nodes/PhysicsSimulationBox.scss @@ -63,12 +63,10 @@ button { z-index: 1000; } -.mechanicsSimulationSettingsMenuColumn { +.mechanicsSimulationSettingsMenuRow { display: flex; - flex-direction: column; - width: 50%; } -.mechanicsSimulationSettingsMenuContents { - display: flex; +.mechanicsSimulationSettingsMenuRowDescription { + width: 50%; } \ No newline at end of file diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index 7eb9092bf..1a64ec795 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -119,6 +119,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent {this.dataDoc.weight && (

Simulation Settings

-
-
-

Show forces

-

Show acceleration

-

Show velocity

- {this.dataDoc.simulationType == "Free Weight" &&

Elastic collisions

} -
-
-
{this.dataDoc.showForces = !this.dataDoc.showForces}}/>
-
{this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/>
-
{this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/>
- {this.dataDoc.simulationType == "Free Weight" &&
{this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/>
} -
+
+

Show forces

+
{this.dataDoc.showForces = !this.dataDoc.showForces}}/>
+
+
+

Show acceleration

+
{this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/>
+
+
+

Show velocity

+
{this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/>
+
+
+ {this.dataDoc.simulationType == "Free Weight" &&
+

Elastic collisions

+
{this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/>
+
} + {this.dataDoc.simulationType == "Pendulum" &&
+

Pendulum start angle

+
+ { + let angle = e.target.value; + if (angle > 35) { + angle = 35 + } + if (angle < 0) { + angle = 0 + } + let length = this.xMax*0.7; + let x = length * Math.cos(((90 - angle) * Math.PI) / 180); + let y = length * Math.sin(((90 - angle) * Math.PI) / 180); + let xPos = this.xMax / 2 - x - this.radius; + let yPos = y - this.radius; + this.dataDoc.startPosX = xPos; + this.dataDoc.startPosY = yPos; + let mag = 9.81 * Math.cos((angle * Math.PI) / 180); + this.dataDoc.pendulumAngle = angle; + this.dataDoc.pendulumLength = length; + this.dataDoc.startPendulumAngle = angle; + this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle; + }} + /> +
+
} {/* {this.dataDoc.simulationType == "Inclined Plane" &&

Inclined plane angle

input field!

} */} - {/* {this.dataDoc.simulationType == "Pendulum" && -
-

Pendulum angle

-

input field!

-
- } */}
)} diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index 66af645b5..9aa5a6aab 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -293,6 +293,7 @@ export default class Weight extends React.Component { this.setState({xVelocity: this.props.startVelX ?? 0}) this.setState({yVelocity: this.props.startVelY ?? 0}) this.props.dataDoc['updatedForces'] = (this.props.dataDoc['startForces']) + this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle']* 100) / 100}) this.setDisplayValues(); }; @@ -356,7 +357,7 @@ export default class Weight extends React.Component { magnitude: mag, directionInDegrees: angle, }; - this.setState({angleLabel: Math.round(oppositeAngle * 100) / 100}) + this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle']* 100) / 100}) return [this.forceOfGravity, forceOfTension]; }; -- cgit v1.2.3-70-g09d2 From 4c0336f3d7380595f9a5e074ec8c0e31f061a709 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Wed, 22 Feb 2023 14:38:26 -0500 Subject: wedge angle --- src/client/views/nodes/PhysicsSimulationBox.tsx | 31 ++++++++++++++++++------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index 1a64ec795..2db49de3c 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -194,8 +194,6 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentShow velocity

{this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/>
-
+
{this.dataDoc.simulationType == "Free Weight" &&

Elastic collisions

{this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/>
@@ -421,12 +419,29 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
} - {/* {this.dataDoc.simulationType == "Inclined Plane" && -
-

Inclined plane angle

-

input field!

+ {this.dataDoc.simulationType == "Inclined Plane" &&
+

Inclined plane angle

+
+ { + let angle = e.target.value ?? 0 + if (angle > 70) { + angle = 70 + } + if (angle < 0) { + angle = 0 + } + this.dataDoc.wedgeAngle = angle + this.changeWedgeBasedOnNewAngle(angle) + }} + />
- } */} +
}
)} -- cgit v1.2.3-70-g09d2 From dffb5bdfdcffc7e1f85888b7222468bfb95a05ac Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Wed, 22 Feb 2023 22:37:37 -0500 Subject: improvements --- src/client/views/nodes/PhysicsSimulationBox.tsx | 12 +- src/client/views/nodes/PhysicsSimulationWedge.tsx | 4 +- src/client/views/nodes/PhysicsSimulationWeight.tsx | 160 ++++++++++----------- 3 files changed, 88 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx index 2db49de3c..d0e854263 100644 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsSimulationBox.tsx @@ -271,8 +271,8 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent )} - {/*
- {this.dataDoc.wallPositions.map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { +
+ {(this.dataDoc.wallPositions ?? []).map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { return (
); })} -
*/} +
@@ -468,11 +468,13 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { } componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { - if (prevState.coordinates != this.state.coordinates) { - this.updateCoordinates(); - } if (prevProps.startHeight != this.props.startHeight || prevProps.startWidth != this.props.startWidth) { this.setState({angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth)}); + this.updateCoordinates(); } } diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx index 9aa5a6aab..39b3249e8 100644 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ b/src/client/views/nodes/PhysicsSimulationWeight.tsx @@ -518,86 +518,86 @@ export default class Weight extends React.Component {
{ - if (this.draggable) { - e.preventDefault(); - this.props.dataDoc['simulationPaused'] = true; - this.setState({dragging: true}); - this.setState({clickPositionX: e.clientX}) - this.setState({clickPositionY: e.clientY}) - } - }} - onPointerMove={(e) => { - e.preventDefault(); - if (this.state.dragging) { - let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; - if (newY > this.props.yMax - 2 * this.props.radius) { - newY = this.props.yMax - 2 * this.props.radius; - } - - let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; - if (newX > this.props.xMax - 2 * this.props.radius) { - newX = this.props.xMax - 2 * this.props.radius; - } else if (newX < 0) { - newX = 0; - } - this.setState({xPosition: newX}) - this.setState({yPosition: newY}) - this.setState({updatedStartPosX: newX}) - this.setState({updatedStartPosY: newY}) - this.props.dataDoc['positionYDisplay'] = Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100; - this.setState({clickPositionX: e.clientX}) - this.setState({clickPositionY: e.clientY}) - this.setDisplayValues(); - } - }} - onPointerUp={(e) => { - if (this.state.dragging) { - e.preventDefault(); - if (!this.props.dataDoc['pendulum']) { - this.resetEverything(); - } - this.setState({dragging: false}); - let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; - if (newY > this.props.yMax - 2 * this.props.radius) { - newY = this.props.yMax - 2 * this.props.radius; - } - - let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; - if (newX > this.props.xMax - 2 * this.props.radius) { - newX = this.props.xMax - 2 * this.props.radius; - } else if (newX < 0) { - newX = 0; - } - if (this.props.dataDoc['pendulum']) { - const x = this.props.xMax / 2 - newX - this.props.radius; - const y = newY + this.props.radius + 5; - let angle = (Math.atan(y / x) * 180) / Math.PI; - if (angle < 0) { - angle += 180; - } - let oppositeAngle = 90 - angle; - if (oppositeAngle < 0) { - oppositeAngle = 90 - (180 - angle); - } - - const pendulumLength = Math.sqrt(x * x + y * y); - this.props.dataDoc['pendulumAngle'] = oppositeAngle; - this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y); - const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180); - const forceOfTension: IForce = { - description: "Tension", - magnitude: mag, - directionInDegrees: angle, - }; - this.setState({kineticFriction: false}) - this.setState({xVelocity: this.props.startVelX ?? 0}) - this.setState({yVelocity: this.props.startVelY ?? 0}) - this.setDisplayValues(); - this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, forceOfTension]); - } - } - }} + // onPointerDown={(e) => { + // if (this.draggable) { + // e.preventDefault(); + // this.props.dataDoc['simulationPaused'] = true; + // this.setState({dragging: true}); + // this.setState({clickPositionX: e.clientX}) + // this.setState({clickPositionY: e.clientY}) + // } + // }} + // onPointerMove={(e) => { + // e.preventDefault(); + // if (this.state.dragging) { + // let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; + // if (newY > this.props.yMax - 2 * this.props.radius) { + // newY = this.props.yMax - 2 * this.props.radius; + // } + + // let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; + // if (newX > this.props.xMax - 2 * this.props.radius) { + // newX = this.props.xMax - 2 * this.props.radius; + // } else if (newX < 0) { + // newX = 0; + // } + // this.setState({xPosition: newX}) + // this.setState({yPosition: newY}) + // this.setState({updatedStartPosX: newX}) + // this.setState({updatedStartPosY: newY}) + // this.props.dataDoc['positionYDisplay'] = Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100; + // this.setState({clickPositionX: e.clientX}) + // this.setState({clickPositionY: e.clientY}) + // this.setDisplayValues(); + // } + // }} + // onPointerUp={(e) => { + // if (this.state.dragging) { + // e.preventDefault(); + // if (!this.props.dataDoc['pendulum']) { + // this.resetEverything(); + // } + // this.setState({dragging: false}); + // let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; + // if (newY > this.props.yMax - 2 * this.props.radius) { + // newY = this.props.yMax - 2 * this.props.radius; + // } + + // let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; + // if (newX > this.props.xMax - 2 * this.props.radius) { + // newX = this.props.xMax - 2 * this.props.radius; + // } else if (newX < 0) { + // newX = 0; + // } + // if (this.props.dataDoc['pendulum']) { + // const x = this.props.xMax / 2 - newX - this.props.radius; + // const y = newY + this.props.radius + 5; + // let angle = (Math.atan(y / x) * 180) / Math.PI; + // if (angle < 0) { + // angle += 180; + // } + // let oppositeAngle = 90 - angle; + // if (oppositeAngle < 0) { + // oppositeAngle = 90 - (180 - angle); + // } + + // const pendulumLength = Math.sqrt(x * x + y * y); + // this.props.dataDoc['pendulumAngle'] = oppositeAngle; + // this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y); + // const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180); + // const forceOfTension: IForce = { + // description: "Tension", + // magnitude: mag, + // directionInDegrees: angle, + // }; + // this.setState({kineticFriction: false}) + // this.setState({xVelocity: this.props.startVelX ?? 0}) + // this.setState({yVelocity: this.props.startVelY ?? 0}) + // this.setDisplayValues(); + // this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, forceOfTension]); + // } + // } + // }} >

{this.props.mass} kg

-- cgit v1.2.3-70-g09d2 From 62666034718378f4d970331665019b23659c1f3d Mon Sep 17 00:00:00 2001 From: srichman333 Date: Wed, 22 Mar 2023 17:01:17 -0400 Subject: visual changes to collaboration on doc and in PropertiesView --- package-lock.json | 609 +++++++------- report.20230313.165455.65490.0.001.json | 1294 +++++++++++++++++++++++++++++ src/client/views/DocumentDecorations.scss | 81 +- src/client/views/DocumentDecorations.tsx | 64 +- src/client/views/PropertiesView.scss | 70 +- src/client/views/PropertiesView.tsx | 96 ++- src/client/views/StyleProvider.tsx | 7 +- src/fields/util.ts | 4 +- 8 files changed, 1883 insertions(+), 342 deletions(-) create mode 100644 report.20230313.165455.65490.0.001.json (limited to 'src') diff --git a/package-lock.json b/package-lock.json index d1e9ce7fa..622733acf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1250,7 +1250,7 @@ "@types/bcrypt-nodejs": { "version": "0.0.30", "resolved": "https://registry.npmjs.org/@types/bcrypt-nodejs/-/bcrypt-nodejs-0.0.30.tgz", - "integrity": "sha1-TN2WtJKTs5MhIuS34pVD415rrlg=", + "integrity": "sha512-gSWCu7EOXhcM0FYM8tanV0deaX1VM07sgBS8dSUmgnAQ5/3Xn6k+mWF+ZfE+c/OCW14IVnNdTOKcHgvL78oDFQ==", "dev": true }, "@types/bezier-js": { @@ -2232,7 +2232,7 @@ "@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", + "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", "dev": true }, "@types/strip-json-comments": { @@ -2268,7 +2268,7 @@ "@types/typescript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/typescript/-/typescript-2.0.0.tgz", - "integrity": "sha1-xDNTnJi64oaCswfqp6D9IRW4PCg=", + "integrity": "sha512-WMEWfMISiJ2QKyk5/dSdgL0ZwP//PZj0jmDU0hMh51FmLq4WIYzjlngsUQZXejQL+QtkXJUOGjb3G3UCvgZuSQ==", "dev": true, "requires": { "typescript": "*" @@ -2602,7 +2602,7 @@ "Base64": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/Base64/-/Base64-0.2.1.tgz", - "integrity": "sha1-ujpCMHCOGGcFBl5mur3Uw1z2ACg=" + "integrity": "sha512-reGEWshDmTDQDsCec/HduOO9Wyj6yMOupMfhIf3ugN1TDlK2NQW4DDJSqNNtp380SNcvRfXtO8HSCQot0d0SMw==" }, "D": { "version": "1.0.0", @@ -2851,7 +2851,7 @@ "any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, "anymatch": { "version": "2.0.0", @@ -3004,7 +3004,7 @@ "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==" }, "arr-flatten": { "version": "1.1.0", @@ -3014,7 +3014,7 @@ "arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==" }, "array-back": { "version": "2.0.0", @@ -3116,7 +3116,7 @@ "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "array-includes": { "version": "3.1.6", @@ -3149,7 +3149,7 @@ "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==" }, "array.prototype.flat": { "version": "1.3.1", @@ -3226,7 +3226,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" }, "assertion-error": { "version": "1.1.0", @@ -3236,7 +3236,7 @@ "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==" }, "ast-types-flow": { "version": "0.0.7", @@ -3266,7 +3266,7 @@ "async-foreach": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", - "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=" + "integrity": "sha512-VUeSMD8nEGBWaZK4lizI1sf3yEC7pnAQ/mrI7pC2fBz2s/tq5jWWEngTwaf0Gruu/OoXRGLGg1XFqpYBiGTYJA==" }, "async-limiter": { "version": "1.0.1", @@ -3277,7 +3277,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "atob": { "version": "2.1.2", @@ -3327,7 +3327,7 @@ "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==" }, "aws4": { "version": "1.12.0", @@ -3405,7 +3405,7 @@ "babel": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel/-/babel-6.23.0.tgz", - "integrity": "sha1-0NHn2APpdHZb7qMjLU4VPA77kPQ=" + "integrity": "sha512-ZDcCaI8Vlct8PJ3DvmyqUz+5X2Ylz3ZuuItBe/74yXosk2dwyVo/aN7MCJ8HJzhnnJ+6yP4o+lDgG9MBe91DLA==" }, "babel-code-frame": { "version": "6.26.0", @@ -3530,12 +3530,12 @@ "babel-plugin-syntax-jsx": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" + "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==" }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", "requires": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" @@ -3608,7 +3608,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "requires": { "is-descriptor": "^1.0.0" } @@ -3644,7 +3644,7 @@ "base16": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz", - "integrity": "sha1-4pf2DX7BAUp6lxo568ipjAtoHnA=" + "integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==" }, "base64-arraybuffer": { "version": "0.1.4", @@ -3669,18 +3669,18 @@ "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, "bcrypt-nodejs": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz", - "integrity": "sha1-xgkX8m3CNWYVZsaBBhwwPCsohCs=" + "integrity": "sha512-NmTbLm867btBHCBZ222FQXkQKzecB0KG6pTXFa6NeTVZaSnLfCsx7EK2PL3J+kX8xJThUquEBbhimRCKKZX9zA==" }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "requires": { "tweetnacl": "^0.14.3" } @@ -3693,7 +3693,7 @@ "bezier-curve": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/bezier-curve/-/bezier-curve-1.0.0.tgz", - "integrity": "sha1-o9+v6rEqlMRicw1QeYxSqEBdc3k=" + "integrity": "sha512-h6uZJ6qdFfswS1rIRericgouhTeiVi/MnH10OKtCu2IZzXa+ZcjaxRLHY4u/evRsJcxYbbiNkgWQj2Z4UIcpEQ==" }, "bezier-js": { "version": "4.1.1", @@ -3832,7 +3832,7 @@ "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, "bootstrap": { "version": "4.6.2", @@ -3894,7 +3894,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { "is-extendable": "^0.1.0" } @@ -3939,7 +3939,7 @@ "browser-assert": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/browser-assert/-/browser-assert-1.2.1.tgz", - "integrity": "sha1-mqpaKox0aFwq4Fv+Ru/WBvBowgA=" + "integrity": "sha512-nfulgvOR6S4gt9UKCeGJOuSGBPGiFT6oQ/2UBnvTY/5aQ1PnksW72fhZkM30DzoRRv2WpwZf1vHHEr3mtuXIWQ==" }, "browser-process-hrtime": { "version": "1.0.0", @@ -3983,7 +3983,7 @@ "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" }, "buffer-equal-constant-time": { "version": "1.0.1", @@ -4009,7 +4009,7 @@ "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=", + "integrity": "sha512-5XD5cujru60ooKJ4sGZqoH5v2Xvgw7ezV54gJX/OnPkgDKoH3BnlMEi8xW6hl8xaEjxKHebgrsawroeZnGwIMA==", "requires": { "math-codegen": "^0.3.5" } @@ -4132,7 +4132,7 @@ "caller-callsite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", "requires": { "callsites": "^2.0.0" }, @@ -4140,14 +4140,14 @@ "callsites": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==" } } }, "caller-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", "requires": { "caller-callsite": "^2.0.0" } @@ -4215,7 +4215,7 @@ "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" }, "ccount": { "version": "2.0.1", @@ -4287,12 +4287,12 @@ "check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=" + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==" }, "child_process": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", - "integrity": "sha1-sffn/HPSXn/R1FWtyU4UODAYK1o=" + "integrity": "sha512-Wmza/JzL0SiWz7kl6MhIKT5ceIlnFPJX+lwUGj7Clhy5MMldsSoJR0+uvRzOS5Kv45Mq7t1PoE8TsOA9bzvb6g==" }, "chokidar": { "version": "2.1.8", @@ -4341,7 +4341,7 @@ "clamp": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz", - "integrity": "sha1-ZqDmQBGBbjcZaCj9yMjBRzEshjQ=" + "integrity": "sha512-kgMuFyE78OC6Dyu3Dy7vcx4uy97EIbVxJB/B0eJ3bUNAkwdNcxYzgKltnyADiYwsR7SEqkkUPsEUT//OVS6XMA==" }, "class-transformer": { "version": "0.2.3", @@ -4362,7 +4362,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } @@ -4412,7 +4412,7 @@ "clipboard": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-1.7.1.tgz", - "integrity": "sha1-Ng1taUbpmnof7zleQrqStem1oWs=", + "integrity": "sha512-smkaRaIQsrnKN1F3wd1/vY9Q+DeR4L8ZCXKeHCFC2j8RZuSBbuImcLdnIO4GTxmzJxQuDGNKkyfpGoPW7Ua5bQ==", "requires": { "good-listener": "^1.2.2", "select": "^1.1.2", @@ -4487,7 +4487,7 @@ "clj-fuzzy": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/clj-fuzzy/-/clj-fuzzy-0.3.3.tgz", - "integrity": "sha1-seU0MJHFIC28UlMoY+HEp4RX8D0=" + "integrity": "sha512-9cyh9A8+OphDZeKIG21MgyDHWDkWxTvagwvFLVjtdi6eToFENF7iDLlKwhHrnBQRSQwprKNhazG053nE/UgwfQ==" }, "clone-deep": { "version": "4.0.1", @@ -4522,7 +4522,7 @@ "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", "requires": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" @@ -4548,7 +4548,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "color-string": { "version": "1.9.1", @@ -4683,7 +4683,7 @@ "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true }, "debug": { @@ -4698,7 +4698,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -4706,7 +4706,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "concat-stream": { "version": "1.6.2", @@ -4772,7 +4772,7 @@ "connect-flash": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz", - "integrity": "sha1-2GMPJtlaf4UfmVax6MxnMvO2qjA=" + "integrity": "sha512-2rcfELQt/ZMP+SM/pG8PyhJRaLKp+6Hk2IUBNkEit09X+vwn3QsAL3ZbYtxUn7NVPzbMTSLRDhqe0B/eh30RYA==" }, "connect-history-api-fallback": { "version": "1.6.0", @@ -4830,7 +4830,7 @@ "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" }, "constantinople": { "version": "3.1.2", @@ -4911,7 +4911,7 @@ "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "cookies": { "version": "0.8.0", @@ -4956,7 +4956,7 @@ "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==" }, "copy-webpack-plugin": { "version": "4.6.0", @@ -5165,7 +5165,7 @@ "crypto-random-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" + "integrity": "sha512-GsVpkFPlycH7/fRR7Dhcmnoii54gV1nz7y4CWyeFS14N+JVBBhY+r8amRHE4BwSYal7BPTDp8isvAlCxyFt3Hg==" }, "css-box-model": { "version": "1.2.1", @@ -5178,7 +5178,7 @@ "css-color-keywords": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", - "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=" + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==" }, "css-in-js-utils": { "version": "2.0.1", @@ -5337,6 +5337,16 @@ "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", "dev": true }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, "d3-array": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.2.tgz", @@ -5471,7 +5481,7 @@ "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "requires": { "assert-plus": "^1.0.0" } @@ -5523,7 +5533,7 @@ "de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=" + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==" }, "debounce": { "version": "1.2.1", @@ -5541,7 +5551,7 @@ "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" }, "decode-named-character-reference": { "version": "1.0.2", @@ -5767,7 +5777,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "delegate": { "version": "3.2.0", @@ -5777,7 +5787,7 @@ "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, "denque": { "version": "1.5.1", @@ -5880,7 +5890,7 @@ "import-fresh": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", "requires": { "caller-path": "^2.0.0", "resolve-from": "^3.0.0" @@ -5915,7 +5925,7 @@ "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -5929,7 +5939,7 @@ "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==" }, "string-width": { "version": "4.2.3", @@ -6001,7 +6011,7 @@ "deps-regex": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deps-regex/-/deps-regex-0.1.4.tgz", - "integrity": "sha1-UYZnt2kUYKXn4KNBvnbrfOgJAYQ=" + "integrity": "sha512-3tzwGYogSJi8HoG93R5x9NrdefZQOXgHgGih/7eivloOq6yC6O+yoFxZnkgP661twvfILONfoKRdF9GQOGx2RA==" }, "dequal": { "version": "2.0.3", @@ -6206,7 +6216,7 @@ "double-bits": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/double-bits/-/double-bits-1.1.1.tgz", - "integrity": "sha1-WKu6RUlNpND6Nrc60RoobJGEscY=" + "integrity": "sha512-BCLEIBq0O/DWoA7BsCu/R+RP0ZXiowP8BhtJT3qeuuQEBpnS8LK/Wo6UTJQv6v8mK1fj8n90YziHLwGdM5whSg==" }, "duplexer3": { "version": "0.1.5", @@ -6245,7 +6255,7 @@ "dynamic-dedupe": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", - "integrity": "sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=", + "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", "dev": true, "requires": { "xtend": "^4.0.0" @@ -6254,7 +6264,7 @@ "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -6271,7 +6281,7 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "electron-to-chromium": { "version": "1.4.295", @@ -6300,7 +6310,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "encoding": { "version": "0.1.13", @@ -6559,6 +6569,28 @@ "is-symbol": "^1.0.2" } }, + "es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, "es6-promise": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", @@ -6570,6 +6602,7 @@ "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", "dev": true, "requires": { + "d": "^1.0.1", "ext": "^1.1.2" } }, @@ -6581,12 +6614,12 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "escodegen": { "version": "1.14.3", @@ -7906,7 +7939,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "event-target-shim": { "version": "5.0.1", @@ -7979,7 +8012,7 @@ "exeq": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/exeq/-/exeq-2.4.0.tgz", - "integrity": "sha1-Td8qaEZIxCeteZNJzzO9dTWPiEo=", + "integrity": "sha512-B648qbDS00nQZv9UQGLT5RbZm/5dNBX10F8oWeXcgpFHSLm1249u95t/3sn2wXdQjLhlF+edAECdshFtSr1K0Q==", "requires": { "bluebird": "^3.0.3", "native-or-bluebird": "^1.2.0" @@ -7988,7 +8021,7 @@ "exif": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/exif/-/exif-0.6.0.tgz", - "integrity": "sha1-YKYmaAdlQst+T1cZnUrG830sX0o=", + "integrity": "sha512-gEwM4uanNMfLnDNKclZ7jPEA99E3rpy4ntoS6QW8u6murZjl1o8qRaPdMoC46Syg3d9/QaET0bYKhWlTwJCPgg==", "requires": { "debug": "^2.2" }, @@ -8004,7 +8037,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -8016,7 +8049,7 @@ "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", "requires": { "debug": "^2.3.3", "define-property": "^0.2.5", @@ -8038,7 +8071,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } @@ -8046,7 +8079,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { "is-extendable": "^0.1.0" } @@ -8054,7 +8087,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -8137,7 +8170,7 @@ "express-flash": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/express-flash/-/express-flash-0.0.2.tgz", - "integrity": "sha1-I9GovPP5DXB5KOSJ+Whp7K0KzaI=", + "integrity": "sha512-QVUR0ZZRCaa8+iPHoUQaQJrQWcQuK/Q+19M7IUIdIEtvwhrA/ifHT7y1CVJI41YfGiOQnbGtn3uvd2vOdgu58A==", "requires": { "connect-flash": "0.1.x" } @@ -8194,7 +8227,7 @@ "expressjs": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/expressjs/-/expressjs-1.0.1.tgz", - "integrity": "sha1-IgMoRpoY31rWFeK3oM6ZXxf7ru8=" + "integrity": "sha512-eFnQ5bMJxTZ29XwRJPV8ee/OURBBMS6Fm+b5rvMMEyz6u2IxPEh2SRzMZt9WvgnV+SMLmnzkALE1DnGG1HxJCw==" }, "ext": { "version": "1.7.0", @@ -8221,7 +8254,7 @@ "extend-shallow": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -8285,7 +8318,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "requires": { "is-descriptor": "^1.0.0" } @@ -8293,7 +8326,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { "is-extendable": "^0.1.0" } @@ -8363,7 +8396,7 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" }, "fast-deep-equal": { "version": "3.1.3", @@ -8384,7 +8417,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "fast-text-encoding": { @@ -8439,7 +8472,7 @@ "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "requires": { "pend": "~1.2.0" } @@ -8447,7 +8480,7 @@ "ffmpeg": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/ffmpeg/-/ffmpeg-0.0.4.tgz", - "integrity": "sha1-HEYN+OfaUSf2LO70v6BsWciWMMs=", + "integrity": "sha512-3TgWUJJlZGQn+crJFyhsO/oNeRRnGTy6GhgS98oUCIfZrOW5haPPV7DUfOm3xJcHr5q3TJpjk2GudPutrNisRA==", "requires": { "when": ">= 0.0.1" } @@ -8494,7 +8527,7 @@ "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", "requires": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", @@ -8505,7 +8538,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { "is-extendable": "^0.1.0" } @@ -8515,7 +8548,7 @@ "filter-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz", - "integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs=" + "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==" }, "finalhandler": { "version": "1.2.0", @@ -8549,7 +8582,7 @@ "find": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/find/-/find-0.1.7.tgz", - "integrity": "sha1-yGyHrxqxjyIrvjjeyGy8dg0Wpvs=", + "integrity": "sha512-jPrupTOe/pO//3a9Ty2o4NqQCp0L46UG+swUnfFtdmtQVN8pEltKpAqR7Nuf6vWn0GBXx5w+R1MyZzqwjEIqdA==", "requires": { "traverse-chain": "~0.1.0" } @@ -8698,7 +8731,7 @@ "fluent-ffmpeg": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz", - "integrity": "sha1-yVLeIkD4EuvaCqgAbXd27irPfXQ=", + "integrity": "sha512-IZTB4kq5GK0DPp7sGQ0q/BWurGHffRtQQwVkiqDgeO6wYJLLV5ZhgNOQ65loZxxuPMKZKZcICCUnaGtlxBiR0Q==", "requires": { "async": ">=0.2.9", "which": "^1.1.1" @@ -8781,12 +8814,12 @@ "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==" }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==" }, "fork-ts-checker-webpack-plugin": { "version": "1.6.0", @@ -8840,7 +8873,7 @@ "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", "requires": { "map-cache": "^0.2.2" } @@ -8848,7 +8881,7 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, "from2": { "version": "2.3.0", @@ -8885,7 +8918,7 @@ "fs-extra": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", - "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", + "integrity": "sha512-waKu+1KumRhYv8D8gMRCKJGAMI9pRnPuEb1mvgYD0f7wBscg+h6bW4FDTmEZhB9VKxvoTtxW+Y7bnIlB7zja6Q==", "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0", @@ -8959,7 +8992,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { "version": "1.2.13", @@ -9132,7 +9165,7 @@ "get-func-name": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=" + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==" }, "get-intrinsic": { "version": "1.2.0", @@ -9176,12 +9209,12 @@ "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==" }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "requires": { "assert-plus": "^1.0.0" } @@ -9308,7 +9341,7 @@ "golden-layout": { "version": "1.5.9", "resolved": "https://registry.npmjs.org/golden-layout/-/golden-layout-1.5.9.tgz", - "integrity": "sha1-o5vB9qZ+b4hreXwBbdkk6UJrp38=", + "integrity": "sha512-iBXDQCXOTgUEQJo96zPbjDoy5bRIk9XW5l+q+pDgLnIyReqaa1aiQctNud4epsskyLt952BG521dew5Z1liSxA==", "requires": { "jquery": "*" } @@ -9316,7 +9349,7 @@ "good-listener": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", "requires": { "delegate": "^3.1.2" } @@ -9495,7 +9528,7 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==" }, "har-validator": { "version": "5.1.5", @@ -9557,7 +9590,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "has-property-descriptors": { "version": "1.0.0", @@ -9588,12 +9621,12 @@ "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", "requires": { "get-value": "^2.0.6", "has-values": "^1.0.0", @@ -9603,7 +9636,7 @@ "has-values": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", "requires": { "is-number": "^3.0.0", "kind-of": "^4.0.0" @@ -9617,7 +9650,7 @@ "kind-of": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", "requires": { "is-buffer": "^1.1.5" } @@ -9720,7 +9753,7 @@ "hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, "requires": { "inherits": "^2.0.1", @@ -9749,7 +9782,7 @@ "html": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/html/-/html-1.0.0.tgz", - "integrity": "sha1-pUT6nqVJK/s6LMqCEKEL57WvH2E=", + "integrity": "sha512-lw/7YsdKiP3kk5PnR1INY17iJuzdAtJewxr14ozKJWbbR97znovZ0mh+WEMZ8rjc3lgTK+ID/htTjuyGKB52Kw==", "requires": { "concat-stream": "^1.4.7" } @@ -9832,7 +9865,7 @@ "http-browserify": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/http-browserify/-/http-browserify-1.7.0.tgz", - "integrity": "sha1-M3la3nLfiKz7/TZ3PO/tp2RzWyA=", + "integrity": "sha512-Irf/LJXmE3cBzU1eaR4+NEX6bmVLqt1wkmDiA7kBwH7zmb0D8kBAXsDmQ88hhj/qv9iEZKlyGx/hrMcFi8sOHw==", "requires": { "Base64": "~0.2.0", "inherits": "~2.0.1" @@ -9846,7 +9879,7 @@ "http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", "dev": true }, "http-errors": { @@ -9893,7 +9926,7 @@ "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -9912,12 +9945,12 @@ "https": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https/-/https-1.0.0.tgz", - "integrity": "sha1-PDfHrhqO65ZpBKKtHpdaGUt+06Q=" + "integrity": "sha512-4EC57ddXrkaF0x83Oj8sM6SLQHAWXw90Skqu2M4AEWENZ3F02dFJE/GARA8igO79tcgYqGrD7ae4f5L3um2lgg==" }, "https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" }, "https-proxy-agent": { "version": "5.0.1", @@ -9969,7 +10002,7 @@ "icss-replace-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "integrity": "sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==", "dev": true }, "icss-utils": { @@ -10001,7 +10034,7 @@ "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=" + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==" }, "iink-js": { "version": "1.5.4", @@ -10045,7 +10078,7 @@ "image-size-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/image-size-stream/-/image-size-stream-1.1.0.tgz", - "integrity": "sha1-Ivou2mbG31AQh0bacUkmSy0l+Gs=", + "integrity": "sha512-N505B5FSy2Xf5l/Haef+99TwfJqTu40hnU560+rC0Cm6cxtwVz2yRFh9WpOk1YEjfv3dI0PgVYAH0hmXQmjDcw==", "requires": { "image-size": "github:netroy/image-size#da2c863807a3e9602617bdd357b0de3ab4a064c1", "readable-stream": "^1.0.33", @@ -10059,12 +10092,12 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -10075,14 +10108,14 @@ "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" } } }, "immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "import-fresh": { "version": "3.3.0", @@ -10110,7 +10143,7 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" }, "in-publish": { "version": "2.0.1", @@ -10133,7 +10166,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -10150,7 +10183,7 @@ "camelcase": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==" } } }, @@ -10504,7 +10537,7 @@ "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "integrity": "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A==", "requires": { "kind-of": "^3.0.2" }, @@ -10517,7 +10550,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -10546,7 +10579,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "is-bigint": { "version": "1.0.4", @@ -10602,7 +10635,7 @@ "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "integrity": "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg==", "requires": { "kind-of": "^3.0.2" }, @@ -10615,7 +10648,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -10650,7 +10683,7 @@ "is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==" }, "is-expression": { "version": "3.0.0", @@ -10676,7 +10709,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, "is-finite": { "version": "1.1.0", @@ -10686,7 +10719,7 @@ "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" }, "is-generator-function": { "version": "1.0.10", @@ -10707,7 +10740,7 @@ "is-in-browser": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", - "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" }, "is-installed-globally": { "version": "0.1.0", @@ -10737,7 +10770,7 @@ "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", "requires": { "kind-of": "^3.0.2" }, @@ -10750,7 +10783,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -10888,7 +10921,7 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" }, "is-url": { "version": "1.2.4", @@ -10943,17 +10976,17 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" }, "isomorphic-fetch": { "version": "2.2.1", @@ -10978,7 +11011,7 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, "its-set": { "version": "1.2.3", @@ -11060,7 +11093,7 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" }, "jsdom": { "version": "15.2.1", @@ -11186,7 +11219,7 @@ "json-css": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/json-css/-/json-css-1.5.6.tgz", - "integrity": "sha1-65ZPg0ouTqobwvaY/12wB6JsfAA=" + "integrity": "sha512-B/0T0OxZH9tSb93tXV6VOYtXqrPz/Vgz2QrCT/4NXen8HGElYkYr9V+8IrSVTMj/ftxa8cG1kcu7f3iAMlaFlQ==" }, "json-parse-better-errors": { "version": "1.0.2", @@ -11217,7 +11250,7 @@ "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" }, "json5": { "version": "1.0.2", @@ -11239,7 +11272,7 @@ "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", "requires": { "graceful-fs": "^4.1.6" } @@ -11469,7 +11502,7 @@ "klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", "requires": { "graceful-fs": "^4.1.9" } @@ -11614,22 +11647,22 @@ "lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==" }, "lodash.chunk": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", - "integrity": "sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw=" + "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==" }, "lodash.curry": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", - "integrity": "sha1-JI42By7ekGUB11lmIAqG2riyMXA=" + "integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==" }, "lodash.debounce": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz", - "integrity": "sha1-gSIRw3ipTMKdWqTjNGzwv846ffU=", + "integrity": "sha512-lcmJwMpdPAtChA4hfiwxTtgFeNAaow701wWUgVUqeD0XJF7vMXIN+bu/2FJSGxT0NUbZy9g9VFrlOFfPjl+0Ew==", "requires": { "lodash._getnative": "^3.0.0" } @@ -11637,27 +11670,27 @@ "lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" }, "lodash.difference": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" + "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==" }, "lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" }, "lodash.flow": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", - "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=" + "integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==" }, "lodash.get": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" }, "lodash.isequal": { "version": "4.5.0", @@ -11667,12 +11700,12 @@ "lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" }, "lodash.merge": { "version": "4.6.2", @@ -11693,12 +11726,12 @@ "lodash.throttle": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" }, "lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" + "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==" }, "log-symbols": { "version": "2.2.0", @@ -11854,7 +11887,7 @@ "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==" }, "map-obj": { "version": "1.0.1", @@ -11864,7 +11897,7 @@ "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", "requires": { "object-visit": "^1.0.0" } @@ -11914,7 +11947,7 @@ "math-codegen": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/math-codegen/-/math-codegen-0.3.5.tgz", - "integrity": "sha1-R5nuRnfe0Ud2bQA8ykt4ee3UDMo=", + "integrity": "sha512-SsFYMv33FxMKYxI1PBiaZT+8AeDITK+k/PKhbHNlOPHIz5FIPF4wy78yWqanN6luXdsXENUZgCIC6xH6bfUq1g==", "requires": { "extend": "^3.0.0", "mr-parser": "^0.2.1" @@ -12101,7 +12134,7 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, "memfs": { "version": "3.4.13", @@ -12152,7 +12185,7 @@ "memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=" + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==" }, "meow": { "version": "3.7.0", @@ -12182,7 +12215,7 @@ "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "merge-stream": { "version": "2.0.0", @@ -12193,7 +12226,7 @@ "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, "microevent.ts": { "version": "0.1.1", @@ -12757,7 +12790,7 @@ "he": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "integrity": "sha512-z/GDPjlRMNOa2XJiB4em8wJpuuBfrFOlYKTZxtpkdr1uPdibHI8rYA3MY0KDObpVyaes0e/aunid/t88ZI2EKA==", "dev": true }, "minimatch": { @@ -12787,7 +12820,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "supports-color": { @@ -12972,14 +13005,14 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, "mr-parser": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/mr-parser/-/mr-parser-0.2.1.tgz", - "integrity": "sha1-hhi5ukF+KOn0OaQcaVtVTq/u2Sc=" + "integrity": "sha512-hug+mpbSSKnH13rFqy3zm+XiG+QTStiDAgMTHK355TIstQE0qBkBtSJsa5YHP94AuarVX9b/4dcebdTRZ9YiEw==" }, "mri": { "version": "1.2.0", @@ -13049,7 +13082,7 @@ "native-or-bluebird": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/native-or-bluebird/-/native-or-bluebird-1.2.0.tgz", - "integrity": "sha1-OcR7/Xgl0fuf+tMiEK4l2q3xAck=" + "integrity": "sha512-0SH8UubxDfe382eYiwmd12qxAbiWGzlGZv6CkMA+DPojWa/Y0oH4hE0lRtFfFgJmPQFyKXeB8XxPbZz6TvvKaQ==" }, "natural-compare": { "version": "1.4.0", @@ -13076,7 +13109,7 @@ "nextafter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/nextafter/-/nextafter-1.0.0.tgz", - "integrity": "sha1-t9d7U1MQ4+CX5gJauwqQNHfsGjo=", + "integrity": "sha512-7PO+A89Tll2rSEfyrjtqO0MaI37+nnxBdnQcPypfbEYYuGaJxWGCqaOwQX4a3GHNTS08l1kazuiLEWZniZjMUQ==", "requires": { "double-bits": "^1.1.0" } @@ -13107,7 +13140,7 @@ "node-ensure": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/node-ensure/-/node-ensure-0.0.0.tgz", - "integrity": "sha1-7K52QVDemYYexcgQ/V0Jaxg5Mqc=" + "integrity": "sha512-DRI60hzo2oKN1ma0ckc6nQWlHU69RH6xN0sjQTjMpChPfTYvKZdcQFfdYK2RWbJcKyUizSIy/l8OTGxMAM1QDw==" }, "node-environment-flags": { "version": "1.0.5", @@ -17211,7 +17244,7 @@ "oauth": { "version": "0.9.15", "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", - "integrity": "sha1-vR/vr2hslrdUda7VGWQS/2DPucE=" + "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" }, "oauth-sign": { "version": "0.9.0", @@ -17221,12 +17254,12 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", "requires": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", @@ -17236,7 +17269,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } @@ -17249,7 +17282,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -17319,7 +17352,7 @@ "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", "requires": { "isobject": "^3.0.0" } @@ -17381,7 +17414,7 @@ "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", "requires": { "isobject": "^3.0.1" } @@ -17419,7 +17452,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "requires": { "wrappy": "1" } @@ -17486,7 +17519,7 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" }, "osenv": { "version": "0.1.5", @@ -17505,7 +17538,7 @@ "p-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-debounce/-/p-debounce-1.0.0.tgz", - "integrity": "sha1-y38svu/YegnrqGHhErZ1J+Yh4v0=" + "integrity": "sha512-ttOxn4Yt0hzIsLLqKi/Ry9QRxW+UQKdoWHz7g99Ci57zPkqUU3kbWKAeHuv+HfRLe109acYLUY6kuVCOOqnt4g==" }, "p-finally": { "version": "1.0.0", @@ -17682,7 +17715,7 @@ "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==" }, "passport": { "version": "0.4.1", @@ -17704,7 +17737,7 @@ "passport-local": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", - "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=", + "integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==", "requires": { "passport-strategy": "1.x.x" } @@ -17724,7 +17757,7 @@ "passport-strategy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", - "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==" }, "path-browserify": { "version": "1.0.1", @@ -17739,12 +17772,12 @@ "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==" }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-is-inside": { "version": "1.0.2", @@ -17754,7 +17787,7 @@ "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==" }, "path-parse": { "version": "1.0.7", @@ -17764,7 +17797,7 @@ "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "path-type": { "version": "4.0.0", @@ -17779,7 +17812,7 @@ "pause": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", - "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, "pdf-parse": { "version": "1.1.1", @@ -17827,7 +17860,7 @@ "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, "perfect-scrollbar": { "version": "1.5.5", @@ -17837,7 +17870,7 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, "picocolors": { "version": "1.0.0", @@ -17983,7 +18016,7 @@ "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==" }, "postcss": { "version": "7.0.39", @@ -18236,7 +18269,7 @@ "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==" }, "process-nextick-args": { "version": "2.0.1", @@ -18310,7 +18343,7 @@ "prosemirror-find-replace": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/prosemirror-find-replace/-/prosemirror-find-replace-0.9.0.tgz", - "integrity": "sha1-QgsENNF5xdBJD44hSNhVGpVJY4I=" + "integrity": "sha512-LfhQ/Zr0PkkJpCsr9vTJ5ZPYh49mSVVG+hHJ6djT+chlCW+t2ilSxBpBG+2IeE/I5nlbcvuLLAbxeI1g3pTCpA==" }, "prosemirror-history": { "version": "1.3.0", @@ -18415,7 +18448,7 @@ "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true }, "pseudomap": { @@ -18653,12 +18686,12 @@ "pure-color": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz", - "integrity": "sha1-H+Bk+wrIUfDeYTIKi/eWg2Qi8z4=" + "integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==" }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==" }, "qs": { "version": "6.5.3", @@ -18706,7 +18739,7 @@ "random-bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==" }, "randombytes": { "version": "2.1.0", @@ -18809,7 +18842,7 @@ "react-base16-styling": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.5.3.tgz", - "integrity": "sha1-OFjyTpxN2MvT9wLz901YHKKRcmk=", + "integrity": "sha512-EPuchwVvYPSFFIjGpH0k6wM0HQsmJ0vCk7BSl5ryxMVFIWW4hX4Kksu4PNtxfgOxDebTLkJQ8iC7zwAql0eusg==", "requires": { "base16": "^1.0.0", "lodash.curry": "^4.0.1", @@ -18878,7 +18911,7 @@ "react-dock": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/react-dock/-/react-dock-0.2.4.tgz", - "integrity": "sha1-5yfcdVCztzEWY13LnA4E0Lev4Xw=", + "integrity": "sha512-ywUJPC/TIM9PO700skka0fH4aqbrH8RojUXejZFvjtqlc5KZ+xjHqFdo4A3j+dp+0NLFZ3Nai4xzcf3FUJ9BsQ==", "requires": { "lodash.debounce": "^3.1.1", "prop-types": "^15.5.8" @@ -19216,7 +19249,7 @@ "react-themeable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/react-themeable/-/react-themeable-1.1.0.tgz", - "integrity": "sha1-fURm3ZsrX6dQWHJ4JenxUro3mg4=", + "integrity": "sha512-kl5tQ8K+r9IdQXZd8WLa+xxYN04lLnJXRVhHfdgwsUJr/SlKJxIejoc9z9obEkx1mdqbTw1ry43fxEUwyD9u7w==", "requires": { "object-assign": "^3.0.0" }, @@ -19224,7 +19257,7 @@ "object-assign": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=" + "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==" } } }, @@ -19365,12 +19398,12 @@ "readline": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/readline/-/readline-1.3.0.tgz", - "integrity": "sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw=" + "integrity": "sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg==" }, "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "requires": { "resolve": "^1.1.6" } @@ -19480,7 +19513,7 @@ "relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==" }, "remark-gfm": { "version": "3.0.1", @@ -19603,7 +19636,7 @@ "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" }, "repeating": { "version": "2.0.1", @@ -19712,7 +19745,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" }, "require-from-string": { "version": "2.0.2", @@ -19727,7 +19760,7 @@ "require-package-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/require-package-name/-/require-package-name-2.0.1.tgz", - "integrity": "sha1-wR6XJ2tluOKSP3Xav1+y7ww4Qbk=" + "integrity": "sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==" }, "require_optional": { "version": "1.0.1", @@ -19748,7 +19781,7 @@ "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, "resize-observer-polyfill": { "version": "1.5.1", @@ -19793,7 +19826,7 @@ "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==" }, "responselike": { "version": "3.0.0", @@ -19929,7 +19962,7 @@ "safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", "requires": { "ret": "~0.1.10" } @@ -20027,7 +20060,7 @@ "scss-loader": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/scss-loader/-/scss-loader-0.0.1.tgz", - "integrity": "sha1-6uAXueDzjBKlMtslwiC5Avs05nE=", + "integrity": "sha512-SbT/smRJjkvvdHSEdAYAplosVkrtaSwwgUlnQCOuDS5sOKNjrS/eYCMvKeV6+YxK5cCOCsOJZd3vltrXatFp+g==", "dev": true }, "scss-tokenizer": { @@ -20057,17 +20090,17 @@ "section-iterator": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/section-iterator/-/section-iterator-2.0.0.tgz", - "integrity": "sha1-v0RNev7rlK1Dw5rS+yYVFifMuio=" + "integrity": "sha512-xvTNwcbeDayXotnV32zLb3duQsP+4XosHpb/F+tu6VzEZFmIjzPdNk6/O+QOOx5XTh08KL2ufdXeCO33p380pQ==" }, "select": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", - "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=" + "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==" }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", "dev": true }, "selfsigned": { @@ -20087,7 +20120,7 @@ "semver-compare": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=" + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==" }, "semver-diff": { "version": "2.1.0", @@ -20156,7 +20189,7 @@ "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, "requires": { "accepts": "~1.3.4", @@ -20186,7 +20219,7 @@ "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "requires": { "depd": "~1.1.2", @@ -20198,13 +20231,13 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "setprototypeof": { @@ -20216,7 +20249,7 @@ "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true } } @@ -20235,7 +20268,7 @@ "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "set-value": { "version": "2.0.1", @@ -20251,7 +20284,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { "is-extendable": "^0.1.0" } @@ -20269,7 +20302,7 @@ "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" }, "setprototypeof": { "version": "1.2.0", @@ -20439,7 +20472,7 @@ "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "requires": { "shebang-regex": "^1.0.0" } @@ -20447,7 +20480,7 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==" }, "shelljs": { "version": "0.8.5", @@ -20482,7 +20515,7 @@ "simple-assign": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/simple-assign/-/simple-assign-0.1.0.tgz", - "integrity": "sha1-F/0wZqXz13OPUDIbsPFMooHMS6o=" + "integrity": "sha512-otdSSQzuVsmDoe5MnSm4ZgHd5sl0ak6A1CTjW1R/DUHQ8xoZuU1NUzf9x6n9Dvp3nxpvW51WNMQ/7rQ9432xDg==" }, "simple-concat": { "version": "1.0.1", @@ -20502,7 +20535,7 @@ "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", "requires": { "is-arrayish": "^0.3.1" }, @@ -20534,7 +20567,7 @@ "sliced": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==" }, "snapdragon": { "version": "0.8.2", @@ -20562,7 +20595,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } @@ -20570,7 +20603,7 @@ "extend-shallow": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", "requires": { "is-extendable": "^0.1.0" } @@ -20578,7 +20611,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -20595,7 +20628,7 @@ "define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", "requires": { "is-descriptor": "^1.0.0" } @@ -20644,7 +20677,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -20813,7 +20846,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" }, "source-map-resolve": { "version": "0.5.3", @@ -20856,7 +20889,7 @@ "sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", "optional": true, "requires": { "memory-pager": "^1.0.2" @@ -20972,7 +21005,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "sshpk": { "version": "1.17.0", @@ -21002,12 +21035,12 @@ "standard-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/standard-error/-/standard-error-1.1.0.tgz", - "integrity": "sha1-I+UWj6HAggGJ5YEnAaeQWFENDTQ=" + "integrity": "sha512-4v7qzU7oLJfMI5EltUSHCaaOd65J6S4BqKRWgzMi4EYaE5fvNabPxmAPGdxpGXqrcWjhDGI/H09CIdEuUOUeXg==" }, "standard-http-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/standard-http-error/-/standard-http-error-2.0.1.tgz", - "integrity": "sha1-+K6RcuPO+cs40ucIShkl9Xp8NL0=", + "integrity": "sha512-DX/xPIoyXQTuY6BMZK4Utyi4l3A4vFoafsfqrU6/dO4Oe/59c7PyqPd2IQj9m+ZieDg2K3RL9xOYJsabcD9IUA==", "requires": { "standard-error": ">= 1.1.0 < 2" } @@ -21015,7 +21048,7 @@ "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", "requires": { "define-property": "^0.2.5", "object-copy": "^0.1.0" @@ -21024,7 +21057,7 @@ "define-property": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", "requires": { "is-descriptor": "^0.1.0" } @@ -21063,7 +21096,7 @@ "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==" }, "stop-iteration-iterator": { "version": "1.0.0", @@ -21096,7 +21129,7 @@ "stream-parser": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", - "integrity": "sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M=", + "integrity": "sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==", "requires": { "debug": "2" }, @@ -21112,7 +21145,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -21125,7 +21158,7 @@ "strict-uri-encode": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==" }, "string-width": { "version": "2.1.1", @@ -21215,7 +21248,7 @@ "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", "requires": { "ansi-regex": "^3.0.0" } @@ -21251,7 +21284,7 @@ "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" }, "style-loader": { "version": "0.23.1", @@ -21458,7 +21491,7 @@ "temp-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", - "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=" + "integrity": "sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==" }, "tempy": { "version": "0.2.1", @@ -21540,7 +21573,7 @@ "through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, "through2": { "version": "2.0.5", @@ -21622,12 +21655,12 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", "requires": { "kind-of": "^3.0.2" }, @@ -21640,7 +21673,7 @@ "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", "requires": { "is-buffer": "^1.1.5" } @@ -21661,7 +21694,7 @@ "to-regex-range": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", "requires": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" @@ -21688,7 +21721,7 @@ "nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", "requires": { "abbrev": "1" } @@ -21709,7 +21742,7 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "translate-google-api": { "version": "1.0.4", @@ -21737,7 +21770,7 @@ "traverse-chain": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz", - "integrity": "sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE=" + "integrity": "sha512-up6Yvai4PYKhpNp5PkYtx50m3KbwQrqDwbuZP/ItyL64YEWHAvH6Md83LFLV/GRSk/BoUVwwgUzX6SOQSbsfAg==" }, "tree-kill": { "version": "1.2.2", @@ -21771,7 +21804,7 @@ "tryit": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", - "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=" + "integrity": "sha512-6C5h3CE+0qjGp+YKYTs74xR0k/Nw/ePtl/Lp6CCf44hqBQ66qnH1sDFR5mV/Gc48EsrHLB53lCFSffQCkka3kg==" }, "ts-loader": { "version": "5.4.5", @@ -21989,7 +22022,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true } } @@ -22115,7 +22148,7 @@ "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "requires": { "safe-buffer": "^5.0.1" } @@ -22123,7 +22156,13 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true }, "type-check": { "version": "0.4.0", @@ -22172,7 +22211,7 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, "typescript": { "version": "4.9.5", @@ -22217,7 +22256,7 @@ "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "requires": { "graceful-fs": "^4.1.6" } @@ -22329,7 +22368,7 @@ "unicode-trie": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-0.3.1.tgz", - "integrity": "sha1-1nHd3YkQGgi6w3tqUWEBBgIFIIU=", + "integrity": "sha512-WgVuO0M2jDl7hVfbPgXv2LUrD81HM0bQj/bvLGiw6fJ4Zo8nNFnDrA0/hU2Te/wz6pjxCm5cxJwtLjo2eyV51Q==", "requires": { "pako": "^0.2.5", "tiny-inflate": "^1.0.0" @@ -22338,7 +22377,7 @@ "pako": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" } } }, @@ -22388,7 +22427,7 @@ "unique-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "integrity": "sha512-ODgiYu03y5g76A1I9Gt0/chLCzQjvzDy7DsZGsLOE/1MrF6wriEskSncj1+/C58Xk/kPZDppSctDybCwOSaGAg==", "requires": { "crypto-random-string": "^1.0.0" } @@ -22461,12 +22500,12 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", "requires": { "has-value": "^0.3.1", "isobject": "^3.0.0" @@ -22475,7 +22514,7 @@ "has-value": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", "requires": { "get-value": "^2.0.3", "has-values": "^0.1.4", @@ -22485,7 +22524,7 @@ "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", "requires": { "isarray": "1.0.0" } @@ -22495,7 +22534,7 @@ "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==" } } }, @@ -22561,7 +22600,7 @@ "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==" }, "url": { "version": "0.11.0", @@ -22653,12 +22692,12 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "utila": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" }, "utility-types": { "version": "3.10.0", @@ -22668,7 +22707,7 @@ "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, "uuid": { "version": "3.4.0", @@ -22678,7 +22717,7 @@ "uuid-js": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/uuid-js/-/uuid-js-0.7.5.tgz", - "integrity": "sha1-bIhtAqU9LUDc8l2RoXC0p7JblNA=" + "integrity": "sha512-lJFducSMfVDO3E1wBe/zflgU25JbpX9KfF+g0k6OxIt9xeybdZd27n75vPg+4cLN55UKGjJ46w3K3q3l+8KgkQ==" }, "uvu": { "version": "0.5.6", @@ -22713,7 +22752,7 @@ "valid-url": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", - "integrity": "sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=" + "integrity": "sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==" }, "validate-npm-package-license": { "version": "3.0.4", @@ -22732,12 +22771,12 @@ "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -22873,7 +22912,7 @@ "warning": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", - "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "integrity": "sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==", "requires": { "loose-envify": "^1.0.0" } @@ -22905,7 +22944,7 @@ "web-request": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/web-request/-/web-request-1.0.7.tgz", - "integrity": "sha1-twxCs81FV3noLbaIYlOySR8r1Wk=", + "integrity": "sha512-mVySwo0f8FFw77ZCEEjZ93g7SqAvWREj15FefhJgPkkylu7b185N/u3Oa92sNpMdhjcErGB7oGpOkAAIvflSjw==", "requires": { "request": "^2.69.0" } @@ -22918,7 +22957,7 @@ "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "webpack": { "version": "5.75.0", @@ -23395,7 +23434,7 @@ "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -23404,7 +23443,7 @@ "when": { "version": "3.7.8", "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", - "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=" + "integrity": "sha512-5cZ7mecD3eYcMiCH4wtRPA5iFJZ50BJYDfckI5RRpQiktMiYTcn0ccLTZOvcbBume+1304fQztxeNzNS9Gvrnw==" }, "which": { "version": "1.3.1", @@ -23441,7 +23480,7 @@ "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==" }, "which-pm-runs": { "version": "1.1.0", @@ -23590,7 +23629,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "write": { "version": "1.0.3", @@ -23661,7 +23700,7 @@ "xoauth2": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/xoauth2/-/xoauth2-1.2.0.tgz", - "integrity": "sha1-8u76wRRyyXHqO8RuVU60sSMhRuU=" + "integrity": "sha512-hKuNbkj3q/ifCcfWnW6KURP+6ExSuLdLG007gasNhMEMKlLaejNkIA6eu5Ol1xPP0/kzTuA87XHDaAcUw5k73Q==" }, "xregexp": { "version": "4.4.1", @@ -23756,7 +23795,7 @@ "yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "requires": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" diff --git a/report.20230313.165455.65490.0.001.json b/report.20230313.165455.65490.0.001.json new file mode 100644 index 000000000..689fcf9eb --- /dev/null +++ b/report.20230313.165455.65490.0.001.json @@ -0,0 +1,1294 @@ + +{ + "header": { + "reportVersion": 1, + "event": "Allocation failed - JavaScript heap out of memory", + "trigger": "FatalError", + "filename": "report.20230313.165455.65490.0.001.json", + "dumpEventTime": "2023-03-13T16:54:55Z", + "dumpEventTimeStamp": "1678740895169", + "processId": 65490, + "cwd": "/Users/sarah/Desktop/dash/Dash-Web", + "commandLine": [ + "/Users/sarah/.nvm/versions/node/v12.16.0/bin/node", + "--max-old-space-size=2048", + "/Users/sarah/Desktop/dash/Dash-Web/node_modules/ts-node-dev/lib/wrap.js", + "/Users/sarah/Desktop/dash/Dash-Web/node_modules/fork-ts-checker-webpack-plugin/lib/service.js" + ], + "nodejsVersion": "v12.16.0", + "wordSize": 64, + "arch": "x64", + "platform": "darwin", + "componentVersions": { + "node": "12.16.0", + "v8": "7.8.279.23-node.31", + "uv": "1.34.0", + "zlib": "1.2.11", + "brotli": "1.0.7", + "ares": "1.15.0", + "modules": "72", + "nghttp2": "1.40.0", + "napi": "5", + "llhttp": "2.0.4", + "http_parser": "2.9.3", + "openssl": "1.1.1d", + "cldr": "35.1", + "icu": "64.2", + "tz": "2019c", + "unicode": "12.1" + }, + "release": { + "name": "node", + "lts": "Erbium", + "headersUrl": "https://nodejs.org/download/release/v12.16.0/node-v12.16.0-headers.tar.gz", + "sourceUrl": "https://nodejs.org/download/release/v12.16.0/node-v12.16.0.tar.gz" + }, + "osName": "Darwin", + "osRelease": "20.4.0", + "osVersion": "Darwin Kernel Version 20.4.0: Fri Mar 5 01:14:14 PST 2021; root:xnu-7195.101.1~3/RELEASE_X86_64", + "osMachine": "x86_64", + "cpus": [ + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 95972310, + "nice": 0, + "sys": 69742110, + "idle": 1132989220, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 1235990, + "nice": 0, + "sys": 1442360, + "idle": 1293767630, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 77301330, + "nice": 0, + "sys": 43426390, + "idle": 1175757970, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 1270620, + "nice": 0, + "sys": 1351190, + "idle": 1293823030, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 56966210, + "nice": 0, + "sys": 28908780, + "idle": 1210608910, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 1291530, + "nice": 0, + "sys": 1265830, + "idle": 1293886140, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 46074390, + "nice": 0, + "sys": 22963990, + "idle": 1227443730, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 1311400, + "nice": 0, + "sys": 1200930, + "idle": 1293929770, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 36059780, + "nice": 0, + "sys": 17309680, + "idle": 1243110810, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 1303400, + "nice": 0, + "sys": 1134770, + "idle": 1294002540, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 28665300, + "nice": 0, + "sys": 12769180, + "idle": 1255043860, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 1287310, + "nice": 0, + "sys": 1073720, + "idle": 1294078280, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 22112060, + "nice": 0, + "sys": 9084160, + "idle": 1265280170, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 1256320, + "nice": 0, + "sys": 1011250, + "idle": 1294170360, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 17120610, + "nice": 0, + "sys": 6395650, + "idle": 1272958030, + "irq": 0 + }, + { + "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", + "speed": 2300, + "user": 1227540, + "nice": 0, + "sys": 963060, + "idle": 1294245890, + "irq": 0 + } + ], + "networkInterfaces": [ + { + "name": "lo0", + "internal": true, + "mac": "00:00:00:00:00:00", + "address": "127.0.0.1", + "netmask": "255.0.0.0", + "family": "IPv4" + }, + { + "name": "lo0", + "internal": true, + "mac": "00:00:00:00:00:00", + "address": "::1", + "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "lo0", + "internal": true, + "mac": "00:00:00:00:00:00", + "address": "fe80::1", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 1 + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "fe80::cc1:cf3b:afa2:144f", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 6 + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "2620:6e:6000:3100:148e:201a:1a33:145d", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "2620:6e:6000:3100:31e4:88bf:1195:6926", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "fdac:89a:4f49:41ac:83d:26cd:abc5:e973", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "fdac:89a:4f49:41ac:15b2:4a9e:88a9:34c3", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "10.38.53.246", + "netmask": "255.255.192.0", + "family": "IPv4" + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "fd8c:23f:4de7:4523:cc7:18bd:a001:a86b", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "fd8c:23f:4de7:4523:6cbc:dfb0:da3f:fa06", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "fdc9:5cae:17e4:4c54:c1e:4892:ccc4:93ae", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "fdc9:5cae:17e4:4c54:307f:315d:52f7:511f", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "fdd3:9b36:2480:4c6f:cff:ec25:4ee6:54c", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "en0", + "internal": false, + "mac": "88:66:5a:29:28:77", + "address": "fdd3:9b36:2480:4c6f:9dba:7458:3932:be33", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 0 + }, + { + "name": "awdl0", + "internal": false, + "mac": "a6:20:c0:51:e8:8f", + "address": "fe80::a420:c0ff:fe51:e88f", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 12 + }, + { + "name": "llw0", + "internal": false, + "mac": "a6:20:c0:51:e8:8f", + "address": "fe80::a420:c0ff:fe51:e88f", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 13 + }, + { + "name": "utun0", + "internal": false, + "mac": "00:00:00:00:00:00", + "address": "fe80::15ac:b094:e48b:b227", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 14 + }, + { + "name": "utun1", + "internal": false, + "mac": "00:00:00:00:00:00", + "address": "fe80::97ec:93db:83a3:75ce", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 15 + }, + { + "name": "en5", + "internal": false, + "mac": "ac:de:48:00:11:22", + "address": "fe80::aede:48ff:fe00:1122", + "netmask": "ffff:ffff:ffff:ffff::", + "family": "IPv6", + "scopeid": 5 + } + ], + "host": "sarahs-mbp.devices.brown.edu" + }, + "javascriptStack": { + "message": "No stack.", + "stack": [ + "Unavailable." + ] + }, + "nativeStack": [ + { + "pc": "0x000000010015c8ca", + "symbol": "report::TriggerNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, std::__1::basic_string, std::__1::allocator > const&, v8::Local) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100080f3e", + "symbol": "node::OnFatalError(char const*, char const*) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100185467", + "symbol": "v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100185403", + "symbol": "v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x000000010030b5f5", + "symbol": "v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x000000010030ccc4", + "symbol": "v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100309b37", + "symbol": "v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100307afd", + "symbol": "v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x00000001003132ba", + "symbol": "v8::internal::Heap::AllocateRawWithLightRetry(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100313341", + "symbol": "v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x00000001002e065b", + "symbol": "v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationType, v8::internal::AllocationOrigin) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100618a18", + "symbol": "v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + }, + { + "pc": "0x0000000100950c19", + "symbol": "Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit [/Users/sarah/.nvm/versions/node/v12.16.0/bin/node]" + } + ], + "javascriptHeap": { + "totalMemory": 2151882752, + "totalCommittedMemory": 2149824464, + "usedMemory": 2139828064, + "availableMemory": 48165544, + "memoryLimit": 2197815296, + "heapSpaces": { + "read_only_space": { + "memorySize": 262144, + "committedMemory": 33088, + "capacity": 32808, + "used": 32808, + "available": 0 + }, + "new_space": { + "memorySize": 2097152, + "committedMemory": 1076448, + "capacity": 1047456, + "used": 28792, + "available": 1018664 + }, + "old_space": { + "memorySize": 1958100992, + "committedMemory": 1957877576, + "capacity": 1951020152, + "used": 1950853272, + "available": 166880 + }, + "code_space": { + "memorySize": 15372288, + "committedMemory": 14957376, + "capacity": 13767968, + "used": 13767968, + "available": 0 + }, + "map_space": { + "memorySize": 1576960, + "committedMemory": 1406760, + "capacity": 1236000, + "used": 1236000, + "available": 0 + }, + "large_object_space": { + "memorySize": 174424064, + "committedMemory": 174424064, + "capacity": 173906440, + "used": 173906440, + "available": 0 + }, + "code_large_object_space": { + "memorySize": 49152, + "committedMemory": 49152, + "capacity": 2784, + "used": 2784, + "available": 0 + }, + "new_large_object_space": { + "memorySize": 0, + "committedMemory": 0, + "capacity": 1047456, + "used": 0, + "available": 1047456 + } + } + }, + "resourceUsage": { + "userCpuSeconds": 302.098, + "kernelCpuSeconds": 7.74276, + "cpuConsumptionPercent": 10.3834, + "maxRss": 2286298333184, + "pageFaults": { + "IORequired": 35, + "IONotRequired": 2289110 + }, + "fsActivity": { + "reads": 0, + "writes": 0 + } + }, + "libuv": [ + ], + "environmentVariables": { + "npm_config_save_dev": "", + "npm_config_legacy_bundling": "", + "npm_config_dry_run": "", + "npm_package_dependencies_translate_google_api": "^1.0.4", + "npm_package_dependencies_request": "^2.88.2", + "npm_package_dependencies_express_flash": "0.0.2", + "npm_package_dependencies__fortawesome_fontawesome_svg_core": "^1.3.0", + "NVM_INC": "/Users/sarah/.nvm/versions/node/v12.16.0/include/node", + "npm_config_viewer": "man", + "npm_config_only": "", + "npm_config_commit_hooks": "true", + "npm_config_browser": "", + "npm_package_gitHead": "4c2584baf8bae0cde714c832b0768d3c08864422", + "npm_package_dependencies_webpack_dev_middleware": "^5.3.1", + "npm_package_dependencies_webpack_cli": "^4.10.0", + "npm_package_devDependencies_prettier": "^2.7.1", + "npm_package_devDependencies_awesome_typescript_loader": "^5.2.1", + "npm_package_devDependencies__types_archiver": "^3.1.1", + "npm_config_also": "", + "npm_package_dependencies_react_jsx_parser": "^1.29.0", + "npm_package_dependencies_mongoose": "^5.13.14", + "npm_package_dependencies_connect_flash": "^0.1.1", + "npm_package_browser_child_process": "false", + "npm_config_sign_git_commit": "", + "npm_config_rollback": "true", + "npm_package_dependencies_material_ui": "^0.20.2", + "npm_package_devDependencies__types_sharp": "^0.23.1", + "npm_package_devDependencies__types_passport_local": "^1.0.34", + "npm_package_devDependencies__types_dotenv": "^6.1.1", + "npm_package_devDependencies__types_cookie_parser": "^1.4.2", + "TERM_PROGRAM": "Apple_Terminal", + "NODE": "/Users/sarah/.nvm/versions/node/v12.16.0/bin/node", + "npm_config_usage": "", + "npm_config_audit": "true", + "npm_package_dependencies_reveal_js": "^4.3.0", + "npm_package_dependencies_process": "^0.11.10", + "npm_package_dependencies_pdfjs": "^2.4.7", + "npm_package_dependencies_html_to_image": "^0.1.3", + "npm_package_devDependencies_file_loader": "^3.0.1", + "npm_package_devDependencies__types_express_flash": "0.0.0", + "npm_package_scripts_monitor": "cross-env MONITORED=true NODE_OPTIONS=--max_old_space_size=4096 ts-node src/server/index.ts", + "INIT_CWD": "/Users/sarah/Desktop/dash/Dash-Web", + "npm_package_dependencies_rehype_raw": "^6.1.1", + "npm_package_dependencies_react_audio_waveform": "0.0.5", + "npm_package_dependencies_path_browserify": "^1.0.1", + "npm_package_dependencies_nodemailer": "^5.1.1", + "npm_package_dependencies_axios": "^0.19.2", + "npm_package_devDependencies_typescript": "^4.7.4", + "NVM_CD_FLAGS": "-q", + "npm_config_globalignorefile": "/Users/sarah/.nvm/versions/node/v12.16.0/etc/npmignore", + "npm_package_dependencies_react_grid_layout": "^1.3.4", + "npm_package_dependencies_prosemirror_find_replace": "^0.9.0", + "npm_package_dependencies_normalize_css": "^8.0.1", + "npm_package_devDependencies_mocha": "^5.2.0", + "npm_package_devDependencies__types_express_session": "^1.17.5", + "SHELL": "/bin/zsh", + "TERM": "xterm-256color", + "npm_config_shell": "/bin/zsh", + "npm_config_maxsockets": "50", + "npm_config_init_author_url": "", + "npm_package_dependencies_prosemirror_dev_tools": "^3.1.0", + "npm_package_dependencies_p_limit": "^2.2.0", + "npm_package_dependencies_bson": "^4.6.1", + "npm_package_dependencies__types_dom_speech_recognition": "0.0.1", + "npm_package_devDependencies_style_loader": "^0.23.1", + "npm_package_devDependencies__types_react_datepicker": "^3.1.8", + "npm_config_shrinkwrap": "true", + "npm_config_parseable": "", + "npm_config_metrics_registry": "https://registry.npmjs.org/", + "npm_package_dependencies_xregexp": "^4.4.1", + "npm_package_dependencies_shelljs": "^0.8.5", + "npm_package_dependencies_bezier_curve": "^1.0.0", + "npm_package_devDependencies_tslint": "^5.20.1", + "npm_package_devDependencies__types_react_transition_group": "^4.4.5", + "npm_package_scripts_tsc": "tsc", + "TMPDIR": "/var/folders/yk/p_39q8jn673c5p8_66mcxm7r0000gn/T/", + "npm_config_timing": "", + "npm_config_init_license": "ISC", + "npm_package_dependencies_socket_io": "^2.5.0", + "npm_package_dependencies_probe_image_size": "^4.0.0", + "npm_package_dependencies_canvas": "^2.9.3", + "npm_package_dependencies__hig_theme_data": "^2.23.1", + "npm_package_devDependencies__types_react_select": "^3.1.2", + "npm_package_devDependencies__types_prosemirror_model": "^1.16.1", + "CONDA_SHLVL": "1", + "npm_config_if_present": "", + "npm_package_dependencies_typescript_collections": "^1.3.3", + "npm_package_dependencies_rimraf": "^3.0.0", + "npm_package_dependencies_react_autosuggest": "^9.4.3", + "npm_package_dependencies_flexlayout_react": "^0.3.11", + "npm_package_dependencies_find_in_files": "^0.5.0", + "npm_package_devDependencies__types_chai": "^4.3.0", + "CONDA_PROMPT_MODIFIER": "(base) ", + "TERM_PROGRAM_VERSION": "440", + "npm_package_dependencies_prosemirror_inputrules": "^1.1.3", + "npm_package_dependencies_bcrypt_nodejs": "0.0.3", + "npm_package_dependencies_async": "^2.6.2", + "npm_config_sign_git_tag": "", + "npm_config_init_author_email": "", + "npm_config_cache_max": "Infinity", + "npm_package_dependencies_uuid": "^3.4.0", + "npm_package_dependencies_supercluster": "^7.1.4", + "npm_package_dependencies_remark_gfm": "^3.0.1", + "npm_package_dependencies_connect_mongo": "^2.0.3", + "npm_package_dependencies_browser_assert": "^1.2.1", + "npm_package_devDependencies_sass_loader": "^7.3.1", + "npm_config_preid": "", + "npm_config_long": "", + "npm_config_local_address": "", + "npm_config_git_tag_version": "true", + "npm_config_cert": "", + "npm_package_dependencies_js_datepicker": "^4.6.6", + "npm_package_devDependencies__types_webpack_hot_middleware": "^2.25.6", + "npm_package_devDependencies__types_mongodb": "^3.6.20", + "npm_package_devDependencies__types_mocha": "^5.2.6", + "TERM_SESSION_ID": "BF3A3D73-8B2D-4041-BAFA-CCC983EE3D05", + "npm_config_registry": "https://registry.npmjs.org/", + "npm_config_noproxy": "", + "npm_config_fetch_retries": "2", + "npm_package_dependencies_react_compound_slider": "^2.5.0", + "npm_package_dependencies_prosemirror_history": "^1.2.0", + "npm_package_devDependencies__types_react_color": "^2.17.6", + "npm_package_devDependencies__types_google_maps_react": "^2.0.5", + "npm_package_devDependencies__types_color": "^3.0.3", + "npm_package_dependencies_react_dom": "^18.2.0", + "npm_package_dependencies_passport_local": "^1.0.0", + "npm_package_dependencies__octokit_core": "^4.0.4", + "npm_package_devDependencies__types_async": "^2.4.1", + "npm_package_scripts_debug": "cross-env NODE_OPTIONS=--max_old_space_size=8192 ts-node-dev --transpile-only --inspect -- src/server/index.ts", + "npm_package_scripts_oldstart": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --debug -- src/server/index.ts", + "npm_config_versions": "", + "npm_config_message": "%s", + "npm_config_key": "", + "npm_package_readmeFilename": "README.md", + "npm_package_dependencies_react_refresh_typescript": "^2.0.7", + "npm_package_dependencies_image_size": "^0.7.5", + "npm_package_dependencies_html_to_text": "^5.1.1", + "npm_package_dependencies_express_validator": "^5.3.1", + "npm_package_devDependencies_eslint_plugin_jsx_a11y": "^6.6.0", + "npm_package_node_child_process": "empty", + "npm_package_dependencies_react_resizable_rotatable_draggable": "^0.2.0", + "npm_package_dependencies_got": "^12.0.1", + "npm_package_dependencies__types_d3_color": "^2.0.3", + "npm_package_devDependencies_webpack": "^5.69.1", + "npm_package_devDependencies__types_nodemailer": "^4.6.6", + "npm_package_description": "Install Node.js, then, from the project directory, run", + "NVM_DIR": "/Users/sarah/.nvm", + "USER": "sarah", + "npm_package_dependencies__types_d3_scale": "^3.3.2", + "npm_package_devDependencies_dotenv": "^8.6.0", + "npm_package_devDependencies__types_react": "^18.0.15", + "npm_package_devDependencies__types_prosemirror_transform": "^1.1.5", + "npm_package_devDependencies__types_prosemirror_history": "^1.0.3", + "npm_package_dependencies_readline": "^1.3.0", + "npm_package_dependencies__types_supercluster": "^7.1.0", + "npm_config_globalconfig": "/Users/sarah/.nvm/versions/node/v12.16.0/etc/npmrc", + "npm_package_dependencies_depcheck": "^0.9.2", + "npm_package_dependencies__types_web": "0.0.53", + "CONDA_EXE": "/Users/sarah/miniconda3/bin/conda", + "npm_config_prefer_online": "", + "npm_config_logs_max": "10", + "npm_config_always_auth": "", + "npm_package_dependencies_react_icons": "^4.3.1", + "npm_package_dependencies_passport_google_oauth20": "^2.0.0", + "npm_package_devDependencies_webpack_dev_server": "^3.11.3", + "npm_package_dependencies_url_loader": "^1.1.2", + "npm_package_dependencies_stream_browserify": "^3.0.0", + "npm_package_dependencies_prosemirror_transform": "^1.3.4", + "npm_package_dependencies_lodash": "^4.17.21", + "npm_package_dependencies_i": "^0.3.7", + "npm_package_devDependencies_tslint_loader": "^3.6.0", + "SSH_AUTH_SOCK": "/private/tmp/com.apple.launchd.TKuATvqs9j/Listeners", + "npm_package_dependencies_words_to_numbers": "^1.5.1", + "npm_package_dependencies_valid_url": "^1.0.9", + "npm_package_dependencies_styled_components": "^4.4.1", + "npm_package_dependencies_class_transformer": "^0.2.0", + "npm_package_devDependencies_eslint": "^8.18.0", + "npm_package_devDependencies__types_prosemirror_inputrules": "^1.0.4", + "npm_package_devDependencies__types_express": "^4.17.13", + "__CF_USER_TEXT_ENCODING": "0x1F5:0x0:0x0", + "npm_execpath": "/Users/sarah/.nvm/versions/node/v12.16.0/lib/node_modules/npm/bin/npm-cli.js", + "npm_config_global_style": "", + "npm_config_cache_lock_retries": "10", + "npm_package_dependencies_wikijs": "^6.3.3", + "npm_package_dependencies_bluebird": "^3.7.2", + "npm_config_update_notifier": "true", + "npm_config_cafile": "", + "npm_package_dependencies_util": "^0.12.4", + "npm_package_dependencies_raw_loader": "^1.0.0", + "npm_package_dependencies_https_browserify": "^1.0.0", + "npm_package_dependencies__fortawesome_react_fontawesome": "^0.1.19", + "npm_package_devDependencies__types_passport_google_oauth20": "^2.0.11", + "npm_package_dependencies_cors": "^2.8.5", + "npm_package_dependencies_bezier_js": "^4.1.1", + "npm_package_dependencies__fortawesome_free_brands_svg_icons": "^5.15.4", + "npm_config_heading": "npm", + "npm_config_audit_level": "low", + "npm_package_dependencies_chrome": "^0.1.0", + "npm_package_dependencies__react_three_fiber": "^6.2.3", + "npm_package_devDependencies_eslint_plugin_prettier": "^4.2.1", + "npm_package_devDependencies_copy_webpack_plugin": "^4.6.0", + "npm_package_devDependencies__types_react_measure": "^2.0.8", + "npm_package_devDependencies__types_react_dom": "^18.0.6", + "npm_package_devDependencies__types_mobile_detect": "^1.3.4", + "_CE_CONDA": "", + "npm_config_searchlimit": "20", + "npm_config_read_only": "", + "npm_config_offline": "", + "npm_config_fetch_retry_mintimeout": "10000", + "npm_package_dependencies_mobx_react_devtools": "^6.1.1", + "npm_package_dependencies_md5_file": "^5.0.0", + "npm_package_dependencies_forever_agent": "^0.6.1", + "npm_package_devDependencies__types_xregexp": "^4.4.0", + "npm_package_devDependencies__types_typescript": "^2.0.0", + "npm_package_devDependencies__types_request": "^2.48.8", + "npm_package_devDependencies__types_prosemirror_commands": "^1.0.4", + "npm_config_json": "", + "npm_config_access": "", + "npm_config_argv": "{\"remain\":[],\"cooked\":[\"start\"],\"original\":[\"start\"]}", + "npm_package_dependencies__fortawesome_free_solid_svg_icons": "^5.15.4", + "npm_package_devDependencies__types_socket_io": "^2.1.13", + "PATH": "/Users/sarah/.nvm/versions/node/v12.16.0/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/sarah/Desktop/dash/Dash-Web/node_modules/.bin:/Users/sarah/.nvm/versions/node/v12.16.0/bin:/Users/sarah/miniconda3/bin:/Users/sarah/miniconda3/condabin:/Users/sarah/.elan/bin:/Library/Frameworks/Python.framework/Versions/3.9/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin", + "npm_config_allow_same_version": "", + "npm_package_dependencies_webrtc_adapter": "^7.7.1", + "npm_package_dependencies_react_reveal": "^1.2.2", + "npm_package_dependencies_prosemirror_schema_list": "^1.1.6", + "npm_package_dependencies__material_ui_core": "^4.12.3", + "npm_package_devDependencies__types_rimraf": "^2.0.5", + "npm_package_devDependencies__types_connect_flash": "0.0.34", + "npm_config_https_proxy": "", + "npm_config_engine_strict": "", + "npm_config_description": "true", + "npm_package_dependencies_pug": "^2.0.4", + "npm_package_dependencies_prosemirror_keymap": "^1.1.5", + "npm_package_dependencies_pdfjs_dist": "^2.14.305", + "npm_package_dependencies_mobile_detect": "^1.4.5", + "npm_package_dependencies_image_size_stream": "^1.1.0", + "npm_package_dependencies_golden_layout": "^1.5.9", + "npm_package_dependencies_child_process": "^1.0.2", + "npm_package_dependencies__types_d3_axis": "^2.1.3", + "_": "/Users/sarah/Desktop/dash/Dash-Web/node_modules/.bin/cross-env", + "npm_config_userconfig": "/Users/sarah/.npmrc", + "npm_config_init_module": "/Users/sarah/.npm-init.js", + "npm_package_dependencies__react_google_maps_api": "^2.7.0", + "CONDA_PREFIX": "/Users/sarah/miniconda3", + "__CFBundleIdentifier": "com.apple.Terminal", + "npm_config_cidr": "", + "npm_package_dependencies_puppeteer": "^3.3.0", + "npm_package_dependencies_prosemirror_view": "^1.26.5", + "npm_package_dependencies_mongodb": "^3.7.3", + "npm_package_dependencies_google_auth_library": "^4.2.4", + "npm_package_dependencies_bootstrap": "^4.6.1", + "npm_package_devDependencies_eslint_config_airbnb": "^19.0.4", + "PWD": "/Users/sarah/desktop/dash/dash-web", + "npm_config_user": "501", + "npm_config_node_version": "12.16.0", + "npm_package_dependencies_node_sass": "^4.14.1", + "npm_package_dependencies_howler": "^2.2.3", + "npm_package_dependencies_expressjs": "^1.0.1", + "npm_package_dependencies_core_js": "^3.28.0", + "npm_package_dependencies_browndash_components": "0.0.22", + "npm_package_devDependencies_eslint_plugin_react_hooks": "^4.6.0", + "npm_package_devDependencies__types_lodash": "^4.14.179", + "JAVA_HOME": "/Library/Java/JavaVirtualMachines/jdk1.8.0_341.jdk/Contents/Home", + "npm_lifecycle_event": "start", + "npm_package_dependencies_react_table": "^6.11.5", + "npm_package_dependencies_react_loading": "^2.0.3", + "npm_package_dependencies_mobx": "^5.15.7", + "npm_package_dependencies_babel": "^6.23.0", + "npm_package_devDependencies_jsdom": "^15.2.1", + "npm_package_devDependencies_chai": "^4.3.6", + "npm_config_save": "true", + "npm_config_ignore_prepublish": "", + "npm_config_editor": "vi", + "npm_config_auth_type": "legacy", + "npm_package_dependencies_npm": "^6.14.18", + "npm_package_dependencies_node_stream_zip": "^1.15.0", + "npm_package_dependencies_image_data_uri": "^2.0.1", + "npm_package_scripts_start_release": "cross-env RELEASE=true NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev -- src/server/index.ts", + "npm_package_name": "dash", + "LANG": "en_US.UTF-8", + "npm_config_tag": "latest", + "npm_config_script_shell": "", + "npm_package_dependencies_query_string": "^6.14.1", + "npm_package_dependencies_mobx_utils": "^5.6.2", + "npm_package_dependencies_file_saver": "^2.0.5", + "npm_package_dependencies_body_parser": "^1.19.2", + "npm_package_dependencies__types_reveal": "^3.3.33", + "npm_package_devDependencies_eslint_plugin_import": "^2.26.0", + "npm_package_devDependencies__types_prosemirror_view": "^1.23.1", + "npm_config_progress": "true", + "npm_config_global": "", + "npm_config_before": "", + "npm_package_dependencies_xoauth2": "^1.2.0", + "npm_package_dependencies_standard_http_error": "^2.0.1", + "npm_package_dependencies_http_browserify": "^1.7.0", + "npm_package_dependencies__types_d3_selection": "^2.0.1", + "npm_package_dependencies__hig_flyout": "^1.3.1", + "npm_package_devDependencies_fork_ts_checker_webpack_plugin": "^1.6.0", + "npm_package_scripts_build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 webpack --env production", + "npm_package_scripts_start": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --debug --transpile-only -- src/server/index.ts", + "npm_config_searchstaleness": "900", + "npm_config_optional": "true", + "npm_config_ham_it_up": "", + "npm_package_dependencies_sharp": "^0.23.4", + "npm_package_dependencies_rc_switch": "^1.9.2", + "npm_package_dependencies_googlephotos": "^0.2.5", + "npm_package_dependencies_exifr": "^7.1.3", + "npm_package_dependencies__types_google_maps": "^3.2.3", + "npm_package_dependencies__types_bezier_js": "^4.1.0", + "npm_package_dependencies__ffmpeg_core": "0.10.0", + "npm_package_devDependencies_ts_loader": "^5.3.3", + "npm_package_devDependencies__types_bcrypt_nodejs": "0.0.30", + "XPC_FLAGS": "0x0", + "npm_config_save_prod": "", + "npm_config_force": "", + "npm_config_bin_links": "true", + "npm_package_devDependencies__types_youtube": "0.0.39", + "npm_config_searchopts": "", + "npm_package_dependencies_react_beautiful_dnd": "^13.1.0", + "npm_package_dependencies_jszip": "^3.7.1", + "npm_package_devDependencies__types_react_icons": "^3.0.0", + "npm_config_node_gyp": "/Users/sarah/.nvm/versions/node/v12.16.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", + "npm_config_depth": "Infinity", + "npm_package_dependencies_google_maps_react": "^2.0.6", + "npm_package_dependencies_express_session": "^1.17.2", + "npm_package_devDependencies_eslint_plugin_node": "^11.1.0", + "npm_package_devDependencies_eslint_config_prettier": "^8.5.0", + "npm_package_main": "index.js", + "npm_config_sso_poll_frequency": "500", + "npm_config_rebuild_bundle": "true", + "npm_package_devDependencies__types_prosemirror_menu": "^1.0.6", + "npm_package_devDependencies__types_prosemirror_keymap": "^1.0.4", + "npm_package_devDependencies__types_pdfjs_dist": "^2.10.378", + "npm_package_devDependencies__types_exif": "^0.6.3", + "npm_package_version": "1.0.0", + "_CE_M": "", + "XPC_SERVICE_NAME": "0", + "npm_config_unicode": "true", + "npm_package_dependencies_typescript_language_server": "^0.4.0", + "npm_package_dependencies_prosemirror_model": "^1.18.1", + "npm_package_dependencies__ffmpeg_ffmpeg": "0.10.0", + "SHLVL": "2", + "HOME": "/Users/sarah", + "npm_config_fetch_retry_maxtimeout": "60000", + "npm_package_dependencies_request_promise": "^4.2.6", + "npm_package_dependencies_react_markdown": "^8.0.3", + "npm_package_dependencies__hig_theme_context": "^2.1.3", + "npm_package_devDependencies__types_react_autosuggest": "^9.3.14", + "npm_package_devDependencies__types_mongoose": "^5.11.97", + "npm_package_devDependencies__types_animejs": "^2.0.2", + "npm_package_scripts_test": "mocha -r ts-node/register test/**/*.ts", + "npm_config_tag_version_prefix": "v", + "npm_config_strict_ssl": "true", + "npm_config_sso_type": "oauth", + "npm_config_scripts_prepend_node_path": "warn-only", + "npm_config_save_prefix": "^", + "npm_config_loglevel": "notice", + "npm_config_ca": "", + "npm_package_dependencies_three": "^0.127.0", + "npm_package_dependencies_mobx_react": "^5.4.4", + "npm_package_dependencies_cookie_parser": "^1.4.6", + "npm_package_dependencies_adm_zip": "^0.4.16", + "npm_package_devDependencies_eslint_config_node": "^4.1.0", + "npm_config_save_exact": "", + "npm_config_group": "20", + "npm_config_fetch_retry_factor": "10", + "npm_config_dev": "", + "npm_package_devDependencies_webpack_hot_middleware": "^2.25.1", + "npm_package_devDependencies_cross_env": "^5.2.1", + "npm_config_version": "", + "npm_config_prefer_offline": "", + "npm_config_cache_lock_stale": "60000", + "npm_package_devDependencies__types_prosemirror_state": "^1.2.8", + "npm_package_devDependencies__types_body_parser": "^1.19.2", + "npm_config_otp": "", + "npm_config_cache_min": "10", + "npm_package_dependencies_react_color": "^2.19.3", + "npm_package_devDependencies_ts_node": "^10.9.1", + "npm_package_devDependencies__types_react_grid_layout": "^1.3.2", + "npm_config_searchexclude": "", + "npm_config_cache": "/Users/sarah/.npm", + "npm_package_dependencies_tough_cookie": "^4.0.0", + "npm_package_dependencies_googleapis": "^40.0.0", + "npm_package_devDependencies__types_valid_url": "^1.0.3", + "npm_package_devDependencies__types_passport": "^1.0.9", + "npm_package_devDependencies__types_adm_zip": "^0.4.34", + "CONDA_PYTHON_EXE": "/Users/sarah/miniconda3/bin/python", + "LOGNAME": "sarah", + "npm_lifecycle_script": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ts-node-dev --debug --transpile-only -- src/server/index.ts", + "npm_config_color": "true", + "npm_package_dependencies_solr_node": "^1.2.1", + "npm_package_dependencies_react_transition_group": "^4.4.2", + "npm_package_dependencies_iink_js": "^1.5.4", + "npm_package_dependencies_html_webpack_plugin": "^5.5.0", + "npm_config_proxy": "", + "npm_config_package_lock": "true", + "npm_package_dependencies_prosemirror_state": "^1.4.1", + "npm_package_dependencies_nodemon": "^1.19.4", + "npm_package_dependencies_function_plot": "^1.22.8", + "npm_package_dependencies_equation_editor_react": "github:bobzel/equation-editor-react#useLocally", + "npm_package_devDependencies__types_socket_io_parser": "^3.0.0", + "CLASSPATH": "/Users/sarah/Downloads/cs15/*:.", + "npm_config_package_lock_only": "", + "npm_config_fund": "true", + "npm_package_dependencies_react": "^18.2.0", + "npm_package_dependencies_bingmaps_react": "^1.2.10", + "npm_package_devDependencies_scss_loader": "0.0.1", + "npm_package_devDependencies__types_cookie_session": "^2.0.44", + "npm_config_save_optional": "", + "npm_package_dependencies_textarea_caret": "^3.1.0", + "npm_package_dependencies_react_measure": "^2.5.2", + "npm_package_dependencies_exif": "^0.6.0", + "NVM_BIN": "/Users/sarah/.nvm/versions/node/v12.16.0/bin", + "CONDA_DEFAULT_ENV": "base", + "npm_config_ignore_scripts": "", + "npm_config_user_agent": "npm/6.14.7 node/v12.16.0 darwin x64", + "npm_package_dependencies_react_resizable": "^1.11.1", + "npm_package_dependencies_prosemirror_commands": "^1.2.1", + "npm_package_dependencies_memorystream": "^0.3.1", + "npm_package_dependencies_formidable": "1.2.1", + "npm_package_devDependencies__types_uuid": "^3.4.10", + "npm_config_cache_lock_wait": "10000", + "npm_package_dependencies_socket_io_client": "^2.5.0", + "npm_package_dependencies_fluent_ffmpeg": "^2.1.2", + "npm_package_dependencies__types_cors": "^2.8.12", + "npm_package_devDependencies__types_node": "^10.17.60", + "npm_package_devDependencies__types_file_saver": "^2.0.5", + "npm_config_production": "", + "npm_package_dependencies_jsonschema": "^1.4.0", + "npm_package_dependencies_ffmpeg": "0.0.4", + "npm_package_dependencies_cookie_session": "^2.0.0", + "npm_package_dependencies_color": "^3.2.1", + "npm_package_devDependencies__types_webpack": "^4.41.32", + "npm_package_devDependencies__types_request_promise": "^4.1.48", + "npm_package_devDependencies__types_prosemirror_schema_list": "^1.0.3", + "npm_config_send_metrics": "", + "npm_config_save_bundle": "", + "npm_package_dependencies_web_request": "^1.0.7", + "npm_package_dependencies_react_datepicker": "^3.8.0", + "npm_package_dependencies_express": "^4.17.3", + "npm_package_dependencies_D": "^1.0.0", + "npm_package_dependencies__types_formidable": "1.0.31", + "npm_package_devDependencies__types_rc_switch": "^1.9.2", + "npm_package_devDependencies__types_prosemirror_dev_tools": "^2.1.0", + "npm_package_devDependencies__types_jquery": "^3.5.14", + "npm_config_umask": "0022", + "npm_config_node_options": "", + "npm_config_init_version": "1.0.0", + "npm_package_dependencies_https": "^1.0.0", + "npm_package_dependencies_array_batcher": "^1.2.3", + "npm_package_dependencies__fortawesome_free_regular_svg_icons": "^5.15.4", + "npm_package_devDependencies__types_shelljs": "^0.8.11", + "npm_package_devDependencies__types_libxmljs": "^0.18.7", + "npm_package_devDependencies__types_express_validator": "^3.0.0", + "npm_package_devDependencies__types_bluebird": "^3.5.36", + "npm_config_init_author_name": "", + "npm_config_git": "git", + "npm_config_scope": "", + "npm_package_dependencies_react_select": "^3.2.0", + "npm_package_dependencies_pdf_parse": "^1.1.1", + "npm_package_dependencies_colors": "^1.4.0", + "npm_package_dependencies_archiver": "^3.1.1", + "npm_package_devDependencies_css_loader": "^2.1.1", + "npm_package_devDependencies__types_socket_io_client": "^1.4.36", + "npm_config_unsafe_perm": "true", + "npm_config_tmp": "/var/folders/yk/p_39q8jn673c5p8_66mcxm7r0000gn/T", + "npm_config_onload_script": "", + "npm_package_dependencies_serializr": "^1.5.4", + "npm_package_dependencies_fit_curve": "^0.1.7", + "npm_package_dependencies__webscopeio_react_textarea_autocomplete": "^4.9.1", + "npm_package_dependencies__types_three": "^0.126.2", + "npm_package_devDependencies_ts_node_dev": "^2.0.0", + "npm_node_execpath": "/Users/sarah/.nvm/versions/node/v12.16.0/bin/node", + "npm_config_prefix": "/Users/sarah/.nvm/versions/node/v12.16.0", + "npm_config_link": "", + "npm_config_format_package_lock": "true", + "npm_package_dependencies_passport": "^0.4.0", + "npm_package_devDependencies_eslint_plugin_react": "^7.30.1", + "npm_package_devDependencies__types_react_table": "^6.8.9", + "npm_package_devDependencies__types_react_reconciler": "^0.26.4", + "NODE_OPTIONS": "--max_old_space_size=4096", + "TS_NODE_DEV": "true", + "VIPSHOME": "/usr/local/Cellar/vips/8.8.1", + "TYPESCRIPT_PATH": "/Users/sarah/Desktop/dash/Dash-Web/node_modules/typescript/lib/typescript.js", + "TSCONFIG": "/Users/sarah/Desktop/dash/Dash-Web/tsconfig.json", + "COMPILER_OPTIONS": "{}", + "TSLINT": "true", + "CONTEXT": "/Users/sarah/Desktop/dash/Dash-Web", + "TSLINTAUTOFIX": "false", + "ESLINT": "false", + "ESLINT_OPTIONS": "{}", + "WATCH": "", + "WORK_DIVISION": "1", + "MEMORY_LIMIT": "2048", + "CHECK_SYNTACTIC_ERRORS": "false", + "USE_INCREMENTAL_API": "true", + "VUE": "false" + }, + "userLimits": { + "core_file_size_blocks": { + "soft": 0, + "hard": "unlimited" + }, + "data_seg_size_kbytes": { + "soft": "unlimited", + "hard": "unlimited" + }, + "file_size_blocks": { + "soft": "unlimited", + "hard": "unlimited" + }, + "max_locked_memory_bytes": { + "soft": "unlimited", + "hard": "unlimited" + }, + "max_memory_size_kbytes": { + "soft": "unlimited", + "hard": "unlimited" + }, + "open_files": { + "soft": 1048575, + "hard": "unlimited" + }, + "stack_size_bytes": { + "soft": 8388608, + "hard": 67104768 + }, + "cpu_time_seconds": { + "soft": "unlimited", + "hard": "unlimited" + }, + "max_user_processes": { + "soft": 2784, + "hard": 4176 + }, + "virtual_memory_kbytes": { + "soft": "unlimited", + "hard": "unlimited" + } + }, + "sharedObjects": [ + "/Users/sarah/.nvm/versions/node/v12.16.0/bin/node", + "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation", + "/usr/lib/libSystem.B.dylib", + "/usr/lib/libc++.1.dylib", + "/usr/lib/libobjc.A.dylib", + "/usr/lib/liboah.dylib", + "/usr/lib/libfakelink.dylib", + "/usr/lib/libicucore.A.dylib", + "/System/Library/PrivateFrameworks/SoftLinking.framework/Versions/A/SoftLinking", + "/usr/lib/libc++abi.dylib", + "/usr/lib/system/libcache.dylib", + "/usr/lib/system/libcommonCrypto.dylib", + "/usr/lib/system/libcompiler_rt.dylib", + "/usr/lib/system/libcopyfile.dylib", + "/usr/lib/system/libcorecrypto.dylib", + "/usr/lib/system/libdispatch.dylib", + "/usr/lib/system/libdyld.dylib", + "/usr/lib/system/libkeymgr.dylib", + "/usr/lib/system/liblaunch.dylib", + "/usr/lib/system/libmacho.dylib", + "/usr/lib/system/libquarantine.dylib", + "/usr/lib/system/libremovefile.dylib", + "/usr/lib/system/libsystem_asl.dylib", + "/usr/lib/system/libsystem_blocks.dylib", + "/usr/lib/system/libsystem_c.dylib", + "/usr/lib/system/libsystem_collections.dylib", + "/usr/lib/system/libsystem_configuration.dylib", + "/usr/lib/system/libsystem_containermanager.dylib", + "/usr/lib/system/libsystem_coreservices.dylib", + "/usr/lib/system/libsystem_darwin.dylib", + "/usr/lib/system/libsystem_dnssd.dylib", + "/usr/lib/system/libsystem_featureflags.dylib", + "/usr/lib/system/libsystem_info.dylib", + "/usr/lib/system/libsystem_m.dylib", + "/usr/lib/system/libsystem_malloc.dylib", + "/usr/lib/system/libsystem_networkextension.dylib", + "/usr/lib/system/libsystem_notify.dylib", + "/usr/lib/system/libsystem_product_info_filter.dylib", + "/usr/lib/system/libsystem_sandbox.dylib", + "/usr/lib/system/libsystem_secinit.dylib", + "/usr/lib/system/libsystem_kernel.dylib", + "/usr/lib/system/libsystem_platform.dylib", + "/usr/lib/system/libsystem_pthread.dylib", + "/usr/lib/system/libsystem_symptoms.dylib", + "/usr/lib/system/libsystem_trace.dylib", + "/usr/lib/system/libunwind.dylib", + "/usr/lib/system/libxpc.dylib", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices", + "/System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics", + "/System/Library/Frameworks/CoreText.framework/Versions/A/CoreText", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/ImageIO", + "/System/Library/Frameworks/ColorSync.framework/Versions/A/ColorSync", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/ATS", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ColorSyncLegacy.framework/Versions/A/ColorSyncLegacy", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/HIServices", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/LangAnalysis.framework/Versions/A/LangAnalysis", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Versions/A/PrintCore", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/QD.framework/Versions/A/QD", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/SpeechSynthesis.framework/Versions/A/SpeechSynthesis", + "/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight", + "/System/Library/PrivateFrameworks/FontServices.framework/libFontParser.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate", + "/System/Library/Frameworks/IOSurface.framework/Versions/A/IOSurface", + "/usr/lib/libxml2.2.dylib", + "/System/Library/Frameworks/CFNetwork.framework/Versions/A/CFNetwork", + "/usr/lib/libz.1.dylib", + "/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation", + "/System/Library/PrivateFrameworks/RunningBoardServices.framework/Versions/A/RunningBoardServices", + "/usr/lib/libMobileGestalt.dylib", + "/System/Library/PrivateFrameworks/WatchdogClient.framework/Versions/A/WatchdogClient", + "/usr/lib/libcompression.dylib", + "/usr/lib/libDiagnosticMessagesClient.dylib", + "/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration", + "/System/Library/Frameworks/CoreDisplay.framework/Versions/A/CoreDisplay", + "/System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia", + "/System/Library/PrivateFrameworks/IOAccelerator.framework/Versions/A/IOAccelerator", + "/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit", + "/System/Library/Frameworks/Metal.framework/Versions/A/Metal", + "/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/MetalPerformanceShaders", + "/System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/A/MultitouchSupport", + "/System/Library/Frameworks/Security.framework/Versions/A/Security", + "/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore", + "/usr/lib/libbsm.0.dylib", + "/System/Library/PrivateFrameworks/CoreAnalytics.framework/Versions/A/CoreAnalytics", + "/System/Library/Frameworks/VideoToolbox.framework/Versions/A/VideoToolbox", + "/System/Library/PrivateFrameworks/BaseBoard.framework/Versions/A/BaseBoard", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/FSEvents", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Metadata", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/OSServices.framework/Versions/A/OSServices", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SearchKit.framework/Versions/A/SearchKit", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/AE", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/LaunchServices", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/DictionaryServices.framework/Versions/A/DictionaryServices", + "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SharedFileList.framework/Versions/A/SharedFileList", + "/usr/lib/libapple_nghttp2.dylib", + "/usr/lib/libnetwork.dylib", + "/usr/lib/libsqlite3.dylib", + "/usr/lib/libenergytrace.dylib", + "/usr/lib/system/libkxld.dylib", + "/System/Library/PrivateFrameworks/AppleFSCompression.framework/Versions/A/AppleFSCompression", + "/usr/lib/libcoretls.dylib", + "/usr/lib/libcoretls_cfhelpers.dylib", + "/usr/lib/libpam.2.dylib", + "/usr/lib/libxar.1.dylib", + "/System/Library/PrivateFrameworks/CoreAutoLayout.framework/Versions/A/CoreAutoLayout", + "/System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration", + "/usr/lib/libarchive.2.dylib", + "/usr/lib/liblangid.dylib", + "/usr/lib/libCRFSuite.dylib", + "/usr/lib/libpcap.A.dylib", + "/usr/lib/libdns_services.dylib", + "/usr/lib/liblzma.5.dylib", + "/usr/lib/libbz2.1.0.dylib", + "/usr/lib/libiconv.2.dylib", + "/usr/lib/libcharset.1.dylib", + "/System/Library/PrivateFrameworks/AppleSystemInfo.framework/Versions/A/AppleSystemInfo", + "/System/Library/PrivateFrameworks/IOMobileFramebuffer.framework/Versions/A/IOMobileFramebuffer", + "/usr/lib/libCheckFix.dylib", + "/System/Library/PrivateFrameworks/TCC.framework/Versions/A/TCC", + "/System/Library/PrivateFrameworks/CoreNLP.framework/Versions/A/CoreNLP", + "/System/Library/PrivateFrameworks/MetadataUtilities.framework/Versions/A/MetadataUtilities", + "/usr/lib/libmecabra.dylib", + "/System/Library/Frameworks/MLCompute.framework/Versions/A/MLCompute", + "/usr/lib/libmecab.dylib", + "/usr/lib/libgermantok.dylib", + "/usr/lib/libThaiTokenizer.dylib", + "/usr/lib/libChineseTokenizer.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vImage.framework/Versions/A/vImage", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/vecLib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvMisc.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvDSP.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLinearAlgebra.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparseBLAS.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libQuadrature.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBNNS.dylib", + "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparse.dylib", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSCore.framework/Versions/A/MPSCore", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSImage.framework/Versions/A/MPSImage", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNeuralNetwork.framework/Versions/A/MPSNeuralNetwork", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSMatrix.framework/Versions/A/MPSMatrix", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSRayIntersector.framework/Versions/A/MPSRayIntersector", + "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNDArray.framework/Versions/A/MPSNDArray", + "/System/Library/PrivateFrameworks/MetalTools.framework/Versions/A/MetalTools", + "/System/Library/PrivateFrameworks/AggregateDictionary.framework/Versions/A/AggregateDictionary", + "/System/Library/PrivateFrameworks/AppleSauce.framework/Versions/A/AppleSauce", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreFSCache.dylib", + "/System/Library/PrivateFrameworks/LanguageModeling.framework/Versions/A/LanguageModeling", + "/System/Library/PrivateFrameworks/CoreEmoji.framework/Versions/A/CoreEmoji", + "/System/Library/PrivateFrameworks/LinguisticData.framework/Versions/A/LinguisticData", + "/System/Library/PrivateFrameworks/Lexicon.framework/Versions/A/Lexicon", + "/usr/lib/libcmph.dylib", + "/System/Library/Frameworks/OpenDirectory.framework/Versions/A/Frameworks/CFOpenDirectory.framework/Versions/A/CFOpenDirectory", + "/System/Library/Frameworks/OpenDirectory.framework/Versions/A/OpenDirectory", + "/System/Library/PrivateFrameworks/APFS.framework/Versions/A/APFS", + "/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation", + "/usr/lib/libutil.dylib", + "/usr/lib/libapp_launch_measurement.dylib", + "/System/Library/PrivateFrameworks/CoreServicesStore.framework/Versions/A/CoreServicesStore", + "/System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement", + "/usr/lib/libxslt.1.dylib", + "/System/Library/PrivateFrameworks/BackgroundTaskManagement.framework/Versions/A/BackgroundTaskManagement", + "/System/Library/PrivateFrameworks/PersistentConnection.framework/Versions/A/PersistentConnection", + "/System/Library/PrivateFrameworks/ProtocolBuffer.framework/Versions/A/ProtocolBuffer", + "/System/Library/PrivateFrameworks/CommonUtilities.framework/Versions/A/CommonUtilities", + "/System/Library/PrivateFrameworks/Bom.framework/Versions/A/Bom", + "/usr/lib/libate.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libRadiance.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJPEG.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libPng.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libTIFF.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libGIF.dylib", + "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJP2.dylib", + "/usr/lib/libexpat.1.dylib", + "/System/Library/PrivateFrameworks/AppleJPEG.framework/Versions/A/AppleJPEG", + "/System/Library/PrivateFrameworks/GPUWrangler.framework/Versions/A/GPUWrangler", + "/System/Library/PrivateFrameworks/IOPresentment.framework/Versions/A/IOPresentment", + "/System/Library/PrivateFrameworks/DSExternalDisplay.framework/Versions/A/DSExternalDisplay", + "/System/Library/PrivateFrameworks/CMCaptureCore.framework/Versions/A/CMCaptureCore", + "/usr/lib/libspindump.dylib", + "/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio", + "/System/Library/PrivateFrameworks/AppServerSupport.framework/Versions/A/AppServerSupport", + "/System/Library/PrivateFrameworks/perfdata.framework/Versions/A/perfdata", + "/System/Library/PrivateFrameworks/AssertionServices.framework/Versions/A/AssertionServices", + "/System/Library/PrivateFrameworks/AudioToolboxCore.framework/Versions/A/AudioToolboxCore", + "/System/Library/PrivateFrameworks/caulk.framework/Versions/A/caulk", + "/System/Library/PrivateFrameworks/SystemPolicy.framework/Versions/A/SystemPolicy", + "/usr/lib/libIOReport.dylib", + "/usr/lib/libSMC.dylib", + "/usr/lib/libAudioToolboxUtility.dylib", + "/usr/lib/libmis.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGFXShared.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLImage.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCVMSPluginSupport.dylib", + "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreVMClient.dylib", + "/System/Library/Frameworks/CoreImage.framework/Versions/A/CoreImage", + "/System/Library/Frameworks/OpenCL.framework/Versions/A/OpenCL", + "/System/Library/PrivateFrameworks/GraphVisualizer.framework/Versions/A/GraphVisualizer", + "/System/Library/PrivateFrameworks/FaceCore.framework/Versions/A/FaceCore", + "/System/Library/PrivateFrameworks/OTSVG.framework/Versions/A/OTSVG", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/libFontRegistry.dylib", + "/System/Library/PrivateFrameworks/FontServices.framework/libhvf.dylib", + "/System/Library/PrivateFrameworks/AppleVA.framework/Versions/A/AppleVA", + "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATSUI.framework/Versions/A/ATSUI", + "/usr/lib/libcups.2.dylib", + "/System/Library/PrivateFrameworks/NetAuth.framework/Versions/A/NetAuth", + "/System/Library/Frameworks/Kerberos.framework/Versions/A/Kerberos", + "/System/Library/Frameworks/GSS.framework/Versions/A/GSS", + "/usr/lib/libresolv.9.dylib", + "/System/Library/PrivateFrameworks/Heimdal.framework/Versions/A/Heimdal", + "/System/Library/Frameworks/Kerberos.framework/Versions/A/Libraries/libHeimdalProxy.dylib", + "/System/Library/Frameworks/Network.framework/Versions/A/Network", + "/usr/lib/libheimdal-asn1.dylib", + "/System/Library/PrivateFrameworks/CommonAuth.framework/Versions/A/CommonAuth", + "/System/Library/PrivateFrameworks/login.framework/Versions/A/Frameworks/loginsupport.framework/Versions/A/loginsupport", + "/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox", + "/System/Library/PrivateFrameworks/AudioSession.framework/Versions/A/AudioSession", + "/usr/lib/libAudioStatistics.dylib", + "/System/Library/PrivateFrameworks/MediaExperience.framework/Versions/A/MediaExperience", + "/System/Library/PrivateFrameworks/AudioSession.framework/libSessionUtility.dylib", + "/usr/lib/libperfcheck.dylib", + "/System/Library/PrivateFrameworks/AudioResourceArbitration.framework/Versions/A/AudioResourceArbitration", + "/System/Library/Frameworks/CoreData.framework/Versions/A/CoreData", + "/Users/sarah/Desktop/dash/Dash-Web/node_modules/fsevents/build/Release/fse.node" + ] +} \ No newline at end of file diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index ccac5ffe4..ce5378e69 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -112,6 +112,33 @@ $resizeHandler: 8px; } } + .documentDecorations-lockButton { + display: flex; + align-items: center; + justify-content: center; + background: grey; + border: solid 1.5px rgb(72, 71, 71); + color: grey; + transition: 0.1s ease; + opacity: 1; + pointer-events: all; + width: 20px; + height: 20px; + min-width: 20px; + border-radius: 100%; + opacity: 0.5; + cursor: pointer; + + &:hover { + color: rgb(72, 71, 71); + opacity: 1; + } + + > svg { + margin: 0; + } + } + .documentDecorations-minimizeButton { display: flex; align-items: center; @@ -186,6 +213,58 @@ $resizeHandler: 8px; } } + .documentDecorations-share { + background: none; + opacity: 1; + grid-column: 3; + pointer-events: auto; + overflow: hidden; + text-align: center; + width: 100%; + max-width: 120px; + display: flex; + height: 20px; + border-radius: 8px; + border-width: 10px; + opacity: 0.3; + &:hover { + opacity: 1; + } + .documentDecorations-shareNone, + .documentDecorations-shareAdmin{ + width: calc(100% + 10px); + background: grey; + color: rgb(71, 71, 71); + border-color: rgb(71, 71, 71); + } + .documentDecorations-shareEdit, + .documentDecorations-shareSelf-Edit{ + width: calc(100% + 10px); + background: rgb(235, 235, 145); + color: rgb(75, 75, 5); + border-color: rgb(75, 75, 5); + } + .documentDecorations-shareAugment{ + width: calc(100% + 10px); + background: rgb(160, 230, 160); + color:rgb(19, 80, 19); + border-color:rgb(19, 80, 19); + + } + .documentDecorations-shareView{ + width: calc(100% + 10px); + background: rgb(161, 161, 238); + color: rgb(25, 25, 101); + border-color: rgb(25, 25, 101);; + } + .documentDecorations-shareNot-Shared{ + width: calc(100% + 10px); + background: rgb(210, 143, 143); + color: rgb(146, 58, 58); + border-color: rgb(146, 58, 58);; + } + } + .documentDecorations-centerCont { grid-column: 2; background: none; @@ -264,7 +343,7 @@ $resizeHandler: 8px; .documentDecorations-lock { position: relative; background: black; - color: gray; + color: rgb(145, 144, 144); height: 14; width: 14; pointer-events: all; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2982f8a99..d87c13ce6 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,6 +1,6 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Tooltip } from '@material-ui/core'; +import { StylesProvider, Tooltip } from '@material-ui/core'; import { IconButton } from 'browndash-components'; import { action, computed, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -11,7 +11,7 @@ import { Document } from '../../fields/documentSchemas'; import { InkField } from '../../fields/InkField'; import { ScriptField } from '../../fields/ScriptField'; import { Cast, NumCast, StrCast } from '../../fields/Types'; -import { GetEffectiveAcl } from '../../fields/util'; +import { GetEffectiveAcl, SharingPermissions } from '../../fields/util'; import { emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils'; import { Docs } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; @@ -27,10 +27,11 @@ import { Colors } from './global/globalEnums'; import { InkingStroke } from './InkingStroke'; import { InkStrokeProperties } from './InkStrokeProperties'; import { LightboxView } from './LightboxView'; -import { DocumentView, OpenWhere, OpenWhereMod } from './nodes/DocumentView'; +import { DocumentView, OpenWhereMod } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { ImageBox } from './nodes/ImageBox'; import React = require('react'); +import { SharingManager } from '../util/SharingManager'; @observer export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> { @@ -283,12 +284,11 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P openDoc = DocListCast(openDoc.aliases).find(alias => !alias.context) ?? Doc.MakeAlias(openDoc); Doc.deiconifyView(openDoc); } - selectedDocs[0].props.addDocTab(openDoc, OpenWhere.lightbox); - // LightboxView.SetLightboxDoc( - // openDoc, - // undefined, - // selectedDocs.slice(1).map(view => view.props.Document) - // ); + LightboxView.SetLightboxDoc( + openDoc, + undefined, + selectedDocs.slice(1).map(view => view.props.Document) + ); } } SelectionManager.DeselectAll(); @@ -735,6 +735,29 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P setTimeout(action(() => (this._showNothing = true))); return null; } + + // sharing + const docShareMode = seldocview.rootDoc["acl-Public"]; + const shareMode = StrCast(docShareMode); + var shareSymbolIcon = null; + switch(shareMode){ + case ("Edit"): + shareSymbolIcon = "⬢ "; + break; + case ("Self-Edit"): + shareSymbolIcon = "⬢ "; + break; + case ("Augment"): + shareSymbolIcon = "⬟ "; + break; + case ("View"): + shareSymbolIcon = "♦ "; + break; + case ("Not-Shared"): + shareSymbolIcon = "▲ "; + break; + } + // hide the decorations if the parent chooses to hide it or if the document itself hides it const hideDecorations = seldocview.props.hideDecorations || seldocview.rootDoc.hideDecorations; const hideResizers = hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.hideResizeHandles || seldocview.rootDoc._isGroup || this._isRounding || this._isRotating; @@ -775,7 +798,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P undoBatch(e => click!(e)) )) }> - +
); @@ -797,7 +820,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P const resizerScheme = colorScheme ? 'documentDecorations-resizer' + colorScheme : ''; // Radius constants - const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView; + const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox; const borderRadius = numberValue(StrCast(seldocview.rootDoc.borderRounding)); const docMax = Math.min(NumCast(seldocview.rootDoc.width) / 2, NumCast(seldocview.rootDoc.height) / 2); const maxDist = Math.min((this.Bounds.r - this.Bounds.x) / 2, (this.Bounds.b - this.Bounds.y) / 2); @@ -820,15 +843,16 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P ) : (
{`${hideTitle ? '' : this.selectionTitle}`} - {!useLock ? null : ( - toggle ability to interact with document
} placement="top"> -
e.preventDefault()}> - -
- - )}
); + const sharingMenu = docShareMode ? ( +
+
+ {shareSymbolIcon + " " + shareMode} + {/* {shareMode} */} +
+
) : (
+ ); return (
: topBtn('close', 'times', undefined, e => this.onCloseClick(true), 'Close')} {hideResizers || hideDeleteButton ?
: topBtn('minimize', 'window-maximize', undefined, e => this.onCloseClick(undefined), 'Minimize')} {hideTitle ? null : titleArea} + {sharingMenu} + {hideOpenButton ?
: + seldocview.rootDoc._lockedPosition? topBtn('lock', 'lock', this.onLockDown, undefined, 'Toggle ability to interact with document') + : topBtn('lock', 'unlock', this.onLockDown, undefined, 'Toggle ability to interact with document')} {hideOpenButton ?
: topBtn('open', 'external-link-alt', this.onMaximizeDown, undefined, 'Open in Lightbox (ctrl: as alias, shift: in new collection)')}
{hideResizers ? null : ( diff --git a/src/client/views/PropertiesView.scss b/src/client/views/PropertiesView.scss index 897be9a32..3edc7fea8 100644 --- a/src/client/views/PropertiesView.scss +++ b/src/client/views/PropertiesView.scss @@ -160,6 +160,50 @@ } } + .propertiesView-shareDropDown{ + margin-right: 10px; + width: 92%; + + & .propertiesView-shareDropDownNone, + .propertiesView-shareDropDownAdmin{ + padding: 5px; + background: grey; + color: rgb(71, 71, 71); + border-radius: 6px; + border: 1px solid rgb(71, 71, 71); + } + & .propertiesView-shareDropDownEdit, + .propertiesView-shareDropDownSelf-Edit{ + padding: 5px; + background: rgb(235, 235, 145); + color: rgb(75, 75, 5); + border-radius: 6px; + border: 1px solid rgb(75, 75, 5); + } + & .propertiesView-shareDropDownAugment{ + padding: 5px; + background: rgb(160, 230, 160); + color:rgb(19, 80, 19); + border-radius: 6px; + border: 1px solid rgb(19, 80, 19); + + } + & .propertiesView-shareDropDownView{ + padding: 5px; + background: rgb(161, 161, 238); + color: rgb(25, 25, 101); + border-radius: 6px; + border: 1px solid rgb(25, 25, 101); + } + & .propertiesView-shareDropDownNot-Shared{ + padding: 5px; + background: rgb(210, 143, 143); + color: rgb(138, 47, 47); + border-radius: 6px; + border: 1px solid rgb(138, 47, 47); + } + } + .propertiesView-filters { //border-bottom: 1px solid black; //padding: 8.5px; @@ -344,7 +388,6 @@ // display: inline-table; background-color: #ececec; max-height: 130px; - overflow-y: auto; width: 92%; .propertiesView-sharingTable-item { @@ -373,18 +416,6 @@ display: flex; align-items: flex-end; margin-left: auto; - - .permissions-select { - border: none; - background-color: inherit; - width: 87px; - text-align: justify; // for Edge - text-align-last: end; - - &:hover { - cursor: pointer; - } - } } &:last-child { @@ -393,6 +424,19 @@ } } + .propertiesView-permissions-select { + background-color: inherit; + background: inherit; + border: none; + background: inherit; + width: 87px; + text-align: justify; // for Edge + text-align-last: end; + &:hover { + cursor: pointer; + } + } + .propertiesView-fields { //border-bottom: 1px solid black; //padding: 8.5px; diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index e750dc43a..c34760d13 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -7,7 +7,7 @@ import { intersection } from 'lodash'; import { action, autorun, computed, Lambda, observable } from 'mobx'; import { observer } from 'mobx-react'; import { ColorState, SketchPicker } from 'react-color'; -import { AclAdmin, AclSym, HierarchyMapping, DataSym, Doc, DocListCast, Field, HeightSym, NumListCast, Opt, StrListCast, WidthSym } from '../../fields/Doc'; +import { AclAdmin, AclSym, HierarchyMapping, DataSym, Doc, DocListCast, Field, HeightSym, NumListCast, Opt, StrListCast, WidthSym, DocCastAsync } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { InkField } from '../../fields/InkField'; import { List } from '../../fields/List'; @@ -364,8 +364,13 @@ export class PropertiesView extends React.Component { */ @undoBatch changePermissions = (e: any, user: string) => { - const docs = (SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(dv => dv.props.Document)).filter(doc => doc).map(doc => (this.layoutDocAcls ? doc : DocCast(doc)[DataSym])); - SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs); + if (user=="Public"){ + this.selectedDoc!['acl-' +user] = e.currentTarget.value as SharingPermissions; + } + else{ + const docs = (SelectionManager.Views().length < 2 ? [this.selectedDoc] : SelectionManager.Views().map(dv => dv.props.Document)).filter(doc => doc).map(doc => (this.layoutDocAcls ? doc : DocCast(doc)[DataSym])); + SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, docs); + } }; /** @@ -376,11 +381,11 @@ export class PropertiesView extends React.Component { if (permission === '-multiple-') dropdownValues.unshift(permission); if (user !== 'Override') dropdownValues.splice(dropdownValues.indexOf(SharingPermissions.Unset), 1); return ( - this.changePermissions(e, user)}> {dropdownValues .filter(permission => !Doc.noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any)) .map(permission => ( - @@ -433,8 +438,7 @@ export class PropertiesView extends React.Component { // onPointerDown={action(() => this.selectedUser = this.selectedUser === name ? "" : name)} >
- {' '} - {name}{' '} + {' '}{name}{' '}
{/* {name !== "Me" ? this.notifyIcon : null} */}
@@ -445,13 +449,52 @@ export class PropertiesView extends React.Component { ); } + publicACLDropDown(admin: boolean, permission: string, showExpansionIcon?: boolean){ + var dropDownText = ""; + switch(StrCast(permission)){ + case ("Edit"): + dropDownText = "⬢ "; + break; + case ("Self-Edit"): + dropDownText = "⬢ "; + break; + case ("Augment"): + dropDownText = "⬟ "; + break; + case ("View"): + dropDownText = "♦ "; + break; + case ("Not-Shared"): + dropDownText = "▲ "; + break; + } + return ( +
+
+
+
+ {' '}{dropDownText}{' '} + {admin && permission !== 'Owner' ? this.getPermissionsSelect("Public", permission) : permission} + {permission === 'Owner' || showExpansionIcon ? this.expansionIcon : null} +
+
+
+
+ ); + } + /** * @returns the sharing and permissions panel. */ @computed get sharingTable() { + // const docToUse = this.selectedDocumentView?.rootDoc; + const docToUse = this.selectedDoc; + if (!docToUse){ + return null; + } // all selected docs const docs = - SelectionManager.Views().length < 2 ? [this.layoutDocAcls ? this.selectedDoc : this.selectedDoc?.[DataSym]] : SelectionManager.Views().map(docView => (this.layoutDocAcls ? docView.props.Document : docView.props.Document[DataSym])); + SelectionManager.Views().length < 2 ? [this.layoutDocAcls ? docToUse : docToUse?.[DataSym]] : SelectionManager.Views().map(docView => (this.layoutDocAcls ? docView.props.Document : docView.props.Document[DataSym])); const target = docs[0]; @@ -479,17 +522,27 @@ export class PropertiesView extends React.Component { // shifts the current user, owner, public to the top of the doc. // tableEntries.unshift(this.sharingItem("Override", showAdmin, docs.filter(doc => doc).every(doc => doc["acl-Override"] === docs[0]["acl-Override"]) ? (AclMap.get(target[AclSym]?.["acl-Override"]) || "None") : "-multiple-")); if (ownerSame) tableEntries.unshift(this.sharingItem(StrCast(target.author), showAdmin, 'Owner')); - tableEntries.unshift(this.sharingItem('Public', showAdmin, docs.filter(doc => doc).every(doc => doc['acl-Public'] === target['acl-Public']) ? target['acl-Public'] || SharingPermissions.None : '-multiple-')); - tableEntries.unshift( - this.sharingItem( - 'Me', - showAdmin, - docs.filter(doc => doc).every(doc => doc.author === Doc.CurrentUserEmail) ? 'Owner' : effectiveAcls.every(acl => acl === effectiveAcls[0]) ? HierarchyMapping.get(effectiveAcls[0])!.name : '-multiple-', - !ownerSame - ) - ); - return
{tableEntries}
; + // tableEntries.unshift(this.sharingItem(target.author, showAdmin, docs.filter(doc => doc).every(doc => doc['acl-Public'] === target['acl-Public']) ? target['acl-Public'] || SharingPermissions.None : '-multiple-')); + // tableEntries.unshift( + // this.sharingItem( + // 'Me', + // showAdmin, + // docs.filter(doc => doc).every(doc => doc.author === Doc.CurrentUserEmail) ? 'Owner' : effectiveAcls.every(acl => acl === effectiveAcls[0]) ? HierarchyMapping.get(effectiveAcls[0])!.name : '-multiple-', + // !ownerSame + // ) + // ); + docs.map(doc => tableEntries.unshift(this.sharingItem(doc.author, showAdmin, doc['acl-Public'], true))); + + return ( +
Sharing Mode +
{this.publicACLDropDown(true, StrCast(docToUse['acl-Public']), false)}
+


Who has access to the Dashboard?
+
{ +
{tableEntries}
+ }
+
+ ); } @computed get fieldsCheckbox() { @@ -1116,12 +1169,15 @@ export class PropertiesView extends React.Component { {!this.openSharing ? null : (
- {!Doc.noviceMode ? ( + + + {/* {!Doc.noviceMode ? ( // what is the layout checkbox for?
(this.layoutDocAcls = !this.layoutDocAcls))} checked={this.layoutDocAcls} />
Layout
- ) : null} + ) : null} */} + {/*
{"Re-distribute sharing settings"}
}>
+ //
) : null; } } @@ -330,9 +331,9 @@ export function DashboardStyleProvider(doc: Opt, props: Opt {DashboardToggleButton(doc, 'hidden', 'eye-slash', 'eye', () => { doc.hidden = doc.hidden ? undefined : true; - if (!doc.hidden) { - DocFocusOrOpen(doc, props?.ContainingCollectionDoc); - } + // if (!doc.hidden) { + // DocFocusOrOpen(doc, props?.ContainingCollectionDoc); + // } })} ); diff --git a/src/fields/util.ts b/src/fields/util.ts index e517e7604..4f7472842 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -183,10 +183,10 @@ export enum SharingPermissions { Unset = 'None', Admin = 'Admin', Edit = 'Edit', - SelfEdit = 'Self Edit', + SelfEdit = 'Self-Edit', Augment = 'Augment', View = 'View', - None = 'Not Shared', + None = 'Not-Shared', } // return acl from cache or cache the acl and return. -- cgit v1.2.3-70-g09d2 From 4265feca9e63cad6067055497ecabd354ead84f4 Mon Sep 17 00:00:00 2001 From: srichman333 Date: Wed, 22 Mar 2023 17:45:32 -0400 Subject: collaboration icons --- src/client/views/DocumentDecorations.tsx | 3 +++ src/client/views/PropertiesView.tsx | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d87c13ce6..b2b18b245 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -756,6 +756,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P case ("Not-Shared"): shareSymbolIcon = "▲ "; break; + default: + shareSymbolIcon = ""; + break; } // hide the decorations if the parent chooses to hide it or if the document itself hides it diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index c34760d13..e58558aea 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -504,25 +504,22 @@ export class PropertiesView extends React.Component { // users in common between all docs const commonKeys: string[] = intersection(...docs.map(doc => doc?.[AclSym] && Object.keys(doc[AclSym]).filter(key => key !== 'acl-Me'))); - const tableEntries = []; // DocCastAsync(Doc.UserDoc().sidebarUsersDisplayed).then(sidebarUsersDisplayed => { - if (commonKeys.length) { - for (const key of commonKeys) { - const name = denormalizeEmail(key.substring(4)); - const uniform = docs.every(doc => doc?.[AclSym]?.[key] === docs[0]?.[AclSym]?.[key]); - if (name !== Doc.CurrentUserEmail && name !== target.author && name !== 'Public' && name !== 'Override' /* && sidebarUsersDisplayed![name] !== false*/) { - tableEntries.push(this.sharingItem(name, showAdmin, uniform ? HierarchyMapping.get(target[AclSym][key])!.name : '-multiple-')); - } - } - } - + // if (commonKeys.length) { + // for (const key of commonKeys) { + // const name = denormalizeEmail(key.substring(4)); + // const uniform = docs.every(doc => doc?.[AclSym]?.[key] === docs[0]?.[AclSym]?.[key]); + // if (name !== Doc.CurrentUserEmail && name !== target.author && name !== 'Public' && name !== 'Override' /* && sidebarUsersDisplayed![name] !== false*/) { + // tableEntries.push(this.sharingItem(name, showAdmin, uniform ? HierarchyMapping.get(target[AclSym][key])!.name : '-multiple-')); + // } + // } + // } const ownerSame = Doc.CurrentUserEmail !== target.author && docs.filter(doc => doc).every(doc => doc.author === docs[0].author); // shifts the current user, owner, public to the top of the doc. // tableEntries.unshift(this.sharingItem("Override", showAdmin, docs.filter(doc => doc).every(doc => doc["acl-Override"] === docs[0]["acl-Override"]) ? (AclMap.get(target[AclSym]?.["acl-Override"]) || "None") : "-multiple-")); if (ownerSame) tableEntries.unshift(this.sharingItem(StrCast(target.author), showAdmin, 'Owner')); - // tableEntries.unshift(this.sharingItem(target.author, showAdmin, docs.filter(doc => doc).every(doc => doc['acl-Public'] === target['acl-Public']) ? target['acl-Public'] || SharingPermissions.None : '-multiple-')); // tableEntries.unshift( // this.sharingItem( @@ -532,7 +529,10 @@ export class PropertiesView extends React.Component { // !ownerSame // ) // ); - docs.map(doc => tableEntries.unshift(this.sharingItem(doc.author, showAdmin, doc['acl-Public'], true))); + + SharingManager.Instance.users.forEach(eachUser => tableEntries.unshift(this.sharingItem(eachUser.user.email, false, "test", false))); + + docs.map(doc => tableEntries.unshift(this.sharingItem(doc.author, showAdmin, 'Owner', true))); return (
Sharing Mode -- cgit v1.2.3-70-g09d2 From 0cda1a8f8b4e3d79c30291685456c7cb62fd7e8e Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Mon, 24 Apr 2023 13:39:14 -0400 Subject: add folder for physics box --- src/.DS_Store | Bin 10244 -> 10244 bytes src/client/documents/Documents.ts | 2 +- src/client/views/.DS_Store | Bin 10244 -> 10244 bytes src/client/views/nodes/DocumentContentsView.tsx | 2 +- .../nodes/PhysicsBox/PhysicsSimulationBox.scss | 72 ++ .../nodes/PhysicsBox/PhysicsSimulationBox.tsx | 494 ++++++++++++ .../nodes/PhysicsBox/PhysicsSimulationWall.tsx | 34 + .../nodes/PhysicsBox/PhysicsSimulationWedge.tsx | 83 ++ .../nodes/PhysicsBox/PhysicsSimulationWeight.tsx | 860 +++++++++++++++++++++ src/client/views/nodes/PhysicsSimulationBox.scss | 72 -- src/client/views/nodes/PhysicsSimulationBox.tsx | 494 ------------ src/client/views/nodes/PhysicsSimulationWall.tsx | 34 - src/client/views/nodes/PhysicsSimulationWedge.tsx | 83 -- src/client/views/nodes/PhysicsSimulationWeight.tsx | 860 --------------------- 14 files changed, 1545 insertions(+), 1545 deletions(-) create mode 100644 src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.scss create mode 100644 src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx create mode 100644 src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx create mode 100644 src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx create mode 100644 src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx delete mode 100644 src/client/views/nodes/PhysicsSimulationBox.scss delete mode 100644 src/client/views/nodes/PhysicsSimulationBox.tsx delete mode 100644 src/client/views/nodes/PhysicsSimulationWall.tsx delete mode 100644 src/client/views/nodes/PhysicsSimulationWedge.tsx delete mode 100644 src/client/views/nodes/PhysicsSimulationWeight.tsx (limited to 'src') diff --git a/src/.DS_Store b/src/.DS_Store index 4ed785983..be99aa5af 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c7556d668..31c8a7890 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -50,7 +50,7 @@ import { LinkDescriptionPopup } from '../views/nodes/LinkDescriptionPopup'; import { LoadingBox } from '../views/nodes/LoadingBox'; import { MapBox } from '../views/nodes/MapBox/MapBox'; import { PDFBox } from '../views/nodes/PDFBox'; -import PhysicsSimulationBox from '../views/nodes/PhysicsSimulationBox'; +import PhysicsSimulationBox from '../views/nodes/PhysicsBox/PhysicsSimulationBox'; import { RecordingBox } from '../views/nodes/RecordingBox/RecordingBox'; import { ScreenshotBox } from '../views/nodes/ScreenshotBox'; import { ScriptingBox } from '../views/nodes/ScriptingBox'; diff --git a/src/client/views/.DS_Store b/src/client/views/.DS_Store index e4ac87aad..5fa69f28c 100644 Binary files a/src/client/views/.DS_Store and b/src/client/views/.DS_Store differ diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index c6818bf3c..5d72ca019 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -34,7 +34,7 @@ import { LinkAnchorBox } from './LinkAnchorBox'; import { LinkBox } from './LinkBox'; import { MapBox } from './MapBox/MapBox'; import { PDFBox } from './PDFBox'; -import PhysicsSimulationBox from './PhysicsSimulationBox' +import PhysicsSimulationBox from './PhysicsBox/PhysicsSimulationBox' import { RecordingBox } from './RecordingBox'; import { ScreenshotBox } from './ScreenshotBox'; import { ScriptingBox } from './ScriptingBox'; diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.scss new file mode 100644 index 000000000..0f05010b4 --- /dev/null +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.scss @@ -0,0 +1,72 @@ +* { + box-sizing: border-box; + font-size: 14px; +} + +.mechanicsSimulationContainer { + background-color: white; + height: 100%; + width: 100%; + display: flex; + + .mechanicsSimulationEquationContainer { + position: fixed; + left: 70%; + padding: 1em; + + .mechanicsSimulationControls { + display: flex; + justify-content: space-between; + } + } +} + +.coordinateSystem { + z-index: -100; +} + +th, +td { + border-collapse: collapse; + padding: 1em; +} + +table { + min-width: 300px; +} + +tr:nth-child(even) { + background-color: #d6eeee; +} + +button { + z-index: 50; +} + +.angleLabel { + font-weight: bold; + font-size: 20px; + user-select: none; + pointer-events: none; +} + +.mechanicsSimulationSettingsMenu { + width: 100%; + height: 100%; + font-size: 12px; + background-color: rgb(224, 224, 224); + border-radius: 2px; + border-color: black; + border-style: solid; + padding: 10px; + position: fixed; + z-index: 1000; +} + +.mechanicsSimulationSettingsMenuRow { + display: flex; +} + +.mechanicsSimulationSettingsMenuRowDescription { + width: 50%; +} \ No newline at end of file diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx new file mode 100644 index 000000000..d0e854263 --- /dev/null +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -0,0 +1,494 @@ +import "./PhysicsSimulationBox.scss"; +import { FieldView, FieldViewProps } from './FieldView'; +import React = require('react'); +import { ViewBoxAnnotatableComponent } from '../DocComponent'; +import { observer } from 'mobx-react'; +import "./PhysicsSimulationBox.scss"; +import Weight from "./PhysicsSimulationWeight"; +import Wall from "./PhysicsSimulationWall" +import Wedge from "./PhysicsSimulationWedge" +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { CheckBox } from "../search/CheckBox"; +export interface IForce { + description: string; + magnitude: number; + directionInDegrees: number; +} +export interface IWallProps { + length: number; + xPos: number; + yPos: number; + angleInDegrees: number; +} + +interface PhysicsVectorTemplate { + top: number; + left: number; + width: number; + height: number; + x1: number; + y1: number; + x2: number; + y2: number; + weightX: number; + weightY: number; +} + +@observer +export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() { + + public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); } + + // Constants + gravityMagnitude = 9.81; + forceOfGravity: IForce = { + description: "Gravity", + magnitude: this.gravityMagnitude, + directionInDegrees: 270, + }; + xMin = 0; + yMin = 0; + xMax = 300; + yMax = 300; + color = `rgba(0,0,0,0.5)`; + radius = 0.1*this.yMax + update = true + menuIsOpen = false + + constructor(props: any) { + super(props); + } + + // Add one weight to the simulation + addWeight () { + this.dataDoc.weight = true; + this.dataDoc.wedge = false; + this.dataDoc.pendulum = false; + this.addWalls(); + }; + + // Set weight defaults + setToWeightDefault () { + this.dataDoc.startPosY = this.yMin+this.radius; + this.dataDoc.startPosX = (this.xMax+this.xMin-this.radius)/2; + this.dataDoc.updatedForces = [this.forceOfGravity]; + this.dataDoc.startForces = [this.forceOfGravity]; + } + + // Add a wedge with a One Weight to the simulation + addWedge () { + this.dataDoc.weight = true; + this.dataDoc.wedge = true; + this.dataDoc.pendulum = false; + this.addWalls(); + }; + + // Set wedge defaults + setToWedgeDefault () { + this.changeWedgeBasedOnNewAngle(26); + this.updateForcesWithFriction(this.dataDoc.coefficientOfStaticFriction); + } + + // Add a simple pendulum to the simulation + addPendulum = () => { + this.dataDoc.weight = true; + this.dataDoc.wedge = false; + this.dataDoc.pendulum = true; + this.removeWalls(); + let angle = this.dataDoc.pendulumAngle; + let mag = 9.81 * Math.cos((angle * Math.PI) / 180); + let forceOfTension: IForce = { + description: "Tension", + magnitude: mag, + directionInDegrees: 90 - angle, + }; + this.dataDoc.updatedForces = [this.forceOfGravity, forceOfTension]; + this.dataDoc.startForces = [this.forceOfGravity, forceOfTension]; + }; + + // Set pendulum defaults + setToPendulumDefault () { + let length = this.xMax*0.7; + let angle = 35; + let x = length * Math.cos(((90 - angle) * Math.PI) / 180); + let y = length * Math.sin(((90 - angle) * Math.PI) / 180); + let xPos = this.xMax / 2 - x - this.radius; + let yPos = y - this.radius; + this.dataDoc.startPosX = xPos; + this.dataDoc.startPosY = yPos; + let mag = 9.81 * Math.cos((angle * Math.PI) / 180); + this.dataDoc.pendulumAngle = angle; + this.dataDoc.pendulumLength = length; + this.dataDoc.startPendulumAngle = angle; + this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle; + } + + // Update forces when coefficient of static friction changes in freeform mode + updateForcesWithFriction ( + coefficient: number, + width: number = this.dataDoc.wedgeWidth, + height: number = this.dataDoc.wedgeHeight + ) { + let normalForce = { + description: "Normal Force", + magnitude: this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)), + directionInDegrees: + 180 - 90 - (Math.atan(height / width) * 180) / Math.PI, + }; + let frictionForce: IForce = { + description: "Static Friction Force", + magnitude: + coefficient * + this.forceOfGravity.magnitude * + Math.cos(Math.atan(height / width)), + directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI, + }; + // reduce magnitude of friction force if necessary such that block cannot slide up plane + let yForce = -this.forceOfGravity.magnitude; + yForce += + normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180); + yForce += + frictionForce.magnitude * + Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + if (yForce > 0) { + frictionForce.magnitude = + (-normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + + this.forceOfGravity.magnitude) / + Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + } + if (coefficient != 0) { + this.dataDoc.startForces = [this.forceOfGravity, normalForce, frictionForce]; + this.dataDoc.updatedForces = [this.forceOfGravity, normalForce, frictionForce]; + } else { + this.dataDoc.startForces = [this.forceOfGravity, normalForce]; + this.dataDoc.updatedForces = [this.forceOfGravity, normalForce]; + } + }; + + // Change wedge height and width and weight position to match new wedge angle + changeWedgeBasedOnNewAngle = (angle: number) => { + let width = 0; + let height = 0; + if (angle < 50) { + width = this.xMax*0.6; + height = Math.tan((angle * Math.PI) / 180) * width; + this.dataDoc.wedgeWidth = width; + this.dataDoc.wedgeHeight = height; + } else if (angle < 70) { + width = this.xMax*0.3; + height = Math.tan((angle * Math.PI) / 180) * width; + this.dataDoc.wedgeWidth = width; + this.dataDoc.wedgeHeight = height; + } else { + width = this.xMax*0.15; + height = Math.tan((angle * Math.PI) / 180) * width; + this.dataDoc.wedgeWidth = width; + this.dataDoc.wedgeHeight = height; + } + + // update weight position based on updated wedge width/height + let xPos = (this.xMax * 0.2)-this.radius; + let yPos = width * Math.tan((angle * Math.PI) / 180) - this.radius; + + this.dataDoc.startPosX = xPos; + this.dataDoc.startPosY = this.getDisplayYPos(yPos); + this.updateForcesWithFriction( + Number(this.dataDoc.coefficientOfStaticFriction), + width, + height + ); + this.dataDoc['updateDisplay'] = !this.dataDoc['updateDisplay'] + }; + + // Helper function to go between display and real values + getDisplayYPos = (yPos: number) => { + return this.yMax - yPos - 2 * 50 + 5; + }; + + // In review mode, edit force arrow sketch on mouse movement + editForce = (element: PhysicsVectorTemplate) => { + if (!this.dataDoc.sketching) { + let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element); + this.dataDoc.forceSketches = sketches; + this.dataDoc.currentForceSketch = element; + this.dataDoc.sketching = true; + } + }; + + // In review mode, used to delete force arrow sketch on SHIFT+click + deleteForce = (element: PhysicsVectorTemplate) => { + if (!this.dataDoc.sketching) { + let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element); + this.dataDoc.forceSketches = sketches; + } + }; + + // Remove floor and walls from simulation + removeWalls = () => { + this.dataDoc.wallPositions = [] + }; + + // Add floor and walls to simulation + addWalls = () => { + let walls = []; + walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 }); + walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 }); + walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 }); + this.dataDoc.wallPositions = walls + }; + + + componentDidMount() { + this.xMax = this.layoutDoc._width; + this.yMax = this.layoutDoc._height; + this.radius = 0.1*this.layoutDoc._height; + + // Add weight + if (this.dataDoc.simulationType == "Inclined Plane") { + this.addWedge() + } else if (this.dataDoc.simulationType == "Pendulum") { + this.addPendulum() + } else { + this.dataDoc.simulationType = "Free Weight" + this.addWeight() + } + this.dataDoc.accelerationXDisplay = this.dataDoc.accelerationXDisplay ?? 0; + this.dataDoc.accelerationYDisplay = this.dataDoc.accelerationYDisplay ?? 0; + this.dataDoc.coefficientOfKineticFriction = this.dataDoc.coefficientOfKineticFriction ?? 0; + this.dataDoc.coefficientOfStaticFriction = this.dataDoc.coefficientOfStaticFriction ?? 0; + this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? []; + this.dataDoc.elasticCollisions = this.dataDoc.elasticCollisions ?? false; + this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? []; + this.dataDoc.pendulumAngle = this.dataDoc.pendulumAngle ?? 26; + this.dataDoc.pendulumLength = this.dataDoc.pendulumLength ?? 300; + this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0; + this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0; + this.dataDoc.showAcceleration = this.dataDoc.showAcceleration ?? false; + this.dataDoc.showForceMagnitudes = this.dataDoc.showForceMagnitudes ?? false; + this.dataDoc.showForces = this.dataDoc.showForces ?? false; + this.dataDoc.showVelocity = this.dataDoc.showVelocity ?? false; + this.dataDoc.startForces = this.dataDoc.startForces ?? [this.forceOfGravity]; + this.dataDoc.startPendulumAngle = this.dataDoc.startPendulumAngle ?? 0; + this.dataDoc.startPosX = this.dataDoc.startPosX ?? 50; + this.dataDoc.startPosY = this.dataDoc.startPosY ?? 50; + this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0; + this.dataDoc.updateDisplay = this.dataDoc.updateDisplay ?? false; + this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [this.forceOfGravity]; + this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0; + this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0; + this.dataDoc.wallPositions = this.dataDoc.wallPositions ?? []; + this.dataDoc.wedgeAngle = this.dataDoc.wedgeAngle ?? 26; + this.dataDoc.wedgeHeight = this.dataDoc.wedgeHeight ?? Math.tan((26 * Math.PI) / 180) * this.xMax*0.6; + this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? this.xMax*0.6; + + this.dataDoc.adjustPendulumAngle = true; + this.dataDoc.simulationPaused = true; + this.dataDoc.simulationReset = false; + + // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click + document.addEventListener("keydown", (e) => { + if (e.shiftKey) { + this.dataDoc.deleteMode = true; + } + }); + document.addEventListener("keyup", (e) => { + if (e.shiftKey) { + this.dataDoc.deleteMode = false; + } + }); + } + + componentDidUpdate() { + this.xMax = this.layoutDoc._width; + this.yMax = this.layoutDoc._height; + this.radius = 0.1*this.layoutDoc._height; + } + + render () { + return ( +
+
+
+
+
+ {this.dataDoc.weight && ( + + )} + {this.dataDoc.wedge && ( + + )} +
+
+ {(this.dataDoc.wallPositions ?? []).map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { + return ( +
+ +
+ ); + })} +
+
+
+
+ {this.menuIsOpen && ( +
+
{this.menuIsOpen = false; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}}> + +
+

Simulation Settings

+
+

Show forces

+
{this.dataDoc.showForces = !this.dataDoc.showForces}}/>
+
+
+

Show acceleration

+
{this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/>
+
+
+
+

Show velocity

+
{this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/>
+
+
+ {this.dataDoc.simulationType == "Free Weight" &&
+

Elastic collisions

+
{this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/>
+
} + {this.dataDoc.simulationType == "Pendulum" &&
+

Pendulum start angle

+
+ { + let angle = e.target.value; + if (angle > 35) { + angle = 35 + } + if (angle < 0) { + angle = 0 + } + let length = this.xMax*0.7; + let x = length * Math.cos(((90 - angle) * Math.PI) / 180); + let y = length * Math.sin(((90 - angle) * Math.PI) / 180); + let xPos = this.xMax / 2 - x - this.radius; + let yPos = y - this.radius; + this.dataDoc.startPosX = xPos; + this.dataDoc.startPosY = yPos; + let mag = 9.81 * Math.cos((angle * Math.PI) / 180); + this.dataDoc.pendulumAngle = angle; + this.dataDoc.pendulumLength = length; + this.dataDoc.startPendulumAngle = angle; + this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle; + }} + /> +
+
} + {this.dataDoc.simulationType == "Inclined Plane" &&
+

Inclined plane angle

+
+ { + let angle = e.target.value ?? 0 + if (angle > 70) { + angle = 70 + } + if (angle < 0) { + angle = 0 + } + this.dataDoc.wedgeAngle = angle + this.changeWedgeBasedOnNewAngle(angle) + }} + /> +
+
} +
+ )} +
+
+
+
+ {this.dataDoc.simulationPaused && ( + + )} + {!this.dataDoc.simulationPaused && ( + + )} + {this.dataDoc.simulationPaused && ( + + )} + {this.dataDoc.simulationPaused && ( )} + +
+
+
+
+
+ ); + } + } \ No newline at end of file diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx new file mode 100644 index 000000000..9283e8d46 --- /dev/null +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWall.tsx @@ -0,0 +1,34 @@ +import React = require('react'); + +export interface Force { + magnitude: number; + directionInDegrees: number; +} +export interface IWallProps { + length: number; + xPos: number; + yPos: number; + angleInDegrees: number; +} + +export default class App extends React.Component { + + constructor(props: any) { + super(props) + } + + wallStyle = { + width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "3%", + height: this.props.angleInDegrees == 0 ? "3%" : this.props.length + "%", + position: "absolute" as "absolute", + left: this.props.xPos + "%", + top: this.props.yPos + "%", + backgroundColor: "#6c7b8b", + margin: 0, + padding: 0, + }; + + render () { + return (
); + } +}; diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx new file mode 100644 index 000000000..6134a6bc0 --- /dev/null +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx @@ -0,0 +1,83 @@ +import React = require('react'); +import "./PhysicsSimulationBox.scss"; + +export interface IWedgeProps { + startHeight: number; + startWidth: number; + startLeft: number; + xMax: number; + yMax: number; +} + +interface IState { + angleInRadians: number, + left: number, + coordinates: string, +} + +export default class Wedge extends React.Component { + + constructor(props: any) { + super(props) + this.state = { + angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth), + left: this.props.startLeft, + coordinates: "", + } + } + + color = "#deb887"; + + updateCoordinates() { + const coordinatePair1 = + Math.round(this.state.left) + "," + Math.round(this.props.yMax) + " "; + const coordinatePair2 = + Math.round(this.state.left + this.props.startWidth) + + "," + + Math.round(this.props.yMax) + + " "; + const coordinatePair3 = + Math.round(this.state.left) + + "," + + Math.round(this.props.yMax - this.props.startHeight); + const coord = coordinatePair1 + coordinatePair2 + coordinatePair3; + this.setState({coordinates: coord}); + } + + componentDidMount() { + this.updateCoordinates() + } + + componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { + if (prevProps.startHeight != this.props.startHeight || prevProps.startWidth != this.props.startWidth) { + this.setState({angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth)}); + this.updateCoordinates(); + } + } + + render() { + return ( +
+
+ + + +
+ +

+ {Math.round(((this.state.angleInRadians * 180) / Math.PI) * 100) / 100}° +

+
+ ); + } +}; diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx new file mode 100644 index 000000000..39b3249e8 --- /dev/null +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWeight.tsx @@ -0,0 +1,860 @@ +import React = require('react'); +import { Doc } from '../../../fields/Doc'; +import { IWallProps } from "./PhysicsSimulationWall"; + +export interface IForce { + description: string; + magnitude: number; + directionInDegrees: number; +} +export interface IWeightProps { + adjustPendulumAngle: boolean; + color: string; + dataDoc: Doc; + mass: number; + radius: number; + simulationReset: boolean; + startPosX: number; + startPosY: number; + startVelX?: number; + startVelY?: number; + timestepSize: number; + updateDisplay: boolean, + walls: IWallProps[]; + wedge: boolean; + wedgeHeight: number; + wedgeWidth: number; + xMax: number; + xMin: number; + yMax: number; + yMin: number; +} + +interface IState { + angleLabel: number, + clickPositionX: number, + clickPositionY: number, + dragging: boolean, + kineticFriction: boolean, + timer: number; + update: boolean, + updatedStartPosX: number, + updatedStartPosY: number, + xPosition: number, + xVelocity: number, + yPosition: number, + yVelocity: number, +} +export default class Weight extends React.Component { + + constructor(props: any) { + super(props) + this.state = { + clickPositionX: 0, + clickPositionY: 0, + dragging: false, + kineticFriction: false, + timer: 0, + angleLabel: 0, + updatedStartPosX: this.props.dataDoc['startPosX'], + updatedStartPosY: this.props.dataDoc['startPosY'], + xPosition: this.props.dataDoc['startPosX'], + xVelocity: this.props.startVelX ? this.props.startVelX: 0, + yPosition: this.props.dataDoc['startPosY'], + yVelocity: this.props.startVelY ? this.props.startVelY: 0, + } + } + + // Constants + draggable = !this.props.dataDoc['wedge'] ; + epsilon = 0.0001; + forceOfGravity: IForce = { + description: "Gravity", + magnitude: this.props.mass * 9.81, + directionInDegrees: 270, + }; + + // Var + weightStyle = { + alignItems: "center", + backgroundColor: this.props.color, + borderColor: "black", + borderRadius: 50 + "%", + borderStyle: "solid", + display: "flex", + height: 2 * this.props.radius + "px", + justifyContent: "center", + left: this.props.dataDoc['startPosX'] + "px", + position: "absolute" as "absolute", + top: this.props.dataDoc['startPosY'] + "px", + touchAction: "none", + width: 2 * this.props.radius + "px", + zIndex: 5, + }; + + // Helper function to go between display and real values + getDisplayYPos = (yPos: number) => { + return this.props.yMax - yPos - 2 * this.props.radius + 5; + }; + getYPosFromDisplay = (yDisplay: number) => { + return this.props.yMax - yDisplay - 2 * this.props.radius + 5; + }; + + // Set display values based on real values + setYPosDisplay = (yPos: number) => { + const displayPos = this.getDisplayYPos(yPos); + this.props.dataDoc['positionYDisplay'] = Math.round(displayPos * 100) / 100 + }; + setXPosDisplay = (xPos: number) => { + this.props.dataDoc['positionXDisplay'] = Math.round(xPos * 100) / 100; + }; + setYVelDisplay = (yVel: number) => { + this.props.dataDoc['velocityYDisplay'] = (-1 * Math.round(yVel * 100)) / 100; + }; + setXVelDisplay = (xVel: number) => { + this.props.dataDoc['velocityXDisplay'] = Math.round(xVel * 100) / 100; + }; + + setDisplayValues = ( + xPos: number = this.state.xPosition, + yPos: number = this.state.yPosition, + xVel: number = this.state.xVelocity, + yVel: number = this.state.yVelocity + ) => { + this.setYPosDisplay(yPos); + this.setXPosDisplay(xPos); + this.setYVelDisplay(yVel); + this.setXVelDisplay(xVel); + this.props.dataDoc['accelerationYDisplay'] = + (-1 * Math.round(this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 100)) / 100 + ; + this.props.dataDoc['accelerationXDisplay'] = + Math.round(this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 100) / 100 + ; + }; + + componentDidMount() { + // Timer for animating the simulation + setInterval(() => { + this.setState({timer: this.state.timer + 1}); + }, 60); + } + + componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { + + // When display values updated by user, update real values + if (this.props.updateDisplay != prevProps.updateDisplay) { + if (this.props.dataDoc['positionXDisplay'] != this.state.xPosition) { + let x = this.props.dataDoc['positionXDisplay']; + x = Math.max(0, x); + x = Math.min(x, this.props.xMax - 2 * this.props.radius); + this.setState({updatedStartPosX: x}) + this.setState({xPosition: x}) + this.props.dataDoc['positionXDisplay'] = x; + } + + if (this.props.dataDoc['positionYDisplay'] != this.getDisplayYPos(this.state.yPosition)) { + let y = this.props.dataDoc['positionYDisplay']; + y = Math.max(0, y); + y = Math.min(y, this.props.yMax - 2 * this.props.radius); + this.props.dataDoc['positionYDisplay'] = y; + let coordinatePosition = this.getYPosFromDisplay(y); + this.setState({updatedStartPosY: coordinatePosition}) + this.setState({yPosition: coordinatePosition}) + } + + if (this.props.dataDoc['velocityXDisplay'] != this.state.xVelocity) { + let x = this.props.dataDoc['velocityXDisplay']; + this.setState({xVelocity: x}) + this.props.dataDoc['velocityXDisplay'] = x; + } + + if (this.props.dataDoc['velocityYDisplay'] != this.state.yVelocity) { + let y = this.props.dataDoc['velocityYDisplay']; + this.setState({yVelocity: -y}) + this.props.dataDoc['velocityYDisplay'] + } + } + // Update sim + if (this.state.timer != prevState.timer) { + if (!this.props.dataDoc['simulationPaused']) { + let collisions = false; + if (!this.props.dataDoc['pendulum']) { + const collisionsWithGround = this.checkForCollisionsWithGround(); + const collisionsWithWalls = this.checkForCollisionsWithWall(); + collisions = collisionsWithGround || collisionsWithWalls; + } + if (!collisions) { + this.update(); + } + this.setDisplayValues(); + } + } + + if (this.props.simulationReset != prevProps.simulationReset) { + this.resetEverything(); + } + if (this.props.adjustPendulumAngle != prevProps.adjustPendulumAngle) { + console.log('update angle') + // Change pendulum angle based on input field + let length = this.props.dataDoc['pendulumLength'] ?? 0; + const x = + length * Math.cos(((90 - this.props.dataDoc['pendulumAngle']) * Math.PI) / 180); + const y = + length * Math.sin(((90 - this.props.dataDoc['pendulumAngle']) * Math.PI) / 180); + const xPos = this.props.xMax / 2 - x - this.props.radius; + const yPos = y - this.props.radius - 5; + this.setState({xPosition: xPos}) + this.setState({yPosition: yPos}) + this.setState({updatedStartPosX: xPos}) + this.setState({updatedStartPosY: yPos}) + this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle'] * 100) / 100}) + } + // Update x start position + if (this.props.startPosX != prevProps.startPosX) { + this.setState({updatedStartPosX: this.props.dataDoc['startPosX']}) + this.setState({xPosition: this.props.dataDoc['startPosX']}) + this.setXPosDisplay(this.props.dataDoc['startPosX']); + } + // Update y start position + if (this.props.startPosY != prevProps.startPosY) { + this.setState({updatedStartPosY: this.props.dataDoc['startPosY']}) + this.setState({yPosition: this.props.dataDoc['startPosY']}) + this.setYPosDisplay(this.props.dataDoc['startPosY']); + } + if (!this.props.dataDoc['simulationPaused']) { + if (this.state.xVelocity != prevState.xVelocity) { + if (this.props.dataDoc['wedge'] && this.state.xVelocity != 0 && !this.state.kineticFriction) { + this.setState({kineticFriction: true}); + //switch from static to kinetic friction + const normalForce: IForce = { + description: "Normal Force", + magnitude: + this.forceOfGravity.magnitude * + Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), + directionInDegrees: + 180 - 90 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, + }; + let frictionForce: IForce = { + description: "Kinetic Friction Force", + magnitude: + this.props.dataDoc['coefficientOfKineticFriction'] * + this.forceOfGravity.magnitude * + Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), + directionInDegrees: + 180 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, + }; + // reduce magnitude of friction force if necessary such that block cannot slide up plane + let yForce = -this.forceOfGravity.magnitude; + yForce += + normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180); + yForce += + frictionForce.magnitude * + Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + if (yForce > 0) { + frictionForce.magnitude = + (-normalForce.magnitude * + Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + + this.forceOfGravity.magnitude) / + Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); + } + if (this.props.dataDoc['coefficientOfKineticFriction'] != 0) { + this.props.dataDoc['updatedForces'] = [this.forceOfGravity, normalForce, frictionForce]; + } else { + this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, normalForce]); + } + } + } + } + + this.weightStyle = { + alignItems: "center", + backgroundColor: this.props.color, + borderColor: this.state.dragging ? "lightblue" : "black", + borderRadius: 50 + "%", + borderStyle: "solid", + display: "flex", + height: 2 * this.props.radius + "px", + justifyContent: "center", + left: this.state.xPosition + "px", + position: "absolute" as "absolute", + top: this.state.yPosition + "px", + touchAction: "none", + width: 2 * this.props.radius + "px", + zIndex: 5, + }; + } + + resetEverything = () => { + this.setState({kineticFriction: false}) + this.setState({xPosition: this.state.updatedStartPosX}) + this.setState({yPosition: this.state.updatedStartPosY}) + this.setState({xVelocity: this.props.startVelX ?? 0}) + this.setState({yVelocity: this.props.startVelY ?? 0}) + this.props.dataDoc['updatedForces'] = (this.props.dataDoc['startForces']) + this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle']* 100) / 100}) + this.setDisplayValues(); + }; + + getNewAccelerationX = (forceList: IForce[]) => { + let newXAcc = 0; + if (forceList) { + forceList.forEach((force) => { + newXAcc += + (force.magnitude * + Math.cos((force.directionInDegrees * Math.PI) / 180)) / + this.props.mass; + }); + } + return newXAcc; + }; + + getNewAccelerationY = (forceList: IForce[]) => { + let newYAcc = 0; + if (forceList) { + forceList.forEach((force) => { + newYAcc += + (-1 * + (force.magnitude * + Math.sin((force.directionInDegrees * Math.PI) / 180))) / + this.props.mass; + }); + } + return newYAcc; + }; + + getNewForces = ( + xPos: number, + yPos: number, + xVel: number, + yVel: number + ) => { + if (!this.props.dataDoc['pendulum']) { + return this.props.dataDoc['updatedForces']; + } + const x = this.props.xMax / 2 - xPos - this.props.radius; + const y = yPos + this.props.radius + 5; + let angle = (Math.atan(y / x) * 180) / Math.PI; + if (angle < 0) { + angle += 180; + } + let oppositeAngle = 90 - angle; + if (oppositeAngle < 0) { + oppositeAngle = 90 - (180 - angle); + } + + const pendulumLength = Math.sqrt(x * x + y * y); + this.props.dataDoc['pendulumAngle'] = oppositeAngle; + this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y); + + const mag = + this.props.mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) + + (this.props.mass * (xVel * xVel + yVel * yVel)) / pendulumLength; + + const forceOfTension: IForce = { + description: "Tension", + magnitude: mag, + directionInDegrees: angle, + }; + this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle']* 100) / 100}) + + return [this.forceOfGravity, forceOfTension]; + }; + + getNewPosition = (pos: number, vel: number) => { + return pos + vel * this.props.timestepSize; + }; + + getNewVelocity = (vel: number, acc: number) => { + return vel + acc * this.props.timestepSize; + }; + + checkForCollisionsWithWall = () => { + let collision = false; + const minX = this.state.xPosition; + const maxX = this.state.xPosition + 2 * this.props.radius; + const containerWidth = 300; + if (this.state.xVelocity != 0) { + if (this.props.dataDoc.wallPositions) { + this.props.dataDoc['wallPositions'].forEach((wall) => { + if (wall.angleInDegrees == 90) { + const wallX = (wall.xPos / 100) * 300; + if (wall.xPos < 0.35) { + if (minX <= wallX) { + if (this.props.dataDoc['elasticCollisions']) { + this.setState({xVelocity: -this.state.xVelocity}); + } else { + this.setState({xVelocity: 0}); + this.setState({xPosition: wallX+5}); + } + collision = true; + } + } else { + if (maxX >= wallX) { + if (this.props.dataDoc['elasticCollisions']) { + this.setState({xVelocity: -this.state.xVelocity}); + } else { + this.setState({xVelocity: 0}); + this.setState({xPosition: wallX - 2 * this.props.radius + 5}); + } + collision = true; + } + } + } + }); + } + } + return collision; + }; + + checkForCollisionsWithGround = () => { + let collision = false; + const maxY = this.state.yPosition + 2 * this.props.radius; + if (this.state.yVelocity > 0) { + if (this.props.dataDoc.wallPositions) { + this.props.dataDoc['wallPositions'].forEach((wall) => { + if (wall.angleInDegrees == 0) { + const groundY = (wall.yPos / 100) * this.props.yMax; + if (maxY >= groundY) { + if (this.props.dataDoc['elasticCollisions']) { + this.setState({yVelocity: -this.state.yVelocity}) + } else { + this.setState({yVelocity: 0}) + this.setState({yPosition: groundY - 2 * this.props.radius + 5}) + const forceOfGravity: IForce = { + description: "Gravity", + magnitude: 9.81 * this.props.mass, + directionInDegrees: 270, + }; + const normalForce: IForce = { + description: "Normal force", + magnitude: 9.81 * this.props.mass, + directionInDegrees: wall.angleInDegrees + 90, + }; + this.props.dataDoc['updatedForces'] = ([forceOfGravity, normalForce]); + } + collision = true; + } + } + }); + } + } + return collision; + }; + + update = () => { + // RK4 update + let xPos = this.state.xPosition; + let yPos = this.state.yPosition; + let xVel = this.state.xVelocity; + let yVel = this.state.yVelocity; + for (let i = 0; i < 60; i++) { + let forces1 = this.getNewForces(xPos, yPos, xVel, yVel); + const xAcc1 = this.getNewAccelerationX(forces1); + const yAcc1 = this.getNewAccelerationY(forces1); + const xVel1 = this.getNewVelocity(xVel, xAcc1); + const yVel1 = this.getNewVelocity(yVel, yAcc1); + + let xVel2 = this.getNewVelocity(xVel, xAcc1 / 2); + let yVel2 = this.getNewVelocity(yVel, yAcc1 / 2); + let xPos2 = this.getNewPosition(xPos, xVel1 / 2); + let yPos2 = this.getNewPosition(yPos, yVel1 / 2); + const forces2 = this.getNewForces(xPos2, yPos2, xVel2, yVel2); + const xAcc2 = this.getNewAccelerationX(forces2); + const yAcc2 = this.getNewAccelerationY(forces2); + xVel2 = this.getNewVelocity(xVel2, xAcc2); + yVel2 = this.getNewVelocity(yVel2, yAcc2); + xPos2 = this.getNewPosition(xPos2, xVel2); + yPos2 = this.getNewPosition(yPos2, yVel2); + + let xVel3 = this.getNewVelocity(xVel, xAcc2 / 2); + let yVel3 = this.getNewVelocity(yVel, yAcc2 / 2); + let xPos3 = this.getNewPosition(xPos, xVel2 / 2); + let yPos3 = this.getNewPosition(yPos, yVel2 / 2); + const forces3 = this.getNewForces(xPos3, yPos3, xVel3, yVel3); + const xAcc3 = this.getNewAccelerationX(forces3); + const yAcc3 = this.getNewAccelerationY(forces3); + xVel3 = this.getNewVelocity(xVel3, xAcc3); + yVel3 = this.getNewVelocity(yVel3, yAcc3); + xPos3 = this.getNewPosition(xPos3, xVel3); + yPos3 = this.getNewPosition(yPos3, yVel3); + + let xVel4 = this.getNewVelocity(xVel, xAcc3); + let yVel4 = this.getNewVelocity(yVel, yAcc3); + let xPos4 = this.getNewPosition(xPos, xVel3); + let yPos4 = this.getNewPosition(yPos, yVel3); + const forces4 = this.getNewForces(xPos4, yPos4, xVel4, yVel4); + const xAcc4 = this.getNewAccelerationX(forces4); + const yAcc4 = this.getNewAccelerationY(forces4); + xVel4 = this.getNewVelocity(xVel4, xAcc4); + yVel4 = this.getNewVelocity(yVel4, yAcc4); + xPos4 = this.getNewPosition(xPos4, xVel4); + yPos4 = this.getNewPosition(yPos4, yVel4); + + xVel += + this.props.timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0); + yVel += + this.props.timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0); + xPos += + this.props.timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0); + yPos += + this.props.timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0); + } + + this.setState({xVelocity: xVel}); + this.setState({yVelocity: yVel}); + this.setState({xPosition: xPos}); + this.setState({yPosition: yPos}); + + this.props.dataDoc['updatedForces'] = (this.getNewForces(xPos, yPos, xVel, yVel)); + }; + + + labelBackgroundColor = `rgba(255,255,255,0.5)`; + + render () { + return ( +
+
{ + // if (this.draggable) { + // e.preventDefault(); + // this.props.dataDoc['simulationPaused'] = true; + // this.setState({dragging: true}); + // this.setState({clickPositionX: e.clientX}) + // this.setState({clickPositionY: e.clientY}) + // } + // }} + // onPointerMove={(e) => { + // e.preventDefault(); + // if (this.state.dragging) { + // let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; + // if (newY > this.props.yMax - 2 * this.props.radius) { + // newY = this.props.yMax - 2 * this.props.radius; + // } + + // let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; + // if (newX > this.props.xMax - 2 * this.props.radius) { + // newX = this.props.xMax - 2 * this.props.radius; + // } else if (newX < 0) { + // newX = 0; + // } + // this.setState({xPosition: newX}) + // this.setState({yPosition: newY}) + // this.setState({updatedStartPosX: newX}) + // this.setState({updatedStartPosY: newY}) + // this.props.dataDoc['positionYDisplay'] = Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100; + // this.setState({clickPositionX: e.clientX}) + // this.setState({clickPositionY: e.clientY}) + // this.setDisplayValues(); + // } + // }} + // onPointerUp={(e) => { + // if (this.state.dragging) { + // e.preventDefault(); + // if (!this.props.dataDoc['pendulum']) { + // this.resetEverything(); + // } + // this.setState({dragging: false}); + // let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; + // if (newY > this.props.yMax - 2 * this.props.radius) { + // newY = this.props.yMax - 2 * this.props.radius; + // } + + // let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; + // if (newX > this.props.xMax - 2 * this.props.radius) { + // newX = this.props.xMax - 2 * this.props.radius; + // } else if (newX < 0) { + // newX = 0; + // } + // if (this.props.dataDoc['pendulum']) { + // const x = this.props.xMax / 2 - newX - this.props.radius; + // const y = newY + this.props.radius + 5; + // let angle = (Math.atan(y / x) * 180) / Math.PI; + // if (angle < 0) { + // angle += 180; + // } + // let oppositeAngle = 90 - angle; + // if (oppositeAngle < 0) { + // oppositeAngle = 90 - (180 - angle); + // } + + // const pendulumLength = Math.sqrt(x * x + y * y); + // this.props.dataDoc['pendulumAngle'] = oppositeAngle; + // this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y); + // const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180); + // const forceOfTension: IForce = { + // description: "Tension", + // magnitude: mag, + // directionInDegrees: angle, + // }; + // this.setState({kineticFriction: false}) + // this.setState({xVelocity: this.props.startVelX ?? 0}) + // this.setState({yVelocity: this.props.startVelY ?? 0}) + // this.setDisplayValues(); + // this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, forceOfTension]); + // } + // } + // }} + > +
+

{this.props.mass} kg

+
+
+ {this.props.dataDoc['pendulum'] && ( +
+ + + + {!this.state.dragging && ( +
+

+ {this.state.angleLabel}° +

+
+ )} +
+ )} + {!this.state.dragging && this.props.dataDoc['showAcceleration'] && ( +
+
+ + + + + + + + +
+

+ {Math.round( + 100 * + Math.sqrt( + Math.pow(this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 3, 2) + + Math.pow(this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 3, 2) + ) + ) / 100}{" "} + m/s2 +

+
+
+
+ )} + {!this.state.dragging && this.props.dataDoc['showVelocity'] && ( +
+
+ + + + + + + + +
+

+ {Math.round( + 100 * Math.sqrt(this.state.xVelocity**2 + this.state.yVelocity**2) + ) / 100}{" "} + m/s +

+
+
+
+ )} + {!this.state.dragging && + this.props.dataDoc['showForces'] && + this.props.dataDoc['updatedForces'].map((force, index) => { + if (force.magnitude < this.epsilon) { + return; + } + let arrowStartY: number = this.state.yPosition + this.props.radius; + const arrowStartX: number = this.state.xPosition + this.props.radius; + let arrowEndY: number = + arrowStartY - + Math.abs(force.magnitude) * + 10 * + Math.sin((force.directionInDegrees * Math.PI) / 180); + const arrowEndX: number = + arrowStartX + + Math.abs(force.magnitude) * + 10 * + Math.cos((force.directionInDegrees * Math.PI) / 180); + + let color = "#0d0d0d"; + + let labelTop = arrowEndY; + let labelLeft = arrowEndX; + if (force.directionInDegrees > 90 && force.directionInDegrees < 270) { + labelLeft -= 120; + } else { + labelLeft += 30; + } + if (force.directionInDegrees >= 0 && force.directionInDegrees < 180) { + labelTop += 40; + } else { + labelTop -= 40; + } + labelTop = Math.min(labelTop, this.props.yMax + 50); + labelTop = Math.max(labelTop, this.props.yMin); + labelLeft = Math.min(labelLeft, this.props.xMax - 60); + labelLeft = Math.max(labelLeft, this.props.xMin); + + return ( +
+
+ + + + + + + + +
+
+ {force.description &&

{force.description}

} + {!force.description &&

Force

} + {this.props.dataDoc['showForceMagnitudes'] && ( +

{Math.round(100 * force.magnitude) / 100} N

+ )} +
+
+ ); + })} +
+ ); + } +}; diff --git a/src/client/views/nodes/PhysicsSimulationBox.scss b/src/client/views/nodes/PhysicsSimulationBox.scss deleted file mode 100644 index 0f05010b4..000000000 --- a/src/client/views/nodes/PhysicsSimulationBox.scss +++ /dev/null @@ -1,72 +0,0 @@ -* { - box-sizing: border-box; - font-size: 14px; -} - -.mechanicsSimulationContainer { - background-color: white; - height: 100%; - width: 100%; - display: flex; - - .mechanicsSimulationEquationContainer { - position: fixed; - left: 70%; - padding: 1em; - - .mechanicsSimulationControls { - display: flex; - justify-content: space-between; - } - } -} - -.coordinateSystem { - z-index: -100; -} - -th, -td { - border-collapse: collapse; - padding: 1em; -} - -table { - min-width: 300px; -} - -tr:nth-child(even) { - background-color: #d6eeee; -} - -button { - z-index: 50; -} - -.angleLabel { - font-weight: bold; - font-size: 20px; - user-select: none; - pointer-events: none; -} - -.mechanicsSimulationSettingsMenu { - width: 100%; - height: 100%; - font-size: 12px; - background-color: rgb(224, 224, 224); - border-radius: 2px; - border-color: black; - border-style: solid; - padding: 10px; - position: fixed; - z-index: 1000; -} - -.mechanicsSimulationSettingsMenuRow { - display: flex; -} - -.mechanicsSimulationSettingsMenuRowDescription { - width: 50%; -} \ No newline at end of file diff --git a/src/client/views/nodes/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsSimulationBox.tsx deleted file mode 100644 index d0e854263..000000000 --- a/src/client/views/nodes/PhysicsSimulationBox.tsx +++ /dev/null @@ -1,494 +0,0 @@ -import "./PhysicsSimulationBox.scss"; -import { FieldView, FieldViewProps } from './FieldView'; -import React = require('react'); -import { ViewBoxAnnotatableComponent } from '../DocComponent'; -import { observer } from 'mobx-react'; -import "./PhysicsSimulationBox.scss"; -import Weight from "./PhysicsSimulationWeight"; -import Wall from "./PhysicsSimulationWall" -import Wedge from "./PhysicsSimulationWedge" -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { CheckBox } from "../search/CheckBox"; -export interface IForce { - description: string; - magnitude: number; - directionInDegrees: number; -} -export interface IWallProps { - length: number; - xPos: number; - yPos: number; - angleInDegrees: number; -} - -interface PhysicsVectorTemplate { - top: number; - left: number; - width: number; - height: number; - x1: number; - y1: number; - x2: number; - y2: number; - weightX: number; - weightY: number; -} - -@observer -export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() { - - public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); } - - // Constants - gravityMagnitude = 9.81; - forceOfGravity: IForce = { - description: "Gravity", - magnitude: this.gravityMagnitude, - directionInDegrees: 270, - }; - xMin = 0; - yMin = 0; - xMax = 300; - yMax = 300; - color = `rgba(0,0,0,0.5)`; - radius = 0.1*this.yMax - update = true - menuIsOpen = false - - constructor(props: any) { - super(props); - } - - // Add one weight to the simulation - addWeight () { - this.dataDoc.weight = true; - this.dataDoc.wedge = false; - this.dataDoc.pendulum = false; - this.addWalls(); - }; - - // Set weight defaults - setToWeightDefault () { - this.dataDoc.startPosY = this.yMin+this.radius; - this.dataDoc.startPosX = (this.xMax+this.xMin-this.radius)/2; - this.dataDoc.updatedForces = [this.forceOfGravity]; - this.dataDoc.startForces = [this.forceOfGravity]; - } - - // Add a wedge with a One Weight to the simulation - addWedge () { - this.dataDoc.weight = true; - this.dataDoc.wedge = true; - this.dataDoc.pendulum = false; - this.addWalls(); - }; - - // Set wedge defaults - setToWedgeDefault () { - this.changeWedgeBasedOnNewAngle(26); - this.updateForcesWithFriction(this.dataDoc.coefficientOfStaticFriction); - } - - // Add a simple pendulum to the simulation - addPendulum = () => { - this.dataDoc.weight = true; - this.dataDoc.wedge = false; - this.dataDoc.pendulum = true; - this.removeWalls(); - let angle = this.dataDoc.pendulumAngle; - let mag = 9.81 * Math.cos((angle * Math.PI) / 180); - let forceOfTension: IForce = { - description: "Tension", - magnitude: mag, - directionInDegrees: 90 - angle, - }; - this.dataDoc.updatedForces = [this.forceOfGravity, forceOfTension]; - this.dataDoc.startForces = [this.forceOfGravity, forceOfTension]; - }; - - // Set pendulum defaults - setToPendulumDefault () { - let length = this.xMax*0.7; - let angle = 35; - let x = length * Math.cos(((90 - angle) * Math.PI) / 180); - let y = length * Math.sin(((90 - angle) * Math.PI) / 180); - let xPos = this.xMax / 2 - x - this.radius; - let yPos = y - this.radius; - this.dataDoc.startPosX = xPos; - this.dataDoc.startPosY = yPos; - let mag = 9.81 * Math.cos((angle * Math.PI) / 180); - this.dataDoc.pendulumAngle = angle; - this.dataDoc.pendulumLength = length; - this.dataDoc.startPendulumAngle = angle; - this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle; - } - - // Update forces when coefficient of static friction changes in freeform mode - updateForcesWithFriction ( - coefficient: number, - width: number = this.dataDoc.wedgeWidth, - height: number = this.dataDoc.wedgeHeight - ) { - let normalForce = { - description: "Normal Force", - magnitude: this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)), - directionInDegrees: - 180 - 90 - (Math.atan(height / width) * 180) / Math.PI, - }; - let frictionForce: IForce = { - description: "Static Friction Force", - magnitude: - coefficient * - this.forceOfGravity.magnitude * - Math.cos(Math.atan(height / width)), - directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI, - }; - // reduce magnitude of friction force if necessary such that block cannot slide up plane - let yForce = -this.forceOfGravity.magnitude; - yForce += - normalForce.magnitude * - Math.sin((normalForce.directionInDegrees * Math.PI) / 180); - yForce += - frictionForce.magnitude * - Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - if (yForce > 0) { - frictionForce.magnitude = - (-normalForce.magnitude * - Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + - this.forceOfGravity.magnitude) / - Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - } - if (coefficient != 0) { - this.dataDoc.startForces = [this.forceOfGravity, normalForce, frictionForce]; - this.dataDoc.updatedForces = [this.forceOfGravity, normalForce, frictionForce]; - } else { - this.dataDoc.startForces = [this.forceOfGravity, normalForce]; - this.dataDoc.updatedForces = [this.forceOfGravity, normalForce]; - } - }; - - // Change wedge height and width and weight position to match new wedge angle - changeWedgeBasedOnNewAngle = (angle: number) => { - let width = 0; - let height = 0; - if (angle < 50) { - width = this.xMax*0.6; - height = Math.tan((angle * Math.PI) / 180) * width; - this.dataDoc.wedgeWidth = width; - this.dataDoc.wedgeHeight = height; - } else if (angle < 70) { - width = this.xMax*0.3; - height = Math.tan((angle * Math.PI) / 180) * width; - this.dataDoc.wedgeWidth = width; - this.dataDoc.wedgeHeight = height; - } else { - width = this.xMax*0.15; - height = Math.tan((angle * Math.PI) / 180) * width; - this.dataDoc.wedgeWidth = width; - this.dataDoc.wedgeHeight = height; - } - - // update weight position based on updated wedge width/height - let xPos = (this.xMax * 0.2)-this.radius; - let yPos = width * Math.tan((angle * Math.PI) / 180) - this.radius; - - this.dataDoc.startPosX = xPos; - this.dataDoc.startPosY = this.getDisplayYPos(yPos); - this.updateForcesWithFriction( - Number(this.dataDoc.coefficientOfStaticFriction), - width, - height - ); - this.dataDoc['updateDisplay'] = !this.dataDoc['updateDisplay'] - }; - - // Helper function to go between display and real values - getDisplayYPos = (yPos: number) => { - return this.yMax - yPos - 2 * 50 + 5; - }; - - // In review mode, edit force arrow sketch on mouse movement - editForce = (element: PhysicsVectorTemplate) => { - if (!this.dataDoc.sketching) { - let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element); - this.dataDoc.forceSketches = sketches; - this.dataDoc.currentForceSketch = element; - this.dataDoc.sketching = true; - } - }; - - // In review mode, used to delete force arrow sketch on SHIFT+click - deleteForce = (element: PhysicsVectorTemplate) => { - if (!this.dataDoc.sketching) { - let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element); - this.dataDoc.forceSketches = sketches; - } - }; - - // Remove floor and walls from simulation - removeWalls = () => { - this.dataDoc.wallPositions = [] - }; - - // Add floor and walls to simulation - addWalls = () => { - let walls = []; - walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 }); - walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 }); - walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 }); - this.dataDoc.wallPositions = walls - }; - - - componentDidMount() { - this.xMax = this.layoutDoc._width; - this.yMax = this.layoutDoc._height; - this.radius = 0.1*this.layoutDoc._height; - - // Add weight - if (this.dataDoc.simulationType == "Inclined Plane") { - this.addWedge() - } else if (this.dataDoc.simulationType == "Pendulum") { - this.addPendulum() - } else { - this.dataDoc.simulationType = "Free Weight" - this.addWeight() - } - this.dataDoc.accelerationXDisplay = this.dataDoc.accelerationXDisplay ?? 0; - this.dataDoc.accelerationYDisplay = this.dataDoc.accelerationYDisplay ?? 0; - this.dataDoc.coefficientOfKineticFriction = this.dataDoc.coefficientOfKineticFriction ?? 0; - this.dataDoc.coefficientOfStaticFriction = this.dataDoc.coefficientOfStaticFriction ?? 0; - this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? []; - this.dataDoc.elasticCollisions = this.dataDoc.elasticCollisions ?? false; - this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? []; - this.dataDoc.pendulumAngle = this.dataDoc.pendulumAngle ?? 26; - this.dataDoc.pendulumLength = this.dataDoc.pendulumLength ?? 300; - this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0; - this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0; - this.dataDoc.showAcceleration = this.dataDoc.showAcceleration ?? false; - this.dataDoc.showForceMagnitudes = this.dataDoc.showForceMagnitudes ?? false; - this.dataDoc.showForces = this.dataDoc.showForces ?? false; - this.dataDoc.showVelocity = this.dataDoc.showVelocity ?? false; - this.dataDoc.startForces = this.dataDoc.startForces ?? [this.forceOfGravity]; - this.dataDoc.startPendulumAngle = this.dataDoc.startPendulumAngle ?? 0; - this.dataDoc.startPosX = this.dataDoc.startPosX ?? 50; - this.dataDoc.startPosY = this.dataDoc.startPosY ?? 50; - this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0; - this.dataDoc.updateDisplay = this.dataDoc.updateDisplay ?? false; - this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [this.forceOfGravity]; - this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0; - this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0; - this.dataDoc.wallPositions = this.dataDoc.wallPositions ?? []; - this.dataDoc.wedgeAngle = this.dataDoc.wedgeAngle ?? 26; - this.dataDoc.wedgeHeight = this.dataDoc.wedgeHeight ?? Math.tan((26 * Math.PI) / 180) * this.xMax*0.6; - this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? this.xMax*0.6; - - this.dataDoc.adjustPendulumAngle = true; - this.dataDoc.simulationPaused = true; - this.dataDoc.simulationReset = false; - - // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click - document.addEventListener("keydown", (e) => { - if (e.shiftKey) { - this.dataDoc.deleteMode = true; - } - }); - document.addEventListener("keyup", (e) => { - if (e.shiftKey) { - this.dataDoc.deleteMode = false; - } - }); - } - - componentDidUpdate() { - this.xMax = this.layoutDoc._width; - this.yMax = this.layoutDoc._height; - this.radius = 0.1*this.layoutDoc._height; - } - - render () { - return ( -
-
-
-
-
- {this.dataDoc.weight && ( - - )} - {this.dataDoc.wedge && ( - - )} -
-
- {(this.dataDoc.wallPositions ?? []).map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { - return ( -
- -
- ); - })} -
-
-
-
- {this.menuIsOpen && ( -
-
{this.menuIsOpen = false; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}}> - -
-

Simulation Settings

-
-

Show forces

-
{this.dataDoc.showForces = !this.dataDoc.showForces}}/>
-
-
-

Show acceleration

-
{this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/>
-
-
-
-

Show velocity

-
{this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/>
-
-
- {this.dataDoc.simulationType == "Free Weight" &&
-

Elastic collisions

-
{this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/>
-
} - {this.dataDoc.simulationType == "Pendulum" &&
-

Pendulum start angle

-
- { - let angle = e.target.value; - if (angle > 35) { - angle = 35 - } - if (angle < 0) { - angle = 0 - } - let length = this.xMax*0.7; - let x = length * Math.cos(((90 - angle) * Math.PI) / 180); - let y = length * Math.sin(((90 - angle) * Math.PI) / 180); - let xPos = this.xMax / 2 - x - this.radius; - let yPos = y - this.radius; - this.dataDoc.startPosX = xPos; - this.dataDoc.startPosY = yPos; - let mag = 9.81 * Math.cos((angle * Math.PI) / 180); - this.dataDoc.pendulumAngle = angle; - this.dataDoc.pendulumLength = length; - this.dataDoc.startPendulumAngle = angle; - this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle; - }} - /> -
-
} - {this.dataDoc.simulationType == "Inclined Plane" &&
-

Inclined plane angle

-
- { - let angle = e.target.value ?? 0 - if (angle > 70) { - angle = 70 - } - if (angle < 0) { - angle = 0 - } - this.dataDoc.wedgeAngle = angle - this.changeWedgeBasedOnNewAngle(angle) - }} - /> -
-
} -
- )} -
-
-
-
- {this.dataDoc.simulationPaused && ( - - )} - {!this.dataDoc.simulationPaused && ( - - )} - {this.dataDoc.simulationPaused && ( - - )} - {this.dataDoc.simulationPaused && ( )} - -
-
-
-
-
- ); - } - } \ No newline at end of file diff --git a/src/client/views/nodes/PhysicsSimulationWall.tsx b/src/client/views/nodes/PhysicsSimulationWall.tsx deleted file mode 100644 index 9283e8d46..000000000 --- a/src/client/views/nodes/PhysicsSimulationWall.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React = require('react'); - -export interface Force { - magnitude: number; - directionInDegrees: number; -} -export interface IWallProps { - length: number; - xPos: number; - yPos: number; - angleInDegrees: number; -} - -export default class App extends React.Component { - - constructor(props: any) { - super(props) - } - - wallStyle = { - width: this.props.angleInDegrees == 0 ? this.props.length + "%" : "3%", - height: this.props.angleInDegrees == 0 ? "3%" : this.props.length + "%", - position: "absolute" as "absolute", - left: this.props.xPos + "%", - top: this.props.yPos + "%", - backgroundColor: "#6c7b8b", - margin: 0, - padding: 0, - }; - - render () { - return (
); - } -}; diff --git a/src/client/views/nodes/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsSimulationWedge.tsx deleted file mode 100644 index 6134a6bc0..000000000 --- a/src/client/views/nodes/PhysicsSimulationWedge.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React = require('react'); -import "./PhysicsSimulationBox.scss"; - -export interface IWedgeProps { - startHeight: number; - startWidth: number; - startLeft: number; - xMax: number; - yMax: number; -} - -interface IState { - angleInRadians: number, - left: number, - coordinates: string, -} - -export default class Wedge extends React.Component { - - constructor(props: any) { - super(props) - this.state = { - angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth), - left: this.props.startLeft, - coordinates: "", - } - } - - color = "#deb887"; - - updateCoordinates() { - const coordinatePair1 = - Math.round(this.state.left) + "," + Math.round(this.props.yMax) + " "; - const coordinatePair2 = - Math.round(this.state.left + this.props.startWidth) + - "," + - Math.round(this.props.yMax) + - " "; - const coordinatePair3 = - Math.round(this.state.left) + - "," + - Math.round(this.props.yMax - this.props.startHeight); - const coord = coordinatePair1 + coordinatePair2 + coordinatePair3; - this.setState({coordinates: coord}); - } - - componentDidMount() { - this.updateCoordinates() - } - - componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { - if (prevProps.startHeight != this.props.startHeight || prevProps.startWidth != this.props.startWidth) { - this.setState({angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth)}); - this.updateCoordinates(); - } - } - - render() { - return ( -
-
- - - -
- -

- {Math.round(((this.state.angleInRadians * 180) / Math.PI) * 100) / 100}° -

-
- ); - } -}; diff --git a/src/client/views/nodes/PhysicsSimulationWeight.tsx b/src/client/views/nodes/PhysicsSimulationWeight.tsx deleted file mode 100644 index 39b3249e8..000000000 --- a/src/client/views/nodes/PhysicsSimulationWeight.tsx +++ /dev/null @@ -1,860 +0,0 @@ -import React = require('react'); -import { Doc } from '../../../fields/Doc'; -import { IWallProps } from "./PhysicsSimulationWall"; - -export interface IForce { - description: string; - magnitude: number; - directionInDegrees: number; -} -export interface IWeightProps { - adjustPendulumAngle: boolean; - color: string; - dataDoc: Doc; - mass: number; - radius: number; - simulationReset: boolean; - startPosX: number; - startPosY: number; - startVelX?: number; - startVelY?: number; - timestepSize: number; - updateDisplay: boolean, - walls: IWallProps[]; - wedge: boolean; - wedgeHeight: number; - wedgeWidth: number; - xMax: number; - xMin: number; - yMax: number; - yMin: number; -} - -interface IState { - angleLabel: number, - clickPositionX: number, - clickPositionY: number, - dragging: boolean, - kineticFriction: boolean, - timer: number; - update: boolean, - updatedStartPosX: number, - updatedStartPosY: number, - xPosition: number, - xVelocity: number, - yPosition: number, - yVelocity: number, -} -export default class Weight extends React.Component { - - constructor(props: any) { - super(props) - this.state = { - clickPositionX: 0, - clickPositionY: 0, - dragging: false, - kineticFriction: false, - timer: 0, - angleLabel: 0, - updatedStartPosX: this.props.dataDoc['startPosX'], - updatedStartPosY: this.props.dataDoc['startPosY'], - xPosition: this.props.dataDoc['startPosX'], - xVelocity: this.props.startVelX ? this.props.startVelX: 0, - yPosition: this.props.dataDoc['startPosY'], - yVelocity: this.props.startVelY ? this.props.startVelY: 0, - } - } - - // Constants - draggable = !this.props.dataDoc['wedge'] ; - epsilon = 0.0001; - forceOfGravity: IForce = { - description: "Gravity", - magnitude: this.props.mass * 9.81, - directionInDegrees: 270, - }; - - // Var - weightStyle = { - alignItems: "center", - backgroundColor: this.props.color, - borderColor: "black", - borderRadius: 50 + "%", - borderStyle: "solid", - display: "flex", - height: 2 * this.props.radius + "px", - justifyContent: "center", - left: this.props.dataDoc['startPosX'] + "px", - position: "absolute" as "absolute", - top: this.props.dataDoc['startPosY'] + "px", - touchAction: "none", - width: 2 * this.props.radius + "px", - zIndex: 5, - }; - - // Helper function to go between display and real values - getDisplayYPos = (yPos: number) => { - return this.props.yMax - yPos - 2 * this.props.radius + 5; - }; - getYPosFromDisplay = (yDisplay: number) => { - return this.props.yMax - yDisplay - 2 * this.props.radius + 5; - }; - - // Set display values based on real values - setYPosDisplay = (yPos: number) => { - const displayPos = this.getDisplayYPos(yPos); - this.props.dataDoc['positionYDisplay'] = Math.round(displayPos * 100) / 100 - }; - setXPosDisplay = (xPos: number) => { - this.props.dataDoc['positionXDisplay'] = Math.round(xPos * 100) / 100; - }; - setYVelDisplay = (yVel: number) => { - this.props.dataDoc['velocityYDisplay'] = (-1 * Math.round(yVel * 100)) / 100; - }; - setXVelDisplay = (xVel: number) => { - this.props.dataDoc['velocityXDisplay'] = Math.round(xVel * 100) / 100; - }; - - setDisplayValues = ( - xPos: number = this.state.xPosition, - yPos: number = this.state.yPosition, - xVel: number = this.state.xVelocity, - yVel: number = this.state.yVelocity - ) => { - this.setYPosDisplay(yPos); - this.setXPosDisplay(xPos); - this.setYVelDisplay(yVel); - this.setXVelDisplay(xVel); - this.props.dataDoc['accelerationYDisplay'] = - (-1 * Math.round(this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 100)) / 100 - ; - this.props.dataDoc['accelerationXDisplay'] = - Math.round(this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 100) / 100 - ; - }; - - componentDidMount() { - // Timer for animating the simulation - setInterval(() => { - this.setState({timer: this.state.timer + 1}); - }, 60); - } - - componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { - - // When display values updated by user, update real values - if (this.props.updateDisplay != prevProps.updateDisplay) { - if (this.props.dataDoc['positionXDisplay'] != this.state.xPosition) { - let x = this.props.dataDoc['positionXDisplay']; - x = Math.max(0, x); - x = Math.min(x, this.props.xMax - 2 * this.props.radius); - this.setState({updatedStartPosX: x}) - this.setState({xPosition: x}) - this.props.dataDoc['positionXDisplay'] = x; - } - - if (this.props.dataDoc['positionYDisplay'] != this.getDisplayYPos(this.state.yPosition)) { - let y = this.props.dataDoc['positionYDisplay']; - y = Math.max(0, y); - y = Math.min(y, this.props.yMax - 2 * this.props.radius); - this.props.dataDoc['positionYDisplay'] = y; - let coordinatePosition = this.getYPosFromDisplay(y); - this.setState({updatedStartPosY: coordinatePosition}) - this.setState({yPosition: coordinatePosition}) - } - - if (this.props.dataDoc['velocityXDisplay'] != this.state.xVelocity) { - let x = this.props.dataDoc['velocityXDisplay']; - this.setState({xVelocity: x}) - this.props.dataDoc['velocityXDisplay'] = x; - } - - if (this.props.dataDoc['velocityYDisplay'] != this.state.yVelocity) { - let y = this.props.dataDoc['velocityYDisplay']; - this.setState({yVelocity: -y}) - this.props.dataDoc['velocityYDisplay'] - } - } - // Update sim - if (this.state.timer != prevState.timer) { - if (!this.props.dataDoc['simulationPaused']) { - let collisions = false; - if (!this.props.dataDoc['pendulum']) { - const collisionsWithGround = this.checkForCollisionsWithGround(); - const collisionsWithWalls = this.checkForCollisionsWithWall(); - collisions = collisionsWithGround || collisionsWithWalls; - } - if (!collisions) { - this.update(); - } - this.setDisplayValues(); - } - } - - if (this.props.simulationReset != prevProps.simulationReset) { - this.resetEverything(); - } - if (this.props.adjustPendulumAngle != prevProps.adjustPendulumAngle) { - console.log('update angle') - // Change pendulum angle based on input field - let length = this.props.dataDoc['pendulumLength'] ?? 0; - const x = - length * Math.cos(((90 - this.props.dataDoc['pendulumAngle']) * Math.PI) / 180); - const y = - length * Math.sin(((90 - this.props.dataDoc['pendulumAngle']) * Math.PI) / 180); - const xPos = this.props.xMax / 2 - x - this.props.radius; - const yPos = y - this.props.radius - 5; - this.setState({xPosition: xPos}) - this.setState({yPosition: yPos}) - this.setState({updatedStartPosX: xPos}) - this.setState({updatedStartPosY: yPos}) - this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle'] * 100) / 100}) - } - // Update x start position - if (this.props.startPosX != prevProps.startPosX) { - this.setState({updatedStartPosX: this.props.dataDoc['startPosX']}) - this.setState({xPosition: this.props.dataDoc['startPosX']}) - this.setXPosDisplay(this.props.dataDoc['startPosX']); - } - // Update y start position - if (this.props.startPosY != prevProps.startPosY) { - this.setState({updatedStartPosY: this.props.dataDoc['startPosY']}) - this.setState({yPosition: this.props.dataDoc['startPosY']}) - this.setYPosDisplay(this.props.dataDoc['startPosY']); - } - if (!this.props.dataDoc['simulationPaused']) { - if (this.state.xVelocity != prevState.xVelocity) { - if (this.props.dataDoc['wedge'] && this.state.xVelocity != 0 && !this.state.kineticFriction) { - this.setState({kineticFriction: true}); - //switch from static to kinetic friction - const normalForce: IForce = { - description: "Normal Force", - magnitude: - this.forceOfGravity.magnitude * - Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), - directionInDegrees: - 180 - 90 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, - }; - let frictionForce: IForce = { - description: "Kinetic Friction Force", - magnitude: - this.props.dataDoc['coefficientOfKineticFriction'] * - this.forceOfGravity.magnitude * - Math.cos(Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] )), - directionInDegrees: - 180 - (Math.atan(this.props.dataDoc['wedgeHeight'] / this.props.dataDoc['wedgeWidth'] ) * 180) / Math.PI, - }; - // reduce magnitude of friction force if necessary such that block cannot slide up plane - let yForce = -this.forceOfGravity.magnitude; - yForce += - normalForce.magnitude * - Math.sin((normalForce.directionInDegrees * Math.PI) / 180); - yForce += - frictionForce.magnitude * - Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - if (yForce > 0) { - frictionForce.magnitude = - (-normalForce.magnitude * - Math.sin((normalForce.directionInDegrees * Math.PI) / 180) + - this.forceOfGravity.magnitude) / - Math.sin((frictionForce.directionInDegrees * Math.PI) / 180); - } - if (this.props.dataDoc['coefficientOfKineticFriction'] != 0) { - this.props.dataDoc['updatedForces'] = [this.forceOfGravity, normalForce, frictionForce]; - } else { - this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, normalForce]); - } - } - } - } - - this.weightStyle = { - alignItems: "center", - backgroundColor: this.props.color, - borderColor: this.state.dragging ? "lightblue" : "black", - borderRadius: 50 + "%", - borderStyle: "solid", - display: "flex", - height: 2 * this.props.radius + "px", - justifyContent: "center", - left: this.state.xPosition + "px", - position: "absolute" as "absolute", - top: this.state.yPosition + "px", - touchAction: "none", - width: 2 * this.props.radius + "px", - zIndex: 5, - }; - } - - resetEverything = () => { - this.setState({kineticFriction: false}) - this.setState({xPosition: this.state.updatedStartPosX}) - this.setState({yPosition: this.state.updatedStartPosY}) - this.setState({xVelocity: this.props.startVelX ?? 0}) - this.setState({yVelocity: this.props.startVelY ?? 0}) - this.props.dataDoc['updatedForces'] = (this.props.dataDoc['startForces']) - this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle']* 100) / 100}) - this.setDisplayValues(); - }; - - getNewAccelerationX = (forceList: IForce[]) => { - let newXAcc = 0; - if (forceList) { - forceList.forEach((force) => { - newXAcc += - (force.magnitude * - Math.cos((force.directionInDegrees * Math.PI) / 180)) / - this.props.mass; - }); - } - return newXAcc; - }; - - getNewAccelerationY = (forceList: IForce[]) => { - let newYAcc = 0; - if (forceList) { - forceList.forEach((force) => { - newYAcc += - (-1 * - (force.magnitude * - Math.sin((force.directionInDegrees * Math.PI) / 180))) / - this.props.mass; - }); - } - return newYAcc; - }; - - getNewForces = ( - xPos: number, - yPos: number, - xVel: number, - yVel: number - ) => { - if (!this.props.dataDoc['pendulum']) { - return this.props.dataDoc['updatedForces']; - } - const x = this.props.xMax / 2 - xPos - this.props.radius; - const y = yPos + this.props.radius + 5; - let angle = (Math.atan(y / x) * 180) / Math.PI; - if (angle < 0) { - angle += 180; - } - let oppositeAngle = 90 - angle; - if (oppositeAngle < 0) { - oppositeAngle = 90 - (180 - angle); - } - - const pendulumLength = Math.sqrt(x * x + y * y); - this.props.dataDoc['pendulumAngle'] = oppositeAngle; - this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y); - - const mag = - this.props.mass * 9.81 * Math.cos((oppositeAngle * Math.PI) / 180) + - (this.props.mass * (xVel * xVel + yVel * yVel)) / pendulumLength; - - const forceOfTension: IForce = { - description: "Tension", - magnitude: mag, - directionInDegrees: angle, - }; - this.setState({angleLabel: Math.round(this.props.dataDoc['pendulumAngle']* 100) / 100}) - - return [this.forceOfGravity, forceOfTension]; - }; - - getNewPosition = (pos: number, vel: number) => { - return pos + vel * this.props.timestepSize; - }; - - getNewVelocity = (vel: number, acc: number) => { - return vel + acc * this.props.timestepSize; - }; - - checkForCollisionsWithWall = () => { - let collision = false; - const minX = this.state.xPosition; - const maxX = this.state.xPosition + 2 * this.props.radius; - const containerWidth = 300; - if (this.state.xVelocity != 0) { - if (this.props.dataDoc.wallPositions) { - this.props.dataDoc['wallPositions'].forEach((wall) => { - if (wall.angleInDegrees == 90) { - const wallX = (wall.xPos / 100) * 300; - if (wall.xPos < 0.35) { - if (minX <= wallX) { - if (this.props.dataDoc['elasticCollisions']) { - this.setState({xVelocity: -this.state.xVelocity}); - } else { - this.setState({xVelocity: 0}); - this.setState({xPosition: wallX+5}); - } - collision = true; - } - } else { - if (maxX >= wallX) { - if (this.props.dataDoc['elasticCollisions']) { - this.setState({xVelocity: -this.state.xVelocity}); - } else { - this.setState({xVelocity: 0}); - this.setState({xPosition: wallX - 2 * this.props.radius + 5}); - } - collision = true; - } - } - } - }); - } - } - return collision; - }; - - checkForCollisionsWithGround = () => { - let collision = false; - const maxY = this.state.yPosition + 2 * this.props.radius; - if (this.state.yVelocity > 0) { - if (this.props.dataDoc.wallPositions) { - this.props.dataDoc['wallPositions'].forEach((wall) => { - if (wall.angleInDegrees == 0) { - const groundY = (wall.yPos / 100) * this.props.yMax; - if (maxY >= groundY) { - if (this.props.dataDoc['elasticCollisions']) { - this.setState({yVelocity: -this.state.yVelocity}) - } else { - this.setState({yVelocity: 0}) - this.setState({yPosition: groundY - 2 * this.props.radius + 5}) - const forceOfGravity: IForce = { - description: "Gravity", - magnitude: 9.81 * this.props.mass, - directionInDegrees: 270, - }; - const normalForce: IForce = { - description: "Normal force", - magnitude: 9.81 * this.props.mass, - directionInDegrees: wall.angleInDegrees + 90, - }; - this.props.dataDoc['updatedForces'] = ([forceOfGravity, normalForce]); - } - collision = true; - } - } - }); - } - } - return collision; - }; - - update = () => { - // RK4 update - let xPos = this.state.xPosition; - let yPos = this.state.yPosition; - let xVel = this.state.xVelocity; - let yVel = this.state.yVelocity; - for (let i = 0; i < 60; i++) { - let forces1 = this.getNewForces(xPos, yPos, xVel, yVel); - const xAcc1 = this.getNewAccelerationX(forces1); - const yAcc1 = this.getNewAccelerationY(forces1); - const xVel1 = this.getNewVelocity(xVel, xAcc1); - const yVel1 = this.getNewVelocity(yVel, yAcc1); - - let xVel2 = this.getNewVelocity(xVel, xAcc1 / 2); - let yVel2 = this.getNewVelocity(yVel, yAcc1 / 2); - let xPos2 = this.getNewPosition(xPos, xVel1 / 2); - let yPos2 = this.getNewPosition(yPos, yVel1 / 2); - const forces2 = this.getNewForces(xPos2, yPos2, xVel2, yVel2); - const xAcc2 = this.getNewAccelerationX(forces2); - const yAcc2 = this.getNewAccelerationY(forces2); - xVel2 = this.getNewVelocity(xVel2, xAcc2); - yVel2 = this.getNewVelocity(yVel2, yAcc2); - xPos2 = this.getNewPosition(xPos2, xVel2); - yPos2 = this.getNewPosition(yPos2, yVel2); - - let xVel3 = this.getNewVelocity(xVel, xAcc2 / 2); - let yVel3 = this.getNewVelocity(yVel, yAcc2 / 2); - let xPos3 = this.getNewPosition(xPos, xVel2 / 2); - let yPos3 = this.getNewPosition(yPos, yVel2 / 2); - const forces3 = this.getNewForces(xPos3, yPos3, xVel3, yVel3); - const xAcc3 = this.getNewAccelerationX(forces3); - const yAcc3 = this.getNewAccelerationY(forces3); - xVel3 = this.getNewVelocity(xVel3, xAcc3); - yVel3 = this.getNewVelocity(yVel3, yAcc3); - xPos3 = this.getNewPosition(xPos3, xVel3); - yPos3 = this.getNewPosition(yPos3, yVel3); - - let xVel4 = this.getNewVelocity(xVel, xAcc3); - let yVel4 = this.getNewVelocity(yVel, yAcc3); - let xPos4 = this.getNewPosition(xPos, xVel3); - let yPos4 = this.getNewPosition(yPos, yVel3); - const forces4 = this.getNewForces(xPos4, yPos4, xVel4, yVel4); - const xAcc4 = this.getNewAccelerationX(forces4); - const yAcc4 = this.getNewAccelerationY(forces4); - xVel4 = this.getNewVelocity(xVel4, xAcc4); - yVel4 = this.getNewVelocity(yVel4, yAcc4); - xPos4 = this.getNewPosition(xPos4, xVel4); - yPos4 = this.getNewPosition(yPos4, yVel4); - - xVel += - this.props.timestepSize * (xAcc1 / 6.0 + xAcc2 / 3.0 + xAcc3 / 3.0 + xAcc4 / 6.0); - yVel += - this.props.timestepSize * (yAcc1 / 6.0 + yAcc2 / 3.0 + yAcc3 / 3.0 + yAcc4 / 6.0); - xPos += - this.props.timestepSize * (xVel1 / 6.0 + xVel2 / 3.0 + xVel3 / 3.0 + xVel4 / 6.0); - yPos += - this.props.timestepSize * (yVel1 / 6.0 + yVel2 / 3.0 + yVel3 / 3.0 + yVel4 / 6.0); - } - - this.setState({xVelocity: xVel}); - this.setState({yVelocity: yVel}); - this.setState({xPosition: xPos}); - this.setState({yPosition: yPos}); - - this.props.dataDoc['updatedForces'] = (this.getNewForces(xPos, yPos, xVel, yVel)); - }; - - - labelBackgroundColor = `rgba(255,255,255,0.5)`; - - render () { - return ( -
-
{ - // if (this.draggable) { - // e.preventDefault(); - // this.props.dataDoc['simulationPaused'] = true; - // this.setState({dragging: true}); - // this.setState({clickPositionX: e.clientX}) - // this.setState({clickPositionY: e.clientY}) - // } - // }} - // onPointerMove={(e) => { - // e.preventDefault(); - // if (this.state.dragging) { - // let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; - // if (newY > this.props.yMax - 2 * this.props.radius) { - // newY = this.props.yMax - 2 * this.props.radius; - // } - - // let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; - // if (newX > this.props.xMax - 2 * this.props.radius) { - // newX = this.props.xMax - 2 * this.props.radius; - // } else if (newX < 0) { - // newX = 0; - // } - // this.setState({xPosition: newX}) - // this.setState({yPosition: newY}) - // this.setState({updatedStartPosX: newX}) - // this.setState({updatedStartPosY: newY}) - // this.props.dataDoc['positionYDisplay'] = Math.round((this.props.yMax - 2 * this.props.radius - newY + 5) * 100) / 100; - // this.setState({clickPositionX: e.clientX}) - // this.setState({clickPositionY: e.clientY}) - // this.setDisplayValues(); - // } - // }} - // onPointerUp={(e) => { - // if (this.state.dragging) { - // e.preventDefault(); - // if (!this.props.dataDoc['pendulum']) { - // this.resetEverything(); - // } - // this.setState({dragging: false}); - // let newY = this.state.yPosition + e.clientY - this.state.clickPositionY; - // if (newY > this.props.yMax - 2 * this.props.radius) { - // newY = this.props.yMax - 2 * this.props.radius; - // } - - // let newX = this.state.xPosition + e.clientX - this.state.clickPositionX; - // if (newX > this.props.xMax - 2 * this.props.radius) { - // newX = this.props.xMax - 2 * this.props.radius; - // } else if (newX < 0) { - // newX = 0; - // } - // if (this.props.dataDoc['pendulum']) { - // const x = this.props.xMax / 2 - newX - this.props.radius; - // const y = newY + this.props.radius + 5; - // let angle = (Math.atan(y / x) * 180) / Math.PI; - // if (angle < 0) { - // angle += 180; - // } - // let oppositeAngle = 90 - angle; - // if (oppositeAngle < 0) { - // oppositeAngle = 90 - (180 - angle); - // } - - // const pendulumLength = Math.sqrt(x * x + y * y); - // this.props.dataDoc['pendulumAngle'] = oppositeAngle; - // this.props.dataDoc['pendulumLength'] = Math.sqrt(x * x + y * y); - // const mag = 9.81 * Math.cos((oppositeAngle * Math.PI) / 180); - // const forceOfTension: IForce = { - // description: "Tension", - // magnitude: mag, - // directionInDegrees: angle, - // }; - // this.setState({kineticFriction: false}) - // this.setState({xVelocity: this.props.startVelX ?? 0}) - // this.setState({yVelocity: this.props.startVelY ?? 0}) - // this.setDisplayValues(); - // this.props.dataDoc['updatedForces'] = ([this.forceOfGravity, forceOfTension]); - // } - // } - // }} - > -
-

{this.props.mass} kg

-
-
- {this.props.dataDoc['pendulum'] && ( -
- - - - {!this.state.dragging && ( -
-

- {this.state.angleLabel}° -

-
- )} -
- )} - {!this.state.dragging && this.props.dataDoc['showAcceleration'] && ( -
-
- - - - - - - - -
-

- {Math.round( - 100 * - Math.sqrt( - Math.pow(this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 3, 2) + - Math.pow(this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 3, 2) - ) - ) / 100}{" "} - m/s2 -

-
-
-
- )} - {!this.state.dragging && this.props.dataDoc['showVelocity'] && ( -
-
- - - - - - - - -
-

- {Math.round( - 100 * Math.sqrt(this.state.xVelocity**2 + this.state.yVelocity**2) - ) / 100}{" "} - m/s -

-
-
-
- )} - {!this.state.dragging && - this.props.dataDoc['showForces'] && - this.props.dataDoc['updatedForces'].map((force, index) => { - if (force.magnitude < this.epsilon) { - return; - } - let arrowStartY: number = this.state.yPosition + this.props.radius; - const arrowStartX: number = this.state.xPosition + this.props.radius; - let arrowEndY: number = - arrowStartY - - Math.abs(force.magnitude) * - 10 * - Math.sin((force.directionInDegrees * Math.PI) / 180); - const arrowEndX: number = - arrowStartX + - Math.abs(force.magnitude) * - 10 * - Math.cos((force.directionInDegrees * Math.PI) / 180); - - let color = "#0d0d0d"; - - let labelTop = arrowEndY; - let labelLeft = arrowEndX; - if (force.directionInDegrees > 90 && force.directionInDegrees < 270) { - labelLeft -= 120; - } else { - labelLeft += 30; - } - if (force.directionInDegrees >= 0 && force.directionInDegrees < 180) { - labelTop += 40; - } else { - labelTop -= 40; - } - labelTop = Math.min(labelTop, this.props.yMax + 50); - labelTop = Math.max(labelTop, this.props.yMin); - labelLeft = Math.min(labelLeft, this.props.xMax - 60); - labelLeft = Math.max(labelLeft, this.props.xMin); - - return ( -
-
- - - - - - - - -
-
- {force.description &&

{force.description}

} - {!force.description &&

Force

} - {this.props.dataDoc['showForceMagnitudes'] && ( -

{Math.round(100 * force.magnitude) / 100} N

- )} -
-
- ); - })} -
- ); - } -}; -- cgit v1.2.3-70-g09d2 From f327a27d664f45c10a90a4464cd0fa5edec59b68 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Mon, 1 May 2023 12:51:12 -0400 Subject: start adding box code --- .../nodes/PhysicsBox/PhysicsSimulationBox.tsx | 745 ++++++++++----------- .../nodes/PhysicsBox/PhysicsSimulationWedge.tsx | 83 --- 2 files changed, 346 insertions(+), 482 deletions(-) delete mode 100644 src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx (limited to 'src') diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index d0e854263..f27843ab0 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -6,22 +6,41 @@ import { observer } from 'mobx-react'; import "./PhysicsSimulationBox.scss"; import Weight from "./PhysicsSimulationWeight"; import Wall from "./PhysicsSimulationWall" -import Wedge from "./PhysicsSimulationWedge" import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { CheckBox } from "../search/CheckBox"; -export interface IForce { - description: string; - magnitude: number; - directionInDegrees: number; -} -export interface IWallProps { - length: number; - xPos: number; - yPos: number; - angleInDegrees: number; -} - -interface PhysicsVectorTemplate { +import PauseIcon from "@mui/icons-material/Pause"; +import PlayArrowIcon from "@mui/icons-material/PlayArrow"; +import ReplayIcon from "@mui/icons-material/Replay"; +import QuestionMarkIcon from "@mui/icons-material/QuestionMark"; +import ArrowLeftIcon from "@mui/icons-material/ArrowLeft"; +import ArrowRightIcon from "@mui/icons-material/ArrowRight"; +import EditIcon from "@mui/icons-material/Edit"; +import EditOffIcon from "@mui/icons-material/EditOff"; +import { + Box, + Button, + Checkbox, + Dialog, + DialogTitle, + DialogContent, + DialogContentText, + DialogActions, + FormControl, + FormControlLabel, + FormGroup, + IconButton, + LinearProgress, + Stack, +} from "@mui/material"; +import Typography from "@mui/material/Typography"; +import React, { useEffect, useState } from "react"; +import "./App.scss"; +import { InputField } from "./InputField"; +import questions from "./PhysicsSimulationQuestions.json"; +import tutorials from "./PhysicsSimulationTutorial.json"; +import { IWallProps, Wall } from "./Wall"; +import { IForce, Weight } from "./Weight"; +interface VectorTemplate { top: number; left: number; width: number; @@ -33,118 +52,191 @@ interface PhysicsVectorTemplate { weightX: number; weightY: number; } +interface QuestionTemplate { + questionSetup: string[]; + variablesForQuestionSetup: string[]; + question: string; + answerParts: string[]; + answerSolutionDescriptions: string[]; + goal: string; + hints: { description: string; content: string }[]; +} + +interface TutorialTemplate { + question: string; + steps: { + description: string; + content: string; + forces: { + description: string; + magnitude: number; + directionInDegrees: number; + component: boolean; + }[]; + showMagnitude: boolean; + }[]; +} @observer export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent() { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PhysicsSimulationBox, fieldKey); } - // Constants - gravityMagnitude = 9.81; - forceOfGravity: IForce = { - description: "Gravity", - magnitude: this.gravityMagnitude, - directionInDegrees: 270, - }; - xMin = 0; - yMin = 0; - xMax = 300; - yMax = 300; - color = `rgba(0,0,0,0.5)`; - radius = 0.1*this.yMax - update = true - menuIsOpen = false - constructor(props: any) { super(props); } - // Add one weight to the simulation - addWeight () { - this.dataDoc.weight = true; - this.dataDoc.wedge = false; - this.dataDoc.pendulum = false; - this.addWalls(); - }; + // Constants + const xMin = 0; + const yMin = 0; + const xMax = window.innerWidth * 0.7; + const yMax = window.innerHeight * 0.8; + const color = `rgba(0,0,0,0.5)`; + const radius = 50; + const wallPositions: IWallProps[] = []; - // Set weight defaults - setToWeightDefault () { - this.dataDoc.startPosY = this.yMin+this.radius; - this.dataDoc.startPosX = (this.xMax+this.xMin-this.radius)/2; - this.dataDoc.updatedForces = [this.forceOfGravity]; - this.dataDoc.startForces = [this.forceOfGravity]; - } - // Add a wedge with a One Weight to the simulation - addWedge () { - this.dataDoc.weight = true; - this.dataDoc.wedge = true; - this.dataDoc.pendulum = false; - this.addWalls(); - }; + componentDidMount() { + this.wallPositions.push({ length: 70, xPos: 0, yPos: 0, angleInDegrees: 0 }); + this.wallPositions.push({ length: 70, xPos: 0, yPos: 80, angleInDegrees: 0 }); + this.wallPositions.push({ length: 80, xPos: 0, yPos: 0, angleInDegrees: 90 }); + this.wallPositions.push({ length: 80, xPos: 69.5, yPos: 0, angleInDegrees: 90 }); - // Set wedge defaults - setToWedgeDefault () { - this.changeWedgeBasedOnNewAngle(26); - this.updateForcesWithFriction(this.dataDoc.coefficientOfStaticFriction); - } + // Used throughout sims + this.xMax = this.layoutDoc._width; + this.yMax = this.layoutDoc._height; + this.radius = 0.1*this.layoutDoc._height; + this.dataDoc.reviewCoefficient = this.dataDoc.reviewCoefficient ?? 0; + this.dataDoc.questionVariables = this.dataDoc.questionVariables ?? []; + this.dataDoc.accelerationXDisplay = this.dataDoc.accelerationXDisplay ?? 0; + this.dataDoc.accelerationYDisplay = this.dataDoc.accelerationYDisplay ?? 0; + this.dataDoc.componentForces = this.dataDoc.componentForces ?? []; + this.dataDoc.displayChange = this.dataDoc.displayChange ?? { xDisplay: 0, yDisplay: 0 }; + this.dataDoc.elasticCollisions = this.dataDoc.elasticCollisions ?? false; + this.dataDoc.gravity = this.dataDoc.gravity ?? -9.81; + this.dataDoc.mass = this.dataDoc.mass ?? 1; + this.dataDoc.mode = this.dataDoc.mode ?? "Freeform"; + this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0; + this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0; + this.dataDoc.resetAll = this.dataDoc.resetAll ?? true; + this.dataDoc.showAcceleration = this.dataDoc.showAcceleration ?? false; + this.dataDoc.showComponentForces = this.dataDoc.showComponentForces ?? false; + this.dataDoc.showForces = this.dataDoc.showForces ?? true; + this.dataDoc.showForceMagnitudes = this.dataDoc.showForceMagnitudes ?? true; + this.dataDoc.showVelocity = this.dataDoc.showVelocity ?? false; + this.dataDoc.simulationPaused = this.dataDoc.simulationPaused ?? true; + this.dataDoc.simulationReset = this.dataDoc.simulationReset ?? false; + this.dataDoc.simulationSpeed = this.dataDoc.simulationSpeed ?? 2; + this.dataDoc.simulationType = this.dataDoc.simulationType ?? "Inclined Plane"; + this.dataDoc.startForces = this.dataDoc.startForces ?? []; + this.dataDoc.startPosX = this.dataDoc.startPosX ?? 0; + this.dataDoc.startPosY = this.dataDoc.startPosY ?? 0; + this.dataDoc.startVelX = this.dataDoc.startVelX ?? 0; + this.dataDoc.startVelY = this.dataDoc.startVelY ?? 0; + this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0; + this.dataDoc.timer = this.dataDoc.timer ?? 0; + this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? []; + this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0; + this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0; - // Add a simple pendulum to the simulation - addPendulum = () => { - this.dataDoc.weight = true; - this.dataDoc.wedge = false; - this.dataDoc.pendulum = true; - this.removeWalls(); - let angle = this.dataDoc.pendulumAngle; - let mag = 9.81 * Math.cos((angle * Math.PI) / 180); - let forceOfTension: IForce = { - description: "Tension", - magnitude: mag, - directionInDegrees: 90 - angle, - }; - this.dataDoc.updatedForces = [this.forceOfGravity, forceOfTension]; - this.dataDoc.startForces = [this.forceOfGravity, forceOfTension]; - }; + // Used for review mode + this.dataDoc.answerInputFields = this.dataDoc.answerInputFields ??
; + this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? null; + this.dataDoc.deleteMode = this.dataDoc.deleteMode ?? false; + this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? []; + this.dataDoc.hintDialogueOpen = this.dataDoc.hintDialogueOpen ?? false; + this.dataDoc.noMovement = this.dataDoc.noMovement ?? false; + this.dataDoc.questionNumber = this.dataDoc.questionNumber ?? 0; + this.dataDoc.questionPartOne = this.dataDoc.questionPartOne ?? ""; + this.dataDoc.questionPartTwo = this.dataDoc.questionPartTwo ?? ""; + this.dataDoc.reviewGravityAngle = this.dataDoc.reviewGravityAngle ?? 0; + this.dataDoc.reviewGravityMagnitude = this.dataDoc.reviewGravityMagnitude ?? 0; + this.dataDoc.reviewNormalAngle = this.dataDoc.reviewNormalAngle ?? 0; + this.dataDoc.reviewNormalMagnitude = this.dataDoc.reviewNormalMagnitude ?? 0; + this.dataDoc.reviewStaticAngle = this.dataDoc.reviewStaticAngle ?? 0; + this.dataDoc.reviewStaticMagnitude = this.dataDoc.reviewStaticMagnitude ?? 0; + this.dataDoc.selectedSolutions = this.dataDoc.selectedSolutions ?? []; + this.dataDoc.selectedQuestion = this.dataDoc.selectedQuestion ?? questions.inclinePlane[0]; + this.dataDoc.sketching = this.dataDoc.sketching ?? false; + + // Used for tutorial mode + this.dataDoc.selectedTutorial = this.dataDoc.selectedTutorial ?? tutorials.inclinePlane; - // Set pendulum defaults - setToPendulumDefault () { - let length = this.xMax*0.7; - let angle = 35; - let x = length * Math.cos(((90 - angle) * Math.PI) / 180); - let y = length * Math.sin(((90 - angle) * Math.PI) / 180); - let xPos = this.xMax / 2 - x - this.radius; - let yPos = y - this.radius; - this.dataDoc.startPosX = xPos; - this.dataDoc.startPosY = yPos; - let mag = 9.81 * Math.cos((angle * Math.PI) / 180); - this.dataDoc.pendulumAngle = angle; - this.dataDoc.pendulumLength = length; - this.dataDoc.startPendulumAngle = angle; - this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle; + // Used for uniform circular motion + this.dataDoc.circularMotionRadius = this.dataDoc.circularMotionRadius ?? 150; + + // Used for spring simulation + this.dataDoc.springConstant = this.dataDoc.springConstant ?? 0.5; + this.dataDoc.springRestLength = this.dataDoc.springRestLength ?? 200; + this.dataDoc.springStartLength = this.dataDoc.springStartLength ?? 200; + + // Used for pendulum simulation + this.dataDoc.adjustPendulumAngle = this.dataDoc.adjustPendulumAngle ?? { angle: 0, length: 0 }; + this.dataDoc.pendulumAngle = this.dataDoc.pendulumAngle ?? 0; + this.dataDoc.pendulumLength = this.dataDoc.pendulumLength ?? 300; + this.dataDoc.startPendulumAngle = this.dataDoc.startPendulumAngle ?? 0; + + // Used for wedge simulation + this.dataDoc.coefficientOfKineticFriction = this.dataDoc.coefficientOfKineticFriction ?? 0; + this.dataDoc.coefficientOfStaticFriction = this.dataDoc.coefficientOfStaticFriction ?? 0; + this.dataDoc.wedgeAngle = this.dataDoc.wedgeAngle ?? 26; + this.dataDoc.wedgeHeight = this.dataDoc.wedgeHeight ?? Math.tan((26 * Math.PI) / 180) * 400; + this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? 400; + + // Used for pulley simulation + this.dataDoc.positionXDisplay2 = this.dataDoc.positionXDisplay2 ?? 0; + this.dataDoc.velocityXDisplay2 = this.dataDoc.velocityXDisplay2 ?? 0; + this.dataDoc.accelerationXDisplay2 = this.dataDoc.accelerationXDisplay2 ?? 0; + this.dataDoc.positionYDisplay2 = this.dataDoc.positionYDisplay2 ?? 0; + this.dataDoc.velocityYDisplay2 = this.dataDoc.velocityYDisplay2 ?? 0; + this.dataDoc.accelerationYDisplay2 = this.dataDoc.accelerationYDisplay2 ?? 0; + this.dataDoc.startPosX2 = this.dataDoc.startPosX2 ?? 0; + this.dataDoc.startPosY2 = this.dataDoc.startPosY2 ?? 0; + this.dataDoc.displayChange2 = this.dataDoc.displayChange2 ?? { xDisplay: 0, yDisplay: 0 }; + this.dataDoc.startForces2 = this.dataDoc.startForces2 ?? []; + this.dataDoc.updatedForces2 = this.dataDoc.updatedForces2 ?? []; + this.dataDoc.mass2 = this.dataDoc.mass2 ?? 1; + } + + componentDidUpdate() { + this.xMax = this.layoutDoc._width; + this.yMax = this.layoutDoc._height; + this.radius = 0.1*this.layoutDoc._height; } + // Helper function to go between display and real values + getDisplayYPos = (yPos: number) => { + return this.yMax - this.dataDoc.yPos - 2 * this.radius + 5; + }; + getYPosFromDisplay = (yDisplay: number) => { + return this.yMax - this.dataDoc.yDisplay - 2 * this.radius + 5; + }; + // Update forces when coefficient of static friction changes in freeform mode - updateForcesWithFriction ( + updateForcesWithFriction = ( coefficient: number, - width: number = this.dataDoc.wedgeWidth, - height: number = this.dataDoc.wedgeHeight - ) { - let normalForce = { + width: number = this.wedgeWidth, + height: number = this.wedgeHeight + ) => { + const normalForce: IForce = { description: "Normal Force", - magnitude: this.forceOfGravity.magnitude * Math.cos(Math.atan(height / width)), + magnitude: Math.abs(this.gravity) * Math.cos(Math.atan(height / width)) * this.mass, directionInDegrees: 180 - 90 - (Math.atan(height / width) * 180) / Math.PI, + component: false, }; let frictionForce: IForce = { description: "Static Friction Force", magnitude: coefficient * - this.forceOfGravity.magnitude * - Math.cos(Math.atan(height / width)), + Math.abs(this.gravity) * + Math.cos(Math.atan(height / width)) * + this.mass, directionInDegrees: 180 - (Math.atan(height / width) * 180) / Math.PI, + component: false, }; - // reduce magnitude of friction force if necessary such that block cannot slide up plane - let yForce = -this.forceOfGravity.magnitude; + // reduce magnitude or friction force if necessary such that block cannot slide up plane + let yForce = -Math.abs(this.gravity) * this.mass; yForce += normalForce.magnitude * Math.sin((normalForce.directionInDegrees * Math.PI) / 180); @@ -155,15 +247,65 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { - return this.yMax - yPos - 2 * 50 + 5; - }; - - // In review mode, edit force arrow sketch on mouse movement - editForce = (element: PhysicsVectorTemplate) => { - if (!this.dataDoc.sketching) { - let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element); - this.dataDoc.forceSketches = sketches; - this.dataDoc.currentForceSketch = element; - this.dataDoc.sketching = true; + if (this.dataDoc.mode == "Freeform") { + this.updateForcesWithFriction( + Number(this.dataDoc.coefficientOfStaticFriction), + width, + height + ); } }; - // In review mode, used to delete force arrow sketch on SHIFT+click - deleteForce = (element: PhysicsVectorTemplate) => { - if (!this.dataDoc.sketching) { - let sketches = this.dataDoc.forceSketches.filter((sketch: PhysicsVectorTemplate) => sketch != element); - this.dataDoc.forceSketches = sketches; + // In review mode, update forces when coefficient of static friction changed + updateReviewForcesBasedOnCoefficient = (coefficient: number) => { + let theta: number = Number(this.dataDoc.wedgeAngle); + let index = + this.dataDoc.selectedQuestion.variablesForQuestionSetup.indexOf("theta - max 45"); + if (index >= 0) { + theta = this.dataDoc.questionVariables[index]; } + if (isNaN(theta)) { + return; + } + this.dataDoc.reviewGravityMagnitude = (Math.abs(this.dataDoc.gravity)); + this.dataDoc.reviewGravityAngle = (270); + this.dataDoc.reviewNormalMagnitude = ( + Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180) + ); + this.dataDoc.reviewNormalAngle = (90 - theta); + let yForce = -Math.abs(this.dataDoc.gravity); + yForce += + Math.abs(this.dataDoc.gravity) * + Math.cos((theta * Math.PI) / 180) * + Math.sin(((90 - theta) * Math.PI) / 180); + yForce += + coefficient * + Math.abs(this.dataDoc.gravity) * + Math.cos((theta * Math.PI) / 180) * + Math.sin(((180 - theta) * Math.PI) / 180); + let friction = + coefficient * Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180); + if (yForce > 0) { + friction = + (-(Math.abs(this.dataDoc.gravity) * Math.cos((theta * Math.PI) / 180)) * + Math.sin(((90 - theta) * Math.PI) / 180) + + Math.abs(this.dataDoc.gravity)) / + Math.sin(((180 - theta) * Math.PI) / 180); + } + this.dataDoc.reviewStaticMagnitude = (friction); + this.dataDoc.reviewStaticAngle = (180 - theta); }; - // Remove floor and walls from simulation - removeWalls = () => { - this.dataDoc.wallPositions = [] - }; - - // Add floor and walls to simulation - addWalls = () => { - let walls = []; - walls.push({ length: 100, xPos: 0, yPos: 97, angleInDegrees: 0 }); - walls.push({ length: 100, xPos: 0, yPos: 0, angleInDegrees: 90 }); - walls.push({ length: 100, xPos: 97, yPos: 0, angleInDegrees: 90 }); - this.dataDoc.wallPositions = walls - }; - - - componentDidMount() { - this.xMax = this.layoutDoc._width; - this.yMax = this.layoutDoc._height; - this.radius = 0.1*this.layoutDoc._height; - - // Add weight - if (this.dataDoc.simulationType == "Inclined Plane") { - this.addWedge() - } else if (this.dataDoc.simulationType == "Pendulum") { - this.addPendulum() - } else { - this.dataDoc.simulationType = "Free Weight" - this.addWeight() + // In review mode, update forces when wedge angle changed + updateReviewForcesBasedOnAngle = (angle: number) => { + this.dataDoc.reviewGravityMagnitude = (Math.abs(this.dataDoc.gravity)); + this.dataDoc.reviewGravityAngle = (270); + this.dataDoc.reviewNormalMagnitude = ( + Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180) + ); + this.dataDoc.reviewNormalAngle = (90 - angle); + let yForce = -Math.abs(this.dataDoc.gravity); + yForce += + Math.abs(this.dataDoc.gravity) * + Math.cos((Number(angle) * Math.PI) / 180) * + Math.sin(((90 - Number(angle)) * Math.PI) / 180); + yForce += + this.dataDoc.reviewCoefficient * + Math.abs(this.dataDoc.gravity) * + Math.cos((Number(angle) * Math.PI) / 180) * + Math.sin(((180 - Number(angle)) * Math.PI) / 180); + let friction = + this.dataDoc.reviewCoefficient * + Math.abs(this.dataDoc.gravity) * + Math.cos((Number(angle) * Math.PI) / 180); + if (yForce > 0) { + friction = + (-(Math.abs(this.dataDoc.gravity) * Math.cos((Number(angle) * Math.PI) / 180)) * + Math.sin(((90 - Number(angle)) * Math.PI) / 180) + + Math.abs(this.dataDoc.gravity)) / + Math.sin(((180 - Number(angle)) * Math.PI) / 180); } - this.dataDoc.accelerationXDisplay = this.dataDoc.accelerationXDisplay ?? 0; - this.dataDoc.accelerationYDisplay = this.dataDoc.accelerationYDisplay ?? 0; - this.dataDoc.coefficientOfKineticFriction = this.dataDoc.coefficientOfKineticFriction ?? 0; - this.dataDoc.coefficientOfStaticFriction = this.dataDoc.coefficientOfStaticFriction ?? 0; - this.dataDoc.currentForceSketch = this.dataDoc.currentForceSketch ?? []; - this.dataDoc.elasticCollisions = this.dataDoc.elasticCollisions ?? false; - this.dataDoc.forceSketches = this.dataDoc.forceSketches ?? []; - this.dataDoc.pendulumAngle = this.dataDoc.pendulumAngle ?? 26; - this.dataDoc.pendulumLength = this.dataDoc.pendulumLength ?? 300; - this.dataDoc.positionXDisplay = this.dataDoc.positionXDisplay ?? 0; - this.dataDoc.positionYDisplay = this.dataDoc.positionYDisplay ?? 0; - this.dataDoc.showAcceleration = this.dataDoc.showAcceleration ?? false; - this.dataDoc.showForceMagnitudes = this.dataDoc.showForceMagnitudes ?? false; - this.dataDoc.showForces = this.dataDoc.showForces ?? false; - this.dataDoc.showVelocity = this.dataDoc.showVelocity ?? false; - this.dataDoc.startForces = this.dataDoc.startForces ?? [this.forceOfGravity]; - this.dataDoc.startPendulumAngle = this.dataDoc.startPendulumAngle ?? 0; - this.dataDoc.startPosX = this.dataDoc.startPosX ?? 50; - this.dataDoc.startPosY = this.dataDoc.startPosY ?? 50; - this.dataDoc.stepNumber = this.dataDoc.stepNumber ?? 0; - this.dataDoc.updateDisplay = this.dataDoc.updateDisplay ?? false; - this.dataDoc.updatedForces = this.dataDoc.updatedForces ?? [this.forceOfGravity]; - this.dataDoc.velocityXDisplay = this.dataDoc.velocityXDisplay ?? 0; - this.dataDoc.velocityYDisplay = this.dataDoc.velocityYDisplay ?? 0; - this.dataDoc.wallPositions = this.dataDoc.wallPositions ?? []; - this.dataDoc.wedgeAngle = this.dataDoc.wedgeAngle ?? 26; - this.dataDoc.wedgeHeight = this.dataDoc.wedgeHeight ?? Math.tan((26 * Math.PI) / 180) * this.xMax*0.6; - this.dataDoc.wedgeWidth = this.dataDoc.wedgeWidth ?? this.xMax*0.6; - - this.dataDoc.adjustPendulumAngle = true; - this.dataDoc.simulationPaused = true; - this.dataDoc.simulationReset = false; + this.dataDoc.reviewStaticMagnitude = (friction); + this.dataDoc.reviewStaticAngle = (180 - angle); + }; - // Add listener for SHIFT key, which determines if sketch force arrow will be edited or deleted on click - document.addEventListener("keydown", (e) => { - if (e.shiftKey) { - this.dataDoc.deleteMode = true; - } - }); - document.addEventListener("keyup", (e) => { - if (e.shiftKey) { - this.dataDoc.deleteMode = false; - } - }); - } - - componentDidUpdate() { - this.xMax = this.layoutDoc._width; - this.yMax = this.layoutDoc._height; - this.radius = 0.1*this.layoutDoc._height; - } render () { - return ( -
-
-
-
-
- {this.dataDoc.weight && ( - - )} - {this.dataDoc.wedge && ( - - )} -
-
- {(this.dataDoc.wallPositions ?? []).map((element: { length: number; xPos: number; yPos: number; angleInDegrees: number; }, index: React.Key | null | undefined) => { - return ( -
- -
- ); - })} -
-
-
-
- {this.menuIsOpen && ( -
-
{this.menuIsOpen = false; this.dataDoc.simulationReset = !this.dataDoc.simulationReset;}}> - -
-

Simulation Settings

-
-

Show forces

-
{this.dataDoc.showForces = !this.dataDoc.showForces}}/>
-
-
-

Show acceleration

-
{this.dataDoc.showAcceleration = !this.dataDoc.showAcceleration}}/>
-
-
-
-

Show velocity

-
{this.dataDoc.showVelocity = !this.dataDoc.showVelocity}}/>
-
-
- {this.dataDoc.simulationType == "Free Weight" &&
-

Elastic collisions

-
{this.dataDoc.elasticCollisions = !this.dataDoc.elasticCollisions}}/>
-
} - {this.dataDoc.simulationType == "Pendulum" &&
-

Pendulum start angle

-
- { - let angle = e.target.value; - if (angle > 35) { - angle = 35 - } - if (angle < 0) { - angle = 0 - } - let length = this.xMax*0.7; - let x = length * Math.cos(((90 - angle) * Math.PI) / 180); - let y = length * Math.sin(((90 - angle) * Math.PI) / 180); - let xPos = this.xMax / 2 - x - this.radius; - let yPos = y - this.radius; - this.dataDoc.startPosX = xPos; - this.dataDoc.startPosY = yPos; - let mag = 9.81 * Math.cos((angle * Math.PI) / 180); - this.dataDoc.pendulumAngle = angle; - this.dataDoc.pendulumLength = length; - this.dataDoc.startPendulumAngle = angle; - this.dataDoc.adjustPendulumAngle = !this.dataDoc.adjustPendulumAngle; - }} - /> -
-
} - {this.dataDoc.simulationType == "Inclined Plane" &&
-

Inclined plane angle

-
- { - let angle = e.target.value ?? 0 - if (angle > 70) { - angle = 70 - } - if (angle < 0) { - angle = 0 - } - this.dataDoc.wedgeAngle = angle - this.changeWedgeBasedOnNewAngle(angle) - }} - /> -
-
} -
- )} -
-
-
-
- {this.dataDoc.simulationPaused && ( - - )} - {!this.dataDoc.simulationPaused && ( - - )} - {this.dataDoc.simulationPaused && ( - - )} - {this.dataDoc.simulationPaused && ( )} - -
-
-
-
-
- ); - } } \ No newline at end of file diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx deleted file mode 100644 index 6134a6bc0..000000000 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationWedge.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React = require('react'); -import "./PhysicsSimulationBox.scss"; - -export interface IWedgeProps { - startHeight: number; - startWidth: number; - startLeft: number; - xMax: number; - yMax: number; -} - -interface IState { - angleInRadians: number, - left: number, - coordinates: string, -} - -export default class Wedge extends React.Component { - - constructor(props: any) { - super(props) - this.state = { - angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth), - left: this.props.startLeft, - coordinates: "", - } - } - - color = "#deb887"; - - updateCoordinates() { - const coordinatePair1 = - Math.round(this.state.left) + "," + Math.round(this.props.yMax) + " "; - const coordinatePair2 = - Math.round(this.state.left + this.props.startWidth) + - "," + - Math.round(this.props.yMax) + - " "; - const coordinatePair3 = - Math.round(this.state.left) + - "," + - Math.round(this.props.yMax - this.props.startHeight); - const coord = coordinatePair1 + coordinatePair2 + coordinatePair3; - this.setState({coordinates: coord}); - } - - componentDidMount() { - this.updateCoordinates() - } - - componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot?: any): void { - if (prevProps.startHeight != this.props.startHeight || prevProps.startWidth != this.props.startWidth) { - this.setState({angleInRadians: Math.atan(this.props.startHeight / this.props.startWidth)}); - this.updateCoordinates(); - } - } - - render() { - return ( -
-
- - - -
- -

- {Math.round(((this.state.angleInRadians * 180) / Math.PI) * 100) / 100}° -

-
- ); - } -}; -- cgit v1.2.3-70-g09d2 From 1eb8bee423564970c15ea0fbe9898d9e8c6b0491 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Mon, 1 May 2023 13:02:18 -0400 Subject: start adding box code --- .../nodes/PhysicsBox/PhysicsSimulationBox.tsx | 406 ++++++++++++++++++++- 1 file changed, 405 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index f27843ab0..3ae281177 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -198,7 +198,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { + const solutions: number[] = []; + + let theta: number = Number(this.dataDoc.wedgeAngle); + let index = question.variablesForQuestionSetup.indexOf("theta - max 45"); + if (index >= 0) { + theta = questionVars[index]; + } + let muS: number = Number(this.dataDoc.coefficientOfStaticFriction); + index = question.variablesForQuestionSetup.indexOf( + "coefficient of static friction" + ); + if (index >= 0) { + muS = questionVars[index]; + } + + for (let i = 0; i < question.answerSolutionDescriptions.length; i++) { + const description = question.answerSolutionDescriptions[i]; + if (!isNaN(Number(description))) { + solutions.push(Number(description)); + } else if (description == "solve normal force angle from wedge angle") { + solutions.push(90 - theta); + } else if ( + description == "solve normal force magnitude from wedge angle" + ) { + solutions.push(Math.abs(this.dataDoc.gravity) * Math.cos((theta / 180) * Math.PI)); + } else if ( + description == + "solve static force magnitude from wedge angle given equilibrium" + ) { + let normalForceMagnitude = + Math.abs(this.dataDoc.gravity) * Math.cos((theta / 180) * Math.PI); + let normalForceAngle = 90 - theta; + let frictionForceAngle = 180 - theta; + let frictionForceMagnitude = + (-normalForceMagnitude * + Math.sin((normalForceAngle * Math.PI) / 180) + + Math.abs(this.dataDoc.gravity)) / + Math.sin((frictionForceAngle * Math.PI) / 180); + solutions.push(frictionForceMagnitude); + } else if ( + description == + "solve static force angle from wedge angle given equilibrium" + ) { + solutions.push(180 - theta); + } else if ( + description == + "solve minimum static coefficient from wedge angle given equilibrium" + ) { + let normalForceMagnitude = + Math.abs(this.dataDoc.gravity) * Math.cos((theta / 180) * Math.PI); + let normalForceAngle = 90 - theta; + let frictionForceAngle = 180 - theta; + let frictionForceMagnitude = + (-normalForceMagnitude * + Math.sin((normalForceAngle * Math.PI) / 180) + + Math.abs(this.dataDoc.gravity)) / + Math.sin((frictionForceAngle * Math.PI) / 180); + let frictionCoefficient = frictionForceMagnitude / normalForceMagnitude; + solutions.push(frictionCoefficient); + } else if ( + description == + "solve maximum wedge angle from coefficient of static friction given equilibrium" + ) { + solutions.push((Math.atan(muS) * 180) / Math.PI); + } + } + this.dataDoc.selectedSolutions = (solutions); + return solutions; + }; + + // In review mode, check if input answers match correct answers and optionally generate alert + checkAnswers = (showAlert: boolean = true) => { + let error: boolean = false; + let epsilon: number = 0.01; + if (this.dataDoc.selectedQuestion) { + for (let i = 0; i < this.dataDoc.selectedQuestion.answerParts.length; i++) { + if (this.dataDoc.selectedQuestion.answerParts[i] == "force of gravity") { + if ( + Math.abs(this.dataDoc.reviewGravityMagnitude - this.dataDoc.selectedSolutions[i]) > epsilon + ) { + error = true; + } + } else if (this.dataDoc.selectedQuestion.answerParts[i] == "angle of gravity") { + if (Math.abs(this.dataDoc.reviewGravityAngle - this.dataDoc.selectedSolutions[i]) > epsilon) { + error = true; + } + } else if (this.dataDoc.selectedQuestion.answerParts[i] == "normal force") { + if ( + Math.abs(this.dataDoc.reviewNormalMagnitude - this.dataDoc.selectedSolutions[i]) > epsilon + ) { + error = true; + } + } else if (this.dataDoc.selectedQuestion.answerParts[i] == "angle of normal force") { + if (Math.abs(this.dataDoc.reviewNormalAngle - this.dataDoc.selectedSolutions[i]) > epsilon) { + error = true; + } + } else if ( + this.dataDoc.selectedQuestion.answerParts[i] == "force of static friction" + ) { + if ( + Math.abs(this.dataDoc.reviewStaticMagnitude - this.dataDoc.selectedSolutions[i]) > epsilon + ) { + error = true; + } + } else if ( + this.dataDoc.selectedQuestion.answerParts[i] == "angle of static friction" + ) { + if (Math.abs(this.dataDoc.reviewStaticAngle - this.dataDoc.selectedSolutions[i]) > epsilon) { + error = true; + } + } else if ( + this.dataDoc.selectedQuestion.answerParts[i] == "coefficient of static friction" + ) { + if ( + Math.abs( + Number(this.dataDoc.coefficientOfStaticFriction) - this.dataDoc.selectedSolutions[i] + ) > epsilon + ) { + error = true; + } + } else if (this.dataDoc.selectedQuestion.answerParts[i] == "wedge angle") { + if (Math.abs(Number(this.dataDoc.wedgeAngle) - this.dataDoc.selectedSolutions[i]) > epsilon) { + error = true; + } + } + } + } + if (showAlert) { + if (!error) { + this.dataDoc.simulationPaused = (false); + setTimeout(() => { + this.dataDoc.simulationPaused = (true); + }, 3000); + } else { + this.dataDoc.simulationPaused = (false); + setTimeout(() => { + this.dataDoc.simulationPaused = (true); + }, 3000); + } + } + if (this.dataDoc.selectedQuestion.goal == "noMovement") { + if (!error) { + this.dataDoc.noMovement = (true); + } else { + this.dataDoc.roMovement = (false); + } + } + }; + + // Reset all review values to default + resetReviewValuesToDefault = () => { + this.dataDoc.reviewGravityMagnitude = (0); + this.dataDoc.reviewGravityAngle = (0); + this.dataDoc.reviewNormalMagnitude = (0); + this.dataDoc.reviewNormalAngle = (0); + this.dataDoc.reviewStaticMagnitude = (0); + this.dataDoc.reviewStaticAngle = (0); + this.dataDoc.coefficientOfKineticFriction = (0); + this.dataDoc.simulationPaused = (true); + this.dataDoc.answerInputFields = (
); + }; + + // In review mode, reset problem variables and generate a new question + generateNewQuestion = () => { + this.resetReviewValuesToDefault(); + + const vars: number[] = []; + let question: QuestionTemplate = questions.inclinePlane[0]; + + if (this.dataDoc.simulationType == "Inclined Plane") { + if (this.dataDoc.questionNumber == questions.inclinePlane.length - 1) { + this.dataDoc.questionNumber = (0); + } else { + this.dataDoc.questionNumber =(questionNumber + 1); + } + question = questions.inclinePlane[this.dataDoc.questionNumber]; + + let coefficient = 0; + let wedgeAngle = 0; + + for (let i = 0; i < question.variablesForQuestionSetup.length; i++) { + if (question.variablesForQuestionSetup[i] == "theta - max 45") { + let randValue = Math.floor(Math.random() * 44 + 1); + vars.push(randValue); + wedgeAngle = randValue; + } else if ( + question.variablesForQuestionSetup[i] == + "coefficient of static friction" + ) { + let randValue = Math.round(Math.random() * 1000) / 1000; + vars.push(randValue); + coefficient = randValue; + } + } + this.dataDoc.wedgeAngle = (wedgeAngle); + this.changeWedgeBasedOnNewAngle(wedgeAngle); + this.dataDoc.coefficientOfStaticFriction = (coefficient); + this.dataDoc.reviewCoefficient = coefficient; + } + let q = ""; + for (let i = 0; i < question.questionSetup.length; i++) { + q += question.questionSetup[i]; + if (i != question.questionSetup.length - 1) { + q += vars[i]; + if (question.variablesForQuestionSetup[i].includes("theta")) { + q += + " degree (≈" + + Math.round((1000 * (vars[i] * Math.PI)) / 180) / 1000 + + " rad)"; + } + } + } + this.dataDoc.questionVariables = vars; + this.dataDoc.selectedQuestion = (question); + this.dataDoc.questionPartOne = (q); + this.dataDoc.questionPartTwo = (question.question); + const answers = this.getAnswersToQuestion(question, vars); + this.generateInputFieldsForQuestion(false, question, answers); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); + }; + + // Generate answerInputFields for new review question + generateInputFieldsForQuestion = ( + showIcon: boolean = false, + question: QuestionTemplate = this.dataDoc.selectedQuestion, + answers: number[] = this.dataDoc.selectedSolutions + ) => { + let answerInput = []; + const d = new Date(); + for (let i = 0; i < question.answerParts.length; i++) { + if (question.answerParts[i] == "force of gravity") { + this.dataDoc.reviewGravityMagnitude = (0); + answerInput.push( +
+ Gravity magnitude

} + lowerBound={0} + changeValue={this.dataDoc.reviewGravityMagnitude} + step={0.1} + unit={"N"} + upperBound={50} + value={this.dataDoc.reviewGravityMagnitude} + showIcon={showIcon} + correctValue={answers[i]} + labelWidth={"7em"} + /> +
+ ); + } else if (question.answerParts[i] == "angle of gravity") { + this.dataDoc.reviewGravityAngle = (0); + answerInput.push( +
+ Gravity angle

} + lowerBound={0} + changeValue={this.dataDoc.reviewGravityAngle} + step={1} + unit={"°"} + upperBound={360} + value={this.dataDoc.reviewGravityAngle} + radianEquivalent={true} + showIcon={showIcon} + correctValue={answers[i]} + labelWidth={"7em"} + /> +
+ ); + } else if (question.answerParts[i] == "normal force") { + this.dataDoc.reviewNormalMagnitude = (0); + answerInput.push( +
+ Normal force magnitude

} + lowerBound={0} + changeValue={this.dataDoc.reviewNormalMagnitude} + step={0.1} + unit={"N"} + upperBound={50} + value={this.dataDoc.reviewNormalMagnitude} + showIcon={showIcon} + correctValue={answers[i]} + labelWidth={"7em"} + /> +
+ ); + } else if (question.answerParts[i] == "angle of normal force") { + this.dataDoc.reviewNormalAngle = (0); + answerInput.push( +
+ Normal force angle

} + lowerBound={0} + changeValue={this.dataDoc.reviewNormalAngle} + step={1} + unit={"°"} + upperBound={360} + value={this.dataDoc.reviewNormalAngle} + radianEquivalent={true} + showIcon={showIcon} + correctValue={answers[i]} + labelWidth={"7em"} + /> +
+ ); + } else if (question.answerParts[i] == "force of static friction") { + this.dataDoc.reviewStaticMagnitude = (0); + answerInput.push( +
+ Static friction magnitude

} + lowerBound={0} + changeValue={this.dataDoc.reviewStaticMagnitude} + step={0.1} + unit={"N"} + upperBound={50} + value={this.dataDoc.reviewStaticMagnitude} + showIcon={showIcon} + correctValue={answers[i]} + labelWidth={"7em"} + /> +
+ ); + } else if (question.answerParts[i] == "angle of static friction") { + this.dataDoc.reviewStaticAngle = (0); + answerInput.push( +
+ Static friction angle

} + lowerBound={0} + changeValue={this.dataDoc.reviewStaticAngle} + step={1} + unit={"°"} + upperBound={360} + value={this.dataDoc.reviewStaticAngle} + radianEquivalent={true} + showIcon={showIcon} + correctValue={answers[i]} + labelWidth={"7em"} + /> +
+ ); + } else if (question.answerParts[i] == "coefficient of static friction") { + this.updateReviewForcesBasedOnCoefficient(0); + answerInput.push( +
+ + μs + + } + lowerBound={0} + changeValue={this.dataDoc.coefficientOfStaticFriction} + step={0.1} + unit={""} + upperBound={1} + value={this.dataDoc.coefficientOfStaticFriction} + effect={this.updateReviewForcesBasedOnCoefficient} + showIcon={showIcon} + correctValue={answers[i]} + /> +
+ ); + } else if (question.answerParts[i] == "wedge angle") { + this.updateReviewForcesBasedOnAngle(0); + answerInput.push( +
+ θ} + lowerBound={0} + changeValue={this.dataDoc.qedgeAngle} + step={1} + unit={"°"} + upperBound={49} + value={this.dataDoc.wedgeAngle} + effect={(val: number) => { + this.changeWedgeBasedOnNewAngle(val); + this.updateReviewForcesBasedOnAngle(val); + }} + radianEquivalent={true} + showIcon={showIcon} + correctValue={answers[i]} + /> +
+ ); + } + } + + this.dataDoc.answerInputFields = ( +
+ {answerInput} +
+ ); + }; + + + render () { } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From a936f7c60c56e4a92aed99cae8e4194fa7fdeda5 Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Mon, 1 May 2023 14:19:49 -0400 Subject: add to box --- .../nodes/PhysicsBox/PhysicsSimulationBox.tsx | 343 ++++++++++++++++++++- 1 file changed, 341 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index 3ae281177..88338d9b8 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -95,7 +95,6 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { + this.dataDoc.showComponentForces = (false); + this.dataDoc.startVelY = (0); + this.dataDoc.startVelX = (value); + let xPos = (this.xMax + this.xMin) / 2 - this.radius; + let yPos = (this.yMax + this.yMin) / 2 + this.dataDoc.circularMotionRadius - this.radius; + this.dataDoc.startPosY = (yPos); + this.dataDoc.startPosX = (xPos); + const tensionForce: IForce = { + description: "Centripetal Force", + magnitude: (this.dataDoc.startVelX ** 2 * this.dataDoc.mass) / this.dataDoc.circularMotionRadius, + directionInDegrees: 90, + component: false, + }; + this.dataDoc.updatedForces = ([tensionForce]); + this.dataDoc.startForces = ([tensionForce]); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); + }; + + // Default setup for pendulum simulation + setupPendulum = () => { + const length = 300; + const angle = 30; + const x = length * Math.cos(((90 - angle) * Math.PI) / 180); + const y = length * Math.sin(((90 - angle) * Math.PI) / 180); + const xPos = this.xMax / 2 - x - this.radius; + const yPos = y - this.radius - 5; + this.dataDoc.startPosX = (xPos); + this.dataDoc.startPosY = (yPos); + const mag = this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.sin((60 * Math.PI) / 180); + const forceOfTension: IForce = { + description: "Tension", + magnitude: mag, + directionInDegrees: 90 - angle, + component: false, + }; + + const tensionComponent: IForce = { + description: "Tension", + magnitude: mag, + directionInDegrees: 90 - angle, + component: true, + }; + const gravityParallel: IForce = { + description: "Gravity Parallel Component", + magnitude: + this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.sin(((90 - angle) * Math.PI) / 180), + directionInDegrees: -angle - 90, + component: true, + }; + const gravityPerpendicular: IForce = { + description: "Gravity Perpendicular Component", + magnitude: + this.dataDoc.mass * Math.abs(this.dataDoc.gravity) * Math.cos(((90 - angle) * Math.PI) / 180), + directionInDegrees: -angle, + component: true, + }; + + this.dataDoc.componentForces = ([ + tensionComponent, + gravityParallel, + gravityPerpendicular, + ]); + this.dataDoc.updatedForces = ([ + { + description: "Gravity", + magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity), + directionInDegrees: 270, + component: false, + }, + forceOfTension, + ]); + this.dataDoc.startForces = ([ + { + description: "Gravity", + magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity), + directionInDegrees: 270, + component: false, + }, + forceOfTension, + ]); + this.dataDoc.startPendulumAngle = (30); + this.dataDoc.pendulumAngle = (30); + this.dataDoc.pendulumLength = (300); + this.dataDoc.adjustPendulumAngle = ({ angle: 30, length: 300 }); + }; + + // Default setup for spring simulation + setupSpring = () => { + this.dataDoc.showComponentForces = (false); + const gravityForce: IForce = { + description: "Gravity", + magnitude: Math.abs(this.dataDoc.gravity) * this.dataDoc.mass, + directionInDegrees: 270, + component: false, + }; + this.dataDoc.updatedForces = ([gravityForce]); + this.dataDoc.startForces = ([gravityForce]); + this.dataDoc.startPosX = (this.xMax / 2 - this.radius); + this.dataDoc.startPosY = (200); + this.dataDoc.springConstant = (0.5); + this.dataDoc.springRestLength = (200); + this.dataDoc.springStartLength = (200); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); + }; + + // Default setup for suspension simulation + setupSuspension = () => { + let xPos = (this.xMax + this.xMin) / 2 - this.radius; + let yPos = this.yMin + 200; + this.dataDoc.startPosY = (yPos); + this.dataDoc.startPosX = (xPos); + this.dataDoc.positionYDisplay = (getDisplayYPos(yPos)); + this.dataDoc.positionXDisplay = (xPos); + let tensionMag = (this.dataDoc.mass * Math.abs(this.dataDoc.gravity)) / (2 * Math.sin(Math.PI / 4)); + const tensionForce1: IForce = { + description: "Tension", + magnitude: tensionMag, + directionInDegrees: 45, + component: false, + }; + const tensionForce2: IForce = { + description: "Tension", + magnitude: tensionMag, + directionInDegrees: 135, + component: false, + }; + const grav: IForce = { + description: "Gravity", + magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity), + directionInDegrees: 270, + component: false, + }; + this.dataDoc.updatedForces = ([tensionForce1, tensionForce2, grav]); + this.dataDoc.startForces = ([tensionForce1, tensionForce2, grav]); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); + }; + + // Default setup for pulley simulation + setupPulley = () => { + this.dataDoc.showComponentForces = (false); + this.dataDoc.startPosY = ((this.yMax + this.yMin) / 2); + this.dataDoc.startPosX = ((this.xMin + this.xMax) / 2 - 105); + this.dataDoc.positionYDisplay = (getDisplayYPos((this.yMax + this.yMin) / 2)); + this.dataDoc.positionXDisplay = ((this.xMin + this.xMax) / 2 - 105); + let a = (-1 * ((mass - mass2) * Math.abs(gravity))) / (mass + mass2); + const gravityForce1: IForce = { + description: "Gravity", + magnitude: this.dataDoc.mass * Math.abs(this.dataDoc.gravity), + directionInDegrees: 270, + component: false, + }; + const tensionForce1: IForce = { + description: "Tension", + magnitude: this.dataDoc.mass * a + this.dataDoc.mass * Math.abs(this.dataDoc.gravity), + directionInDegrees: 90, + component: false, + }; + a *= -1; + const gravityForce2: IForce = { + description: "Gravity", + magnitude: this.dataDoc.mass2 * Math.abs(this.dataDoc.gravity), + directionInDegrees: 270, + component: false, + }; + const tensionForce2: IForce = { + description: "Tension", + magnitude: this.dataDoc.mass2 * a + this.dataDoc.mass2 * Math.abs(this.dataDoc.gravity), + directionInDegrees: 90, + component: false, + }; + this.dataDoc.updatedForces = ([gravityForce1, tensionForce1]); + this.dataDoc.startForces = ([gravityForce1, tensionForce1]); + this.dataDoc.startPosY2 = ((yMax + yMin) / 2); + this.dataDoc.startPosX2 = ((xMin + xMax) / 2 + 5); + this.dataDoc.positionYDisplay2 = (getDisplayYPos((yMax + yMin) / 2)); + this.dataDoc.positionXDisplay2 = ((xMin + xMax) / 2 + 5); + this.dataDoc.updatedForces2 = ([gravityForce2, tensionForce2]); + this.dataDoc.startForces2 = ([gravityForce2, tensionForce2]); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); + }; -- cgit v1.2.3-70-g09d2 From abeb2b59b46e2c6de224d53b341495c162c75c7a Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Mon, 1 May 2023 14:34:04 -0400 Subject: add box --- .../nodes/PhysicsBox/PhysicsSimulationBox.tsx | 1302 ++++++++++++++++++++ 1 file changed, 1302 insertions(+) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index 88338d9b8..101cf1d4a 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -1178,7 +1178,1309 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { + const forces: IForce[] = []; + for (let i = 0; i < json.length; i++) { + const force: IForce = { + description: json[i].description, + magnitude: json[i].magnitude, + directionInDegrees: json[i].directionInDegrees, + component: json[i].component, + }; + forces.push(force); + } + return forces; + }; + + // Handle force change in review mode + updateReviewModeValues = () => { + const forceOfGravityReview: IForce = { + description: "Gravity", + magnitude: this.dataDoc.reviewGravityMagnitude, + directionInDegrees: this.dataDoc.reviewGravityAngle, + component: false, + }; + const normalForceReview: IForce = { + description: "Normal Force", + magnitude: this.dataDoc.reviewNormalMagnitude, + directionInDegrees: this.dataDoc.reviewNormalAngle, + component: false, + }; + const staticFrictionForceReview: IForce = { + description: "Static Friction Force", + magnitude: this.dataDoc.reviewStaticMagnitude, + directionInDegrees: this.dataDoc.reviewStaticAngle, + component: false, + }; + this.dataDoc.startForces = ([ + forceOfGravityReview, + normalForceReview, + staticFrictionForceReview, + ]); + this.dataDoc.updatedForces = ([ + forceOfGravityReview, + normalForceReview, + staticFrictionForceReview, + ]); + } + + // Timer for animating the simulation, update every 0.05 seconds + setInterval(() => { + setTimer(timer + 1); + }, 50); + render () { +
+
+
+
+
+ {!this.dataDoc.simulationPaused && ( +
+ +
+ )} +
+
+ +
+
+
+
+ + {this.dataDoc.simulationType == "Pulley" && ( + + )} +
+
+ {(this.dataDoc.simulationType == "One Weight" || + this.dataDoc.simulationType == "Inclined Plane") && + this.wallPositions.map((element, index) => { + return ( + + ); + })} +
+
+
+
+
+ + {this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && ( + { + this.dataDoc.simulationPaused = (false); + }} + > + + + )} + {!this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && ( + { + this.dataDoc.simulationPaused = (true); + }} + > + + + )} + {this.dataDoc.simulationPaused && this.dataDoc.mode != "Tutorial" && ( + { + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); + }} + > + + + )} + +
+ +
+
+ {this.dataDoc.mode == "Review" && this.dataDoc.simulationType != "Inclined Plane" && ( +
+

{this.dataDoc.simulationType} review problems in progress!

+
+ )} + {this.dataDoc.mode == "Review" && this.dataDoc.simulationType == "Inclined Plane" && ( +
+ {!this.dataDoc.hintDialogueOpen && ( + { + this.dataDoc.hintDialogueOpen = (true); + }} + sx={{ + position: "fixed", + left: xMax - 50 + "px", + top: yMin + 14 + "px", + }} + > + + + )} + this.dataDoc.hintDialogueOpen = (false)} + > + Hints + + {this.dataDoc.selectedQuestion.hints.map((hint, index) => { + return ( +
+ +
+ + + Hint {index + 1}: {hint.description} + + + {hint.content} +
+
+
+ ); + })} +
+ + + +
+
+
+

{this.dataDoc.questionPartOne}

+

{this.dataDoc.questionPartTwo}

+
+
{this.dataDoc.answerInputFields}
+
+
+ )} + {this.dataDoc.mode == "Tutorial" && ( +
+
+

Problem

+

{this.dataDoc.selectedTutorial.question}

+
+
+ { + let step = this.dataDoc.stepNumber - 1; + step = Math.max(step, 0); + step = Math.min(step, this.dataDoc.selectedTutorial.steps.length - 1); + this.dataDoc.stepNumber = (step); + this.dataDoc.startForces = ( + this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces) + ); + this.dataDoc.updatedForces = ( + this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces) + ); + this.dataDoc.showForceMagnitudes = ( + this.dataDoc.selectedTutorial.steps[step].showMagnitude + ); + }} + disabled={stepNumber == 0} + > + + +
+

+ Step {this.dataDoc.stepNumber + 1}:{" "} + {this.dataDoc.selectedTutorial.steps[stepNumber].description} +

+

{this.dataDoc.selectedTutorial.steps[stepNumber].content}

+
+ { + let step = this.dataDoc.stepNumber + 1; + step = Math.max(step, 0); + step = Math.min(step, this.dataDoc.selectedTutorial.steps.length - 1); + this.dataDoc.stepNumber = (step); + this.dataDoc.startForces = ( + this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces) + ); + this.dataDoc.updatedForces = ( + this.getForceFromJSON(this.dataDoc.selectedTutorial.steps[step].forces) + ); + this.dataDoc.showForceMagnitudes = ( + this.dataDoc.selectedTutorial.steps[step].showMagnitude + ); + }} + disabled={this.dataDoc.stepNumber == this.dataDoc.selectedTutorial.steps.length - 1} + > + + +
+
+ {(this.dataDoc.simulationType == "One Weight" || + this.dataDoc.simulationType == "Inclined Plane" || + this.dataDoc.simulationType == "Pendulum") &&

Resources

} + {this.dataDoc.simulationType == "One Weight" && ( + + )} + {this.dataDoc.simulationType == "Inclined Plane" && ( + + )} + {this.dataDoc.simulationType == "Pendulum" && ( + + )} +
+
+ )} + {this.dataDoc.mode == "Review" && this.dataDoc.simulationType == "Inclined Plane" && ( +
+

this.dataDoc.mode = ("Tutorial")} + > + {" "} + Go to walkthrough{" "} +

+
+ + +
+
+ )} + {this.dataDoc.mode == "Freeform" && ( +
+ + + {this.dataDoc.simulationType == "One Weight" && ( + + this.dataDoc.elasticCollisions= (!this.dataDoc.elasticCollisions) + } + /> + } + label="Make collisions elastic" + labelPlacement="start" + /> + )} + this.dataDoc.showForces = (!this.dataDoc.showForces)} + /> + } + label="Show force vectors" + labelPlacement="start" + /> + {(this.dataDoc.simulationType == "Inclined Plane" || + this.dataDoc.simulationType == "Pendulum") && ( + + this.dataDoc.showComponentForces = (!this.dataDoc.showComponentForces) + } + /> + } + label="Show component force vectors" + labelPlacement="start" + /> + )} + this.dataDoc.showAcceleration = (!this.dataDoc.showAcceleration)} + /> + } + label="Show acceleration vector" + labelPlacement="start" + /> + this.dataDoc.showVelocity = (!this.dataDoc.showVelocity)} + /> + } + label="Show velocity vector" + labelPlacement="start" + /> + + Speed} + lowerBound={1} + changeValue={setSimulationSpeed} + step={1} + unit={"x"} + upperBound={10} + value={simulationSpeed} + labelWidth={"5em"} + /> + {simulationPaused && simulationType != "Circular Motion" && ( + Gravity} + lowerBound={-30} + changeValue={setGravity} + step={0.01} + unit={"m/s2"} + upperBound={0} + value={gravity} + effect={(val: number) => { + setResetAll(!resetAll); + }} + labelWidth={"5em"} + /> + )} + {simulationPaused && simulationType != "Pulley" && ( + Mass} + lowerBound={1} + changeValue={setMass} + step={0.1} + unit={"kg"} + upperBound={5} + value={mass} + effect={(val: number) => { + setResetAll(!resetAll); + }} + labelWidth={"5em"} + /> + )} + {simulationPaused && simulationType == "Pulley" && ( + Red mass} + lowerBound={1} + changeValue={setMass} + step={0.1} + unit={"kg"} + upperBound={5} + value={mass} + effect={(val: number) => { + setResetAll(!resetAll); + }} + labelWidth={"5em"} + /> + )} + {simulationPaused && simulationType == "Pulley" && ( + Blue mass} + lowerBound={1} + changeValue={setMass2} + step={0.1} + unit={"kg"} + upperBound={5} + value={mass2} + effect={(val: number) => { + setResetAll(!resetAll); + }} + labelWidth={"5em"} + /> + )} + {simulationPaused && simulationType == "Circular Motion" && ( + Rod length} + lowerBound={100} + changeValue={setCircularMotionRadius} + step={5} + unit={"kg"} + upperBound={250} + value={circularMotionRadius} + effect={(val: number) => { + setResetAll(!resetAll); + }} + labelWidth={"5em"} + /> + )} + + + {simulationType == "Spring" && simulationPaused && ( +
+ Spring stiffness + } + lowerBound={0.1} + changeValue={setSpringConstant} + step={1} + unit={"N/m"} + upperBound={500} + value={springConstant} + effect={(val: number) => { + setSimulationReset(!simulationReset); + }} + radianEquivalent={false} + mode={"Freeform"} + labelWidth={"7em"} + /> + Rest length} + lowerBound={10} + changeValue={setSpringRestLength} + step={100} + unit={""} + upperBound={500} + value={springRestLength} + effect={(val: number) => { + setSimulationReset(!simulationReset); + }} + radianEquivalent={false} + mode={"Freeform"} + labelWidth={"7em"} + /> + + Starting displacement + + } + lowerBound={-(springRestLength - 10)} + changeValue={(val: number) => {}} + step={10} + unit={""} + upperBound={springRestLength} + value={springStartLength - springRestLength} + effect={(val: number) => { + setStartPosY(springRestLength + val); + setSpringStartLength(springRestLength + val); + setSimulationReset(!simulationReset); + }} + radianEquivalent={false} + mode={"Freeform"} + labelWidth={"7em"} + /> +
+ )} + {simulationType == "Inclined Plane" && simulationPaused && ( +
+ θ} + lowerBound={0} + changeValue={setWedgeAngle} + step={1} + unit={"°"} + upperBound={49} + value={wedgeAngle} + effect={(val: number) => { + changeWedgeBasedOnNewAngle(val); + setSimulationReset(!simulationReset); + }} + radianEquivalent={true} + mode={"Freeform"} + labelWidth={"2em"} + /> + + μs + + } + lowerBound={0} + changeValue={setCoefficientOfStaticFriction} + step={0.1} + unit={""} + upperBound={1} + value={coefficientOfStaticFriction} + effect={(val: number) => { + updateForcesWithFriction(val); + if (val < Number(coefficientOfKineticFriction)) { + setCoefficientOfKineticFriction(val); + } + setSimulationReset(!simulationReset); + }} + mode={"Freeform"} + labelWidth={"2em"} + /> + + μk + + } + lowerBound={0} + changeValue={setCoefficientOfKineticFriction} + step={0.1} + unit={""} + upperBound={Number(coefficientOfStaticFriction)} + value={coefficientOfKineticFriction} + effect={(val: number) => { + setSimulationReset(!simulationReset); + }} + mode={"Freeform"} + labelWidth={"2em"} + /> +
+ )} + {simulationType == "Inclined Plane" && !simulationPaused && ( + + θ: {Math.round(Number(wedgeAngle) * 100) / 100}° ≈{" "} + {Math.round(((Number(wedgeAngle) * Math.PI) / 180) * 100) / + 100}{" "} + rad +
+ μ s: {coefficientOfStaticFriction} +
+ μ k: {coefficientOfKineticFriction} +
+ )} + {simulationType == "Pendulum" && !simulationPaused && ( + + θ: {Math.round(pendulumAngle * 100) / 100}° ≈{" "} + {Math.round(((pendulumAngle * Math.PI) / 180) * 100) / 100}{" "} + rad + + )} + {simulationType == "Pendulum" && simulationPaused && ( +
+ Angle} + lowerBound={0} + changeValue={setPendulumAngle} + step={1} + unit={"°"} + upperBound={59} + value={pendulumAngle} + effect={(value) => { + setStartPendulumAngle(value); + if (simulationType == "Pendulum") { + const mag = + mass * + Math.abs(gravity) * + Math.cos((value * Math.PI) / 180); + + const forceOfTension: IForce = { + description: "Tension", + magnitude: mag, + directionInDegrees: 90 - value, + component: false, + }; + + const tensionComponent: IForce = { + description: "Tension", + magnitude: mag, + directionInDegrees: 90 - value, + component: true, + }; + const gravityParallel: IForce = { + description: "Gravity Parallel Component", + magnitude: + Math.abs(gravity) * + Math.cos((value * Math.PI) / 180), + directionInDegrees: 270 - value, + component: true, + }; + const gravityPerpendicular: IForce = { + description: "Gravity Perpendicular Component", + magnitude: + Math.abs(gravity) * + Math.sin((value * Math.PI) / 180), + directionInDegrees: -value, + component: true, + }; + + const length = pendulumLength; + const x = + length * Math.cos(((90 - value) * Math.PI) / 180); + const y = + length * Math.sin(((90 - value) * Math.PI) / 180); + const xPos = xMax / 2 - x - radius; + const yPos = y - radius - 5; + setStartPosX(xPos); + setStartPosY(yPos); + + setStartForces([ + { + description: "Gravity", + magnitude: Math.abs(gravity) * mass, + directionInDegrees: 270, + component: false, + }, + forceOfTension, + ]); + setUpdatedForces([ + { + description: "Gravity", + magnitude: Math.abs(gravity) * mass, + directionInDegrees: 270, + component: false, + }, + forceOfTension, + ]); + setComponentForces([ + tensionComponent, + gravityParallel, + gravityPerpendicular, + ]); + setAdjustPendulumAngle({ + angle: value, + length: pendulumLength, + }); + setSimulationReset(!simulationReset); + } + }} + radianEquivalent={true} + mode={"Freeform"} + labelWidth={"5em"} + /> + Rod length} + lowerBound={0} + changeValue={setPendulumLength} + step={1} + unit={"m"} + upperBound={400} + value={Math.round(pendulumLength)} + effect={(value) => { + if (simulationType == "Pendulum") { + setAdjustPendulumAngle({ + angle: pendulumAngle, + length: value, + }); + setSimulationReset(!simulationReset); + } + }} + radianEquivalent={false} + mode={"Freeform"} + labelWidth={"5em"} + /> +
+ )} +
+ )} +
+ {mode == "Freeform" && ( + + + + + + + + + + {(!simulationPaused || + simulationType == "Inclined Plane" || + simulationType == "Suspension" || + simulationType == "Circular Motion" || + simulationType == "Pulley") && ( + + )}{" "} + {simulationPaused && + simulationType != "Inclined Plane" && + simulationType != "Suspension" && + simulationType != "Circular Motion" && + simulationType != "Pulley" && ( + + )}{" "} + {(!simulationPaused || + simulationType == "Inclined Plane" || + simulationType == "Suspension" || + simulationType == "Circular Motion" || + simulationType == "Pulley") && ( + + )}{" "} + {simulationPaused && + simulationType != "Inclined Plane" && + simulationType != "Suspension" && + simulationType != "Circular Motion" && + simulationType != "Pulley" && ( + + )}{" "} + + + + {(!simulationPaused || + (simulationType != "One Weight" && + simulationType != "Circular Motion")) && ( + + )}{" "} + {simulationPaused && + (simulationType == "One Weight" || + simulationType == "Circular Motion") && ( + + )}{" "} + {(!simulationPaused || simulationType != "One Weight") && ( + + )}{" "} + {simulationPaused && simulationType == "One Weight" && ( + + )}{" "} + + + + + + + + + + + + +
{simulationType == "Pulley" ? "Red Weight" : ""}XY
{ + window.open( + "https://www.khanacademy.org/science/physics/two-dimensional-motion" + ); + }} + > + Position + + {positionXDisplay} m + + { + setDisplayChange({ + xDisplay: value, + yDisplay: positionYDisplay, + }); + }} + small={true} + mode={"Freeform"} + /> + + {positionYDisplay} m + + { + setDisplayChange({ + xDisplay: positionXDisplay, + yDisplay: value, + }); + }} + small={true} + mode={"Freeform"} + /> +
{ + window.open( + "https://www.khanacademy.org/science/physics/two-dimensional-motion" + ); + }} + > + Velocity + + {velocityXDisplay} m/s + + { + setStartVelX(value); + setSimulationReset(!simulationReset); + }} + small={true} + mode={"Freeform"} + /> + + {velocityYDisplay} m/s + + { + setStartVelY(-value); + setDisplayChange({ + xDisplay: positionXDisplay, + yDisplay: positionYDisplay, + }); + }} + small={true} + mode={"Freeform"} + /> +
{ + window.open( + "https://www.khanacademy.org/science/physics/two-dimensional-motion" + ); + }} + > + Acceleration + + {accelerationXDisplay} m/s2 + + {accelerationYDisplay} m/s2 +
+ Momentum + + {Math.round(velocityXDisplay * mass * 10) / 10} kg*m/s + + {Math.round(velocityYDisplay * mass * 10) / 10} kg*m/s +
+ )} + {mode == "Freeform" && simulationType == "Pulley" && ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Blue WeightXY
+ Position + {positionXDisplay2} m{positionYDisplay2} m
+ Velocity + + {velocityXDisplay2} m/s + + {velocityYDisplay2} m/s +
+ Acceleration + + {accelerationXDisplay2} m/s2 + + {accelerationYDisplay2} m/s2 +
+ Momentum + + {Math.round(velocityXDisplay2 * mass * 10) / 10} kg*m/s + + {Math.round(velocityYDisplay2 * mass * 10) / 10} kg*m/s +
+ )} +
+ {simulationType != "Pendulum" && simulationType != "Spring" && ( +
+

Kinematic Equations

+
    +
  • + Position: x1=x0+v0t+ + 1⁄ + 2at + 2 +
  • +
  • + Velocity: v1=v0+at +
  • +
  • Acceleration: a = F/m
  • +
+
+ )} + {simulationType == "Spring" && ( +
+

Harmonic Motion Equations: Spring

+
    +
  • + Spring force: Fs=kd +
  • +
  • + Spring period: Ts=2π√m⁄ + k +
  • +
  • Equilibrium displacement for vertical spring: d = mg/k
  • +
  • + Elastic potential energy: Us=1⁄ + 2kd2 +
  • +
      +
    • + Maximum when system is at maximum displacement, 0 when + system is at 0 displacement +
    • +
    +
  • + Translational kinetic energy: K=1⁄ + 2mv2 +
  • +
      +
    • + Maximum when system is at maximum/minimum velocity (at 0 + displacement), 0 when velocity is 0 (at maximum + displacement) +
    • +
    +
+
+ )} + {simulationType == "Pendulum" && ( +
+

Harmonic Motion Equations: Pendulum

+
    +
  • + Pendulum period: Tp=2π√l⁄ + g +
  • +
+
+ )} +
+
+
+ + + + + + + + + +

+ {simulationType == "Circular Motion" ? "Z" : "Y"} +

+

+ X +

+
+
} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From f6ad7cf21b8763a0dd54275a8e433e473e382afe Mon Sep 17 00:00:00 2001 From: brynnchernosky <56202540+brynnchernosky@users.noreply.github.com> Date: Mon, 1 May 2023 14:45:01 -0400 Subject: add box --- .../nodes/PhysicsBox/PhysicsSimulationBox.tsx | 355 ++++++++++----------- 1 file changed, 177 insertions(+), 178 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx index 101cf1d4a..446c4933b 100644 --- a/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx +++ b/src/client/views/nodes/PhysicsBox/PhysicsSimulationBox.tsx @@ -89,8 +89,8 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent - Speed} lowerBound={1} - changeValue={setSimulationSpeed} + changeValue={this.dataDoc.simulationSpeed} //TODO - deal with input field change value now that datadoc is being used! step={1} unit={"x"} upperBound={10} - value={simulationSpeed} + value={this.dataDoc.simulationSpeed} labelWidth={"5em"} /> - {simulationPaused && simulationType != "Circular Motion" && ( + {this.dataDoc.simulationPaused && this.dataDoc.simulationType != "Circular Motion" && ( Gravity} lowerBound={-30} - changeValue={setGravity} + changeValue={this.dataDoc.gravity} step={0.01} unit={"m/s2"} upperBound={0} - value={gravity} + value={this.dataDoc.gravity} effect={(val: number) => { - setResetAll(!resetAll); + this.dataDoc.resetAll = (!this.dataDoc.resetAll); }} labelWidth={"5em"} /> )} - {simulationPaused && simulationType != "Pulley" && ( + {this.dataDoc.simulationPaused && this.dataDoc.simulationType != "Pulley" && ( Mass} lowerBound={1} - changeValue={setMass} + changeValue={this.dataDoc.mass} step={0.1} unit={"kg"} upperBound={5} - value={mass} + value={this.dataDoc.mass} effect={(val: number) => { - setResetAll(!resetAll); + this.dataDoc.resetAll = (!this.dataDoc.resetAll); }} labelWidth={"5em"} /> )} - {simulationPaused && simulationType == "Pulley" && ( + {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "Pulley" && ( Red mass} lowerBound={1} - changeValue={setMass} + changeValue={this.dataDoc.mass} step={0.1} unit={"kg"} upperBound={5} - value={mass} + value={this.dataDoc.mass} effect={(val: number) => { - setResetAll(!resetAll); + this.dataDoc.resetAll = (!this.dataDoc.resetAll); }} labelWidth={"5em"} /> )} - {simulationPaused && simulationType == "Pulley" && ( + {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "Pulley" && ( Blue mass} lowerBound={1} - changeValue={setMass2} + changeValue={this.dataDoc.mass2} step={0.1} unit={"kg"} upperBound={5} - value={mass2} + value={this.dataDoc.mass2} effect={(val: number) => { - setResetAll(!resetAll); + this.dataDoc.resetAll = (!this.dataDoc.resetAll); }} labelWidth={"5em"} /> )} - {simulationPaused && simulationType == "Circular Motion" && ( + {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "Circular Motion" && ( Rod length} lowerBound={100} - changeValue={setCircularMotionRadius} + changeValue={this.dataDoc.circularMotionRadius} step={5} unit={"kg"} upperBound={250} - value={circularMotionRadius} + value={this.dataDoc.circularMotionRadius} effect={(val: number) => { - setResetAll(!resetAll); + this.dataDoc.resetAll = (!this.dataDoc.resetAll); }} labelWidth={"5em"} /> )} - {simulationType == "Spring" && simulationPaused && ( + {this.dataDoc.simulationType == "Spring" && this.dataDoc.simulationPaused && (
Spring stiffness } lowerBound={0.1} - changeValue={setSpringConstant} + changeValue={this.dataDoc.springConstant} step={1} unit={"N/m"} upperBound={500} value={springConstant} effect={(val: number) => { - setSimulationReset(!simulationReset); + this.dataDoc.simulationReset(!this.dataDoc.simulationReset); }} radianEquivalent={false} mode={"Freeform"} @@ -1872,13 +1871,13 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentRest length} lowerBound={10} - changeValue={setSpringRestLength} + changeValue={this.dataDoc.springRestLength} step={100} unit={""} upperBound={500} - value={springRestLength} + value={this.dataDoc.springRestLength} effect={(val: number) => { - setSimulationReset(!simulationReset); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); }} radianEquivalent={false} mode={"Freeform"} @@ -1890,16 +1889,16 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent } - lowerBound={-(springRestLength - 10)} + lowerBound={-(this.dataDoc.springRestLength - 10)} changeValue={(val: number) => {}} step={10} unit={""} - upperBound={springRestLength} - value={springStartLength - springRestLength} + upperBound={this.dataDoc.springRestLength} + value={this.dataDoc.springStartLength - this.dataDoc.springRestLength} effect={(val: number) => { - setStartPosY(springRestLength + val); - setSpringStartLength(springRestLength + val); - setSimulationReset(!simulationReset); + this.dataDoc.startPosY = (this.dataDoc.springRestLength + val); + this.dataDoc.springStartLength = (this.dataDoc.springRestLength + val); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); }} radianEquivalent={false} mode={"Freeform"} @@ -1907,19 +1906,19 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
)} - {simulationType == "Inclined Plane" && simulationPaused && ( + {this.dataDoc.simulationType == "Inclined Plane" && this.dataDoc.simulationPaused && (
θ} lowerBound={0} - changeValue={setWedgeAngle} + changeValue={this.dataDoc.wedgeAngle} step={1} unit={"°"} upperBound={49} - value={wedgeAngle} + value={this.dataDoc.wedgeAngle} effect={(val: number) => { - changeWedgeBasedOnNewAngle(val); - setSimulationReset(!simulationReset); + this.changeWedgeBasedOnNewAngle(val); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); }} radianEquivalent={true} mode={"Freeform"} @@ -1932,17 +1931,17 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent } lowerBound={0} - changeValue={setCoefficientOfStaticFriction} + changeValue={this.dataDoc.coefficientOfStaticFriction} step={0.1} unit={""} upperBound={1} - value={coefficientOfStaticFriction} + value={this.dataDoc.coefficientOfStaticFriction} effect={(val: number) => { - updateForcesWithFriction(val); - if (val < Number(coefficientOfKineticFriction)) { - setCoefficientOfKineticFriction(val); + this.updateForcesWithFriction(val); + if (val < Number(this.dataDoc.coefficientOfKineticFriction)) { + this.dataDoc.soefficientOfKineticFriction = (val); } - setSimulationReset(!simulationReset); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); }} mode={"Freeform"} labelWidth={"2em"} @@ -1954,54 +1953,54 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent } lowerBound={0} - changeValue={setCoefficientOfKineticFriction} + changeValue={this.dataDoc.coefficientOfKineticFriction} step={0.1} unit={""} - upperBound={Number(coefficientOfStaticFriction)} - value={coefficientOfKineticFriction} + upperBound={Number(this.dataDoc.coefficientOfStaticFriction)} + value={this.dataDoc.coefficientOfKineticFriction} effect={(val: number) => { - setSimulationReset(!simulationReset); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); }} mode={"Freeform"} labelWidth={"2em"} />
)} - {simulationType == "Inclined Plane" && !simulationPaused && ( + {this.dataDoc.simulationType == "Inclined Plane" && !this.dataDoc.simulationPaused && ( - θ: {Math.round(Number(wedgeAngle) * 100) / 100}° ≈{" "} - {Math.round(((Number(wedgeAngle) * Math.PI) / 180) * 100) / + θ: {Math.round(Number(this.dataDoc.wedgeAngle) * 100) / 100}° ≈{" "} + {Math.round(((Number(this.dataDoc.wedgeAngle) * Math.PI) / 180) * 100) / 100}{" "} rad
- μ s: {coefficientOfStaticFriction} + μ s: {this.dataDoc.coefficientOfStaticFriction}
- μ k: {coefficientOfKineticFriction} + μ k: {this.dataDoc.coefficientOfKineticFriction}
)} - {simulationType == "Pendulum" && !simulationPaused && ( + {this.dataDoc.simulationType == "Pendulum" && !this.dataDoc.simulationPaused && ( - θ: {Math.round(pendulumAngle * 100) / 100}° ≈{" "} - {Math.round(((pendulumAngle * Math.PI) / 180) * 100) / 100}{" "} + θ: {Math.round(this.dataDoc.pendulumAngle * 100) / 100}° ≈{" "} + {Math.round(((this.dataDoc.pendulumAngle * Math.PI) / 180) * 100) / 100}{" "} rad )} - {simulationType == "Pendulum" && simulationPaused && ( + {this.dataDoc.simulationType == "Pendulum" && this.dataDoc.simulationPaused && (
Angle} lowerBound={0} - changeValue={setPendulumAngle} + changeValue={this.dataDoc.pendulumAngle} step={1} unit={"°"} upperBound={59} - value={pendulumAngle} + value={this.dataDoc.pendulumAngle} effect={(value) => { - setStartPendulumAngle(value); + this.dataDoc.startPendulumAngle = (value); if (simulationType == "Pendulum") { const mag = mass * - Math.abs(gravity) * + Math.abs(this.dataDoc.gravity) * Math.cos((value * Math.PI) / 180); const forceOfTension: IForce = { @@ -2020,7 +2019,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentRod length} lowerBound={0} - changeValue={setPendulumLength} + changeValue={this.dataDoc.pendulumLength} step={1} unit={"m"} upperBound={400} - value={Math.round(pendulumLength)} + value={Math.round(this.dataDoc.pendulumLength)} effect={(value) => { if (simulationType == "Pendulum") { - setAdjustPendulumAngle({ - angle: pendulumAngle, + this.dataDoc.adjustPendulumAngle = ({ + angle: this.dataDoc.pendulumAngle, length: value, }); - setSimulationReset(!simulationReset); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); } }} radianEquivalent={false} @@ -2104,39 +2103,39 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent )}
- {mode == "Freeform" && ( + {this.dataDoc.mode == "Freeform" && ( - + - {(!simulationPaused || - simulationType == "Inclined Plane" || - simulationType == "Suspension" || - simulationType == "Circular Motion" || - simulationType == "Pulley") && ( + {(!this.dataDoc.simulationPaused || + this.dataDoc.simulationType == "Inclined Plane" || + this.dataDoc.simulationType == "Suspension" || + this.dataDoc.simulationType == "Circular Motion" || + this.dataDoc.simulationType == "Pulley") && ( )}{" "} - {simulationPaused && - simulationType != "Inclined Plane" && - simulationType != "Suspension" && - simulationType != "Circular Motion" && - simulationType != "Pulley" && ( + {this.dataDoc.simulationPaused && + this.dataDoc.simulationType != "Inclined Plane" && + this.dataDoc.simulationType != "Suspension" && + this.dataDoc.simulationType != "Circular Motion" && + this.dataDoc.simulationType != "Pulley" && ( )}{" "} - {(!simulationPaused || - simulationType == "Inclined Plane" || - simulationType == "Suspension" || - simulationType == "Circular Motion" || - simulationType == "Pulley") && ( + {(!this.dataDoc.simulationPaused || + this.dataDoc.simulationType == "Inclined Plane" || + this.dataDoc.simulationType == "Suspension" || + this.dataDoc.simulationType == "Circular Motion" || + this.dataDoc.simulationType == "Pulley") && ( )}{" "} - {simulationPaused && - simulationType != "Inclined Plane" && - simulationType != "Suspension" && - simulationType != "Circular Motion" && - simulationType != "Pulley" && ( + {this.dataDoc.simulationPaused && + this.dataDoc.simulationType != "Inclined Plane" && + this.dataDoc.simulationType != "Suspension" && + this.dataDoc.simulationType != "Circular Motion" && + this.dataDoc.simulationType != "Pulley" && ( - {(!simulationPaused || - (simulationType != "One Weight" && - simulationType != "Circular Motion")) && ( + {(!this.dataDoc.simulationPaused || + (this.dataDoc.simulationType != "One Weight" && + this.dataDoc.simulationType != "Circular Motion")) && ( )}{" "} - {simulationPaused && - (simulationType == "One Weight" || - simulationType == "Circular Motion") && ( + {this.dataDoc.simulationPaused && + (this.dataDoc.simulationType == "One Weight" || + this.dataDoc.simulationType == "Circular Motion") && ( )}{" "} - {(!simulationPaused || simulationType != "One Weight") && ( + {(!this.dataDoc.simulationPaused || this.dataDoc.simulationType != "One Weight") && ( )}{" "} - {simulationPaused && simulationType == "One Weight" && ( + {this.dataDoc.simulationPaused && this.dataDoc.simulationType == "One Weight" && ( @@ -2294,16 +2293,16 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentMomentum
{simulationType == "Pulley" ? "Red Weight" : ""}{this.dataDoc.simulationType == "Pulley" ? "Red Weight" : ""} X Y
{ - window.open( - "https://www.khanacademy.org/science/physics/two-dimensional-motion" - ); - }} + // onClick={() => { + // window.open( + // "https://www.khanacademy.org/science/physics/two-dimensional-motion" + // ); + // }} > Position - {positionXDisplay} m + {this.dataDoc.positionXDisplay} m { - setDisplayChange({ + this.dataDoc.displayChange = ({ xDisplay: value, - yDisplay: positionYDisplay, + yDisplay: this.dataDoc.positionYDisplay, }); }} small={true} @@ -2160,20 +2159,20 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent - {positionYDisplay} m + {this.dataDoc.positionYDisplay} m { - setDisplayChange({ - xDisplay: positionXDisplay, + this.dataDoc.displayChange = ({ + xDisplay: this.dataDoc.positionXDisplay, yDisplay: value, }); }} @@ -2201,24 +2200,24 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { - window.open( - "https://www.khanacademy.org/science/physics/two-dimensional-motion" - ); - }} + // onClick={() => { + // window.open( + // "https://www.khanacademy.org/science/physics/two-dimensional-motion" + // ); + // }} > Velocity - {velocityXDisplay} m/s + {this.dataDoc.velocityXDisplay} m/s { - setStartVelX(value); - setSimulationReset(!simulationReset); + this.dataDoc.startVelX = (value); + this.dataDoc.simulationReset = (!this.dataDoc.simulationReset); }} small={true} mode={"Freeform"} /> - {velocityYDisplay} m/s + {this.dataDoc.velocityYDisplay} m/s { - setStartVelY(-value); - setDisplayChange({ - xDisplay: positionXDisplay, - yDisplay: positionYDisplay, + this.dataDoc.startVelY = (-value); + this.dataDoc.displayChange = ({ + xDisplay: this.dataDoc.positionXDisplay, + yDisplay: this.dataDoc.positionYDisplay, }); }} small={true} @@ -2274,19 +2273,19 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent { - window.open( - "https://www.khanacademy.org/science/physics/two-dimensional-motion" - ); - }} + // onClick={() => { + // window.open( + // "https://www.khanacademy.org/science/physics/two-dimensional-motion" + // ); + // }} > Acceleration - {accelerationXDisplay} m/s2 + {this.dataDoc.accelerationXDisplay} m/s2 - {accelerationYDisplay} m/s2 + {this.dataDoc.accelerationYDisplay} m/s2
- {Math.round(velocityXDisplay * mass * 10) / 10} kg*m/s + {Math.round(this.dataDoc.velocityXDisplay * this.dataDoc.mass * 10) / 10} kg*m/s - {Math.round(velocityYDisplay * mass * 10) / 10} kg*m/s + {Math.round(this.dataDoc.velocityYDisplay * this.dataDoc.mass * 10) / 10} kg*m/s
)} - {mode == "Freeform" && simulationType == "Pulley" && ( + {this.dataDoc.mode == "Freeform" && this.dataDoc.simulationType == "Pulley" && ( @@ -2315,19 +2314,19 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent Position - - + + @@ -2335,10 +2334,10 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentAcceleration @@ -2346,17 +2345,17 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponentMomentum
{positionXDisplay2} m{positionYDisplay2} m{this.dataDoc.positionXDisplay2} m{this.dataDoc.positionYDisplay2} m
Velocity - {velocityXDisplay2} m/s + {this.dataDoc.velocityXDisplay2} m/s - {velocityYDisplay2} m/s + {this.dataDoc.velocityYDisplay2} m/s
- {accelerationXDisplay2} m/s2 + {this.dataDoc.accelerationXDisplay2} m/s2 - {accelerationYDisplay2} m/s2 + {this.dataDoc.accelerationYDisplay2} m/s2
- {Math.round(velocityXDisplay2 * mass * 10) / 10} kg*m/s + {Math.round(this.dataDoc.velocityXDisplay2 * this.dataDoc.mass * 10) / 10} kg*m/s - {Math.round(velocityYDisplay2 * mass * 10) / 10} kg*m/s + {Math.round(this.dataDoc.velocityYDisplay2 * this.dataDoc.mass * 10) / 10} kg*m/s
)}
- {simulationType != "Pendulum" && simulationType != "Spring" && ( + {this.dataDoc.simulationType != "Pendulum" && this.dataDoc.simulationType != "Spring" && (

Kinematic Equations

    @@ -2373,7 +2372,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
)} - {simulationType == "Spring" && ( + {this.dataDoc.simulationType == "Spring" && (

Harmonic Motion Equations: Spring

    @@ -2409,7 +2408,7 @@ export default class PhysicsSimulationBox extends ViewBoxAnnotatableComponent
)} - {simulationType == "Pendulum" && ( + {this.dataDoc.simulationType == "Pendulum" && (

Harmonic Motion Equations: Pendulum