livebook-dev / kino

Client-driven interactive widgets for Livebook

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add inline layout

mat-hek opened this issue · comments

Hi, what do you think about having an inline layout, that would display kinos next to each other?

My case is that I have many charts so I place them in a grid, like this:

image

There are two problems with that:

  • No chart can be wider than the grid column. In practice, all charts have to have the same width.
  • The number of columns stays the same after zooming the cell, so I have big gaps instead of more charts in each row

image

Both could be solved by an inline layout so that I could do

Kino.Layout.inline([chart1, chart2, ... chartN])

and the charts would be displayed in a row until they exceed the cell width, like CSS display: inline or display: inline-block.

If you like the idea, would it be hard to implement? I can try to find some time to try ;)

I considered this briefly in the past, the tricky part is that each plot is in an absolutely positioned iframe on top of an empty placeholder element. We sync height of the iframe content into the placeholder (which is fine since we have infinite height), but we don't do that for width, since it's limited, so we basically assume the iframe takes the whole row and in case of overflow it gets scroll. But now that I think more about it, I have ideas of how to make it work reasonably, I need to look at different cases. The case we won't be able to do is a single row with 100 charts and a single scroll, but a flex-wrapped layout should be possible.

Sounds great!

(Note to self) After revisiting, I think this doesn't really work unless the outputs have predefined width (and that is usually not the case, the chart is more of an exception). Things work such that the placeholder element is a regular element on the page and subject to layout calculation, we know how much width it has available and resize the iframe to match that size. So the iframe is given a specific width, layouts elements inside it and that results in some scroll height, which we then respect by mirroring it back onto the placeholder. We can't do that for width (especially that in some cases, like grid or smart cells, we actually want to use all the available width).

@mat-hek an alternative solution which we could support is something like this:

Kino.Layout.inline([{400, kino}, {400, kino}, {600, kino}])

So we would display things in an flex wrap, but the user needs to specify the width of each block. This is not as flexible, but probably works for the original use case you posted?

This is not as flexible, but probably works for the original use case you posted?

Yes, doesn't look the most pleasant TBH, but should do the job ;) Some random ideas that come to my mind:

  • How about checking the ctx.root width in the iframe and shrinking the iframe if it's less than the available width?
  • Maybe give kinos some way to explicitly tell their dimensions? For charts, it should be quite simple
  • A Kino.Box that could wrap any kino and have dimensions specified. Possibly the inline layout wouldn't be needed, just putting the boxes one after another would suffice?
  • Since it's mostly about charts, maybe there's a place for that in kino_vega_lite?

How about checking the ctx.root width in the iframe and shrinking the iframe if it's less than the available width?

I tried a number of ways, but didn't arrive at anything reliable. This is kinda the chicken and egg problem - on one hand the placeholder width is relevant, especially during page resizing, on the other the iframe contents width is relevant; in an inline layout neither is a source of truth.

A Kino.Box that could wrap any kino and have dimensions specified

Could be that, but we still need a notion of inline layout and since we need width specifically for that having two abstractions may be too much. Not sure yet :)

I may be focusing on the wrong thing but I also wonder if this would be better addressed if we could allow positioning within each grid cell. The current version places everything on the top left but I wonder if something that does this:

1 | 2 | 3
4 | 5 | 6
7 | 8 | 9

Where they all point to the center (i.e. 1 is bottom right, 9 is top left, 5 is center, etc) would alleviate the problem by making it look compact even on large screens.

@josevalim you mean instead of this:

1  |2  |
--------
3  |4  |

you are proposing this?

 1 | 2 |
--------
 3 | 4 |

@jonatanklosko that's one option, yes.

The output still needs to take the whole available width, so this is up to the specific kino to center itself or not. For example Kino.VegaLite could center the chart, but that means it would be centered as a single output and so far we never did that.