Widgets — MARV Robotics 3.4.0 documentation

# Widgets

The frontend detail view consists of sections displayed as tabs containing widgets. Specific nodes produce the output rendered by the frontend into sections and widgets. See Tutorial: Write your own nodes for an introduction to this.

Section nodes are decorated with `@marv.node(Section)` and push a dictionary with title and a list of widgets:

    section = {'title': 'Section title', 'widgets': [widget, ...]}

Widget nodes are decorated with `@marv.node(Widget)` and push a dictionary with an optional title and one key corresponding to a `widget_type` (e.g. `image`) and `value` with data extracted from a dataset to be rendered by the widget (e.g. `{'src': 'img/path'}`.

    widget = {'title': 'Widget title', widget_type: data}

Widgets are either rendered directly into a section or are used as part of another composite widget, e.g. an `image` in a `gallery` (see below).

Valid values for `widget_type` are given in the following sections. The `title` key is optional and omitted for brevity.

## Image

    image = {'image': {'src': img.relpath}}

Example: Image used inside gallery `marv_robotics.detail.galleries()`

## Gallery

    gallery = {'gallery': {'images': [image, ...]}}

Example: `marv_robotics.detail.galleries()`

## Video

    video = {'video': {'src': videofile.relpath}}

Example: `marv_robotics.detail.video_section()`

## Trajectory

The trajectory widget renders a list of layers on top of each other.

    {'zoom': {'min': -10, 'max': 30},
     'layers': [
         {'title': 'Vector floor map',
          'geojson': geojson_object1},
         {'title': 'Trajectory',
          'color': (0., 1., 0., 1.),
          'geojson': geojson_object2},
     ]
    }

The zoom value defines the valid zoom range that will be enforced in the frontend. Each layer in the list is defined by its name that is displayed in the legend, an optional legend color, and its GeoJSON definition.

The geojson value conforms the official GeoJSON format specification, and adds a few styling extensions. For now the widget supports a subset of the GeoJSON standard. The widget expects a feature collection as the toplevel GeoJSON object and the supported geometries are LineString and Polygon.

    {'feature_collection': {'features': [
     {'geometry': {'line_string': {'coordinates': coord_list}},
      'properties': {'coordinatesystem': 'WGS84',      # or `cartesian`
                     'color': (0., 1., 0., 1.),        # per geometry color
                     'colors': color_list,             # or per vertex color list
                     'fillcolor': (0., 1., 0., 1.),    # per geometry fillcolor
                     'fillcolors': fillcolor_list,     # or per vertex fillcolor list
                     'width': 4.,                      # line or polygon stroke width
                     'timestamps': timestamp_list,     # per vertex timestamp used for playback
                     'rotations': rotations_list,      # per vertex rotations if markers are used
                     'markervertices' marker_geometry, # rotation marker polygon (e.g. `[0, 0, -1, .3, -1, -.3]`)
                     }},
    ]}}

The properties object holds styling and animation information for the trajectory player widget. Properties should at least define one of the color values, apart from that all entries are optional. The default coordinatesystem is WGS84 which is used per default in the GeoJSON standard and in sensor_msgs/NavSatFix Message. The value cartesian allows the use of any Cartesian coordinate system.

Colors can be given either as a per geometry value or as a list of values for each vertex in the geometry.

The width value corresponds to the rendered line width in pixels. When the geometry is of type polygon and either of color or colors is set, then a stroke of width pixels is rendered.

EE only: The presence of a timestamps list enables the player functionality. This option works only with geometries of type LineString and should hold one value per geometry vertex. The widget assumes that the timestamps are in ascending order, as usually delivered by a GPS sensor.

EE only: The presence of a markervertices enables rendering of a marker at the current trajectory location during playback. The triangle size is not affected by zoom. If not set explicitly its rotation is calculated by the last significant heading from the coordinates.

EE only: The rotations list can be used to set the rotation of the marker at each coordinate. Each value is a scalar indicating the rotation around the z axis, e.g. obtained from an IMU. The rotation angles have to be given counter clock wise in radians, with zero pointing in the direction of the x axis.

Example: `marv_robotics.detail.trajectory_section()`

## Table

Example: `marv_robotics.detail.bagmeta_table()`

## Key/value

Example: `marv_robotics.detail.summary_keyval()`

## Preformatted

Wraps data into an html `<pre></pre>` tag.

    pre = {'pre': 'foo\nbar'}

## Custom

Renders custom widgets.

    custom = {'custom': {'type': 'foo', 'data': json.dumps(data)}}

Create `site/frontend/custom.js` and restart your instance to customize widgets and formatters.

    /*!
     * Copyright 2016 - 2018  Ternaris.
     * SPDX-License-Identifier: CC0-1.0
     */

    window.marv_extensions = {
      formats: {
        // replace default datetime formatter, show times in UTC
        'datetime': function(date) { return new Date(date).toUTCString(); }
      },
      widgets: {
        // rowcount widget displays the number of rows in a table
        'rowcount': [
          /* insert callback, renders the data

            @function insert
            @param {HTMLElement} element The parent element
            @param {Object} data The data to be rendered
            @return {Object} state Any variable, if required by remove
          */
          function insert(element, data) {
            const doc = element.ownerDocument;
            const el = doc.createTextNode(data.rows.length + ' rows');
            element.appendChild(el);

            const state = { el };
            return state;
          },

          /* remove callback, clean up if necessary

            @function remove
            @param {Object} state The state object returned by insert
          */
          function remove(state) {
            state.el.remove();
          }
        ]
      }
    };

Beginning with MARV 18.04 (2018-04-30) frontend styling is not based on Bootstrap v3 anymore. MARV now uses a custom style sheet with markup that is heavily inspired by Bootstrap v4 and is still undergoing improvements. Custom widgets can make use of existing CSS classes to achieve an identical look and feel to the native widgets. If stability is key, it is advisable to style custom widgets independently of MARV with their own style sheets to avoid migration pains during future MARV updates. Each widget is rendered in a container with the CSS class `.widget-${name}`, and any custom CSS should be scoped to children of these containers.