nestauk / health_mosaic_ui

Health Mosaic User Interface
MIT License
0 stars 0 forks source link

Advanced facets transitions #74

Closed pngwn closed 5 years ago

pngwn commented 5 years ago

Add vertical tabs, large enough to read a medium length phrase, with good padding.

When we transition from a tab to another, we can either:

pngwn commented 5 years ago

I wanted to update this based on the converstaion we have about how we would use the state charts and my explorations this morning. There is a bit of an awkward problem when using the state chart as our main source of truth. The main issue being that it doesn't have enough information for us to declaratively maintain our UI the way want to.

When we have a structure like:

const facetChart = {
  initial: 'tab1',
  states: {
    tab1: {
      type: 'parallel',
      states: {
        map: {},
        force: {}
      }
    },
    tab2: {}
  }
};

We have some of the information we need in the chart but not everything. Ideally if we're going in this direction we would just iterate over the list of states and render our UI but this isn't really possible because the tabs themselves will never all be available on the current state object. Only one tab can be 'active' at a time, so we would need to maintain a list of all of these tabs separately as well as in the state machine, we would need to update these lists separately. We could make them parallel to keep everything visible but if we do that we are sacrificing proper modelling for convenience, which is a bad idea, in my opinion. The main problem with this whole situation is we no longer have a single source of truth, our DOM is dictated by the machine (which is great) but some of the DOM is defined in the component and other parts are defined in the machine (its a bit strange). Maintaining this would also be difficult as we would need to update multiple files whenever we added a new facet or visualisation.

I'm not sure what the best option here is, considering that all of these states are identical (within reason), and we render components based on the state of our machine, I don't think we would lose anything meaningful if we have a machine to control the whole facet and individual machines to control each facet, and a machine for each visuatisation but they would no loner be a nested machine. This would essentally be a situation (as we have discussed previously) where machines instantiate machines by rendering components but we would lose the coupling.

There are advantages and disadvantages here, the main advtange being that everything is decoupled and easy to reuse and refactor. Modifying one machine won't change everything else. The main disadvantage is that we can no longer describe the entire app behaviour in a single nested machine. How significant those advantages and disadvantages are really depends on how we end up using things and what our plans are in the future. There is obviously a larger maintenance costs which a single large machine that has everythign defined on it but I'm less worried about that. I'm mainloy worried about essentially definining the DOM structure in the state machine, I'm not against this (I actually think could be a really nice idea) but we need to figure out a way to do this and change our API accordingly: we wouldn't necessarily need to do it in the component, but we need to use components. Regardless, this is a can of worms and we start to move away from the svelte model when we go down this route, this might be fine but we need to be careful not to break the clever stuff svelte does to keep things performant.

Maybe we need to think more about how to integrate state machine with svelte, we're currently just if/elsing based on an external state machine. Maybe we could come up with something better and then we could start to think of our machine not only as a traiditional one but also as a state -> DOM map that we can use easily inside our svelte compoents.

I'll see if I can come up with anything while I think about the best way to move forwards with this.

mindrones commented 5 years ago

Here are some of the ideas that got us into this pattern:

Stop trying to model screens as parallel machines just because they might contain more charts at the same time and focus on tabs only:

IMG_0227

We should define "global" events (T1, T2, ...), but more specific events should overload the "global" ones. This is indeed how statecharts work:

In a hierarchical machine, transitions are prioritized by how deep they are in the tree; deeper transitions are more specific and thus have higher priority. 

IMG_0228

For specific transitions we enter in a "transition machine" that gets passed Svelte's tweens in the context, so that the machine doesn't know how we'll use these (we don't need to think about passing DOM nodes to machine) and the component will just use the current value of the tween.

IMG_0229

We could conceptualise this as a gantt of charts activities/transitions (even if implementation-wise things are a bit different): IMG_0231

This has the disadvantage that all transitions will have the same keyframes though, how to solve this?

A "transition machine" can be a parallel machine made of "tracks", each one being an independent transition machine. IMG_0232

To make this work we can use delayed transitions.