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