Scala trial: clean up Laminar interface

Also, drop unused Breeze code in favor of Slash.
This commit is contained in:
Aaron Fenyes 2024-08-07 13:40:09 -07:00
parent 4f30f31686
commit 0bd025dd14

View File

@ -8,7 +8,6 @@
// //
import com.raquo.laminar.api.L.{*, given} import com.raquo.laminar.api.L.{*, given}
/*import breeze.linalg._*/
import narr.* import narr.*
import org.scalajs.dom import org.scalajs.dom
import org.scalajs.dom.document import org.scalajs.dom.document
@ -20,57 +19,7 @@ class Circle(var centerX: Double, var centerY: Double, var radius: Double)
object LatticeCircleApp: object LatticeCircleApp:
val canvas = canvasTag(widthAttr := 600, heightAttr := 600) val canvas = canvasTag(widthAttr := 600, heightAttr := 600)
val ctx = canvas.ref.getContext("2d").asInstanceOf[dom.CanvasRenderingContext2D] val ctx = canvas.ref.getContext("2d").asInstanceOf[dom.CanvasRenderingContext2D]
val dataBusList = List.tabulate(6)(_ => new EventBus[Double]) val data = List("-1", "0", "0", "-1", "1", "0").map(Var(_))
val dataStream = dataBusList(0).events
.combineWith(dataBusList(1).events)
.combineWith(dataBusList(2).events)
.combineWith(dataBusList(3).events)
.combineWith(dataBusList(4).events)
.combineWith(dataBusList(5).events)
.map(dataTuple => NArray(dataTuple(0), dataTuple(1), dataTuple(2), dataTuple(3), dataTuple(4), dataTuple(5)))
.filter(data => data.forall(!_.isNaN()))
/*
val dataList = List(-1.0, 0.0, 0.0, -1.0, 1.0, 0.0).map(Var(_))
val dataStream = dataList(0).signal
.combineWith(dataList(1).signal)
.combineWith(dataList(2).signal)
.combineWith(dataList(3).signal)
.combineWith(dataList(4).signal)
.combineWith(dataList(5).signal)
.map(dataTuple => NArray(dataTuple(0), dataTuple(1), dataTuple(2), dataTuple(3), dataTuple(4), dataTuple(5)))
*/
val pointStream = dataStream.map(data => Matrix[3, 2](data))
/* Breeze version */
/*
val pointStream = dataStream.map(data => new DenseMatrix(2, 3, Array(data(0), data(1), data(2), data(3), data(4), data(5))))
*/
/* Breeze version */
/*
def circThru(points: DenseMatrix[Double]): 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 = DenseMatrix.horzcat(
2.0*points.t,
DenseMatrix.ones[Double](3, 1)
)
// find the quadrdatic part of the circle's equation, evaluated at the given
// points
val quadPart = points(::, *).map(v => v dot v)
// find the circle's coefficient vector, and from there its center and
// radius
val coeffs = negLinPart \ quadPart
val centerX = coeffs(0, 0)
val centerY = coeffs(1, 0)
Circle(
centerX,
centerY,
math.sqrt(coeffs(2, 0) + centerX*centerX + centerY*centerY)
)
*/
def circThru(points: Matrix[3, 2]): Option[Circle] = def circThru(points: Matrix[3, 2]): Option[Circle] =
// build the matrix that maps the circle's coefficient vector to the // build the matrix that maps the circle's coefficient vector to the
@ -78,8 +27,6 @@ object LatticeCircleApp:
// given points // given points
val negLinPart = Matrix.ones[3, 3] val negLinPart = Matrix.ones[3, 3]
negLinPart.setMatrix(0, 0, points * 2.0) negLinPart.setMatrix(0, 0, points * 2.0)
println("built neg lin part")
println(negLinPart)
// find the quadrdatic part of the circle's equation, evaluated at the given // find the quadrdatic part of the circle's equation, evaluated at the given
// points // points
@ -88,8 +35,6 @@ object LatticeCircleApp:
k => points(k, 0)*points(k, 0) + points(k, 1)*points(k, 1) k => points(k, 0)*points(k, 0) + points(k, 1)*points(k, 1)
) )
) )
println("build quad part")
println(quadPart)
// find the circle's coefficient vector, and from there its center and // find the circle's coefficient vector, and from there its center and
// radius // radius
@ -105,7 +50,7 @@ object LatticeCircleApp:
catch catch
_ => return None _ => return None
def draw(points: Matrix[3, 2]): Unit = def draw(): Unit =
// center and normalize the coordinate system // center and normalize the coordinate system
val width = canvas.ref.width val width = canvas.ref.width
val height = canvas.ref.height val height = canvas.ref.height
@ -144,6 +89,15 @@ object LatticeCircleApp:
ctx.stroke() ctx.stroke()
// find and draw the circle through the given points // 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 circThru(points) match
case Some(circ) => case Some(circ) =>
ctx.beginPath() ctx.beginPath()
@ -159,95 +113,48 @@ object LatticeCircleApp:
// draw the data points // draw the data points
for n <- 0 to 2 do 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.beginPath()
ctx.fillStyle = pointFillStyles(n) ctx.fillStyle = pointFillStyles(n)
ctx.strokeStyle = pointStrokeStyles(n) ctx.strokeStyle = pointStrokeStyles(n)
ctx.arc( ctx.arc(
res * points(n, 0), res * dataNow(indX),
res * points(n, 1), res * dataNow(indY),
3.0, 3.0,
0.0, 2.0*math.Pi 0.0, 2.0*math.Pi
) )
ctx.fill() ctx.fill()
ctx.stroke() 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 = def main(args: Array[String]): Unit =
lazy val app = div( lazy val app = div(
canvas, canvas,
div( div(
pointStream --> draw,
idAttr := "data-panel", idAttr := "data-panel",
div("x"), div("x"),
div("y"), div("y"),
input(typ := "number", cls := "point-1", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(0))), coordInput(0),
input(typ := "number", cls := "point-1", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(1))), coordInput(1),
input(typ := "number", cls := "point-2", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(2))), coordInput(2),
input(typ := "number", cls := "point-2", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(3))), coordInput(3),
input(typ := "number", cls := "point-3", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(4))), coordInput(4),
input(typ := "number", cls := "point-3", inContext(thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataBusList(5))) coordInput(5)
/* attempt to use controlled inputs */
/*
input(
typ := "number",
cls := "point-1",
controlled(
value <-- dataList(0).signal,
inContext(
thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(0).writer
)
)
),
input(
typ := "number",
cls := "point-1",
controlled(
value <-- dataList(1).signal,
inContext(
thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(1).writer
)
)
),
input(
typ := "number",
cls := "point-2",
controlled(
value <-- dataList(2).signal,
inContext(
thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(2).writer
)
)
),
input(
typ := "number",
cls := "point-2",
controlled(
value <-- dataList(3).signal,
inContext(
thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(3).writer
)
)
),
input(
typ := "number",
cls := "point-3",
controlled(
value <-- dataList(4).signal,
inContext(
thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(4).writer
)
)
),
input(
typ := "number",
cls := "point-3",
controlled(
value <-- dataList(5).signal,
inContext(
thisNode => onInput.mapTo(thisNode.ref.valueAsNumber) --> dataList(5).writer
)
)
)
*/
) )
) )
renderOnDomContentLoaded(document.body, app) renderOnDomContentLoaded(document.body, app)