Scala.js: Selecting and manipulating generated SVG

915 views Asked by At

I'm struggling with something seemingly simple.

Using Scaja.JS, I have generated some SVG with the ScalaTags library.

I now wish to manipulate the SVG elements using events:

circ.onclick = { e: dom.MouseEvent => ... }

Specifically, I want to select all elements of a certain class and then toggle some class attributes on them.

I tried the Scala.js JQuery binding. While I can retrieve selections with it, I cannot manipulate the selected elements (set classes etc). This seems to be a fundamental problem of SVG being a different kind of DOM which cannot be manipulated with JQuery.

Next, I tried the low level DOM API. This gets me the selection:

document.body.getElementsByClassName("myClass").foreach { node =>  ... }

I now struggle with manipulating attributes of node. I can access them but I cannot set them, as node.attributes.setNamedItem(...) requires a raw.Attr argument which I have trouble creating, There is no constructor to set the name of the Attr.

Also, going for the low level API is quite inconvenient. I'd prefer to get a selection of some class that is easier to manipulate, e.g. Element.

Any ideas?

1

There are 1 answers

1
mseddon On BEST ANSWER

There is no constructor for Attr in the javascript DOM api, either. Attempting to evaluate new Attr() in javascript will result in an "Illegal constructor" TypeError. You can however create attributes using document.createAttribute(name: String).

Although getElementsByClassName is returning a NodeList, each item will actually be an Element (you will have to downcast this with pattern matching or similar). From a dom.Element you can invoke setAttribute(name: String, value: String) which may be more convenient than manually creating Attrs at such a low level.

Also, jQuery's ability to select elements of the dom using expressions has now been mostly built into the DOM using document.querySelectorAll. You might try something like svgDocument.querySelectorAll(".foo").map(_.asInstanceOf[dom.raw.SVGElement]) .foreach { _.setAttribute("someAttribute", "newValue") }.

Of course- to treat a NodeList as a Scala Collection will require import org.scalajs.dom.ext._ to bring the implicits into scope, but it looks as though you're already doing that.