visgl / visgl/deck.gl

[Tracker] View System Improvements

Open
#9,670 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

tracker
Dominant language
TypeScript
Stars
14.6k
Forks
2.3k
Avg merge
2d 9h
Merged PRs (30d)
42

Description

Target Use Case

deck view system

A more sophisticated view system could be a powerful addition to deck.gl. Since it is starting to look like we have a long list of ideas around view system improvements, it is probably best to collect them and ensure that any changes we make fit into the bigger picture.

Proposal
Views
Improved declarative support
  • Support for calc() expressions? #9842
    • In Infovis, adding synchronized timelines and legend views would benefit from width: 'calc(100% - 250px)' type expressions.
    • It is not hard to implement the CSS spec and handle most of the supported units.
View override logic (declarative)
  • Views: ViewState prop override support for object / array values?
    • Views can be declared with props that override viewState. But this does not handle partial overrides like zoom: [2,] or position: [,,10] well.
    • Such props are more common in the non-geospatial view states.
View filtering
  • Currently deck.layerFilter has to be a "global" function.
    • Add support for a declarative version, a list or map of strings to include or exclude, a list of regexps etc.

    • Allow layer filters to be specified on views?

    • Allow view filters to be specified on layers?

    • Intuitiveness of filtering API: Filtering can gets stuck on composite layers, preventing actual layers from rendering, not super intuitive. Maybe multiple ways to address this.

      • Perhaps there is a difference in internal composite layers and primary composite layers?
Nesting Layers in Views.
  • An alternative to view filtering is to allow layers to be nested in views.
views: [new OrthographicView({layers: ....})]
  • LayerGroups? - a problem occurs when wanting to render a group of layers in multiple views. By defining a LayerGroup:
views: [
    new LayerGroup({id: 'group1', layers: [...], 
    new OrthographicView({id: 'view1, layers: 'group1', ....})
]

or

layers: [new LayerGroup({id: 'group1', layers: [...]}),
views: [new OrthographicView({id: 'view1, layers: 'group1', ....})]
View Override logic
  • Widgets that manipulate views are really cool. Being able to create a sophisticated configurable UI by just adding a widget is a powerful feature.
  • If we allow widgets to override views, should we define a system for that independently of widtets.
  • Can we define a view override cycle that is predictable (e.g. Widgets apply their changes in order? can application opt in?, ...)
  • Or do we want Widgets to accept views and layer props? If so ,should should we allow views to accept Widgets as children?
ViewState manipulation logic

A number of widgets are implementing hacky ways to manipulate the view state.

  • Consolidate this, perhaps first on the WidgetManager, and move such logic out of the widgets.
Controllers
  • Boundaries / extents
    • In infovis orhtographic views, defining a world size and preventing the user from panning away from the "world" would be usefl.
  • Inertia pans behave poorly when rendering very large datasets. (Likely a bug, not a feature)
    • The timing uses to calculate the inertia seems to assume that the render cycle doesn't exceed its tick, creates a wobbly effect.

View Layout RFC

image

Changes

  • Adds plain (non-class) discriminated view layout types for row, column, overlay, and spacer layouts.
  • Adds buildViewsFromViewLayout, including view reuse, length parsing, split metadata, and viewPropsById bounds overrides.
  • Exports the compiler and associated types from @deck.gl/widgets and deck.gl.
  • Adds focused compiler tests and API docs with a usage section.

View Layout Syntax Audit

We do have a point of reference in existing 9.3 splitter widget which provides a minimal layout syntax for its views prop

What changes could be made to the new view layout syntax that would make it more similar to the old syntax

The closest change would be to let the new compiler accept a split-container shape that mirrors

SplitterWidget ViewLayout Concerns with aligning
list of views, horizontal or vertical nested hierarchy of layouts and views Scope is different
<item>.orientation <item>.layout ViewLayout supports more layout types, not just orientation
<item>.orientation: horizontal <item>.layout: row Could be aligned <item>.layout: 'horizontal'
<item>: vertical layout: column Could be aligned
SplitterWidgetProps.views <item>.children Could be aligned though children can be layout items not just views

SplitterWidgetViewLayout:

const layout = {
  orientation: 'horizontal',
  splitId: 'sidebar-main',
  initialSplit: 0.25,
  minSplit: 0.15,
  maxSplit: 0.5,
  views: [
    new OrthographicView({id: 'sidebar'}),
    new OrthographicView({id: 'main'})
  ]
};

This would map internally to the proposed:

{
  type: 'row',
  splitId: 'sidebar-main',
  children: [...]
}

How to align?

Use views instead of children for row, column, and overlay.

  • Pro: This reads closer to deck.gl and SplitterWidgetViewLayout.
  • Downside: overlay can contain layout nodes and spacers too, so children is semantically a little more accurate.
  • Use orientation for split layouts, keep type only for non-split nodes

Split containers use orientation.

  • Overlay/spacer keep type: 'overlay' | 'spacer'.
  • This is closest to the old syntax, but the union becomes less uniform.

ViewLayout Compared To CSS

CSS is a useful benchmark for whether the ViewLayout API feels obvious. The current API maps most closely to a constrained subset of Flexbox plus absolute-positioned overlays.

CSS concept Current ViewLayout equivalent Fit
display: flex; flex-direction: row/column `type: 'row' 'column'ororientation`
Flex item fixed basis child width / height Strong
Flex item min/max minPixels / maxPixels Good, but less CSS-like naming
position: absolute inside parent overlay + child x/y/width/height Strong
padding inset Reasonable, but CSS would call this padding
gap manual spacer Weak
flex-grow / fr units flexible unspecified children divide remaining equally Basic only
CSS Grid named areas none Missing
minmax() / clamp() width: '50%' + minPixels/maxPixels Good conceptually
subgrid nested layouts Similar spirit, simpler
container queries caller recompiles with measured size Similar responsibility, not declarative
anchor positioning viewPropsById / overlay offsets Partial
resize/split panes splitId + splittersById Not CSS, but app-layout-specific

The biggest CSS-like gaps are:

  1. No gap

    Spacer works, but it is verbose. A gap: 8 prop on row/column would feel natural and map directly to CSS flex/grid.

  2. No flex weights

    Today unspecified children divide remaining space equally. CSS users may expect something like flex: 2 or weight: 2.

  3. Axis-dependent minPixels / maxPixels

    This is pragmatic, but CSS would likely spell this as minWidth / maxWidth and minHeight / maxHeight, or minSize / maxSize for stack-axis sizing.

  4. No named grid/areas

    If the API wants to compete with CSS Grid, it would need named cells or areas. That may be too much for the current PR.

  5. Generated split ids are less CSS-like than line names

    CSS Grid has named lines. A closer model might be splitIds: ['sidebar-main', 'main-inspector'] for multi-child splits. Generated ids are simpler, but less authored and less semantic.

Suggested docs language:

ViewLayout is closest to a constrained subset of Flexbox plus absolute-positioned overlays. Rows and columns distribute space, children may declare fixed or percentage sizes plus pixel min/max constraints, and overlay children are positioned within their parent rect.

For future CSS-inspired API additions, the highest-value options are gap and flex / weight.

CSS grid

CSS grids could be nice, to make a number of views for different cities etc. For “N city views” the current row/column API gets awkward because you either manually nest rows/columns or generate a tree. A grid layout would be more natural:

const layout = {
  type: 'grid',
  columns: 3,
  gap: 8,
  children: cities.map(city => new MapView({id: city.id}))
};

Stacked PRs

The Follow-up "PoC" PR adds a number experimental widgets, website example, playground JSON sample, and widget docs, this is mainly for exposition at the moment, to show the system working and things that could be built by users.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by narrowing the tracker to one proposal, such as the View Layout RFC, and read the existing 9.3 splitter widget syntax alongside buildViewsFromViewLayout and the @deck.gl/widgets exports. A complete contribution would need an agreed scope, implementation, focused compiler tests, and API documentation; this issue does not identify files or a single acceptance criterion.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.