I spent some time last week playing with Meteor’s Blaze templates and Polymer elements to build recursive components. The final result is a neat DOM based Cantor set. Before we dig into the source, take a look at a polished version of the Polymer implementation on Codepen:
See the Pen Polymer Cantor Set by Pete Corey (@pcorey) on CodePen.
Building Our Cantor Set
The general idea is to build a component that renders one iteration of the Cantor set construction. By one iteration, I mean a single line (or block), and below it another line divided equally with another instance of the component, and blank space and another instance of the component.
I’m using flexbox to simplify the spacing between my components.
To get a better idea of the construction I’m describing, try inspecting the DOM generated by either, or both, of the implementations.
Meteor Implementation
I started by experimenting with recursive custom block helpers in Meteor. After some trial and error, I came up with a cantor
template that renders the Template.contentBlock
for the set pieces, and Template.elseBlock
for the empty pieces. Take a look at the template and the template’s helpers:
<template name="cantor">
<div class="row">
{{> Template.contentBlock}}
{{#if more}}
<div class="flex">
{{#cantor max=max i=next}}
{{> Template.contentBlock}}
{{else}}
{{> Template.elseBlock}}
{{/cantor}}
{{> Template.elseBlock}}
{{#cantor max=max i=next}}
{{> Template.contentBlock}}
{{else}}
{{> Template.elseBlock}}
{{/cantor}}
</div>
{{/if}}
</div>
</template>
Template.cantor.helpers({
more: function () {
return (this.i || 0) < this.max-1;
},
next: function() {
return (this.i || 0) + 1;
}
});
There are a few key take-aways from this layout. The row
element defaults to display:block
, which forces its content onto a new line. The flex
element is set to display:flex
. All of its children have their widths set to 100%, which effectively evenly distributes them within the flex element.
The recursion is where the magic happens. You can see what we’re including the cantor custom block helper inside of itself! We’re passing in an incremented value of i
to the next iteration of the component. The component guards itself against infinite repetition with the {{#if more}}
check before recursing.
The Meteor implementation can be used like this:
{{#cantor max=6}}
<section> </section>
{{else}}
<div class="E"> </div>
{{/cantor}}
Polymer Implementation
The Polymer implementation is very similar, if a little cleaner. Check out the source below:
<polymer-element name="flex-cantor" attributes="max i">
<template>
<style>
.e { border: 1px solid rgba(0,0,0,1); border-bottom: none; }
.c { height: {{100/max}}vh; background-color: tomato; }
.f { display: flex; }
* { width: 100%; }
</style>
<div class="row">
<section class="c"> </section>
<template if="{{i < max - 1}}">
<div class="f">
<flex-cantor max="{{max}}" i="{{i + 1}}"></flex-cantor>
<section class="e"> </section>
<flex-cantor max="{{max}}" i="{{i + 1}}"></flex-cantor>
</div>
</template>
</div>
</template>
<script>
Polymer({
i: 0,
max: 0
});
</script>
</polymer-element>
Polymer allows us to declare the style for the component inline with the component declaration. Additionally, due to the power of Polymer interpolation, we can include all of our increment and guard logic inline in the markup, rather than offloading these to helper methods like we were forced to do in the Meteor implementation.
The Polymer implementation can be used like this:
<flex-cantor max="6"></flex-cantor>
Final Thoughts
I set up a Github repository with branches for both the Meteor implementation and the Polymer implementation. Check it out!
This was very much an experiment, but I’m very interested in further developing this idea. I can already think of other fun implementations of this idea, like a recursive version of my golden spiral layout, but I’m more interested in practical applications for this type of component composition.
Let me know if you have any ideas for recursive components!