Publish Custom Cross-Visual Filters

This applies to: Visual Data Discovery

You can build and enable your own custom cross-visual filters. An example is provided below.

If you use date-time fields in your custom cross-visual filters, they must be in the format required by Symphony. See Date-Time Formats in Cross-Visual Filters for information on the required date-time format and an example for how to convert your data to the required format.

// START: PUB/SUB COMMON SECTION
// An embedding application should listen for the 'composer-dashboard-ready' event
// BEFORE attempting to publish or subscribe to cross-visual filters. The code below
// should be specified at the beginning of both publish and subscribe Javascript code.

const DASHBOARD_READY_EVENT = 'composer-dashboard-ready';
  const pubSubReady = new Promise((resolve) => {
    const resolvePubSubReady = (message, publisherId) => {
      resolve();
      document.removeEventListener(DASHBOARD_READY_EVENT, resolvePubSubReady);
    }
    document.addEventListener(DASHBOARD_READY_EVENT, resolvePubSubReady);
  });
/* END: Pub/Sub common section */

/* START: Publish to Cross-Visual Filters */

// The following code represents the From and To date pickers on the
// embedding application's page that allow users to filter the data by
// a date range.  The BETWEEN operator is used for the link name
// defined in the dashboard called 'LaunchedDate'. Note that the first part of
// this code converts the date-time data to the format expected by Composer.

const dateFromInput = document.getElementById('date-from');
  const dateToInput = document.getElementById('date-to');

const formatDate = (date) => {  
    const d = new Date(date);
  const year = `${d.getFullYear()}`;
    let month = `${d.getMonth() + 1}`; 
  let day = `${d.getDate()}`;
    if (month.length < 2) {    
      month = `0${month}`;
    }
    if (day.length < 2) {
      day = `0${day}`;
    }

    return `${year}-${month}-${day}`;
  }
  
  const getEndOfDayString = dateString => `${dateString} 23:59:59.999`;
  const getStartOfDayString = dateString => `${dateString} 00:00:00.000`;

    const dateInputChangeHandler = (event) => {    
        const dateFromInputValue = dateFromInput.value;
        const dateToInputValue = dateToInput.value;

      const dateFrom = dateFromInputValue ? new Date(dateFromInput.value) : null;    
      const dateTo = dateToInputValue ? new Date(dateToInput.value) : null;

        const dateFromString = dateFrom ? formatDate(dateFrom) : null;
        const dateToString = dateTo ? formatDate(dateTo) : null;
   
        const dateTimeFromString = dateFromString ? getEndOfDayString(dateFromString) : null;
      const dateTimeToString = dateToString ? getStartOfDayString(dateToString) : null;

        let operation = 'BETWEEN';
      let value = [dateTimeFromString, dateTimeToString];

          if (!dateTimeFromString) {
          operation = 'LT';
          value = dateTimeToString;
        }

          if (!dateTimeToString) {
          operation = 'GT';        
          value = dateTimeFromString;
        }

          let publishObject = {
            type: 'selection',
            valueType: 'TIME',
            ranges: [
                {
                  operation: '<operation>',
                  value: '<value>'
                }
            ]
        }


          if (!dateTimeFromString && !dateTimeToString) {
          publishObject = null;
        }
       
        pubSubReady.then(() =>  embedManager.publish('LaunchedDate', publishObject));
      }

      dateFromInput.addEventListener('change', dateInputChangeHandler);
      dateToInput.addEventListener('change', dateInputChangeHandler);

// This represents a drop-down field on the embedding application's page that 
// lists a set of countries the user can filter by. After selecting a value,
// the embedding application calls its 'publishValue' function, defined
// below with the link name '<linkname> and the selected country value.
// The link name is defined in the dashboard. To clear the value filter,
// make sure you pass a null value as shown below.

      const fieldSelect = document.getElementById('field-select');
      fieldSelect.addEventListener('change', (event) => { 
          const value = event.target.value;
          const publishObject = value !== 'null' ? {
              type: 'selection',
              valueType: 'ATTRIBUTE',
              ranges: [
                {
                  operation: 'IN',
                  value: '<value>'
                }
              ]
          } : null;
          pubSubReady.then(() =>  embedManager.publish('Country', publishObject));
        });
/* END: Publish to Cross-Visual Filters */

The publish Method

The publish method publishes a message (filter) for a specific cross-source or same-source link (channel). Publishing a link filter causes any subscribing handlers for the link to be called and passed the filter message. There is no registration process for a link, simply call the publish method with a link name and it will be created. No value is returned.

The publish Properties

The properties for the publish method of the Zoomdata class are described in the following table.

Property/Object Description
<linkName>

The link (channel) name. Link names can be custom names, specified when a cross-source link is created, or names in the format <source-name>.<field-name>, automatically generated for every field in a data source for same-source links.

The link name is defined when you define a cross-source link. See Define Cross-Source Links. It is published for use by a dashboard as a cross-visual filter. See Publish a Link. The link name represents the channel into which the message should be published. It is typically called a topic in standard publish/subscribe systems.

There is a one-to-one relationship between cross-source link names and your data fields. You cannot use the same link name for multiple data fields. In addition, you cannot create multiple cross-source links for the same data field.

Type: string

<message>

The message sent with the link. The message published can either be an arbitrary object or null. An object published to a link channel is not restricted to any particular structure but a Symphony dashboard only recognizes messages in the structure described in The publish Filter Message Structure.

Publishing a null message can clear the last published message from the channel. If the last published message's publisherId matches the null message's publisherId, the last message is removed from the channel and subscribers receive a null message. If the publisherId of the last published message on the channel does not match the null message's publisherId, nothing happens.

The most recently published message on each channel is stored and sent to new subscribers at the time of subscription.

Type: object or null

<options>

Options for how the link should be applied. All values are optional. Options include:

  • options.publisherId: An arbitrary sting identifying the publisher of the link. This can be used to handle subscriptions differently based on publisher. For example, a subscriber may decide not to apply messages they posted themselves.

  • options.timestamp: A number representing the time at which the link is published. It defaults to Date.now().

  • options.targetComponents: A string that allows the publisher to target only specific dashboards when more than one dashboard is embedded on a page. If not provided, it applies the link to all embedded dashboards. To target a component, add its componentInstanceId (provided in the return from the call to embedManager.createComponent).

Type: object

The publish Filter Message Structure

All filter messages (cross-visual filters) that can be consumed by Symphony or that will be published by Symphony must conform to the following structure. The value of the type property defines the structure of the rest of the message.

Property Description
type: 'selection'

Only a value of selection is supported at this time, identifying a selection of values on a visual or widget. This signifies that the message is a SelectionMessage.

Type: string

valueType: 'NUMBER'

Identifies the type of value being selected. The following value types are supported:

  • ATTRIBUTE - Use for string values
  • NUMBER - Use for integer and floating point values
  • TIME - Use for date and date-time values

Type: string

ranges

An array of selected ranges. The set of allowed operations depends on the specified valueType. Currently only a single range is supported per message (filter). Ranges after the first range will be ignored. Ranges should be structured as follows:

ranges: [
   {
      operation: '<operation>',
      value: '<value>'
   },
]

The operation and value properties are described next.

Type: array

operation: 'EQUALS'

The filter operation. Supported operations include:

  • IN - Includes. Supported for ATTRIBUTE and NUMBER valueTypes. Provide an array of values for value.
  • NOTIN - Excludes. Supported for ATTRIBUTE and NUMBER valueTypes. Provide an array of values for value.
  • BETWEEN - Between. Supported for NUMBER or TIME valueTypes. Provide a two-item array of the start and end values for value.
  • GT - Greater Than. Supported for NUMBER or TIME valueTypes. Provide a single value to compare against for value.
  • GE - Greater Than or Equal To. Supported for NUMBER or TIME valueTypess. Provide a single value to compare against for value.
  • EQUALS - Equal To. Supported for NUMBER or TIME valueTypess. Provide a single value to compare against for value.
  • NOTEQUALS - Not Equal To. Supported for NUMBER or TIME valueTypess. Provide a single value to compare against for value.
  • LE - Less Than or Equal To. Supported for NUMBER or TIME valueTypess. Provide a single value to compare against for value.
  • LT - Less Than. Supported for NUMBER or TIME valueTypess. Provide a single value to compare against for value.

Type: string

value: '6'

Provide a value as described for each filter operation.

Type: string, number, array<string | number | null>