Is it possible to create a library like react-vis?


#1

If you’re not familiar with react-vis, it’s a visualization library for React by Uber which has a very easy to use and easy to read way of composing charts. Here’s a sample of the typical definition of a chart in the library:

const data = [
  {x: 0, y: 8},
  {x: 1, y: 5},
  {x: 2, y: 4},
  {x: 3, y: 9},
  {x: 4, y: 1},
  {x: 5, y: 7},
  {x: 6, y: 6},
  {x: 7, y: 3},
  {x: 8, y: 2},
  {x: 9, y: 0}
];
<XYPlot height={300} width= {300}>
  <VerticalGridLines />
  <HorizontalGridLines />
  <XAxis />
  <YAxis />
  <LineSeries data={data} />
</XYPlot>

The thing to note is that the data is only being passed in to the LineSeries component (which displays a simple line series in the chart, a similar chart can be found here) but not in to the gridlines components, the axes, or the plot itself.

In Ember, composing components in to a component like this works when the outer component yields inside of its template, and Ember’s templating system will render the inner components inside of the {{yield}} block, without the component (the object that extends Ember.Component) knowing about its children.

In React, composing components works by passing in the children component as a property called ‘children’ on the outer component, and then the implementation of the outer component will pass the ‘this.props.children’ property inside the render function, instead of yielding control to the template system.

Setting that up, I believe the way react-vis can be composed this way is because the outer component (XYPlot in this case) has direct access to its children, and can therefore look at certain properties of its children (such as data passed in to the LineSeries) and coordinate what each component needs to do its job (for axes – what ticks will be drawn, for series’ – the height or width to draw the elements in), and then passes in the properties to the children without the user having to do any of the coordination.

I don’t see how this kind of thing would be possible in Ember.js, since components don’t have a way of knowing anything about their children as far as I can tell. Components can yield back properties that can be passed in to its children like so (with ‘post’ being yielded by blog-post, and then used inside of the block):

{{#blog-post editStyle="markdown-style" postData=myText as |post|}}
  <p class="author">by {{author}}</p>
  {{post.body}}
{{/blog-post}}

so something like this could be used to share data between the parent and its children, but the user would need to coordinate the data sharing by passing the yielded object to all of its children.

I looked around at a few charting libraries for Ember (actually that’s a lie, it was only one), but they seemed to be centered around monolithic charts (i.e. you just call {{BarChart}} and pass in config options) instead of composing it out of smaller components.

Is there any way of doing something like this with Ember outside of yielding some kind of object from the root component (XYPlot), which needs to be explicitly passed in to all of its children and handle the task of taking in the data for the different series’ and coordinating root-level data about the graph (bounds, scales, etc.)?


#2

There are a ton of addons that does this. None of them gained much traction though and are eventually abandoned. That’s why you don’t hear about them.