diff --git a/lang-trials/rust-benchmark/.gitignore b/lang-trials/rust-benchmark/.gitignore deleted file mode 100644 index 5b910ca..0000000 --- a/lang-trials/rust-benchmark/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -target/* -dist/* -Cargo.lock \ No newline at end of file diff --git a/lang-trials/rust-benchmark/Cargo.toml b/lang-trials/rust-benchmark/Cargo.toml deleted file mode 100644 index 8dde7b0..0000000 --- a/lang-trials/rust-benchmark/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "sycamore-trial" -version = "0.1.0" -authors = ["Aaron"] -edition = "2021" - -[features] -default = ["console_error_panic_hook"] - -[dependencies] -nalgebra = "0.33.0" -sycamore = "0.9.0-beta.2" -typenum = "1.17.0" - -# The `console_error_panic_hook` crate provides better debugging of panics by -# logging them with `console.error`. This is great for development, but requires -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for -# code size when deploying. -console_error_panic_hook = { version = "0.1.7", optional = true } - -[dependencies.web-sys] -version = "0.3.69" -features = [ - 'CanvasRenderingContext2d', - 'HtmlCanvasElement', - 'Window', - 'Performance' -] - -[dev-dependencies] -wasm-bindgen-test = "0.3.34" - -[profile.release] -opt-level = "s" # optimize for small code size -debug = true # include debug symbols diff --git a/lang-trials/rust-benchmark/index.html b/lang-trials/rust-benchmark/index.html deleted file mode 100644 index 82823fc..0000000 --- a/lang-trials/rust-benchmark/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - The circular law - - - - diff --git a/lang-trials/rust-benchmark/main.css b/lang-trials/rust-benchmark/main.css deleted file mode 100644 index f79e62c..0000000 --- a/lang-trials/rust-benchmark/main.css +++ /dev/null @@ -1,23 +0,0 @@ -body { - margin-left: 20px; - margin-top: 20px; - color: #fcfcfc; - background-color: #202020; -} - -#app { - display: flex; - flex-direction: column; - width: 600px; -} - -canvas { - float: left; - background-color: #020202; - border-radius: 10px; - margin-top: 5px; -} - -input { - margin-top: 5px; -} \ No newline at end of file diff --git a/lang-trials/rust-benchmark/notes b/lang-trials/rust-benchmark/notes deleted file mode 100644 index 79a4030..0000000 --- a/lang-trials/rust-benchmark/notes +++ /dev/null @@ -1,13 +0,0 @@ -in profiling, most time is being spent in the `reflect` method: - -f64: - sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::reflect::h7899977a4ba0b1d3 - sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::reflect::hc337c3cb6e3b4061 - sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::reflect_rows::h43d0f6838d0c2833 - -f32: - sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::reflect::h0e8ec322f198f847 - sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::reflect::h9928bdd5e72743ea - sycamore_trial-3d0aca3efee8b5fd.wasm.nalgebra::geometry::reflection::Reflection::reflect_rows::h49f571fd8fc9b0f2 - -in one test, we spent 4000 ms in "WASM closure", but the enveloping "VoidFunction" takes 1300 ms longer. in another test, though, there's no overhang; the 7000 ms we spent in `rand_eigval_series` accounts for basically the entire load time, and matches the clock timing diff --git a/lang-trials/rust-benchmark/src/engine.rs b/lang-trials/rust-benchmark/src/engine.rs deleted file mode 100644 index a2661aa..0000000 --- a/lang-trials/rust-benchmark/src/engine.rs +++ /dev/null @@ -1,164 +0,0 @@ -use nalgebra::{*, allocator::Allocator}; -use std::f64::consts::{PI, E}; -/*use std::ops::Sub;*/ -/*use typenum::{B1, UInt, UTerm};*/ - -/* dynamic matrices */ -pub fn rand_eigval_series(time_res: usize) -> Vec, Dyn>> - where - N: ToTypenum + DimName + DimSub, - DefaultAllocator: - Allocator + - Allocator + - Allocator<>::Output> + - Allocator>::Output> -{ - // initialize the random matrix - let dim = N::try_to_usize().unwrap(); - let mut rand_mat = DMatrix::::from_fn(dim, dim, |j, k| { - let n = j*dim + k; - E*((n*n) as f64) % 2.0 - 1.0 - }) * (3.0 / (dim as f64)).sqrt(); - - // initialize the rotation step - let mut rot_step = DMatrix::::identity(dim, dim); - let max_freq = 4; - for n in (0..dim).step_by(2) { - let ang = PI * ((n % max_freq) as f64) / (time_res as f64); - let ang_cos = ang.cos(); - let ang_sin = ang.sin(); - rot_step[(n, n)] = ang_cos; - rot_step[(n+1, n)] = ang_sin; - rot_step[(n, n+1)] = -ang_sin; - rot_step[(n+1, n+1)] = ang_cos; - } - - // find the eigenvalues - let mut eigval_series = Vec::, Dyn>>::with_capacity(time_res); - eigval_series.push(rand_mat.complex_eigenvalues()); - for _ in 1..time_res { - rand_mat = &rot_step * rand_mat; - eigval_series.push(rand_mat.complex_eigenvalues()); - } - eigval_series -} - -/* dynamic single float matrices */ -/*pub fn rand_eigval_series(time_res: usize) -> Vec, Dyn>> - where - N: ToTypenum + DimName + DimSub, - DefaultAllocator: - Allocator + - Allocator + - Allocator<>::Output> + - Allocator>::Output> -{ - // initialize the random matrix - let dim = N::try_to_usize().unwrap(); - let mut rand_mat = DMatrix::::from_fn(dim, dim, |j, k| { - let n = j*dim + k; - (E as f32)*((n*n) as f32) % 2.0_f32 - 1.0_f32 - }) * (3.0_f32 / (dim as f32)).sqrt(); - - // initialize the rotation step - let mut rot_step = DMatrix::::identity(dim, dim); - let max_freq = 4; - for n in (0..dim).step_by(2) { - let ang = (PI as f32) * ((n % max_freq) as f32) / (time_res as f32); - let ang_cos = ang.cos(); - let ang_sin = ang.sin(); - rot_step[(n, n)] = ang_cos; - rot_step[(n+1, n)] = ang_sin; - rot_step[(n, n+1)] = -ang_sin; - rot_step[(n+1, n+1)] = ang_cos; - } - - // find the eigenvalues - let mut eigval_series = Vec::, Dyn>>::with_capacity(time_res); - eigval_series.push(rand_mat.complex_eigenvalues()); - for _ in 1..time_res { - rand_mat = &rot_step * rand_mat; - eigval_series.push(rand_mat.complex_eigenvalues()); - } - eigval_series -}*/ - -/* static matrices. should only be used when the dimension is really small */ -/*pub fn rand_eigval_series(time_res: usize) -> Vec, N>> - where - N: ToTypenum + DimName + DimSub, - DefaultAllocator: - Allocator + - Allocator + - Allocator<>::Output> + - Allocator>::Output> -{ - // initialize the random matrix - let dim = N::try_to_usize().unwrap(); - let mut rand_mat = OMatrix::::from_fn(|j, k| { - let n = j*dim + k; - E*((n*n) as f64) % 2.0 - 1.0 - }) * (3.0 / (dim as f64)).sqrt(); - /*let mut rand_mat = OMatrix::::identity();*/ - - // initialize the rotation step - let mut rot_step = OMatrix::::identity(); - let max_freq = 4; - for n in (0..dim).step_by(2) { - let ang = PI * ((n % max_freq) as f64) / (time_res as f64); - let ang_cos = ang.cos(); - let ang_sin = ang.sin(); - rot_step[(n, n)] = ang_cos; - rot_step[(n+1, n)] = ang_sin; - rot_step[(n, n+1)] = -ang_sin; - rot_step[(n+1, n+1)] = ang_cos; - } - - // find the eigenvalues - let mut eigval_series = Vec::, N>>::with_capacity(time_res); - eigval_series.push(rand_mat.complex_eigenvalues()); - for _ in 1..time_res { - rand_mat = &rot_step * rand_mat; - eigval_series.push(rand_mat.complex_eigenvalues()); - } - eigval_series -}*/ - -/* another attempt at static matrices. i couldn't get the types to work out */ -/*pub fn random_eigval_series(time_res: usize) -> Vec, Const>> - where - Const: ToTypenum, - as ToTypenum>::Typenum: Sub>, - < as ToTypenum>::Typenum as Sub>>::Output: ToConst -{ - // initialize the random matrix - /*let mut rand_mat = SMatrix::::zeros(); - for n in 0..N*N { - rand_mat[n] = E*((n*n) as f64) % 2.0 - 1.0; - }*/ - let rand_mat = OMatrix::, Const>::from_fn(|j, k| { - let n = j*N + k; - E*((n*n) as f64) % 2.0 - 1.0 - }); - - // initialize the rotation step - let mut rot_step = OMatrix::, Const>::identity(); - let max_freq = 4; - for n in (0..N).step_by(2) { - let ang = PI * ((n % max_freq) as f64) / (time_res as f64); - let ang_cos = ang.cos(); - let ang_sin = ang.sin(); - rot_step[(n, n)] = ang_cos; - rot_step[(n+1, n)] = ang_sin; - rot_step[(n, n+1)] = -ang_sin; - rot_step[(n+1, n+1)] = ang_cos; - } - - // find the eigenvalues - let mut eigvals = Vec::, Const>>::with_capacity(time_res); - unsafe { eigvals.set_len(time_res); } - for t in 0..time_res { - eigvals[t] = rand_mat.complex_eigenvalues(); - } - eigvals -}*/ \ No newline at end of file diff --git a/lang-trials/rust-benchmark/src/main.rs b/lang-trials/rust-benchmark/src/main.rs deleted file mode 100644 index 9662dd7..0000000 --- a/lang-trials/rust-benchmark/src/main.rs +++ /dev/null @@ -1,78 +0,0 @@ -use nalgebra::*; -use std::f64::consts::PI as PI; -use sycamore::{prelude::*, rt::{JsCast, JsValue}}; -use web_sys::window; - -mod engine; - -fn main() { - // set up a config option that forwards panic messages to `console.error` - #[cfg(feature = "console_error_panic_hook")] - console_error_panic_hook::set_once(); - - sycamore::render(|| { - let time_res: usize = 100; - let time_step = create_signal(0.0); - let run_time_report = create_signal(-1.0); - let display = create_node_ref(); - - on_mount(move || { - let performance = window().unwrap().performance().unwrap(); - let start_time = performance.now(); - let eigval_series = engine::rand_eigval_series::(time_res); - let run_time = performance.now() - start_time; - run_time_report.set(run_time); - - let canvas = display - .get::() - .unchecked_into::(); - let ctx = canvas - .get_context("2d") - .unwrap() - .unwrap() - .dyn_into::() - .unwrap(); - ctx.set_fill_style(&JsValue::from("white")); - - create_effect(move || { - // center and normalize the coordinate system - let width = canvas.width() as f64; - let height = canvas.height() as f64; - ctx.set_transform(1.0, 0.0, 0.0, -1.0, 0.5*width, 0.5*height).unwrap(); - - // clear the previous frame - ctx.clear_rect(-0.5*width, -0.5*width, width, height); - - // find the resolution - const R_DISP: f64 = 1.5; - let res = width / (2.0*R_DISP); - - // draw the eigenvalues - let eigvals = &eigval_series[time_step.get() as usize]; - for n in 0..eigvals.len() { - ctx.begin_path(); - ctx.arc( - /* typecast only needed for single float version */ - res * f64::from(eigvals[n].re), - res * f64::from(eigvals[n].im), - 3.0, - 0.0, 2.0*PI - ).unwrap(); - ctx.fill(); - } - }); - }); - - view! { - div(id="app") { - div { (run_time_report.get()) " ms" } - canvas(ref=display, width="600", height="600") - input( - type="range", - max=(time_res - 1).to_string(), - bind:valueAsNumber=time_step - ) - } - } - }); -} \ No newline at end of file diff --git a/lang-trials/rust/.gitignore b/lang-trials/rust/.gitignore index 5b910ca..1d4e644 100644 --- a/lang-trials/rust/.gitignore +++ b/lang-trials/rust/.gitignore @@ -1,3 +1,2 @@ target/* -dist/* -Cargo.lock \ No newline at end of file +dist/* \ No newline at end of file diff --git a/lang-trials/scala-benchmark/.gitignore b/lang-trials/scala-benchmark/.gitignore deleted file mode 100644 index 9f2a453..0000000 --- a/lang-trials/scala-benchmark/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -sbt.json \ No newline at end of file diff --git a/lang-trials/scala-benchmark/build.sbt b/lang-trials/scala-benchmark/build.sbt deleted file mode 100644 index 507885d..0000000 --- a/lang-trials/scala-benchmark/build.sbt +++ /dev/null @@ -1,9 +0,0 @@ -enablePlugins(ScalaJSPlugin) - -name := "Circular Law" -scalaVersion := "3.4.2" -scalaJSUseMainModuleInitializer := true - -libraryDependencies += "com.raquo" %%% "laminar" % "17.0.0" -libraryDependencies += "ai.dragonfly" %%% "slash" % "0.3.1" -libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.8.0" diff --git a/lang-trials/scala-benchmark/index.html b/lang-trials/scala-benchmark/index.html deleted file mode 100644 index f9eb11c..0000000 --- a/lang-trials/scala-benchmark/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - The circular law - - - - - diff --git a/lang-trials/scala-benchmark/main.css b/lang-trials/scala-benchmark/main.css deleted file mode 100644 index f79e62c..0000000 --- a/lang-trials/scala-benchmark/main.css +++ /dev/null @@ -1,23 +0,0 @@ -body { - margin-left: 20px; - margin-top: 20px; - color: #fcfcfc; - background-color: #202020; -} - -#app { - display: flex; - flex-direction: column; - width: 600px; -} - -canvas { - float: left; - background-color: #020202; - border-radius: 10px; - margin-top: 5px; -} - -input { - margin-top: 5px; -} \ No newline at end of file diff --git a/lang-trials/scala-benchmark/project/build.properties b/lang-trials/scala-benchmark/project/build.properties deleted file mode 100644 index ee4c672..0000000 --- a/lang-trials/scala-benchmark/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.10.1 diff --git a/lang-trials/scala-benchmark/project/plugins.sbt b/lang-trials/scala-benchmark/project/plugins.sbt deleted file mode 100644 index e5b2699..0000000 --- a/lang-trials/scala-benchmark/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") diff --git a/lang-trials/scala-benchmark/src/main/scala/CircularLawApp.scala b/lang-trials/scala-benchmark/src/main/scala/CircularLawApp.scala deleted file mode 100644 index 950e661..0000000 --- a/lang-trials/scala-benchmark/src/main/scala/CircularLawApp.scala +++ /dev/null @@ -1,89 +0,0 @@ -import com.raquo.laminar.api.L.{*, given} -import narr.* -import org.scalajs.dom -import org.scalajs.dom.document -import scala.math.{cos, sin} -import slash.matrix.Matrix -import slash.matrix.decomposition.Eigen - -object CircularLawApp: - val canvas = canvasTag(widthAttr := 600, heightAttr := 600) - val ctx = canvas.ref.getContext("2d").asInstanceOf[dom.CanvasRenderingContext2D] - - val (eigvalSeries, runTimeReport) = randEigvalSeries[60]() - val timeStepState = Var("0") - - def draw(timeStep: String): Unit = - // center and normalize the coordinate system - val width = canvas.ref.width - val height = canvas.ref.height - ctx.setTransform(1d, 0d, 0d, -1d, 0.5*width, 0.5*height) - - // clear the previous frame - ctx.clearRect(-0.5*width, -0.5*width, width, height) - - // find the resolution - val rDisp: Double = 1.5 - val res = width / (2*rDisp) - - // draw the eigenvalues - val eigvals = eigvalSeries(timeStep.toInt) - for n <- 0 to eigvals(0).length-1 do - ctx.beginPath() - ctx.arc( - res * eigvals(0)(n), - res * eigvals(1)(n), - 3d, - 0d, 2*math.Pi - ) - ctx.fill() - - def eigvalsRotated[N <: Int](A: Matrix[N, N], time: Double)(using ValueOf[N]): (NArray[Double], NArray[Double]) = - // create transformation - val maxFreq = 4 - val T = Matrix.identity[N, N] - val dim: Int = valueOf[N] - for n <- 0 to dim by 2 do - val a = cos(math.Pi * time * (n % maxFreq)) - val b = sin(math.Pi * time * (n % maxFreq)) - T(n, n) = a - T(n+1, n) = b - T(n, n+1) = -b - T(n+1, n+1) = a - - // find eigenvalues - val eigen = Eigen(T*A) - ( - eigen.realEigenvalues.asInstanceOf[NArray[Double]], - eigen.imaginaryEigenvalues.asInstanceOf[NArray[Double]] - ) - - def randEigvalSeries[N <: Int]()(using ValueOf[N]): (List[(NArray[Double], NArray[Double])], String) = - val timeRes = 100 - val dim: Int = valueOf[N] - val startTime = System.currentTimeMillis() - val A = new Matrix[N, N]( - NArray.tabulate(dim*dim)(k => (math.E*k*k) % 2 - 1) - ).times(math.sqrt(3d / dim)) - val series = List.tabulate(timeRes)(t => eigvalsRotated(A, t.toDouble / timeRes)) - val runTime = System.currentTimeMillis() - startTime - (series, runTime.toString() + " ms") - - def main(args: Array[String]): Unit = - ctx.fillStyle = "white" - - lazy val app = div( - idAttr := "app", - div(runTimeReport), - canvas, - input( - typ := "range", - maxAttr := (eigvalSeries.length-1).toString, - controlled( - value <-- timeStepState.signal, - onInput.mapToValue --> timeStepState.writer - ), - timeStepState.signal --> draw - ) - ) - renderOnDomContentLoaded(document.body, app) diff --git a/lang-trials/scala/.gitignore b/lang-trials/scala/.gitignore deleted file mode 100644 index 9f2a453..0000000 --- a/lang-trials/scala/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target -sbt.json \ No newline at end of file diff --git a/lang-trials/scala/build.sbt b/lang-trials/scala/build.sbt deleted file mode 100644 index 908e7e9..0000000 --- a/lang-trials/scala/build.sbt +++ /dev/null @@ -1,12 +0,0 @@ -enablePlugins(ScalaJSPlugin) - -name := "Lattice Circle" -scalaVersion := "3.4.2" - -// This is an application with a main method -scalaJSUseMainModuleInitializer := true - -libraryDependencies += "com.raquo" %%% "laminar" % "17.0.0" -/*libraryDependencies += "org.scalanlp" %% "breeze" % "2.1.0"*/ -libraryDependencies += "ai.dragonfly" %%% "slash" % "0.3.1" -libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "2.8.0" diff --git a/lang-trials/scala/index.html b/lang-trials/scala/index.html deleted file mode 100644 index ff30e9f..0000000 --- a/lang-trials/scala/index.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - Lattice circle - - - - - diff --git a/lang-trials/scala/main.css b/lang-trials/scala/main.css deleted file mode 100644 index 3aedb99..0000000 --- a/lang-trials/scala/main.css +++ /dev/null @@ -1,45 +0,0 @@ -body { - margin-left: 20px; - margin-top: 20px; - color: #fcfcfc; - background-color: #202020; -} - -input { - color: inherit; - background-color: #020202; - border: 1px solid #606060; - min-width: 40px; - border-radius: 4px; -} - -input.point-1 { - border-color: #ba5d09; -} - -input.point-2 { - border-color: #0e8a06; -} - -input.point-3 { - border-color: #8951fb; -} - -#data-panel { - float: left; - margin-left: 20px; - display: grid; - grid-template-columns: auto auto; - gap: 10px 10px; - width: 120px; -} - -#data-panel > div { - text-align: center; -} - -canvas { - float: left; - background-color: #020202; - border-radius: 10px; -} diff --git a/lang-trials/scala/project/build.properties b/lang-trials/scala/project/build.properties deleted file mode 100644 index ee4c672..0000000 --- a/lang-trials/scala/project/build.properties +++ /dev/null @@ -1 +0,0 @@ -sbt.version=1.10.1 diff --git a/lang-trials/scala/project/plugins.sbt b/lang-trials/scala/project/plugins.sbt deleted file mode 100644 index e5b2699..0000000 --- a/lang-trials/scala/project/plugins.sbt +++ /dev/null @@ -1 +0,0 @@ -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0") diff --git a/lang-trials/scala/src/main/scala/LatticeCircleApp.scala b/lang-trials/scala/src/main/scala/LatticeCircleApp.scala deleted file mode 100644 index 12ee36c..0000000 --- a/lang-trials/scala/src/main/scala/LatticeCircleApp.scala +++ /dev/null @@ -1,160 +0,0 @@ -// based on the Laminar example app -// -// https://github.com/raquo/laminar-examples/blob/master/src/main/scala/App.scala -// -// and Li Haoyi's example canvas app -// -// http://www.lihaoyi.com/hands-on-scala-js/#MakingaCanvasApp -// - -import com.raquo.laminar.api.L.{*, given} -import narr.* -import org.scalajs.dom -import org.scalajs.dom.document -import scala.math -import slash.matrix.* - -class Circle(var centerX: Double, var centerY: Double, var radius: Double) - -object LatticeCircleApp: - val canvas = canvasTag(widthAttr := 600, heightAttr := 600) - val ctx = canvas.ref.getContext("2d").asInstanceOf[dom.CanvasRenderingContext2D] - val data = List("-1", "0", "0", "-1", "1", "0").map(Var(_)) - - def circThru(points: Matrix[3, 2]): Option[Circle] = - // build the matrix that maps the circle's coefficient vector to the - // negative of the linear part of the circle's equation, evaluated at the - // given points - val negLinPart = Matrix.ones[3, 3] - negLinPart.setMatrix(0, 0, points * 2.0) - - // find the quadrdatic part of the circle's equation, evaluated at the given - // points - val quadPart = Matrix[3, 1]( - NArray.tabulate[Double](3)( - k => points(k, 0)*points(k, 0) + points(k, 1)*points(k, 1) - ) - ) - - // find the circle's coefficient vector, and from there its center and - // radius - try - val coeffs = negLinPart.solve(quadPart) - val centerX = coeffs(0, 0) - val centerY = coeffs(1, 0) - Some(Circle( - centerX, - centerY, - math.sqrt(coeffs(2, 0) + centerX*centerX + centerY*centerY) - )) - catch - _ => return None - - def draw(): Unit = - // center and normalize the coordinate system - val width = canvas.ref.width - val height = canvas.ref.height - ctx.setTransform(1.0, 0.0, 0.0, -1.0, 0.5*width, 0.5*height) - - // clear the previous frame - ctx.clearRect(-0.5*width, -0.5*width, width, height) - - // find the resolution - val rDisp = 5.0 - val res = width / (2.0*rDisp) - - // set colors - val highlightStyle = "white" - val gridStyle = "#404040" - val pointFillStyles = List("#ba5d09", "#0e8a06", "#8951fb") - val pointStrokeStyles = List("#f89142", "#58c145", "#c396fc") - - // draw the grid - val rGrid = (rDisp - 0.01).floor.toInt - val edgeScr = res * rDisp - ctx.strokeStyle = gridStyle - for t <- -rGrid to rGrid do - val tScr = res * t - - // draw horizontal grid line - ctx.beginPath(); - ctx.moveTo(-edgeScr, tScr) - ctx.lineTo(edgeScr, tScr) - ctx.stroke() - - // draw vertical grid line - ctx.beginPath(); - ctx.moveTo(tScr, -edgeScr) - ctx.lineTo(tScr, edgeScr) - ctx.stroke() - - // find and draw the circle through the given points - val dataNow = NArray.tabulate(6)(n => - try - data(n).signal.now().toDouble - catch - _ => Double.NaN - ) - if dataNow.forall(t => t == t.floor) then - // all of the coordinates are integer and non-NaN - val points = Matrix[3, 2](dataNow) - circThru(points) match - case Some(circ) => - ctx.beginPath() - ctx.strokeStyle = highlightStyle - ctx.arc( - res * circ.centerX, - res * circ.centerY, - res * circ.radius, - 0.0, 2.0*math.Pi - ) - ctx.stroke() - case None => - - // draw the data points - for n <- 0 to 2 do - val indX = 2*n - val indY = indX + 1 - if - dataNow(indX) == dataNow(indX).floor && - dataNow(indY) == dataNow(indY).floor - then - ctx.beginPath() - ctx.fillStyle = pointFillStyles(n) - ctx.strokeStyle = pointStrokeStyles(n) - ctx.arc( - res * dataNow(indX), - res * dataNow(indY), - 3.0, - 0.0, 2.0*math.Pi - ) - ctx.fill() - ctx.stroke() - - def coordInput(n: Int): Input = - input( - typ := "number", - cls := s"point-${(1.0 + 0.5*n).floor.toInt}", - controlled( - value <-- data(n).signal, - onInput.mapToValue --> data(n).writer - ), - data(n).signal --> { _ => draw() } - ) - - def main(args: Array[String]): Unit = - lazy val app = div( - canvas, - div( - idAttr := "data-panel", - div("x"), - div("y"), - coordInput(0), - coordInput(1), - coordInput(2), - coordInput(3), - coordInput(4), - coordInput(5) - ) - ) - renderOnDomContentLoaded(document.body, app)