diff options
Diffstat (limited to 'src/client/views/nodes/PhysicsSimulationWeight.tsx')
-rw-r--r-- | src/client/views/nodes/PhysicsSimulationWeight.tsx | 860 |
1 files changed, 0 insertions, 860 deletions
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<IWeightProps, IState> { - - 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<IWeightProps>, prevState: Readonly<IState>, 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 ( - <div> - <div - className="weightContainer" - // 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]); - // } - // } - // }} - > - <div className="weight" style={this.weightStyle}> - <p className="weightLabel">{this.props.mass} kg</p> - </div> - </div> - {this.props.dataDoc['pendulum'] && ( - <div - className="rod" - style={{ - pointerEvents: "none", - position: "absolute", - left: 0, - top: 0, - }} - > - <svg width={this.props.xMax + "px"} height={300 + "px"}> - <line - x1={this.state.xPosition + this.props.radius} - y1={this.state.yPosition + this.props.radius} - x2={this.props.xMax / 2} - y2={-5} - stroke={"#deb887"} - strokeWidth="10" - /> - </svg> - {!this.state.dragging && ( - <div> - <p - style={{ - position: "absolute", - left: this.props.xMax / 2 + "px", - top: 30 + "px", - backgroundColor: this.labelBackgroundColor, - }} - > - {this.state.angleLabel}° - </p> - </div> - )} - </div> - )} - {!this.state.dragging && this.props.dataDoc['showAcceleration'] && ( - <div> - <div - style={{ - pointerEvents: "none", - position: "absolute", - left: 0, - top: 0, - }} - > - <svg width={this.props.xMax + "px"} height={300 + "px"}> - <defs> - <marker - id="accArrow" - markerWidth="10" - markerHeight="10" - refX="0" - refY="3" - orient="auto" - markerUnits="strokeWidth" - > - <path d="M0,0 L0,6 L9,3 z" fill="green" /> - </marker> - </defs> - <line - x1={this.state.xPosition + this.props.radius} - y1={this.state.yPosition + this.props.radius} - x2={this.state.xPosition + this.props.radius + this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 5} - y2={this.state.yPosition + this.props.radius + this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 5} - stroke={"green"} - strokeWidth="5" - markerEnd="url(#accArrow)" - /> - </svg> - <div - style={{ - pointerEvents: "none", - position: "absolute", - left: - this.state.xPosition + - this.props.radius + - this.getNewAccelerationX(this.props.dataDoc['updatedForces']) * 5 + - 25 + - "px", - top: - this.state.yPosition + - this.props.radius + - this.getNewAccelerationY(this.props.dataDoc['updatedForces']) * 5 + - 25 + - "px", - lineHeight: 0.5, - }} - > - <p> - {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/s<sup>2</sup> - </p> - </div> - </div> - </div> - )} - {!this.state.dragging && this.props.dataDoc['showVelocity'] && ( - <div> - <div - style={{ - pointerEvents: "none", - position: "absolute", - left: 0, - top: 0, - }} - > - <svg width={this.props.xMax + "px"} height={300 + "px"}> - <defs> - <marker - id="velArrow" - markerWidth="10" - markerHeight="10" - refX="0" - refY="3" - orient="auto" - markerUnits="strokeWidth" - > - <path d="M0,0 L0,6 L9,3 z" fill="blue" /> - </marker> - </defs> - <line - x1={this.state.xPosition + this.props.radius} - y1={this.state.yPosition + this.props.radius} - x2={this.state.xPosition + this.props.radius + this.state.xVelocity * 3} - y2={this.state.yPosition + this.props.radius + this.state.yVelocity * 3} - stroke={"blue"} - strokeWidth="5" - markerEnd="url(#velArrow)" - /> - </svg> - <div - style={{ - pointerEvents: "none", - 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", - lineHeight: 0.5, - }} - > - <p> - {Math.round( - 100 * Math.sqrt(this.state.xVelocity**2 + this.state.yVelocity**2) - ) / 100}{" "} - m/s - </p> - </div> - </div> - </div> - )} - {!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 ( - <div key={index}> - <div - style={{ - pointerEvents: "none", - position: "absolute", - left: this.props.xMin, - top: this.props.yMin, - }} - > - <svg - width={this.props.xMax - this.props.xMin + "px"} - height={300 + "px"} - > - <defs> - <marker - id="forceArrow" - markerWidth="10" - markerHeight="10" - refX="0" - refY="3" - orient="auto" - markerUnits="strokeWidth" - > - <path d="M0,0 L0,6 L9,3 z" fill={color} /> - </marker> - </defs> - <line - x1={arrowStartX} - y1={arrowStartY} - x2={arrowEndX} - y2={arrowEndY} - stroke={color} - strokeWidth="5" - markerEnd="url(#forceArrow)" - /> - </svg> - </div> - <div - style={{ - pointerEvents: "none", - position: "absolute", - left: labelLeft + "px", - top: labelTop + "px", - lineHeight: 0.5, - backgroundColor: this.labelBackgroundColor, - }} - > - {force.description && <p>{force.description}</p>} - {!force.description && <p>Force</p>} - {this.props.dataDoc['showForceMagnitudes'] && ( - <p>{Math.round(100 * force.magnitude) / 100} N</p> - )} - </div> - </div> - ); - })} - </div> - ); - } -}; |