diff options
author | Jakob Odersky <jakob@odersky.com> | 2016-02-24 20:33:51 -0800 |
---|---|---|
committer | Jakob Odersky <jakob@odersky.com> | 2016-02-24 20:33:51 -0800 |
commit | 8186b3622ce1c9d2b50df3d264ab526dc1e61d77 (patch) | |
tree | b4446408291c9f179e1c270a561523023ac6a105 /vfd-dashboard/src/main | |
parent | 6c4e8849d753734b3e50523dcdb372fbdbccc2c1 (diff) | |
parent | a41de68066007852d7d3dbf019d75b4caf7463ad (diff) | |
download | mavigator-8186b3622ce1c9d2b50df3d264ab526dc1e61d77.tar.gz mavigator-8186b3622ce1c9d2b50df3d264ab526dc1e61d77.tar.bz2 mavigator-8186b3622ce1c9d2b50df3d264ab526dc1e61d77.zip |
Merge branch 'akka-streams'
Diffstat (limited to 'vfd-dashboard/src/main')
16 files changed, 0 insertions, 747 deletions
diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/Environment.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/Environment.scala deleted file mode 100644 index 57cd39d..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/Environment.scala +++ /dev/null @@ -1,14 +0,0 @@ -package vfd.dashboard - -import org.scalajs.dom.html - -/** Represents an application's environment */ -trait Environment { - - /** The application's root element. */ - def root: html.Element - - /** Retrieve an asset's URL based on its file location. */ - def asset(file: String): String - -}
\ No newline at end of file diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/Main.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/Main.scala deleted file mode 100644 index 71c5378..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/Main.scala +++ /dev/null @@ -1,25 +0,0 @@ -package vfd.dashboard - -import scala.scalajs.js -import scala.scalajs.js.annotation.JSExport - -import org.scalajs.dom.html - -import vfd.dashboard.ui.Layout - -@JSExport("Main") -object Main { - - @JSExport - def main(rootElement: html.Element, assetsBase: String, args: js.Dictionary[String]) = { - implicit val env = new Environment { - def root = rootElement - def asset(file: String) = assetsBase + "/" + file - } - - val socket = new MavlinkSocket(args("socketUrl"), args("remoteSystemId").toInt) - val layout = new Layout(socket) - - env.root.appendChild(layout.element) - } -}
\ No newline at end of file diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/MavlinkSocket.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/MavlinkSocket.scala deleted file mode 100644 index 2fe8262..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/MavlinkSocket.scala +++ /dev/null @@ -1,69 +0,0 @@ -package vfd.dashboard - -import scala.scalajs.js -import scala.scalajs.js.Any.fromFunction1 -import org.mavlink.Packet -import org.mavlink.Parser -import org.mavlink.Parser.Errors._ -import org.mavlink.messages.Message -import org.scalajs.dom -import scala.concurrent.duration._ -import rx._ -import rx.ops._ -import scala.concurrent.ExecutionContext.Implicits.global - -class MavlinkSocket(url: String, val remoteSystemId: Int) { - implicit val scheduler = new DomScheduler - - lazy val packet: Var[Packet] = Var(Packet.empty) - lazy val message: Rx[Message] = packet.map{p => - Message.unpack(p.messageId, p.payload) - } - - object stats { - private val DebounceTime = 1.seconds - - private[MavlinkSocket] val _crcErrors = Var(0) - private[MavlinkSocket] val _overflows = Var(0) - private[MavlinkSocket] val _wrongIds = Var(0) - private[MavlinkSocket] val _packets = Var(0) - - val crcErrors = _crcErrors.debounce(DebounceTime) - val overflows = _overflows.debounce(DebounceTime) - val wrongIds = _wrongIds.debounce(DebounceTime) - val packets = _packets.debounce(DebounceTime) - val open = Var(false) - } - - private val parser = new Parser( - { - case pckt@Packet(seq, `remoteSystemId`, compId, msgId, payload) => - packet() = pckt - stats._packets() += 1 - case _ => - stats._wrongIds() += 1 - }, - { - case CrcError => stats._crcErrors() += 1 - case OverflowError => stats._overflows() += 1 - }) - - private val connection = new dom.WebSocket(url) - - connection.binaryType = "arraybuffer" - connection.onopen = (e: dom.Event) => { - stats.open() = true - } - connection.onmessage = (e: dom.MessageEvent) => { - val buffer = e.data.asInstanceOf[js.typedarray.ArrayBuffer] - val view = new js.typedarray.DataView(buffer) - - for (i <- 0 until view.byteLength) { - parser.push(view.getInt8(i)) - } - } - connection.onclose = (e: dom.CloseEvent) => { - stats.open() = false - } - -}
\ No newline at end of file diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/RxUtil.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/RxUtil.scala deleted file mode 100644 index a73c3ba..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/RxUtil.scala +++ /dev/null @@ -1,70 +0,0 @@ -package vfd.dashboard - -import scala.language.implicitConversions -import scala.util.Failure -import scala.util.Success - -import org.scalajs.dom.html - -import rx.Obs -import rx.Rx -import rx.Rx -import rx.Var -import rx.Var -import scalatags.JsDom.all.Frag -import scalatags.JsDom.all.HtmlTag -import scalatags.JsDom.all.backgroundColor -import scalatags.JsDom.all.bindNode -import scalatags.JsDom.all.span -import scalatags.JsDom.all.stringFrag -import scalatags.JsDom.all.stringStyle - -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 - } - - } - - /** - * Copied from https://github.com/lihaoyi/workbench-example-app/blob/todomvc/src/main/scala/example/Framework.scala - * - * Sticks some Rx into a Scalatags fragment, which means hooking up an Obs - * to propagate changes into the DOM via the element's ID. Monkey-patches - * the Obs onto the element itself so we have a reference to kill it when - * the element leaves the DOM (e.g. it gets deleted). - */ - implicit def rxMod[T <: html.Element](r: Rx[HtmlTag]): Frag = { - def rSafe = r.toTry match { - case Success(v) => v.render - case Failure(e) => span(e.toString, backgroundColor := "red").render - } - var last = rSafe - Obs(r, skipInitial = true) { - val newLast = rSafe - last.parentElement.replaceChild(newLast, last) - last = newLast - } - bindNode(last) - } - -}
\ No newline at end of file diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Hud.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Hud.scala deleted file mode 100644 index 6abdb36..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Hud.scala +++ /dev/null @@ -1,47 +0,0 @@ -package vfd.dashboard.ui - -import vfd.dashboard.Environment -import vfd.dashboard.ui.instruments._ - -import scalatags.JsDom.all._ -import rx._ - -class Hud(attitude: Rx[(Double, Double)])(implicit env: Environment) { - - private def overlay(name: String, z: Int, thinnerThanWide: Boolean = false) = { - val direction = if (thinnerThanWide) "row" else "column" - div( - style:= - "position: absolute; left: 0; right: 0; top: 0; bottom: 0;" + - s"display: flex; align-content: center; align-items: stretch; flex-direction: $direction;"+ - s"z-index: $z;" - )( - `object`(`type`:="image/svg+xml", "data".attr:=env.asset("images/hud/" + name + ".svg"), style := "flex: 1 1 100%;") - ) - } - - object Horizon extends SvgInstrument[(Double, Double)] { - import SvgInstrument._ - - val value = attitude - - lazy val element = `object`(`type`:="image/svg+xml", "data".attr:=env.asset("images/hud/horizon.svg"), style:="flex: 1 1 100%;").render - lazy val horizon = part("horizon") - lazy val moveable = Seq(horizon) - - protected def update(pitchRoll: (Double, Double)) = { - rotate(horizon, pitchRoll._2) - //translate(horizon, 0, (pitchRoll._1 * 180 / math.Pi).toInt) // 1deg === 1px - } - } - - val element = div( - style:= - "position: absolute; left: 0; right: 0; top: 0; bottom: 0;" + - "display: flex; align-content: stretch; align-items: stretch; flex-direction: row;"+ - "z-index: 0;" - )( - Horizon.element - ) -} - diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Layout.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Layout.scala deleted file mode 100644 index fe1b34f..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/Layout.scala +++ /dev/null @@ -1,266 +0,0 @@ -package vfd.dashboard.ui - -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) { - - private def panel(contents: Frag*) = div(`class` := "d-panel")(contents: _*) - - private def mode(name: String, kind: String, on: Boolean = false) = div(`class` := s"mode $kind ${if (!on) "off"}")(name) - - val modes = div( - mode("MANUAL", "warning", true), - mode("STABILIZED", "info", true), - mode("GUIDED", "success", true), - mode("AUTO", "success", true)) - - val infos = div( - mode("BAY", "info"), - mode("RECOVERY", "danger"), - mode("NOGPS", "warning", true), - mode("OVERLOAD", "danger", true), - mode("BATTERY", "danger", false), - mode("LINK", "danger", true), - mode("SOCKET", "danger", true), - div(style := "float: right")(mode("CRITICAL", "danger", true))) - - val map = iframe( - "frameborder".attr := "0", - "scrolling".attr := "no", - "marginheight".attr := "0", - "marginwidth".attr := "0", - src := "http://www.openstreetmap.org/export/embed.html?bbox=6.5611016750335684%2C46.51718501017836%2C6.570038795471191%2C46.520577350893525&layer=mapnik") - - val feed = div(style := "width: 100%; height: 100%; color: #ffffff; background-color: #c2c2c2; text-align: center;") - - 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 => - ( - 1.0 * (s.servo1Raw - 1000) / 1000, - 1.0 * (s.servo2Raw - 1000) / 1000, - 1.0 * (s.servo3Raw - 1000) / 1000, - 1.0 * (s.servo4Raw - 1000) / 1000 - ) - } - ) - val batteryLevel = new Bar( - Var(0.0) - ) - - val top = header( - div("Flight Control Panel"), - div((new Clock).element), - div("UAV " + socket.remoteSystemId) - ) - - val left = div( - panel( - table(`class` := "table-instrument")( - thead("Communication"), - tbody( - tr( - td("Uplink RSSI"), - td("89"), - td("Socket"), - td("5ms") - ), - tr( - td("Something else"), - td("unknown"), - td("Heartbeat"), - td(i(`class` := "fa fa-heart heartbeat")) - ) - ) - ), - table(`class` := "table-instrument")( - thead("Packets"), - tbody( - tr( - td("OK"), - Rx { td(socket.stats.packets()) }, - td("CRC"), - Rx { td(socket.stats.crcErrors()) }, - td("OFLW"), - Rx { td(socket.stats.overflows()) }, - td("BID"), - Rx { td(socket.stats.wrongIds()) } - ), - tr( - td("Ratio"), - Rx { - import socket.stats._ - val sum = packets() + crcErrors() + overflows() + wrongIds() - td(1.0 * packets() / sum formatted "%.2f") - }, - td(), - td(), - td(), - td(), - td(), - td() - ) - ) - ) - ), - panel( - table(`class` := "table-instrument")( - tbody( - tr( - td(compass.element), - td(horizon.element), - td(altimeter.element), - td(altimeter.element) - ) - ) - ) - ), - panel( - div(style := "width: 50%; display: inline-block;")( - table(`class` := "table-instrument")( - tbody( - tr( - td(motor1.element), - td(), - td(motor0.element) - ), - tr( - td(), - td(powerDistribution.element), - td() - ), - tr( - td(motor2.element), - td(), - td(motor3.element) - ) - ) - ) - ), - div(style := "width: 50%; display: inline-block;")( - table(`class` := "table-instrument")( - thead("Power"), - tbody( - tr( - td("VHIGH"), - td("12.6V"), - td("VLOW"), - td("9V") - ), - tr( - td("Voltage"), - td("11.2V"), - td("Remaining"), - td("80%") - ), - tr( - td("Flight"), - td("05:00"), - td("Endurance"), - td("12:00") - ) - ) - ), - table(`class` := "table-instrument")( - thead("Navigation"), - tbody( - tr( - td("Satellites"), - td("5"), - td("Precision"), - td("10cm") - ), - tr( - td("LON"), - td(""), - td("LAT"), - td("") - ), - tr( - td("GSpeed"), - td("3 m/s"), - td(), - td() - ), - tr( - td("Travelled"), - td("5000m"), - td("Home"), - td("1200m") - ) - ) - ) - ) - ) - ) - - - - val hud = { - def overlay(name: String, z: Int, thinnerThanWide: Boolean = false) = { - val direction = if (thinnerThanWide) "row" else "column" - div( - style:= - "position: absolute; left: 0; right: 0; top: 0; bottom: 0;" + - s"display: flex; align-content: center; align-items: stretch; flex-direction: $direction;"+ - s"z-index: $z;" - )( - `object`(`type`:="image/svg+xml", "data".attr:=env.asset("images/hud/" + name + ".svg"), style := "flex: 1 1 100%;") - ) - - } - - Seq( - overlay("horizon", 0), - overlay("roll", 1) - ) - } - - - - val element = div(`class` := "d-container d-column", style:="width: 100%; height: 100%;")( - div(`class` := "d-above")( - top - ), - div(`class` := "d-above d-container d-row")( - panel(modes), - panel(infos) - ), - div(`class` := "d-container d-row")( - div(`class` := "d-container d-left")( - left - ), - div(`class` := "d-main", style:="position: relative;")( - (new Hud(horizon.value)).element - ) - ) - ).render - -} 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 deleted file mode 100644 index b65b374..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Altimeter.scala +++ /dev/null @@ -1,18 +0,0 @@ -package vfd.dashboard.ui.instruments - -import org.scalajs.dom.html -import rx._ -import vfd.dashboard.Environment - -class Altimeter(val value: Rx[Double])(implicit env: Environment) extends SvgInstrument[Double] { - import SvgInstrument._ - - lazy val element = svgObject("altimeter") - lazy val hand = part("hand") - lazy val moveable = Seq(hand) - - // 1m === 36deg = 2Pi / 10 ~= 0.62832 - protected def update(altitude: Double) = { - rotate(hand, (altitude * 0.62832).toInt) - } -}
\ No newline at end of file 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 deleted file mode 100644 index 9f9f81c..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Bar.scala +++ /dev/null @@ -1,18 +0,0 @@ -package vfd.dashboard.ui.instruments - -import org.scalajs.dom.html -import rx._ -import vfd.dashboard.Environment - -class Bar(val value: Rx[Double])(implicit env: Environment) extends SvgInstrument[Double] { - import SvgInstrument._ - - lazy val element = svgObject("bar") - lazy val level = part("level") - lazy val moveable = Seq(level) - - protected def update(value: Double) = { - translate(level, 0, (97 * (1 - value / 100)).toInt) - } - -}
\ No newline at end of file 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 deleted file mode 100644 index a5bfc03..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Clock.scala +++ /dev/null @@ -1,23 +0,0 @@ -package vfd.dashboard.ui.instruments - -import org.scalajs.dom -import rx._ -import scala.scalajs.js.Date -import scalatags.JsDom.all._ - -class Clock extends Instrument[Date] { - - def format(date: Date) = date.toLocaleTimeString() - - val value = Var(new Date) - - val element = span(format(value())).render - - protected def update(value: Date) = { - element.innerHTML = format(value) - } - - dom.setInterval(() => {value() = new Date}, 1000) - ready() - -}
\ No newline at end of file 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 deleted file mode 100644 index 9f1ae4a..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Compass.scala +++ /dev/null @@ -1,17 +0,0 @@ -package vfd.dashboard.ui.instruments - -import org.scalajs.dom.html -import rx._ -import vfd.dashboard.Environment - -class Compass(val value: Rx[Double])(implicit env: Environment) extends SvgInstrument[Double] { - import SvgInstrument._ - - lazy val element = svgObject("compass") - lazy val plate = part("heading") - lazy val moveable = Seq(plate) - - protected def update(heading: Double) = { - rotate(plate, heading) - } -}
\ No newline at end of file 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 deleted file mode 100644 index f750bab..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Distribution.scala +++ /dev/null @@ -1,25 +0,0 @@ -package vfd.dashboard.ui.instruments - -import org.scalajs.dom.html -import rx._ -import vfd.dashboard.Environment - -class Distribution(val value: Rx[(Double, Double, Double, Double)])(implicit env: Environment) extends SvgInstrument[(Double, Double, Double, Double)] { - import SvgInstrument._ - - lazy val element = svgObject("distribution") - lazy val position = part("position") - lazy val moveable = Seq(position) - - private final val Radius = 50 //px - - protected def update(value: (Double, Double, Double, Double)) = { - val sum = value._1 + value._2 + value._3 + value._4 - val i = (value._1 - value._3) / sum - val j = (value._2 - value._4) / sum - val x = math.sqrt(2) / 2 * (i - j) - val y = math.sqrt(2) / 2 * (-i - j) - translate(position, (x * Radius).toInt, (y * Radius).toInt) - } - -}
\ No newline at end of file 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 deleted file mode 100644 index 86c27e1..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Generic.scala +++ /dev/null @@ -1,40 +0,0 @@ -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, - val value: Rx[Double]) - (implicit env: Environment) - extends SvgInstrument[Double] { - - import SvgInstrument._ - - lazy val element = svgObject("generic") - lazy val handElement = part("hand") - lazy val unitElement = element.contentDocument.getElementById("unit") - lazy val valueElement = element.contentDocument.getElementById("value") - lazy val minElement = element.contentDocument.getElementById("min") - lazy val medElement = element.contentDocument.getElementById("med") - lazy val maxElement = element.contentDocument.getElementById("max") - lazy val moveable = Seq(handElement) - - override protected def load(e: dom.Event) = { - unitElement.textContent = unit - minElement.textContent = min.toString - medElement.textContent = med.toString - maxElement.textContent = max.toString - super.load(e) - } - - protected def update(value: Double) = { - 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 deleted file mode 100644 index bbfe8cf..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Horizon.scala +++ /dev/null @@ -1,19 +0,0 @@ -package vfd.dashboard.ui.instruments - -import org.scalajs.dom.html -import rx._ -import vfd.dashboard.Environment - -class Horizon(val value: Rx[(Double, Double)])(implicit env: Environment) extends SvgInstrument[(Double, Double)] { - import SvgInstrument._ - - lazy val element = svgObject("horizon") - lazy val pitch = part("pitch") - lazy val roll = part("roll") - lazy val moveable = Seq(pitch, roll) - - protected def update(pitchRoll: (Double, Double)) = { - translate(pitch, 0, (pitchRoll._1 * 180 / math.Pi).toInt) // 1deg === 1px - rotate(roll, pitchRoll._2) - } -} 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 deleted file mode 100644 index bf5c9ca..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Instrument.scala +++ /dev/null @@ -1,25 +0,0 @@ -package vfd.dashboard.ui.instruments - -import rx._ -import org.scalajs.dom.html - -/** Common trait to all flight instruments. */ -trait Instrument[A] { - - /** Current value that is displayed in the instrument. */ - val value: Rx[A] - - /** HTML element that contains the rendered instrument */ - val element: html.Element - - /** Performs the actual UI update of this instrument. */ - protected def update(newValue: A): Unit - - /** Call when instrument has finished setting up its UI. */ - protected def ready() = { - Obs(value, skipInitial = true) { - update(value()) - } - } - -}
\ No newline at end of file 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 deleted file mode 100644 index f5259b5..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/Led.scala +++ /dev/null @@ -1,17 +0,0 @@ -package vfd.dashboard.ui.instruments - -import rx._ -import scalatags.JsDom.all._ -import vfd.dashboard.Environment - -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 - protected def moveable = Seq() - - protected def update(color: String) = { - part("light").setAttribute("fill", color) - } - -}
\ No newline at end of file diff --git a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/SvgInstrument.scala b/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/SvgInstrument.scala deleted file mode 100644 index fe6c58a..0000000 --- a/vfd-dashboard/src/main/scala/vfd/dashboard/ui/instruments/SvgInstrument.scala +++ /dev/null @@ -1,54 +0,0 @@ -package vfd.dashboard.ui.instruments - - -import org.scalajs.dom -import org.scalajs.dom.html - -import scalatags.JsDom.all._ - -import vfd.dashboard.Environment - -/** An instrument backed by an SVG image. */ -trait SvgInstrument[A] extends Instrument[A] { - - /** SVG object element that contains the rendered instrument */ - val element: html.Object - - /** Retrieves an element of the underlying SVG document by ID. */ - protected def part(id: String) = element.contentDocument.getElementById(id).asInstanceOf[html.Element] - - /** Movable parts of the instrument */ - protected def moveable: Seq[html.Element] - - /** Called when element has been loaded. */ - protected def load(event: dom.Event): Unit = { - for (part <- moveable) { - part.style.transition = "transform 50ms ease-out" - } - ready() - } - - element.addEventListener("load", (e: dom.Event) => load(e)) -} - -/** Contains helpers for SVG instruments. */ -object SvgInstrument { - - /** Retrieves an SVG object element by its instrument's name. */ - def svgObject(name: String)(implicit app: Environment): html.Object = { - val path = app.asset("images/instruments/" + name + ".svg") - `object`(`type` := "image/svg+xml", "data".attr := path, width := 100.pct)( - "Error loading instrument " + name).render - } - - /** Applies translation styling to an element. */ - def translate(elem: html.Element, x: Int, y: Int): Unit = { - elem.style.transform = "translate(" + x + "px, " + y + "px)"; - } - - /** Applies rotation styling to an element. */ - def rotate(elem: html.Element, rad: Double): Unit = { - elem.style.transform = "rotateZ(" + rad + "rad)"; - } - -}
\ No newline at end of file |