Gauge Articles and Tutorials

Gauge Control

Author: Alexander Stoyan
Platform: Visual C++

Gauge Overview

The Gauge Control offers a versatile means to represent diverse numerical and state data, with flexibility, dynamism, and extensive customization options. Built entirely in Markup, it leverages Markup's rendering capabilities and adaptability. Codejock Gauges are fully DPI-responsive, maintaining drawing quality while scaled to any size. The actual gauge implementation is achieved through Codejock's proprietary JavaScript extension for XAML, simplifying the entry level for gauge developers. Furthermore, gauge configurations (traits) can be stored in either JSON format or dynamic JavaScript code that evaluates JSON configuration data.

Given the varied nature of data users may wish to represent on a gauge, along with the customization needs, our approach emphasizes remarkable flexibility in configuring gauges. This means a single implementation of a gauge can yield countless visual variations and behaviors by simply adjusting a traits configuration file without any code alterations. While Codejock offers basic pre-designed gauges, users can tailor more sophisticated ones to their exact requirements by tweaking the gauge traits configuration file. The aim of this article is to furnish comprehensive guidance on modifying the Gauge Control traits file.

Architecture

The following is a simplified overview of the Gauge architecture, outlining its fundamental components, including hypothetical ones:

Gauge Architecture

Let's break down each level of the Gauge architecture:

  • Gauge Control: At the highest level is the Gauge control itself. This control is placed on a window within the application interface. It offers methods and properties for loading and accessing the actual representation of the gauge, as well as its configuration, reflected data, and behavior.

  • Gauge Type: The next level of abstraction is the gauge type. Each Gauge control can operate on only one gauge type at a time, although the implementation doesn't limit the number of possible gauge types. A gauge type, by itself, doesn't perform much action. It primarily provides access to common properties specific to a particular abstract gauge type and ensures that any loaded gauge is compatible with its underlying type. Currently, the implementation provides only two gauge types:

    • Meter: Designed to represent numerical data within a certain range and dimensions. Its key properties include the displayed value, minimum and maximum possible values. Examples of Meter gauge types range from analogue or digital thermometers to speedometers, barometers, and more.

    • State: This type represents a finite number of states, with a basic property being a numerical identifier for the current state. Examples include light indicators for on/off states, battery or coverage level indicators, toggle switches, semaphores, and check marks.

  • Configuration Traits: Below the gauge types lie hypothetical gauge implementations. Each gauge type can load a single gauge implementation markup at a time, with no limitation on the number of possible gauges for a particular type. Each implementation resides in a separate XAML file, declaring all graphical primitives, while an embedded scripting block defines the gauge's behavior and appearance based on the provided configuration traits.

  • Gauge Implementations: Finally, the lowest level entails configuration traits. This layer comprises common traits utilized by all gauges, alongside unique traits specific to each gauge implementation for appearance and behavior configuration. Traits can be stored as fixed data in JSON format or within a JavaScript function definition signature, enabling dynamic trait evaluation. This flexibility allows for configurable traits, accommodating scenarios where resource paths are determined only upon gauge loading.

Each of these layers will be expounded upon in further detail within this article.

Gauge Loading

To initiate gauge loading, the process begins with loading its markup and traits. Once this step is successfully completed, the gauge becomes operable through its type object, which is accessible via the Gauge control object.

  1. Loading gauge traits from a JS file:

    ToolkitPro:
    IStreamPtr pTraitsStream;
    VERIFY(SUCCEEDED(XTPCreateReadOnlyFileStream(GAUGE_PATH _T("meter.digital.js"), &pTraitsStream)));

    Alternatively the following convenience functions can be used for loading traits of markup streams:

    XTPCreateFileStream, XTPCreateReadOnlyResourceStream, XTPCreateReadOnlyStreamOnUri

    SuitePro (VB):
    Dim Traits As New GaugeTraits
    Traits.Load GaugeDir + "meter.digital.js"
  2. Creating a traits collection object from the loaded data stream and specifying a resource path in the file system

    ToolitPro:
    CXTPGaugeTraits traits(*pTraitsStream);
    traits.SetResourcePath(GAUGE_PATH);
    SuitePro (VB):
    Traits.ResourcePath = GaugeDir

    When a gauge utilizes configurable images, typically the images need to be loaded from specific locations. Since the exact image resource location is often not known in advance, the traits only specify the image file names and utilize the provided resource path to construct the actual file locations. It's important to note that resource file locations aren't limited to the file system; they can also be loaded from a resource module. This approach enables the consolidation of a library of gauges, along with their resources and related scripts, within a single resource DLL. In such cases, the resource location must be specified as a resource module:

    ToolkitPro:
    HMODULE hGaugeLib = ...;
    CXTPGaugeTraits traits(*pTraitsStream);
    traits.SetResourceModule(hGaugeLib);
    SuitePro (VB):
    Traits.ResourceModule = ModuleHandle
  3. (optional) Traits customization

    In certain cases it may be required to override known trait values before loading a gauge as some traits may get appliled only once upon gauge loading and cannot be changed at runtime. Each of such value can be customized using CXTPGaugeTraits::SetCustomTrait method with a full JSON object path specified in JavaScript syntax and a new value.

    ToolkitPro:
    traits.SetCustomTrait(_T("transparent"), COleVariant(VARIANT_TRUE, VT_BOOL));
    traits.SetCustomTrait(_T("backgroundColor"), L"#ff00ff");
    traits.SetCustomTrait(_T("dimensions[1].transition.effect"), _T("easeInBounce"));
    SuitePro (VB):
    Traits.SetCustomTrait "transparent", True
    Traits.SetCustomTrait "backgroundColor", "#ff00ff"
    Traits.SetCustomTrait "dimensions[1].transition.effect", "easeInBounce"
  4. Loading gauge markup

    ToolkitPro:
    IStreamPtr pGaugeStream;
    VERIFY(SUCCEEDED(XTPCreateReadOnlyFileStream(GAUGE_PATH _T("digital.markup.xaml"), &pGaugeStream)));
  5. Loading the gauge into the Gauge control

    ToolkitPro:
    CXTPGaugeMeterType* pMeterGauge = m_wndGauge.LoadMeterType(*pGaugeStream, traits);
    VERIFY(NULL != pMeterGauge);

    For this particular example CXTPGaugeCtrl::LoadMeterType is used because a digital gauge is of the Meter type. If it was a gauge of the State type then the CXTPGaugeCtrl::LoadStateType would have to be used instead.

    SuitePro (VB):
    If ctlGauge.LoadMeterType(GaugeDir + "digital.markup.xaml", Traits) Is Nothing Then
      ' Unable to load
    End If
  6. Updating gauge state via its type specific object:

    ToolkitPro:
    pMeterGauge->SetCurrent(nNewValue);
    pMeterGauge->Update();
    SuitePro (VB):
    With ctlGauge.Type.Meter
        .Current = 50
        .Update
    End With

    Some gauge traits are used only once when a gauge is being loaded, so changing their value later has no effect, for such traits consider traits customization described earlier. And changing those traits that can be updated at runtime should follow a call of the Update method for the changes to take effect.

Gauge Markup

All gauge markup script must adhere to a standardized structure at the top level and include a defined script entry. Below is an empty template for a Meter gauge. Templates for gauges of different types will share the same structure, with only the type name and common default traits specified in the GaugeLib.init call differing. It's essential to keep all named markup objects with their pre-defined attributes unchanged across all gauges. While the detailed walkthrough of the actual gauge implementation is omitted in this article, a shallow overview is provided to enhance understanding of its structure.

<Page
     xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
     xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
     xmlns:xtp='urn:schemas-codejock-com:xaml-extensions'>
 
   <Viewbox Stretch='Uniform'>
     <Canvas Name='Canvas' HorizontalAlignment='Center' VerticalAlignment='Center' Background='{x:Static SystemColors.WindowBrush}' Width='1000' Height='1000'>
       <Image Name='Back' Canvas.Left='0' Canvas.Top='0' Width='1000' Height='1000'/>
       <Image Name='BackOverlay' Canvas.Left='0' Canvas.Top='0' Width='1000' Height='1000'/>
 
       <!-- Gauge specific markup goes here -->
 
       <Image Name='FrontOverlay' Canvas.Left='0' Canvas.Top='0' Width='1000' Height='1000'/>
     </Canvas>
 
     <xtp:Script Language='JScript' Requires='lib:runtime, lib:gauge'>
     // <![CDATA[
 
     function onInit() {
         // TODO: required gauge initialization handler
     }
 
     function onUpdate() {
         // TODO: required gauge update handler
     }
 
     function onInput(message, wParam, lParam) {
         // TODO: optional gauge input handler
     }
 
     function onShutdown() {
         // TODO: optional gauge shutdown handler
     }
 
     GaugeLib.init({
       init: onInit,         // required
       update: onUpdate,     // required
       input: onInput,       // optional
       shutdown: onShutdown, // optional
       traits: {             // required
         type: 'Meter',
 
         // Meter specific common default traits
         min: 0,
         max: 100,
         current: 0
       }
     });
       
     //]]>
     </xtp:Script>
 
   </Viewbox>
</Page>

Gauge Traits

As mentioned earlier, gauge traits can be represented either in JSON format or as a JavaScript function that returns an evaluated traits object. Additionally, there are several common traits that are not specific to any particular gauge. These include:

  1. backgroundColor: An optional string defining the background color value in XAML-compatible format (Red, White, Blue, etc.), or an RGB color in HTML format (e.g., #AABBCC). The default color value uses the system-defined window color.

  2. transparent: An optional boolean value specifying whether the gauge has a transparent background or not. Further explanation is provided below in this article. The default value is false. See Gauge transparency for more details.

  3. background: The only required common trait specifying an image to be displayed on the gauge background. Its value can be either a full image path or an image traits object. The format of an image traits object is described further in this article.

  4. backgroundOverlay: An optional image path or image traits object defining another image to be displayed on top of the background image.

  5. foregroundOverlay: An optional image path or image traits object defining another image to be displayed on top of all gauge elements. Combining background and overlay images allows for advanced effects such as glass, etc.

  6. viewboxStretch: An optional viewbox stretch mode constant defining how the XAML viewbox is stretched when the Gauge control size is changed. It can have one of the following values: None, Fill, Uniform, UniformToFill.

  7. actions: An optional JavaScript object that exposes a set of the traits specific actions to be invoked from the client code using CXTPGaugeBaseType::InvokeAction method call.

A simple JSON trait file for the Meter type could resemble the following:

{
    "backgroundColor"   : "Brown",
    "background"        : "file://C:\Data\MyGauge\background.svg",
    "foregroundOverlay" : "file://C:\Data\MyGauge\foreground-overlay.svg",

    "min"     : 0,
    "max"     : 100,
    "current" : 50
}

Certainly, hardcoded image locations are often not acceptable. Here's an example of how to define the traits file in JavaScript, allowing for the evaluation of image locations using the resource location information provided during traits loading in an application:

function (ctx) {
  var rt = ctx.libs['runtime'];
  return {
    backgroundColor   : 'Brown',
    background        : rt.resource('background.svg'),
    foregroundOverlay : rt.resource('foreground-overlay.svg'),
    min     : 0,
    max     : 100,
    current : 50
  };
}

The traits file will begin with the keyword function and contain the implementation of a single JavaScript function that returns an evaluated traits object. This function accepts only one argument, named ctx, which is an object structured as follows:

{
    arg: [object|null],
    libs: {
        runtime: [object]
    }
}

The arg object value is an optional object that can be specified in the client code during gauge traits collection initialization. Its sole purpose is to facilitate data exchange between the client code and traits execution for further customization. However, if a file or module resource path is specified for the traits collection after traits loading, the value of arg gets overwritten as follows:

  • File Resources:
    {
        protocol: 'file',
        path: '<PATH_VALUE>'
    }
  • Module Resources:
    {
        protocol: 'res',
        path: '#HEX_HANDLE'
    }

Where HEX_HANDLE is the hexadecimal representation of the resource module handle value. If custom arguments need to be combined with file or module resource locations, then the arg object value along with the protocol, path, and all necessary custom values must be manually built and provided as a string argument during traits collection initialization.

Traits evaluation can be simplified by leveraging the capabilities of JavaScript and the built-in gauge runtime library. For example, trait object templates can be utilized to define all common properties once and then derive a template object:

function (ctx) {
  var rt = ctx.libs['runtime'];

  var templates = {
    labels: {
      large: {
        cx: 2,
        cy: .2,
        rx: 1,
        ry: .8,
        foreground: '#282828',
        background: null,
        fontSize: 40,
        fontFamily: 'Arial',
        format: '%i'
      },
      small: {
        cx: 2,
        cy: .2,
        rx: 1,
        ry: .8,
        foreground: "#282828",
        background: null,
        fontSize: 30,
        fontFamily: 'Arial',
        format: '%i'
      }
    }
  };

  return {
    backgroundColor   : 'Brown',
    background        : rt.resource('background.svg'),
    foregroundOverlay : rt.resource('foreground-overlay.svg'),
    min     : 0,
    max     : 100,
    current : 50,
    text1   : rt.extend(templates.labels.large, {
        cx: 2,
        cy: .2,
        rx: 1,
        ry: .8,
        format: '-%i'
    }),
    text2   : rt.extend(templates.labels.small, {
        cx: 2,
        cy: .2,
        rx: 1,
        ry: .8,
        format: 'Value: %i'
    })
  };
}

Coordinate System

To ensure smooth scaling of the gauge elements without binding to fixed coordinates, the gauge coordinate system utilizes ranges [-1..1] across the Y and X axes. These axes are directed downward and to the right respectively, with the center point (0,0) positioned at the physical gauge center. Therefore, the top left gauge corner has coordinates (-1, -1), and the bottom right corner has coordinates (1, 1). All position values, absolute and relative offsets, element sizes, and point coordinates must be specified in this coordinate system in the trait files.

Image Traits

  1. An image can be specified in two different ways in a traits file:

    {
        icon  : rt.resource('icon.svg')
    }
  2. Using a JavaScript object that describes image properties such as size, relative offset, opacity, etc.:

    {
        icon: {
            // Image traits
            src     : rt.resource('icon.svg'),
            opacity : 0.5,
    
            // Location traits
            x       : 0.5,
            y       : 0.5,
            cx      : 0.2,
            cy      : 0.2,
            rx      : 0.01,
            ry      : 0.03,
            angle   : 45,
            crx     : 0.01,
            cry     : 0.01
        }
    }

    The numerical attributes of the image traits object can be animated (see Animations and transitions). The image traits object consists of the following properties:

  3. src: A required string that identifies image location to be used as a value of the Image.Source XAML attribute.

  4. opacity: An image opacity level in the range [0..1], where 0 makes the image fully transparent and 1 makes it fully opaque. The default value is 1. The location traits properties format is explained later in the article.

Font Traits

The font traits object describes text formatting options, for example:

{
    // Font traits
    fontSize: 10,
    fontFamily: 'Arial',
    foreground: 'Red',
    background: 'Black'

    // Location traits
    x       : 0.5,
    y       : 0.5,
    cx      : 0.2,
    cy      : 0.2,
    rx      : 0.01,
    ry      : 0.03,
    angle   : 45,
    crx     : 0.01,
    cry     : 0.01
}

The location traits properties format is described below.

Location Traits

The location traits are not a separate object by themselves, but rather a subset of common traits that specify element location. They are particularly used in image and text traits objects, and their properties have the following meanings:

  • x and y: The absolute coordinates of the top-left corner of the element. The default value for both is 0.

  • cx and cy: The displayed width and height of the element. If not specified, the actual element size is used.

  • rx and ry: The relative offset of the assumed top-left corner of the element from the real top-left corner coordinates. For example, if rx is set, then for all calculations where the element's top-left position is needed, the value will be computed as x + rx, while the element itself will remain at position (x, y). These are not used if not specified.

  • angle: The value of the element's rotation angle in degrees relative to its upright position. If specified, the element is rotated clockwise around its computed rotation center. The default value of 0 leaves the element in its default orientation.

  • crx and cry: the relative offset of the element's rotation center. It is always computed from the assumed top-left corner coordinates. If not specified, then the top-left corner serves as the rotation center. For example, if element traits are {..., cx: 1, cy: 1, crx: 0.5, cry: 0.5, angle: 45 }, then the element will be rotated exactly around its center instead of the top-left corner.

The location traits object can also include properties of the view traits object described below.

View Traits

The view traits are a subset of the properties that configure a view of an element or a set of elements. These properties can be included along with the location traits, or they can be part of a parent object or any other object that will be used as a source of view traits for a particular gauge implementation:

{
    // Top level traits
    background: rt.resource('background.svg'),
    min: 0,
    max: 100,
    current: 0,

    // Common view traits for images below
    zoom: 0.5,
    offset: { x: 0.5, y: 0.5 },

    icon1: rt.extend(templates.icon, {
      src: rt.resource('icon1.svg')
    }),
    icon2: rt.extend(templates.icon, {
      src: rt.resource('icon2.svg')
    }),
    icon3: rt.extend(templates.icon, {
      src: rt.resource('icon3.svg'),

      // View traits specific for Icon3
      zoom: 1,
      offset: { x: -1, y: -1 },
    })
}

The view traits properties include:

  • zoom: A multiplier value that is applied to all related location and size metrics of applicable elements.

  • offset.x, offset.y: The absolute offset values that get added to x and y location properties of applicable elements.

Animations and Transitions

Location, image, and text traits can be animated using a specified effect and animation time. Animation involves sequentially changing the specified numeric properties from their start to their stop values within the specified time frame, using the specified animation effect. A special traits object format is required to enable traits animation. For example, a static image can be described with the following image traits object:

{
  src: rt.resource('state0.svg'),
  cx: 1,
  cy: 1,
  x: -.5,
  y: 0
}

To achieve the desired effect of smoothly transitioning the image along the X-axis from left to right over half a second while simultaneously fading it in, an easing effect needs to be applied for a seamless transition. This can be accomplished by modifying the image traits object as follows:

{
  transition: {
    effect: 'easeInBounce',
    time: 500,
    res: 25
  },
  start: {
    src: rt.resource('state0.svg'),
    cx: 1,
    cey: 1,
    x: -.5,
    y: 0,
    opacity: 0
  },
  stop: {
    x: -.5,
    opacity: 1
  }
},

The transition object describes transition configuration:

  • time: Specifies animation duration represented in milliseconds

  • res: Specified animation resolution, i.e. the number of milliseconds after which the animated properties get updated.

  • effect: A required string that specified the easing effect to be used for this transition. The list of supported values is provided below, and detailed information along with preview of every easing method can be found at https://gizma.com/easing:

    • easeInSine
    • easeOutSine
    • easeInOutSine
    • easeInQuad
    • easeOutQuad
    • easeInOutQuad
    • easeInCubic
    • easeOutCubic
    • easeInOutCubic
    • easeInQuart
    • easeOutQuart
    • easeInOutQuart
    • easeInQuint
    • easeOutQuint
    • easeInOutQuint
    • easeInExpo
    • easeOutExpo
    • easeInOutExpo
    • easeInCirc
    • easeOutCirc
    • easeInOutCirc
    • easeInBack
    • easeOutBack
    • easeInOutBack
    • easeInElastic
    • easeOutElastic
    • easeInOutElastic
    • easeInBounce
    • easeOutBounce
    • easeInOutBounce The start object describes the initial state of the animated traits. In this example opacity: 0 is added to the initial image traits object to make image fully transparent when animation starts. The stop object describes the final state of the animated traits. In this example only animation of x and opacity properties is specified, their values will get updated during the animation execution, and other properties will remain intact.

Gauge Transparency

In the preceding section of this article, we discussed how transparency in gauges can be enabled by setting the backgroundColor: ... and transparent: true common traits. Once transparency is enabled, the specified background color serves as an alpha color key value. This means that any pixels matching that color value will become invisible. It's crucial to carefully select a background color that is entirely unique and not used in any images within the gauge. Additionally, this color should not result from semi-transparent image overlaps or animated color/opacity transitions. Otherwise, the gauge will display visual "holes" wherever that color appears.

Furthermore, it's important to note that due to the native implementation of child control transparency in the Windows operating system, certain application manifest entries need to be added.

<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
  <application>

    <!-- Windows 7 and Windows Server 2008 R2 -->
    <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />

    <!-- Windows Windows 8 and Windows Server 2012 -->
    <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />

    <!-- Windows 8.1 and Windows Server 2012 R2 -->
    <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />

    <!-- Windows 10, Windows 11, Windows Server 2016, Windows Server 2019 and Windows Server 2022 -->
    <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />

  </application>
</compatibility>

This also implies that gauge control transparency is supported only starting with Windows 7.

Meter Gauge Type

As mentioned before, the Meter gauge type is designed to represent numerical data within a certain range and dimensions. Its key properties include the displayed vaslue, minimum and maximum possible values. Examples of Meter gauge types range from analogue or digital thermometers to speedometers, barometers, and more. Currently only two Meter gauges are implemented, and this part of the article describes their traits. But first the required common Meter type traits will be covered:

  1. current: The currently displayed value. It must be in range determined by the min and max traits.
  2. min: The minimum allowed displayed value.
  3. max: The maximum allowed displayed value.
  4. dimensions: The array of traits object specific to each dimension.

When current, min and max are defined at the root level they defined a common default values for all dimensions that don't override those values. Once defined in a particular dimension they override the default common value. The dimensions array must be defined in the root traits object only.

For example, it is required to create a odometer gauge to represent the speed value in both metric and imperial unints on different scales, i.e. it has to have 2 scales with 2 pointers. This kind of Meter gauge will need to have 2 dimensions. Each dimension will have a common min value equal to 0 as speed cannot go below it, but the max and current values will be different. Regardless of the actual gauge implementation and its appearance, at the core of such a gauge will be the followg in traits structure:

{
  min: 0, // common for kph/mph
  dimensions: [

    // Metric scale (kph)
    {
      max: 200,
      current: 0
    },

    // Imperial scale (mph)
    {
      max: 124,
      current: 0
    }
  ]
}

All other traits are specific to each particular gauge implementation that are described below.

The Circular Meter gauge (meter.markup.xaml)

The Circular Meter gauge is designed to show round or arc scales with pointers, and provides the following features:

  1. There can be up to 5 scales
  2. Each scale's center position and dimensions can be configured
  3. Each scale has one pointer, a number of ticks, up to 2 optional icons, up to 2 optional labels (hints)
  4. A scale can be directed either clockwise or counter clockwise
  5. The start angle and a span of each can be configured
  6. The total number of ticks for each scale can be split in groups to have each tick group starting with a large tick
  7. Each small and large tick is an image object
  8. Each tick can have an associated label
  9. An individual tick appearance can be customized
  10. Each pointer is an image object
  11. Each scale icon if specified is an image object
  12. Each scale hint if specified is a font object
  13. A cap image can be displayed on top of all displayed scaled

The traits schema for the Circular Meter gauge:

{
  /* Common traits */
  ...

  /* Meter type traits */
  ...

  // Defines the cap image
  cap: { /* Image, View and Location traits */ },

  dimensions: [
    // Defines a particular scale
    {
      /* Optional Meter type traits to override Meter type traits at the top level */
      ...

      // Defines direction orientation
      clockwise: true | false,

      // Defines scale span and angle
      angle: {
        // Defines where the scale starts
        start: /* A numeric degree value in range 0..360  */,

        // Defines how long the scale spans
        span: /* A numeric degree value in range 0..360 */
      },

      // Defines scale pointer image
      pointer: { /* Image, View and Location traits */ },

      // Defines the scale itself
      scale: {
        // Defines scale ticks
        ticks: {
          // Defines the total number of ticks 
          count: /* A numeric number */,

          // Defines how many groups the ticks are split in
          split: /* A numeric number */,

          // Defines a small tick image
          small: { /* Image, View and Location traits */ },

          // Defines a large tick image
          large: { /* Image, View and Location traits */ }

          // An optional definition of individual tick apperance.
          // Each array element corresponds to a tick with with the same index.
          // Only not null elements get processed.
          custom: [
            { /* Image, View and Location traits */ },
            ...
          ]
        },

        // Defines tick labels
        labels: {
          // Defines label format for large ticks
          large: {
            /* Font, View and Location traits */

            format: /* An sprintf-like format string where the only placeholder will receive the current value */
          },

          // Defines label format for small ticks
          small: {
            /* Font, View and Location traits */

            format: /* An sprintf-like format string where the only placeholder will receive the current value */
          }
        }
      },

      // Defines the first optional hint label
      hint1: {
        /* Font, View and Location traits */

        format: /* Label text */
      },

      // Defines the second optional hint label
      hint2: {
        /* Font, View and Location traits */

        format: /* Label text */
      },

      // Defines the first optional scale icon
      icon1: { /* Image, View and Location traits */ },

      // Defines the second optional scale icon
      icon2: { /* Image, View and Location traits */ }
    },
    ...
  ]
}

The following below example shows a built in Circular Quarter Top-Left gauge traits:

function(ctx) {
  var rt = ctx.libs.runtime;
  var gaugeMin = 0;
  var gaugeMax = 10;
  var gaugePos = 0;
  var gaugeWidth = 1000;
  var gaugeHeight = 1000;

  return {
    backgroundColor: '#ababab',
    transparent: true,
    min: gaugeMin,
    max: gaugeMax,
    current: gaugePos,
    background: rt.resource('back.circ.quarter.top.left.svg'),
    cap: {
      src: rt.resource('cap.black.svg'),
      cx:  .25,
      cy:  .25,
      rx: -.58,
      ry: -.58
    },
    dimensions: [
      // Dim 0
      {
        clockwise: true,
        angle: {
          start: 0,
          span: 90
        },
        pointer: {
           src: rt.resource('pointer.black.large.svg'),
           x: .7,
           y: .71,
          cx: .2,
          cy: 1.5,
          rx: .068,
          ry: 1.5,
          crx: 0,
          cry: 1.2
        },
        scale: {
          ticks: {
            count: 51,
            split: 10,
            small: { 
              src: rt.resource('tick.grey.small.svg'),
               x: .7,
               y: .7,
              cx: .01,
              cy: .05,
              rx: .001,
              ry: 1.2
            },
            large: {
              src: rt.resource('tick.grey.large.svg'),
               x: .7,
               y: .7,
              cx: .02,
              cy: .13,
              rx: .001,
              ry: 1.2
            }
          },
          labels: {
            large: {
               x: .7,
               y: .7,
              cx:  10,
              cy: .2,
              rx:  5,
              ry:  1.375,
              foreground: '#3d5a80',
              background: null,
              fontSize: 60,
              fontFamily: 'Arial',
              format: '%i'
            }
          }
        },
        hint1 : {
          format: 'CODEJOCK SOFTWARE',
          x: .26,
          y: .9,
          cx:  2,
          cy: .2,
          foreground: '#c0c0c0',
          background: null,
          fontSize: 30,
          fontFamily: 'Arial'
        }
      }
    ]
  }
}

The Digital Meter gauge (meter.markup.xaml)

The Digital Meter gauge is designed to show numeric data on a digital-like screen. It provide the following features:

  1. It can have up to 5 indepdenent screens
  2. Each screen can have up to 20 digits
  3. Each screen can have its skew configured
  4. Each screen can have up to 2 icons and up to 2 labels
  5. Height, margins, digit thickness and position of each screen are configurable
  6. Thousands groupping can be enabled for each screen
  7. Active and inactive digit parts appearance are configurable
  8. Optional digit background and overlay images can be speicified

The traits schema for the Digital Meter gauge:

{
  /* Common traits */
  ...

  /* Meter type traits */
  ...

  // Optionally defines a common screen height to be used by all screens by default
  height: /* A numeric value in gauge coordinate system */,

  // Optionally defines a common digits margins to be used by all screens by default
  margins: {
    // Defines a horizontal margin value for a digit parts
    x: /* A numeric value */,

    // Defines a vertical margin value for a digit parts
    y: /* A numeric value */
  },

  // Optionally defines a common digit parts thickness for all screens to be used by default
  thickness: /* A numeric value */,

  // Optionally defines a maximum number of digits per screen for all screens to be used by default
  maxDigits: /* A numeric value in range 1..20 */

  // Optionally enable thousand groupping for all screens to be used by default
  groupThousands: true | false,

  // Optionally defines a skew angle for all screens to be used by default
  skew: // A numeric value

  // Optionally defines visual appearance of active digits parts for all screens to be used by default
  active: {
    // Defines an element fill color
    fill: /* A string value of an RGB color in XAML format */,

    // Defines an element stroke color
    stroke: /* A string value of an RGB color in XAML format */,

    // Defines an element stroke size
    strokeSize: /* A numeric value */
  },

  // Optionally defines visual appearance of inactive digits parts for all screens to be used by default
  inactive: {
    // Defines an element fill color
    fill: /* A string value of an RGB color in XAML format */,

    // Defines an element stroke color
    stroke: /* A string value of an RGB color in XAML format */,

    // Defines an element stroke size
    strokeSize: /* A numeric value */
  },

  // Optionally defines a digit background image for all screens to be used by default
  digitBackground: /* Image, View and Location traits */,
  
  // Optionally defines a digit overlay image for all screens to be used by default
  digitOverlay: /* Image, View and Location traits */,

  // Define gauge specific optional icons (not used by the screens)
  icon1: /* Image, View and Location traits */,
  icon2: /* Image, View and Location traits */,

  // Define gauge specific optional labels (not used by the screens)
  label1: {
    /* Font, View and Location traits */
    ...,

    format: /* Label text */
  },
  label2: {
    /* Font, View and Location traits */
    ...,

    format: /* Label text */
  },

  // Defines up to 5 digital screens
  dimensions: [
    {
      /* Optional Meter type traits to override Meter type traits at the top level */
      ...

      // Defines screen position in gauge coordinates
      position: {
        x: /* Numeric value */,
        y: /* Numeric value */
      },

      // Define screen specific optional icons
      icon1: /* Image, View and Location traits */,
      icon2: /* Image, View and Location traits */,

      // Define screen specific optional labels
      label1: {
        /* Font, View and Location traits */
        ...,

        format: /* Label text */
      },
      label2: {
        /* Font, View and Location traits */
        ...,

        format: /* Label text */
      },

      // Top level traits can be overriden for this particular screen:
      height: ...,
      margins: ...,
      thickness: ...,
      maxDigits: ...,
      groupThousands: ...,
      skew: ...,
      active: ...,
      inactive: ...,
      digitBackground: ...,
      digitOverlay: ...
    },

    ...
  ]
}

The following below example shows the built in Clock-HHMM gauge traits (reduced source):

function(ctx) {
  var rt = ctx.libs.runtime;
  var gaugeMin = 0;
  var gaugeMax = 0;
  var gaugePos = 0;
  var gaugeWidth = 1000;
  var gaugeHeight = 600;

  var clockHeight = .3;
  var dcx = clockHeight / 2;
  var pointSize = clockHeight / 8;

  var templates = {
    point: {
      src: rt.resource('clock.point.svg'),
      cx: pointSize,
      cy: pointSize
    }
  };

  return {
   actions: {
        init: function (gauge) { ... },
        setTime: function (gauge, time) { ... },
        runClock: runfunction (gauge) { ... },
        stopClock: function (gauge) { ... },
        setHourFormat: function (gauge, format) { ... },
        showLeadingZeros: function (gauge, show) { ... }
    },
    viewboxStretch: 'None',
    current: 0,
    background: rt.resource('clock.background.svg'),
    height: clockHeight,
    margins: { x: 7, y: 7 },
    thickness: 10,
    maxDigits: 2,
    groupThousands: true,
    skew: -5,
    active: {
        fill: '#a0c0ff',
        stroke: 'Orange',
        strokeSize: 2
    },
    inactive: {
        fill: '#777777',
        stroke: '#666666',
        strokeSize: 2
    },
    dimensions: [
      // Dim 0: Hours
      {
        position: { x: -dcx * 3, y: -dcx },
        min: 0,
        max: 23
      },
      // Dim 1: Minutes
      {
        icon1: rt.extend(templates.point, {
          x: -pointSize / 2,
          y: -dcx + dcx / 2
        }),
        icon2: rt.extend(templates.point, {
          x: -pointSize / 2,
          y: dcx - dcx / 2
        }),
        position: { x: dcx / 2, y: -dcx },
        min: 0,
        max: 59
      }
    ]
  }
}