Commit 42bdff67 authored by Mathieu leclaire's avatar Mathieu leclaire

Rely on Scaladget JsRxTags

parent 96ce80cc
......@@ -26,7 +26,7 @@ import scalatags.JsDom.svgAttrs
import scalatags.JsDom.svgTags
import scaladget.stylesheet.all._
import scaladget.api.svg._
import client.JsRxTags._
import scaladget.tools.JsRxTags._
import org.scalajs.dom.raw._
trait Selectable {
......@@ -42,10 +42,12 @@ object Graph {
val target: Var[Task]) extends Selectable
def task(title: String, x: Double, y: Double) = Task(Var(title), Var((x, y)))
def edge(source: Task, target: Task) = new Edge(Var(source), Var(target))
}
import Graph._
class Window(nodes: Seq[Task] = Seq(), edges: Seq[Edge] = Seq()) {
val svgNode = {
......@@ -75,10 +77,9 @@ class GraphCreator(svg: SVGElement, _tasks: Seq[Task], _edges: Seq[Edge]) {
val DELETE_KEY = 46
val NODE_RADIUS = 50
val END_ARROW: String = "end-arrow"
val URL_END_ARROW: String = "url(#end-arrow)"
val URL_END_ARROW: String = s"url(#${END_ARROW})"
val MARK_END_ARROW: String = "mark-end-arrow"
val URL_MARK_END_ARROW: String = "url(#mark-end-arrow)"
val URL_MARK_END_ARROW: String = s"url(#${MARK_END_ARROW})"
class DragLine {
private val m: Var[(Int, Int)] = Var((0, 0))
......@@ -97,10 +98,10 @@ class GraphCreator(svg: SVGElement, _tasks: Seq[Task], _edges: Seq[Edge]) {
this
}
val render = Rx {
val render: SVGElement = Rx {
path(ms = ms(s"$LINK_DRAGLINE ${
if (dragging()) "" else HIDDEN
}")).m(m()._1, m()._2).l(l()._1, l()._2)(svgAttrs.markerEnd := URL_MARK_END_ARROW).render.render
}")).m(m()._1, m()._2).l(l()._1, l()._2)(svgAttrs.markerEnd := URL_MARK_END_ARROW).render
}
}
......@@ -141,7 +142,7 @@ class GraphCreator(svg: SVGElement, _tasks: Seq[Task], _edges: Seq[Edge]) {
// Hide the drag line
if (me.shiftKey && !dragLine.dragging.now) {
val (x, y) = (me.clientX, me.clientY)
addTask(task(UUID.randomUUID().toString, x, y))
addTask(task(UUID.randomUUID().toString, x, y))
}
mouseDownTask() = None
dragLine.dragging() = false
......@@ -177,22 +178,18 @@ class GraphCreator(svg: SVGElement, _tasks: Seq[Task], _edges: Seq[Edge]) {
}
def circle(task: Task) = {
val gCircle: SVGElement = {
val element: SVGElement = Rx {
svgTags.g(
rxSVGMod(
Rx {
svgTags.g(
ms(CIRCLE + {
if (task.selected()) s" $SELECTED" else ""
})
)(
svgAttrs.transform := s"translate(${
val location = task.location()
s"${location._1}, ${location._2}"
})")(svgTags.circle(svgAttrs.r := NODE_RADIUS).render)
}
))
}.render
ms(CIRCLE + {
if (task.selected()) s" $SELECTED" else ""
})
)(
svgAttrs.transform := s"translate(${
val location = task.location()
s"${location._1}, ${location._2}"
})")(svgTags.circle(svgAttrs.r := NODE_RADIUS).render)
}
val gCircle = svgTags.g(element).render
gCircle.onmousedown = (me: MouseEvent) => {
mouseDownTask() = Some(task)
......@@ -217,30 +214,30 @@ class GraphCreator(svg: SVGElement, _tasks: Seq[Task], _edges: Seq[Edge]) {
addEdge(edge(e.source.now, e.target.now))
}
def link(edge: Edge) =
svgTags.g(
rxSVGMod(Rx {
val p = path(ms = (if (edge.selected()) ms("selected") else emptyMod) +++
ms(LINK)).m(
edge.source().location()._1.toInt,
edge.source().location()._2.toInt
).l(
edge.target().location()._1.toInt,
edge.target().location()._2.toInt
).render(svgAttrs.markerEnd := URL_END_ARROW).render
p.onmousedown = (me: MouseEvent) => {
unselectTasks
unselectEdges
edge.selected() = !edge.selected.now
}
svgTags.g(p)
def link(edge: Edge) = {
val sVGElement: SVGElement = Rx {
val p = path(ms = (if (edge.selected()) ms(SELECTED) else emptyMod) +++
ms(LINK)).m(
edge.source().location()._1.toInt,
edge.source().location()._2.toInt
).l(
edge.target().location()._1.toInt,
edge.target().location()._2.toInt
).render(svgAttrs.markerEnd := URL_END_ARROW).render
p.onmousedown = (me: MouseEvent) => {
unselectTasks
unselectEdges
edge.selected() = !edge.selected.now
}
)
).render
p
}
svgTags.g(sVGElement).render
}
def addToScene[T](s: Var[Seq[Var[T]]], draw: T=> SVGElement) = svgG.appendChild(svgTags.g(
rxSVGMod(Rx {
def addToScene[T](s: Var[Seq[Var[T]]], draw: T => SVGElement) = {
val element: SVGElement = Rx {
svgTags.g(
for {
t <- s()
......@@ -248,8 +245,9 @@ class GraphCreator(svg: SVGElement, _tasks: Seq[Task], _edges: Seq[Edge]) {
draw(t.now)
}
)
}).render
).render)
}
svgG.appendChild(svgTags.g(element).render).render
}
addToScene(edges, link)
addToScene(tasks, circle)
......
/*
* Copyright (C) 21/07/14 mathieu
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package client
import org.scalajs.dom.raw.{HTMLDivElement, HTMLElement, Node, SVGElement}
import scalatags.JsDom._
import scala.util.{Failure, Success}
import all._
import rx._
import org.scalajs.dom.Element
import scaladget.stylesheet.all._
/**
* A minimal binding between Scala.Rx and Scalatags and Scala-Js-Dom
*/
object JsRxTags {
implicit val ctx: Ctx.Owner = Ctx.Owner.safe()
/**
* Wraps reactive strings in spans, so they can be referenced/replaced
* when the Rx changes.
*/
implicit def RxStr[T](r: Rx[T])(implicit f: T Modifier): Modifier = {
rxHTMLMod(Rx(span(r())))
}
// implicit def RxModifierSeq(r: TypedTag[Rx[ModifierSeq]]): TypedTag[ModifierSeq] = {
// r.copy(modifiers = r.modifiers)
// }
/**
* 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 rxHTMLMod[T <: HtmlTag](r: Rx[T]): Modifier = bindNode(rxHTMLNode(r))
// implicit def rxHTMLTagedType[T <: HtmlTag](r: Rx[T]): Modifier = bindNode(rxHTMLNode(r))
implicit def rxHTMLNode[T <: TypedTag[HTMLElement]](r: Rx[T]): HTMLElement = {
def rSafe = r.toTry match {
case Success(v) v.render
case Failure(e) span(e.toString, backgroundColor := "red").render
}
var last = rSafe
r.triggerLater {
val newLast = rSafe
last.parentNode.replaceChild(newLast, last)
last = newLast
}
last
}
/**
* Idem for SVG elements
*/
implicit def rxSVGMod[T <: TypedTag[SVGElement]](r: Rx[T]): SVGElement = {
def rSafe = r.now.render//r.toTry match {
// case Success(v) ⇒ v.render
// case Failure(e) ⇒ span(e.toString, backgroundColor := "red").render
// }
var last = rSafe
r.triggerLater {
val newLast = rSafe
last.parentNode.replaceChild(newLast, last)
last = newLast
}
last
}
implicit def RxAttrValue[T: scalatags.JsDom.AttrValue] = new scalatags.JsDom.AttrValue[Rx.Dynamic[T]] {
def apply(t: Element, a: Attr, r: Rx.Dynamic[T]): Unit = {
r.trigger {
implicitly[scalatags.JsDom.AttrValue[T]].apply(t, a, r.now)
}
}
}
implicit def RxStyleValue[T: scalatags.JsDom.StyleValue] = new scalatags.JsDom.StyleValue[Rx.Dynamic[T]] {
def apply(t: Element, s: Style, r: Rx.Dynamic[T]): Unit = {
r.trigger {
implicitly[scalatags.JsDom.StyleValue[T]].apply(t, s, r.now)
}
}
}
// Convenient implicit conversions
def rxIf[T](dynamic: Rx.Dynamic[Boolean], yes: T, no: T) = {
rx.Rx {
if (dynamic()) yes
else no
}
}
def rxIf[T](dynamic: Var[Boolean], yes: T, no: T) = {
rx.Rx {
if (dynamic()) yes
else no
}
}
implicit def rxNode(r: Rx[Node]): Node = {
def oo = {
def rSafe = r.now
var last = rSafe
r.triggerLater {
val newLast = rSafe
last.parentNode.replaceChild(newLast, last)
last = newLast
}
last
}
bindNode(oo).render
}
// implicit val ctx: Ctx.Owner = Ctx.Owner.safe()
//
// /**
// * Wraps reactive strings in spans, so they can be referenced/replaced
// * when the Rx changes.
// */
// implicit def RxStr[T](r: Rx[T])(implicit f: T ⇒ Modifier): Modifier = {
// rxHTMLMod(Rx(span(r())))
// }
//
// implicit def rxNode(r: Rx[Node]): Node = {
//
// def oo = {
// def rSafe = r.now
//
// var last = rSafe
//
// r.triggerLater {
// val newLast = rSafe
// last.parentNode.replaceChild(newLast, last)
// last = newLast
// }
// last
// }
//
// bindNode(oo).render
// }
// /**
// * 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 rxHTMLMod[T <: HtmlTag](r: Rx[T]): Modifier = bindNode(rxHTMLNode(r))
//
// // implicit def rxHTMLTagedType[T <: HtmlTag](r: Rx[T]): Modifier = bindNode(rxHTMLNode(r))
//
// implicit def rxHTMLNode[T <: HtmlTag](r: Rx[T]): Node = {
// def rSafe = r.toTry match {
// case Success(v) ⇒ v.render
// case Failure(e) ⇒ span(e.toString, backgroundColor := "red").render
// }
// var last = rSafe
// r.triggerLater {
// val newLast = rSafe
// last.parentNode.replaceChild(newLast, last)
// last = newLast
// }
// last
// }
//
// /**
// * Idem for SVG elements
// */
// implicit def rxSVGMod[T <: TypedTag[SVGElement]](r: Rx[T]): Modifier = {
// def rSafe = r.toTry match {
// case Success(v) ⇒ v.render
// case Failure(e) ⇒ span(e.toString, backgroundColor := "red").render
// }
// var last = rSafe
// r.triggerLater {
// val newLast = rSafe
// last.parentNode.replaceChild(newLast, last)
// last = newLast
// }
// last
// }
//
// implicit def RxAttrValue[T: scalatags.JsDom.AttrValue] = new scalatags.JsDom.AttrValue[Rx.Dynamic[T]] {
// def apply(t: Element, a: Attr, r: Rx.Dynamic[T]): Unit = {
// r.trigger {
// implicitly[scalatags.JsDom.AttrValue[T]].apply(t, a, r.now)
// }
// }
// }
//
// implicit def RxStyleValue[T: scalatags.JsDom.StyleValue] = new scalatags.JsDom.StyleValue[Rx.Dynamic[T]] {
// def apply(t: Element, s: Style, r: Rx.Dynamic[T]): Unit = {
// r.trigger {
// implicitly[scalatags.JsDom.StyleValue[T]].apply(t, s, r.now)
// }
// }
// }
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment