Tuesday, May 20, 2014

Limited SVG Manipulation in Dart


Tonight I hope to make use of Dart's built-in dart:svg library to clean up the code in my Polymer custom element.

The custom element in question, <x-pizza>, facilitates pizza buying by drawing (with SVG) the current state of to-be-purchased pizza:



Nearly every aspect of SVG has been a struggle for me, so I did not concern myself much with prettiness of code, although one cannot help oneself sometimes with Dart. Still, there are aspects that can be made better if I dig a little deeper into dart:svg

I notice that the graphical elements in dart:svg all have width, height, and href properties. So it sure would be nice to rewrite _svgImage() with that in mind. That is, this:
  _svgPepperoni()   => _svgImage('pepperoni');
  _svgSausage()     => _svgImage('sausage');
  _svgGreenPepper() => _svgImage('green_pepper');

  _svgImage(basename) {
    var svgImage = new ImageElement()
      ..setAttributeNS(
          'http://www.w3.org/1999/xlink',
          'href',
          '/packages/svg_example/images/$basename.svg'
        )
      ..setAttribute('width', '16')
      ..setAttribute('height', '16');

    return new GElement()
      ..append(svgImage);
  }
Would look better with svgImage being assigned as:
    var svgImage = new ImageElement()
      ..href = '/packages/svg_example/images/$basename.svg'
      ..width = '16'
      ..height = '16';
Sadly, that does not work. Upon closer examination, each of those properties is final in Dart. Huge bummer.

At least Dart makes it possible to set those properties with setAttribute() and setAttributeNS(), but it sure would be cleaner to be able to do so with proper setters. This does not bode well for dart:svg making SVG life easier. In fact most properties turn out to be final (e.g. translate, which sure should have helped).

If manipulating SVG is not going to be pretty in Dart, then perhaps loading it can be? I am currently starting a clean pizza via a combination of static <svg> tags in the Polymer template:
      <svg version="1.1"
        baseProfile="full"
        id="pizza-graphic"
        style="display: block; margin: 10px auto"
        width="300" height="300"
        xmlns="http://www.w3.org/2000/svg">
      </svg>
And a fresh slate that is drawn dynamically each time a topping is added to the pizza:
  _updateGraphic() {
    $['pizza-graphic'].innerHtml = '''
      <circle cx="150" cy="150" r="150" fill="tan" />
      <circle cx="150" cy="150" r="140" fill="darkred" />
      <circle cx="150" cy="150" r="135" fill="lightyellow" />
    ''';

    _addWholeToppings();
    _addFirstHalfToppings();
    _addSecondHalfToppings();
  }
If I save an SVG blank pizza image from Inkscape, I can load it with an HttpRequest:
  _updateGraphic() {
    HttpRequest.
      getString('/packages/svg_example/images/pizza.svg').
      then((svgContent){
        $['pizza'].innerHtml = '';
        svg = new SvgElement.svg(svgContent);
        $['pizza'].append(svg);
      });

    _addWholeToppings();
    _addFirstHalfToppings();
    _addSecondHalfToppings();
  }
That works just fine, but I am unsure that it improves things significantly in this case. Regardless, that seems like a useful trick to keep in my SVG toolbox (thanks to Emanuele Sabetta for the approach). If nothing else, it cuts down on static SVG coding, moving the definition into static files where it belongs. In more complex base SVG images, this approach would likely be a much more significant win.


Day #69


1 comment:

  1. Thanks Chris for the article. Please go on. We still need to understand how to build a true portable polymer dart element using svg, an element reusable in every web page and with integrated interactivity and observable states, like the buttons of the tutorial I linked to you earlier. I hope you will publish something about this soon.

    About the use of inline svg: in real world you ALWAYS load svg files as external resources. Because programmers like me never do the graphics, graphicians do the graphics. The standard workflow for making a web site for a client requires a clean separation between art and code. Often the client speak to the artists separatedly from programmers, and many changes are made at the graphics during all production whitout changing a single line of code.
    This is why in the real world the graphic assets must be external files: the graphicians must be able to create and update those svg files by themselves, without the need of any programmer intervention. And this is important for all kind of graphical complexity. Even a simple svg button can be changed dozen of times in a day by the graphicians, and coders intervention would slow things down enourmously. Also a graphician is unable to understand and work with svg files internal markup or javascript code.
    Their competence is about the use of CG tools like Inkscape or Illustrator, they don't know anything about code and they must be able to focus only on the art and style of the web page elements.
    It is very rare that in the real world you got to use inline svg, and this is for good reasons.
    Now that we are migrating to the new Dart and Polymer technology, we need to keep the same clean separation between code and graphical assets.
    In building a Polymer.Dart button for examples, the Dart and Polymer code should be separated from the svg image files of the various button states and animations frames. But how to do this it's still not clear to me, and your help in demystifing this new paradigm will be awesome, especially considering the fact that nobody have published any article on this subject yet. It's still an uncharted territory!

    ReplyDelete