diff --git a/public/css/style.css b/public/css/style.css index 3946499..558620a 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -2802,4 +2802,4 @@ body { overflow: hidden; } .CtxtMenu_InfoContent { - max-width: 50vw; } + max-width: 90vw !important; } diff --git a/public/css/style.sass b/public/css/style.sass index 4cba55c..6c092d5 100644 --- a/public/css/style.sass +++ b/public/css/style.sass @@ -14,4 +14,4 @@ body overflow: hidden .CtxtMenu_InfoContent - max-width: 50vw + max-width: 50vw !important diff --git a/src/frontend/simulations/mouseconstraint.nim b/src/frontend/simulations/mouseconstraint.nim new file mode 100644 index 0000000..d1b3a35 --- /dev/null +++ b/src/frontend/simulations/mouseconstraint.nim @@ -0,0 +1,53 @@ +import std/[jsffi] + +import matter + +Matter.MouseConstraint.onmousedown = proc(mouseCons, bodies: JsObject) = + let + mouse = mouseCons.mouse + cons = mouseCons.constraint + body = mouseCons.body + + if to(not cons.bodyB, bool): + for body in bodies.to(seq[JsObject]): + if Matter.Bounds.contains(body.bounds, mouse.position).to(bool) and + Matter.Detector.canCollide(body.collisionFilter, mouseCons.collisionFilter).to(bool): + var i = if body.parts.length.to(int) > 1: 1 else: 0 + while i < body.parts.length.to(int): + let part = body.parts[i] + if Matter.Vertices.contains(part.vertices, mouse.position).to(bool): + cons.pointA = mouse.position + mouseCons.body = body + cons.bodyB = mouseCons.body + cons.pointB = jsVec(mouse.position.x - body.position.x, + mouse.position.y - body.position.y) + cons.angleB = body.angle + + Matter.Sleeping.set(body, false) + Matter.Events.trigger(mouseCons, "startdrag", JsObject{mouse: mouse, body: body}) + + break + inc i + +Matter.MouseConstraint.onmouseup = proc(mouseCons, bodies: JsObject) = + let + mouse = mouseCons.mouse + cons = mouseCons.constraint + body = mouseCons.body + + mouseCons.body = jsNull + cons.bodyB = mouseCons.body + cons.pointB = jsNull + + if to(body, bool): + Matter.Events.trigger(mouseCons, "enddrag", JsObject{mouse: mouse, body: body}) + +Matter.MouseConstraint.update = proc(mouseCons, bodies: JsObject) = + let + mouse = mouseCons.mouse + cons = mouseCons.constraint + body = mouseCons.body + + if to(cons.bodyB, bool): + Matter.Sleeping.set(cons.bodyB, false) + cons.pointA = mouse.position diff --git a/src/frontend/simulations/parabola.nim b/src/frontend/simulations/parabola.nim index fdbaeb9..3d76fdf 100644 --- a/src/frontend/simulations/parabola.nim +++ b/src/frontend/simulations/parabola.nim @@ -300,27 +300,36 @@ proc findBy[T](points: openArray[TrajectoryPoint], v: T, by: proc(p: TrajectoryP result.index = e proc updateFormulaAccordion(state: ParabolaState) = - echo "update formulas" - let m1 = getElementById("m1") - let m2 = getElementById("m2") - MathJax.typesetClear([m1, m2]) var siInitialState = state.canon.state.toMu() siInitialState.gravity = siInitialState.gravity * gravityFactor - let h = state.strfloat(siInitialState.height) - let voy = state.strfloat(siInitialState.vel.y) - let g = state.strfloat(siInitialState.gravity.y) - let voySquared = state.strfloat(siInitialState.vel.y ^ 2) let gTwice = state.strfloat(2 * siInitialState.gravity.y) - let m1t = r"\(h_{max} = m + \dfrac{2\:\cdot\:(m/s)^{2}}{2\:\cdot\:m/s^2}\)".fmt('<', '>') - let m2t = r"\(h_{max} = m + \dfrac{2\:\cdot\:m/s^2}{m/s^2}\)".fmt('<', '>') + let m1 = getElementById("m1") + let m2 = getElementById("m2") + + m1.firstChild.firstChild.children[2].firstChild.innerText = + cstring &"{state.strfloat(siInitialState.height)}m" + + m1.firstChild.firstChild.children[2].children[2].firstChild.firstChild. + firstChild.children[1].children[4].firstChild.innerText = + cstring &"({state.strfloat(siInitialState.vel.y)}m/s)" + + m1.firstChild.firstChild.children[2].children[2].firstChild.firstChild. + children[1].firstChild.children[1].firstChild.children[1].children[4]. + innerText = cstring &"{state.strfloat(siInitialState.gravity.y)}m/s²" + + m2.firstChild.firstChild.children[2].firstChild.innerText = + cstring &"{state.strfloat(siInitialState.height)}m" - m1.textContent = cstring m1t - m2.textContent = cstring m2t - # Render all MathJax expressions asynchronously - MathJax.typesetPromise([m1, m2]) + m2.firstChild.firstChild.children[2].children[2].firstChild.firstChild. + firstChild.children[1].children[4].innerText = + cstring &"({state.strfloat(siInitialState.vel.y ^ 2)}m²/s²)" + + m2.firstChild.firstChild.children[2].children[2].firstChild.firstChild. + children[1].firstChild.children[1].firstChild.children[1]. + innerText = cstring &"{state.strfloat(siInitialState.gravity.y * 2)}m/s²" proc updateStateAccordion(state: ParabolaState) = let siInitialState = state.canon.state.toMu() @@ -1147,11 +1156,13 @@ proc onImagesLoaded*(state: var ParabolaState) = state.rendering = true +#proc typesetMathjax(): Future[void] = +# var promise = newPromise() do (resolve: proc()): +# # Render all MathJax expressions synchronously +# (resolve) + ## Loads the simulation proc load*(state: var ParabolaState) = - # Render all MathJax expressions asynchronously - #MathJax.typesetPromise() - # Load wrap's plugin and load matter aliases to point to the correct values Matter.use("matter-wrap") loadMatterAliases() @@ -1250,22 +1261,26 @@ proc load*(state: var ParabolaState) = # Bodies.rectangle(10, 250, 20, 500, JsObject{isStatic: true}), # left ]) - # Wait until all textures are loaded - var loadedImgCount = 0 - var images = newSeq[cstring]() - for b in Composite.allBodies(state.engine.world).to(seq[JsObject]): - if not b.render.sprite.texture.isUndefined and not to(b.render.sprite.texture in state.render.textures, bool): - images.add b.render.sprite.texture.to(cstring) - - for src in images: - let img = newImage() - img.onload = proc() = - inc loadedImgCount - if loadedImgCount == images.len: - state.onImagesLoaded() - - img.src = src - state.render.textures[src] = img + # Typeset before loading textures because when the textures are loaded calcTrajectory is called + # which updates the formulaAccordion which needs mathjax expressions to be rendered + MathJax.typesetPromise().then(proc() = + # Wait until all textures are loaded + var loadedImgCount = 0 + var images = newSeq[cstring]() + for b in Composite.allBodies(state.engine.world).to(seq[JsObject]): + if not b.render.sprite.texture.isUndefined and not to(b.render.sprite.texture in state.render.textures, bool): + images.add b.render.sprite.texture.to(cstring) + + for src in images: + let img = newImage() + img.onload = proc() = + inc loadedImgCount + if loadedImgCount == images.len: + state.onImagesLoaded() + + img.src = src + state.render.textures[src] = img + ) ## Reloads the simulation proc reload*(state: var ParabolaState) = @@ -1336,7 +1351,7 @@ proc renderFormulasAccordion*(state: var ParabolaState): VNode = buildHtml tdiv(class = "container"): tdiv(class = "accordion"): input(`type` = "checkbox", name = "accordion-checkbox", - id = "accordion-f-1", hidden = true, checked = true) + id = "accordion-f-1", hidden = true, checked = false) label(class = "accordion-header", `for` = "accordion-f-1"): #text "Initial State" @@ -1350,8 +1365,10 @@ proc renderFormulasAccordion*(state: var ParabolaState): VNode = tdiv(class = "accordion-body", style = "".toCss): ul: - li(id = "m1", style = "".toCss) # font-size: 1.2em; - li(id = "m2") + li(id = "m1", style = "".toCss): # font-size: 1.2em; + text r"\(h_{max} = h + \dfrac{2\:\cdot\:(v)^{2}}{2\:\cdot\:g}\)" + li(id = "m2"): + text r"\(h_{max} = h + \dfrac{2\:\cdot\:v}{g}\)" proc renderStateAccordion*(state: var ParabolaState): VNode = let siInitialState = state.canon.state.toMu()