I can't resist. The temptation to play around with SVG is simply too great and I am helpless before its wiles.
I really meant to start looking at incorporating Polymer elements in Angular. Perhaps tomorrow. Onto the SVG!
I have a pretty cool
<x-pizza> Polymer that builds pizzas for ordering:
The problem, of course, is that the current pizza state is in the form of text. Saaaay! SVG can help with that!
I start by adding a blank SVG tag to my
<x-pizza> template:<polymer-element name="x-pizza">
<template>
<h2>Build Your Pizza</h2>
<!-- <pre>{{pizzaState}}</pre> -->
<div title="{{pizzaState}}">
<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>
</div>
<!-- ... -->
</template>
<script type="application/dart" src="x_pizza.dart"></script>
</polymer-element>
That creates a 300 by 300 blank SVG canvas on which to paint. I give it an ID so that I can readily look it up using the Polymer $ for automatic node finding.I already have my Polymer updating the pizza state (text-only so far) when new items are selected from the various menus. To do so, the
updatePizzaState() method is called by various change event handlers. I factor the old text-only code out into _updatePizzaText(). In addition to calling this method, I also have updatePizzaState() call my new, SVG powered _updateGraphic() method:@CustomTag('x-pizza')
class XPizza extends PolymerElement {
// ...
updatePizzaState([_]) {
_updateText();
_updateGraphic();
}
_updateGraphic() {
this.$['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" />
''';
}
// ...
}There is not too much to _updateGraphic() so far. It adds three circles in the center of the 300 by 300 SVG element, each slightly smaller than the previous, each representing a different layer of the pizza (crust, sauce, and cheese). I use the $ node finder to ensure that I have the correct SVG element.With that, I have SVG!

To add toppings, I need a generator for each of the supported toppings:
_svgPepperoni() =>
new CircleElement()..attributes = {'r': '10', 'fill': 'red'};
_svgSausage() =>
new CircleElement()..attributes = {'r': '3', 'fill': 'brown'};
_svgGreenPepper() =>
new CircleElement()..attributes = {'r': '10', 'fill': 'green'};Next, I need a way to choose the appropriate SVG maker function given a string representing a topping: _toppingMaker(String topping) {
if (topping == 'pepperoni') return _svgPepperoni;
if (topping == 'sausage') return _svgSausage;
if (topping == 'green peppers') return _svgGreenPepper;
}With that, I can iterate over each topping and add them to the pizza: _addWholeToppings() {
model.wholeToppings.forEach((topping) {
var maker = _toppingMaker(topping);
_addWholeTopping(maker);
});
}The maker now points to the appropriate generator function (e.g. _svgPepperoni). Armed with that, I can make 20 randomly placed toppings with: _addWholeTopping(maker) {
var rand = new Random();
for (var i=0; i<20; i++) {
var topping = maker();
topping.attributes
..['cx'] = "${150 + (90 * cos(PI * rand.nextDouble()))}"
..['cy'] = "${150 + (90 * cos(PI * rand.nextDouble()))}";
$['pizza-graphic'].append(topping);
}
}And that does the trick. The end result is:
So yeah, I need a better green pepper. And maybe some animation. And random placement probably isn't quite right. But it is definitely better than plain text. So, yay SVG!
Day #999
No comments:
Post a Comment