Skip to content

Latest commit

 

History

History

docs

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

Core Concepts

Gleam is designed around a handful of core concepts:

Panes and Painters

Panes

A pane is an object that represents a rectangular region of the canvas.

A pane can have a layout, child panes, painters, and input handlers.

Within a parent pane, each child pane, painter, and input-handler has a zIndex. To render a pane, its child panes and painters are rendered from lowest zIndex to highest. (Tiebreaker is the order in which they were added to the pane -- children added earlier get rendered earlier.) When handling input, events are offered to a pane's child panes and input-handlers in the reverse of rendering order, so that children that appear visually on top also get the first opportunity to claim input events.

The zIndex ordering is capable of interleaving child panes with painters and input-handlers -- e.g. a child pane at zIndex 0 would be rendered before a painter at zIndex 999, so the painter's content would appear on top of the child pane. In most cases you do want child panes on top of painters, but there are situations where it's helpful to have a painter on top -- e.g. HorizontalTimeline has a time-cursor painter and an input-handler for dragging the time-cursor, and their zIndex values make it feel like the time-cursor is on top of everything else in the timeline, including child panes.

Layouts

A pane can contain child panes. Positions and sizes of child panes within their parent pane are determined by the parent pane's layout.

Gleam has built-in general-purpose layouts here. Their params are set via CSS.

Sometimes an ad-hoc layout impl is a clean and easy way to get layout behavior tailored for your specific use-case. The layout interface is easy to implement, e.g. by extending the LayoutBase class.

Painters

A pane can contain painters. A painter uses WebGL to render data or other content onto its pane's rectangular region.

Gleam has built-in general-purpose painters here. Their styles are set via CSS.

Writing custom painters for application-specific needs is encouraged! See the info here on managing GL resources in painters. Custom painters are sometimes the best way to get rendering behavior that is tailored for your specific use-case. They take time to write -- especially if you aren't familiar with GL concepts like buffers, textures, and shaders -- but can provide compelling application-specific visualizations that aren't achievable with general-purpose painters.

Input Handlers

A pane can have input-handlers attached to it.

Each mouse event is first offered to the topmost pane that contains the event's location. If that pane has an input-handler that handles the event, the event is passed to that input-handler. Otherwise, the event is offered to the topmost pane's parent, then to its grandparent, and so on, until an input-handler is found. (To make a pane "opaque" to mouse events, set the Pane.consumesInputEvents field to true. This always prevents mouse events from propagating up to the pane's parent, regardless of whether the pane has a suitable input-handler.)

Each input-handler has a target field, which is a value that indicates the thing being manipulated. After an input-handler handles an event, input-spectators are notified, and the handler's input-target is included in the notification, so that spectators can tell what was being manipulated.

Impls of HoverHandler and DragHandler may have associated mouse-cursor CSS classes. For example, a DragHandler that implements dragging an axis-tag up and down might be associated with CSS class y-tag-dragger, which is configured in defaults.css to set the mouse cursor to ns-resize  ns-resize.

Keyboard events are passed to the input handlers of the focused pane, which is the most recent pane to have received a mouse-press event.

Input Spectators

After an input-event is handled by an input-handler, input-spectators are notified. The notification includes the handler's input-target, which indicates what was being manipulated.

Input-spectators differ from input-handlers in several ways:

  • Spectators run post-facto, after an input-event has been handled
  • Spectators have no effect on how input-events propagate among handlers
  • All spectators fire for all input-events received by any pane in the canvas

Consecutive hover events with the same input-target are considered a single continuous hover. (Input-targets are compared using ImmutableJS equality.) Spectators' hover/unhover callbacks are called when such a sequence begins and ends. Similarly with drag/undrag and focus/unfocus.

For example, the handler that supports dragging a timeline-event bar has an input-target that holds (A) a reference to the dragged bar, and (B) a symbol indicating which part of the bar was being dragged: left edge, right edge, or center. When a spectator fires, it can e.g. highlight/unhighlight the bar on hover/unhover, or select the bar on click.

It's theoretically possible to add so many spectators that they bog down your application. This is not expected to happen in practice: spectators generally decide quickly whether to use or ignore an incoming event, the number of spectators that actually use any given event is small, and we only get a couple of input-events per frame.

Contraptions

A contraption is any class that holds a purpose-specific assemblage of UI objects that are convenient to group together.

The term "contraption" emphasizes the ad-hoc nature of such classes, which need not conform to any particular interface, structure, or pattern. A contraption can have panes, layouts, painters, input-handlers, axes, DOM elements, and any other relevant objects. It can have whatever methods make sense for the purpose.

A couple of examples to illustrate how varied contraptions can be:

  • AxisWidget is a contraption that holds an axis, an axis painter, a pane, a purpose-specific layout, and input-handlers. The layout sets the pane's preferred size based on the painter's settings. The input-handlers allow zooming and panning the axis.

  • TooltipDiv is a contraption with a DOM div element, and convenience methods for setting its text, position, and visibility.

Gleam has built-in general-purpose contraptions here.