Ew. SVG coding is awful in JavaScript. The videos that I am preparing for “Extras” readers of Patterns in Polymer will include some SVG coding. I will focus on the Polymer coding, of course, but SVG coding will be there and I would like to make it as palatable as possible.
Not that it's great in Dart, but built-in Dart language features like method cascades plus actual constructors make it decent:
_svgImage(basename) {
var svg = new GElement()
..append(
new CircleElement()
..setAttribute('r', '15')
..setAttribute('cx', '15')
..setAttribute('cy', '15')
..setAttribute('style', 'opacity:0')
)
..append(new SvgElement.svg(svgContent['$basename.svg']));
// ...
}
That adds a circle element (for mouse events) and an SVG asset to an SVG <g>
tag to be added to the pizza building <x-pizza>
custom element:JavaScript lacks constructors (as far as I can tell) and certainly doesn't have method cascades. So the equivalent JavaScript code wound up looking like:
_svgSausage: function() {
var ns = "http://www.w3.org/2000/svg";
var group = document.createElementNS(ns, "g");
group.innerHTML = this.svgContent['sausage.svg'];
var svg = group.querySelector('svg');
var mouseCircle = document.createElementNS(ns, "circle");
mouseCircle.setAttribute('r', '15');
mouseCircle.setAttribute('cx', '15');
mouseCircle.setAttribute('cy', '15');
mouseCircle.setAttribute('style', 'opacity:0');
group.appendChild(mouseCircle);
// ...
}
Instead of constructing objects, I create elements. Instead of method cascades, I repeat the same object / method on line after line. This is not pleasing.So tonight, I do what all JavaScript programmers do when faced with ugliness—try out a library that someone has created to eliminate some of the sting. In this case, I try Snap. I start with a Bower install:
➜ js git:(master) bower install -S snap.svg ... bower snap.svg#* download https://github.com/adobe-webplatform/Snap.svg/archive/v0.3.0.tar.gz bower snap.svg#* resolved git://github.com/adobe-webplatform/Snap.svg.git#0.3.0 ... bower snap.svg#~0.3.0 install snap.svg#0.3.0 ... snap.svg#0.3.0 bower_components/snap.svgThe chapter on external libraries in Patterns in Polymer still applies so I add this to the HTML definition of
<x-pizza>
:<link rel="import" href="../bower_components/polymer/polymer.html"> <link rel="import" href="../bower_components/core-ajax/core-ajax.html"> <script src="../bower_components/snap.svg/dist/snap.svg.js"></script> <polymer-element name="x-pizza"> <template> <core-ajax auto id="pizza.svg" url="../../assets/images/pizza.svg" on-core-response="{{responseReceived}}"></core-ajax> <!-- ... --> </template> <script src="x_pizza.js"></script> </polymer-element>I am already loading SVG via
<core-ajax>
tags, so I probably will not make use of Snap's SVG loading ability (at least for now). Instead, I want to take an already loaded SVG string and have Snap generate the SVG DOM, which is what Snap.fragement()
does. I replace some innerHTML ugliness above: // ...
group.innerHTML = this.svgContent['sausage.svg'];
var svg = group.querySelector('svg');
// ...
The equivalent in Snap is: // ...
var f = Snap.fragment(this.svgContent['sausage.svg']);
var svg = f.node.firstElementChild;
group.appendChild(svg);
// ...
I have exchange 2 lines of code for 3, which is going in the wrong direction, but I am also working against the Snap.svg rails here. I should not be reaching down for the node
property. Hopefully I can switch off of that in a bit, but this lets me verify that things are still working—and they are:In the end, I am able to work with Snap to reduce the earlier mess to:
_svgSausage: function() {
var s = Snap(0,0);
var group = s.group();
var f = Snap.fragment(this.svgContent['sausage.svg']);
var svg = f.select('svg');
group.add(f);
var mouseCircle = s.circle(15, 15, 15);
mouseCircle.attr({style: 'opacity:0'});
group.add(mouseCircle);
// ...
}
That is a big improvement. The attr()
setter / getter method is almost worth the trouble alone. And really, this wasn't too much trouble considering that I am still a bit off the rails with the whole Snap.fragment()
thing.I think that I might be able to get this in even better shape if I switch the entire library over to Snap. So far, I am only messing around with the pizza toppings in
<x-pizza>
. If I move everything—crust, sauce, cheese, etc—into Snap, I think I might realize a big improvement. Worth a follow-up tomorrow.Day #87
No comments:
Post a Comment