Signals - nyurik/vega GitHub Wiki
This wiki documents Vega version 2. For Vega 3 documentation, see vega.github.io/vega.
Wiki ▸ Documentation ▸ Signals
Signals are dynamic variables that drive interactive behaviors. They can be used throughout a Vega specification (e.g., with mark or data transform properties), and their values are determined by expressions or event streams. Event streams capture and sequence hardware events (e.g., mousedown
or touchmove
). When an event occurs, dependent signals are re-evaluated in their specification order. These new signal values propagate to the rest of the specification, and the visualization is re-rendered automatically. Signals corresponding to the top-level width
, height
, and padding
properties are automatically available, and update in response to changes via the Runtime API.
A signal definition, and its use in the rest of a specification, looks something like this:
{
"signals": [{
"name": "indexDate",
"streams": [{
"type": "mousemove",
"expr": "eventX()",
"scale": {"name": "x", "invert": true}
}]
}],
"data": [{
"name": "index",
"source": "stocks",
"transform": [
{
"type": "filter",
"test": "month(datum.date) == month(indexDate)"
}
]
}],
"marks": [{
"type": "rule",
"properties": {
"update": {
"x": {"scale": "x", "signal": "indexDate"}
}
}
}]
}
Available Events
Property | Description |
---|---|
click | ... |
dblclick | ... |
dragenter | ... |
dragleave | ... |
dragover | ... |
keydown | ... |
keypress | ... |
keyup | ... |
mousedown | ... |
mousemove | ... |
mouseout | ... |
mouseover | ... |
mouseup | ... |
mousewheel | ... |
touchend | ... |
touchmove | ... |
touchstart | ... |
wheel | ... |
Signal Properties
Property | Type | Description |
---|---|---|
name | String | A unique name for the signal. Reserved keywords (including datum , event , signals and function names) may not be used. |
init | Object | * | The initial value of the signal. If init is an object with an expr property, the expression is evaluated to produce the signal's initial value. An additional scale property can also be specified to invoke a Scoped Scale Reference. |
verbose | Boolean | By default, a signal only triggers an update when it evaluates to a new value (i.e., an update does not occur if a signal's new value is equal to its current value). If verbose is set to true , the signal will always trigger an update when its value is set. |
Expression Values
Signal values can be determined in one of two ways: purely by other signals, or by event streams as well. If a signal is only dependent on other signals, two additional properties can be specified:
Property | Type | Description |
---|---|---|
expr | Expression | A string containing an expression (in JavaScript syntax) for the signal value. It is automatically reevaluated whenever used signal values change. |
scale | ScopedScaleRef | A scale transform to apply to the expression. This can be particularly useful for inverting expression values (i.e., moving them from visual/pixel space to data space). |
Event Stream Values
To have interaction events (e.g., mousedown
, or touchmove
) trigger changes in signal values, an additional streams property must be defined as an array of objects with the following properties:
Property | Type | Description |
---|---|---|
type | EventSelector | A string that uses the event selector syntax. |
expr | Expression | A string containing an expression (in JavaScript syntax) that is reevaluated every time the specified events occur. event and datum variables are available for use here, corresponding to the captured DOM event and the data object backing the event's target item. For events that occur within the visualization, the following special event functions are also available: |
eventX | Number | An x-coordinate relative to the visualization container element. |
eventY | Number | A y-coordinate relative to the visualization container element. |
eventXY | Number | Combining the above two functions into an object with x and y properties. |
eventItem | Item | The event target item within the Vega scenegraph. |
eventGroup | Item | The target's enclosing group mark item within the Vega scenegraph. |
eventGroup
takes an optional name argument to return a named ancestor group mark item. Only named ancestors of the event target are addressable here.
Similarly, the eventX
, eventY
, and eventXY
take an optional argument that can either be the name or scenegraph item of an enclosing ancestor. If provided, coordinates are translated to the given group's coordinates.
For example, if a rectangle mark item in the following specification was clicked
{
"marks": [{
"name": "foo",
"type": "group",
"marks": [{
"name": "bar",
"type": "group",
"marks": [{
"type": "rect"
}]
}]
}]
}
eventItem
would return the specific rectangle that was clicked. eventGroup()
would return the enclosing group mark item (bar
), and eventGroup('foo')
would return its parent. eventX
and the others would return the position of the click relative to the entire visualization, whereas eventX('foo')
would return the position of the click within the foo
group mark.
Property | Type | Description |
---|---|---|
scale | ScopedScaleRef | A scale transform to apply to the expression. This can be particularly useful for inverting expression values (i.e., moving them from visual/pixel space to data space). |
Event Stream Selectors
Event selectors specify the sequence of events ("event stream") that must occur in order to trigger an interactive behaviour. The syntax consists of the following:
Name | Description |
---|---|
eventType | Captures events of a specific type, for example mousedown , or touchmove . By default, this captures all events of the given type that occur anywhere on the visualization. |
target:eventType | Filters for only events that occur on the given target. The following targets are recognized: |
markType | Filters for events that occur on mark instances of the given type. All supported mark types are available. For example, rect:mousedown captures all mousedown events that occur on rect marks. |
@markName | Filters for events that occur on marks with the given name. For example, @cell:mousemove captures all mousemove events that occur within the mark named cell . |
CSS selector | The full gamut of CSS selectors can be used to capture events on elements that exist outside the visualization. D3 is used to capture these events, and the custom event functions, described above, are not available. For example #header:mouseover captures mouseover events that occur on the HTML element with ID header . |
eventStream[filterExpr] | Filters for events that match the given expression. The filter expression is specified using normal JavaScript syntax, and the event and datum variables are also available. Multiple expressions can also be specified. For example, mousedown[eventX() > 5][eventY() < 100] captures mousedown events which occur at least 5px horizontally, and no more than 100px vertically within the visualization. |
streamA, streamB | Merges individual event streams into a single stream with the constituent events interleaved correctly. For example, @cell:mousemove, mousedown[eventX() > 5][eventY() < 100] produces a single stream of @cell:mousemove and mousedown[eventX() > 5][eventY() < 100] events, interleaved as they occur. |
[streamA, streamB] > streamC | Captures streamC events that occur between streamA and streamB. For example, [mousedown, mouseup] > mousemove describes a stream of mousemove events that occur between a mousedown and a mouseup , otherwise known as a "drag" stream. |
Scoped Scale Reference
When defining an interactive behaviour, it can often be useful to mix between the visual/pixel space of the rendered visualization, and its backing data space. For example, with brushing & linking a scatterplot matrix, the pixel extents of the brush are inverted to produce a data range to highlight points across all cells of the matrix. Scoped scale references help with this. They can be either an object, or the name of a top-level scale. In the latter case, the scale transform is applied as normal (transforming the signal value from the data domain to the visual range).
If the scope scale reference is an object, the following properties are available:
Property | Type | Description |
---|---|---|
name | String | The name of the scale. |
scope | String | SignalRef | An expression or signal reference to a group mark that contains this scale. If no scope is specified, the scale is expected to be defined at the top-level. |
invert | Boolean | If true, an inverse of the scale transform is applied (i.e., transforming the signal value from the visual range to the data domain). |
For example, in the following specification, the group mark named cell
is captured by the corresponding signal. This signal is used to lookup the x
scale, which subsequently inverts the value of the start_x
signal.
{
"signals": [
{
"name": "cell",
"streams": [
{"type": "@cell:mousedown", "expr": "eventGroup('cell')"}
]
},
{
"name": "start_x",
"init": 0,
"streams": [
{
"type": "mousedown",
"expr": "eventX()",
"scale": {"name": "x", "scope": {"signal": "cell"}, "invert": true}
}
]
}
],
"marks": [
{
"name": "cell",
"type": "group",
"scales": [{"name": "x", ...}],
...
}
]
}
Using and Referencing Signals
Once defined, signals can be used throughout a specification. They are available for use within all expressions (e.g., with the filter or formula transforms), and a signal
property is available with mark property value references. For other areas of the specification, a special signal reference ("SignalRef") can be used. A SignalRef is an object with a single signal
property. For example,
{
"signals": [{"name": "xMin", ...}, {"name": "xMax", ...}],
"scales": [
{
"name": "x",
"range": "width",
"domainMin": {"signal": "xMin"},
"domainMax": {"signal": "xMax"}
}
]
}
Dot notation can also be used to access nested signal values. For example,
{
"signals": [
{
"name": "brush_start",
"init": {"x": 0, "y": 0},
"streams": [{"type": "mousedown", "expr": "{x: eventX(), y: eventY()}"}]
}
],
"marks": [
{
"type": "rect",
"properties": {
"update": {
"x": {"signal": "brush_start.x"},
...
}
}
}
]
}
cursor
signal
The By default, Vega will style the mouse pointer when it is over a mark with a defined cursor
property. However, for many interactive use cases, the cursor style should persist for the entire duration of the interaction. For example, consider the Budget Forecasts example. The cursor should be set to pointer
when hovering over the slider control, and should remain a pointer
when we start dragging it regardless of mouse position.
For these use-cases, Vega provides a specially named cursor
signal. When the value of this signal is set, Vega uses it in lieu of any cursor properties set on marks. If the value is set to default
, then Vega resumes using the mark-based cursor
property. Below, we reproduce a snippet of the Budget Forecasts example that sets the cursor. As we see, a cursor
property is specified for the symbol mark named handle
. A cursor
signal is also provided which determines its value based on whether a drag operation is currently occur. Thus, when the user's mouse is over the handle, it changes to a pointer
; when the mouse moves off the handle, it reverts back to the default cursor; and, when the user begins to drag the slider handle, the cursor style remains fixed as a pointer
regardless of its position.
"signals": [
{
"name": "dragging",
"init": false,
"streams": [
{"type": "@handle:mousedown", "expr": "true"},
{"type": "mouseup", "expr": "false"}
]
},
{
"name": "cursor",
"streams": [
{"type": "dragging", "expr": "dragging ? 'pointer' : 'default'"}
]
}
],
"marks": [
{
"name": "handle",
"type": "symbol",
"properties": {
"hover": {
"cursor": {"value": "pointer"}
}
}
},
]