From faf47af828149e45ec3f0a06d287b9d54600a559 Mon Sep 17 00:00:00 2001 From: Jakob Odersky Date: Tue, 14 Apr 2015 11:49:44 +0200 Subject: pass rx value of instruments as a parameter --- .../src/main/scala/vfd/dashboard/RxUtil.scala | 31 ++++++++++ .../src/main/scala/vfd/dashboard/ui/Layout.scala | 69 ++++++++++------------ .../vfd/dashboard/ui/instruments/Altimeter.scala | 5 +- .../scala/vfd/dashboard/ui/instruments/Bar.scala | 5 +- .../scala/vfd/dashboard/ui/instruments/Clock.scala | 5 +- .../vfd/dashboard/ui/instruments/Compass.scala | 5 +- .../dashboard/ui/instruments/Distribution.scala | 5 +- .../vfd/dashboard/ui/instruments/Generic.scala | 10 ++-- .../vfd/dashboard/ui/instruments/Horizon.scala | 5 +- .../vfd/dashboard/ui/instruments/Instrument.scala | 5 +- .../scala/vfd/dashboard/ui/instruments/Led.scala | 5 +- 11 files changed, 83 insertions(+), 67 deletions(-) create mode 100644 vfd-dashboard/src/main/scala/vfd/dashboard/RxUtil.scala diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/RxUtil.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/RxUtil.scala new file mode 100644 index 0000000..51e2fcd --- /dev/null +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/RxUtil.scala @@ -0,0 +1,31 @@ +package vfd.dashboard + +import rx._ + +package object rxutil { + + /** Rx, implicitly enhanced with additional methods. */ + implicit class RichRx(val rx: Rx[_]) extends AnyVal { + + /** + * Builds a new Rx by applying a partial function to all values of + * this Rx on which the function is defined. + * @param initial initial value of the returned Rx + * @param pf the partial function which filters and maps this Rx + * @return a new Rx resulting from applying the given partial + * function pf to each value on which it is defined and collecting + * the result + */ + def collect[B](initial: B)(pf: PartialFunction[Any, B]): Rx[B] = { + val result: Var[B] = Var(initial) + Obs(rx, skipInitial = true) { + if (pf.isDefinedAt(rx())) { + result() = pf(rx()) + } + } + result + } + + } + +} \ No newline at end of file diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Layout.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Layout.scala index a2e03ef..1d6090d 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Layout.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Layout.scala @@ -1,11 +1,12 @@ package vfd.dashboard.ui -import rx.Obs +import rx._ import scalatags.JsDom.all._ import vfd.dashboard.Environment import vfd.dashboard.MavlinkSocket import vfd.dashboard.ui.instruments._ import org.mavlink.messages._ +import vfd.dashboard.rxutil._ class Layout(socket: MavlinkSocket)(implicit env: Environment) { @@ -41,15 +42,35 @@ class Layout(socket: MavlinkSocket)(implicit env: Environment) { val feed = div(style := "width: 100%; height: 460px; color: #ffffff; background-color: #c2c2c2; text-align: center;")( p(style := "padding-top: 220px")("video feed")) - val altimeter = new Altimeter - val horizon = new Horizon - val compass = new Compass - val motor0 = new Generic(0, 50, 100, "%") - val motor1 = new Generic(0, 50, 100, "%") - val motor2 = new Generic(0, 50, 100, "%") - val motor3 = new Generic(0, 50, 100, "%") - val powerDistribution = new Distribution - val batteryLevel = new Bar + val altimeter = new Altimeter( + Var(0.0) + ) + val horizon = new Horizon(socket.message.collect((0.0, 0.0)) { + case att: Attitude => (att.pitch, att.roll) + }) + val compass = new Compass(socket.message.collect(0.0) { + case att: Attitude => att.yaw + }) + val motor0 = new Generic(0, 50, 100, "%", socket.message.collect(0.0) { + case s: ServoOutputRaw => 100 * (s.servo1Raw - 1000) / 1000 + }) + val motor1 = new Generic(0, 50, 100, "%", socket.message.collect(0.0) { + case s: ServoOutputRaw => 100 * (s.servo2Raw - 1000) / 1000 + }) + val motor2 = new Generic(0, 50, 100, "%", socket.message.collect(0.0) { + case s: ServoOutputRaw => 100 * (s.servo3Raw - 1000) / 1000 + }) + val motor3 = new Generic(0, 50, 100, "%", socket.message.collect(0.0) { + case s: ServoOutputRaw => 100 * (s.servo4Raw - 1000) / 1000 + }) + val powerDistribution = new Distribution( + socket.message.collect((0.0, 0.0, 0.0, 0.0)) { + case s: ServoOutputRaw => (s.servo1Raw, s.servo2Raw, s.servo3Raw, s.servo4Raw) + } + ) + val batteryLevel = new Bar( + Var(0.0) + ) val top = header( div("Flight Control Panel"), @@ -123,32 +144,4 @@ class Layout(socket: MavlinkSocket)(implicit env: Environment) { ) ).render - //message router - Obs(socket.message, skipInitial = true) { - socket.message() match { - - case att: Attitude => - horizon.value() = (att.pitch, att.roll) - compass.value() = att.yaw - - case s: ServoOutputRaw => - val m0 = 100 * (s.servo1Raw - 1000) / 1000 - val m1 = 100 * (s.servo2Raw - 1000) / 1000 - val m2 = 100 * (s.servo3Raw - 1000) / 1000 - val m3 = 100 * (s.servo4Raw - 1000) / 1000 - - motor0.value() = m0 - motor1.value() = m1 - motor2.value() = m2 - motor3.value() = m3 - powerDistribution.value() = (m0, m1, m2, m3) - - //TODO route other messages - - case _ => () - - } - } - - } \ No newline at end of file diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Altimeter.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Altimeter.scala index 732ab43..b65b374 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Altimeter.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Altimeter.scala @@ -1,13 +1,12 @@ package vfd.dashboard.ui.instruments import org.scalajs.dom.html +import rx._ import vfd.dashboard.Environment -class Altimeter(implicit env: Environment) extends SvgInstrument[Double] { +class Altimeter(val value: Rx[Double])(implicit env: Environment) extends SvgInstrument[Double] { import SvgInstrument._ - val initial = 0.0 - lazy val element = svgObject("altimeter") lazy val hand = part("hand") lazy val moveable = Seq(hand) diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Bar.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Bar.scala index 7cda301..9f9f81c 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Bar.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Bar.scala @@ -1,13 +1,12 @@ package vfd.dashboard.ui.instruments import org.scalajs.dom.html +import rx._ import vfd.dashboard.Environment -class Bar(implicit env: Environment) extends SvgInstrument[Double] { +class Bar(val value: Rx[Double])(implicit env: Environment) extends SvgInstrument[Double] { import SvgInstrument._ - val initial = 0.0 - lazy val element = svgObject("bar") lazy val level = part("level") lazy val moveable = Seq(level) diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Clock.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Clock.scala index b456765..a5bfc03 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Clock.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Clock.scala @@ -1,6 +1,7 @@ package vfd.dashboard.ui.instruments import org.scalajs.dom +import rx._ import scala.scalajs.js.Date import scalatags.JsDom.all._ @@ -8,9 +9,9 @@ class Clock extends Instrument[Date] { def format(date: Date) = date.toLocaleTimeString() - val initial = new Date + val value = Var(new Date) - val element = span(format(initial)).render + val element = span(format(value())).render protected def update(value: Date) = { element.innerHTML = format(value) diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Compass.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Compass.scala index 341c866..9f1ae4a 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Compass.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Compass.scala @@ -1,13 +1,12 @@ package vfd.dashboard.ui.instruments import org.scalajs.dom.html +import rx._ import vfd.dashboard.Environment -class Compass(implicit env: Environment) extends SvgInstrument[Double] { +class Compass(val value: Rx[Double])(implicit env: Environment) extends SvgInstrument[Double] { import SvgInstrument._ - val initial = 0.0 - lazy val element = svgObject("compass") lazy val plate = part("heading") lazy val moveable = Seq(plate) diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Distribution.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Distribution.scala index caeac33..f750bab 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Distribution.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Distribution.scala @@ -1,13 +1,12 @@ package vfd.dashboard.ui.instruments import org.scalajs.dom.html +import rx._ import vfd.dashboard.Environment -class Distribution(implicit env: Environment) extends SvgInstrument[(Double, Double, Double, Double)] { +class Distribution(val value: Rx[(Double, Double, Double, Double)])(implicit env: Environment) extends SvgInstrument[(Double, Double, Double, Double)] { import SvgInstrument._ - val initial = (0.0, 0.0, 0.0, 0.0) - lazy val element = svgObject("distribution") lazy val position = part("position") lazy val moveable = Seq(position) diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Generic.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Generic.scala index af9469a..86c27e1 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Generic.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Generic.scala @@ -2,18 +2,19 @@ package vfd.dashboard.ui.instruments import org.scalajs.dom import org.scalajs.dom.html +import rx._ import vfd.dashboard.Environment class Generic( min: Double, med: Double, max: Double, - unit: String)(implicit env: Environment) + unit: String, + val value: Rx[Double]) + (implicit env: Environment) extends SvgInstrument[Double] { import SvgInstrument._ - - val initial = 0.0 lazy val element = svgObject("generic") lazy val handElement = part("hand") @@ -29,12 +30,11 @@ class Generic( minElement.textContent = min.toString medElement.textContent = med.toString maxElement.textContent = max.toString - update(min) super.load(e) } protected def update(value: Double) = { - rotate(handElement, value / (max - min) * math.Pi * 3 / 2) + rotate(handElement, value / (max - min) * math.Pi * 3 / 2) valueElement.textContent = value.toString } } \ No newline at end of file diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Horizon.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Horizon.scala index 0e95843..bbfe8cf 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Horizon.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Horizon.scala @@ -1,13 +1,12 @@ package vfd.dashboard.ui.instruments import org.scalajs.dom.html +import rx._ import vfd.dashboard.Environment -class Horizon(implicit env: Environment) extends SvgInstrument[(Double, Double)] { +class Horizon(val value: Rx[(Double, Double)])(implicit env: Environment) extends SvgInstrument[(Double, Double)] { import SvgInstrument._ - val initial = (0.0, 0.0) - lazy val element = svgObject("horizon") lazy val pitch = part("pitch") lazy val roll = part("roll") diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Instrument.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Instrument.scala index 5b0a13d..bf5c9ca 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Instrument.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Instrument.scala @@ -6,11 +6,8 @@ import org.scalajs.dom.html /** Common trait to all flight instruments. */ trait Instrument[A] { - /** Initial value. */ - val initial: A - /** Current value that is displayed in the instrument. */ - val value: Var[A] = Var(initial) + val value: Rx[A] /** HTML element that contains the rendered instrument */ val element: html.Element diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Led.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Led.scala index 4173f37..f5259b5 100644 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Led.scala +++ b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Led.scala @@ -1,11 +1,10 @@ package vfd.dashboard.ui.instruments +import rx._ import scalatags.JsDom.all._ import vfd.dashboard.Environment -class Led(implicit env: Environment) extends SvgInstrument[String] { - - val initial = "none" +class Led(val value: Rx[String])(implicit env: Environment) extends SvgInstrument[String] { lazy val element = `object`(`type` := "image/svg+xml", "data".attr := env.asset("images/leds/led.svg"), width := 100.pct)( "Error loading led.").render -- cgit v1.2.3