Skip to Content

What's Coming in Design Studio 1.4 SDK

During Design Studio 1.4 development we were able to put some improvements into the Design Studio SDK. Now, as most of the new features of Design Studio 1.4 are announced, it is time to lift the covers from this stuff, which you as a SDK component developer may find useful.

New Extension Types

Design Studio 1.4 supports two new extension types:

CVOM/Lumira SDK Chart Extensions

Both Design Studio and Lumira use a common chart library implemented by colleagues from Shanghai and having about 100 built-in chart types. Since a few months this chart library can even be extended with custom chart types using an new SDK. You can use this SDK, originally called CVOM SDK, now Lumira SDK, to implement new visualizations for Lumira. You can import such a new vizualization for Lumira into Design Studio using this menu item in Design Studio:

The CVOM SDK defines concepts and APIs of its own that differ significantly from the Design Studio SDK. This is necessary, as the CVOM SDK forms a common abstraction layer over the data model of Lumira, Design Studio, and potential other chart containers.

The CVOM SDK also provides a tool called VizPacker that comes with Lumira Desktop. It's a kind of IDE to create and pack extensions. An extension is a ZIP file containing some JavaScipt files and metadata in JSON format. When you import such an extension into Design Studio, it is wrapped into an Eclipse plugin conforming to the Design Studio SDK specification. Thus you can manage it (deploying it to BIP, NW, or HANA) like any other Design Studio SDK extension.

Should you implement a component as a Lumira SDK extension or a Design Studio SDK extension? Here are my thoughts:

  • If it is a chart AND
  • it should be used in both Design Studio and Lumira products AND
  • it doesn't need to fire Design Studio scripting events nor contribute itself to Design Studio scripting

you should consider using the Lumira SDK. Otherwise consider using the Design Studio SDK.

Custom Data Sources


Up to now you can only use data sources based on

  • BW Cubes and Queries
  • HANA Analytic and Calculation Views
  • BI Universes (some supported types)

Now you can implement your own data sources.Here are some ideas what you could do:

  • Connect to a Web Service delivering real time data (for example stock quotes)
  • Connect to a data base (for example exposed by a Web Service)
  • Load a CSV file and provide the data
  • Combine the data of two data sources
  • Enrich data from a data source with extra rows and columns, including simple calculations

Custom data sources are very similar to data-bound SDK components. But instead of consuming data in Design Studio SDK's JSON format, they produce it:

Because custom data sources produce Design Studio SDK JSONs, they can be used with any data-bound Design Studio SDK component and SAP charts. Thus, the components that don't work with custom data sources are the Crosstable and the filter components like Filter Panel, Dimension Filter, etc).

Implementing a data source is not very different from implementing a component: You need

  • a contribution.xml file (using handler_type="datasource")
  • a contribution.ztl file and
  • a handler JavaScript file.

In the handler JavaScript file you can choose from building your custom data source on one of two provided base classes:

  • Implementing a data source directly on the SdkDataSource base class requires you to implement the function fetchData(oSelection, oOptions). This may be challenging as you are responsible to implement aspects like selecting the appropriate data, etc. on your own.
  • To make it easier, you may consider using the base class SdkDataBuffer. It provides the easy-to-use function setDataCell to fill a data buffer and several other helper functions. All details like, for example, selecting data and creating the correct JSON are already built-in this base class.

We will post more information later -- at the latest with the official release of the product -- including an updated Developer Guide and several new samples, for example this one:

General Improvements

Delta Rendering


A feature that was planned from the beginning of the SDK, which finally made it into Design Studio 1.4, is the technique only to send changed properties over the wire. This will improve performance. In the past, all properties were sent with any change in the SDK component. The setter was only called for modified properties. This was achieved by a trick: The getter was called first and only if the new property value was different, the setter was called. Now the backend calculates if a property might need an update. Thus the getter is not called anymore before the setter.

If you rely on the call to the getter, you might need to adjust your component.

New Method

The new method this.firePropertiesChangedAndEvent(aProperties, sEvent) is like a combination of

  • firePropertiesChanged(aProperties) and
  • fireEvent(sEvent)

but is faster, as there is only one round-trip needed.

Improvements for Data-Bound Components

Options for Data-Bound Properties

Currently the only way to customize which data a data-bound property receives is the property type. In Design Studio 1.4 we now introduce the possibility to specify options for data-bound properties. In your contribution.xml file you specify them as <option> sub-element of your property. Here is a data property of the SimpleCrosstab sample SDK extension updated for Design Studio 1.4:

<property id="data" title="Data Selection" type="ResultSet"  group="DataBinding">

  <option name="includeFormattedData" value="true"/>

  <option name="includeData" value="false"/>

</property>

The new options allow you to finer control what data you need. There are also some options to request which data - which was not available so far. Especially the includeFormattedData option is great for table-like SDK components that simply show cell data without additional calculations or formatting.

The following table lists the available option names of data-bound properties:

Option Name

Description

includeAxesTuplesIf true then the JSON properties axis_rows and axis_columns are included in the Data Runtime JSON. They contain the tuples of the row axis and column axis.
includeTuplesIf true then the JSON property tuples is included in the Data Runtime JSON. It contains the tuples of the data.
includeResultsIf true then the result values, for example totals, are included in the Data Runtime JSON.
presentationDelimiterString that separates presentations of dimension member values in the text JSON property of dimension members in the Metadata Runtime JSON
selectionShapeInteger value that indicates the geometry of the data in the Data Runtime JSON. Valid values are: 0 (ResultCell), 1 (ResultCellList), or 2 (ResultCellSet orResultSet).
swapAxesIf true then the axes (and the relevant data) are swapped (transposed) in the Data Runtime JSON and Metadata Runtime JSON.
includeDataIf true then the JSON property data is included in the Data Runtime JSON. It contains the data values (float numbers or null).
includeFormattedDataIf true then the JSON property formattedData is included in the Data Runtime JSON. It contains the formatted data values as strings.
includeMetadataIf true then the Metadata Runtime JSON is included as a part of the Data Runtime JSON.
fillMetadataPropertyIf true then the SDK component's implicit property metadata contains the Metadata Runtime JSON.

You should consider to modify your component to ask for just the data that your code needs. Less data sent over the wire makes your component faster.

In fact, the new options remove the need for different data-bound property types. Now the difference between ResultCell, ResultCellList, ResultCellSet, and ResultSet are simply different default values:

Default Value for Property Type...
Option NameResultCellResultCellListResultCellSetResultSet
includeAxesTuplesfalsefalsefalsetrue
includeTuplestruetruetruetrue
includeResultstruetruetruetrue
presentationDelimiter||||
selectionShape0122
swapAxesfalsefalsefalsefalse
includeDatatruetruetruetrue
includeFormattedDatafalsefalsefalsefalse
includeMetadatafalsefalsefalsetrue
fillMetadataPropertytruetruetruefalse

External Measures

There are cases when measure dimensions are neither on the rows nor on the columns of a result set (having field "containsMeasures=true"): In the Query Designer or the Initial View Editor you could have filtered your measures structure to a single member and then put it into the background or free axis.

In the Design Studio 1.3 SDK you would get a number, but no metadata about the number, for example no format string, no scaling factor, etc. Now you receive metadata about the measure in a new field:

"dimensions": [ */ here are the normal dimensions on columns and rows */ ],

"externalDimensions":[

           {

            "key":"Keyfigures",

            "text":"Key\x20Figures",

            "axis":"FREE",

            "axis_index":2,

            "containsMeasures":true,

            "members":[

             {

              "key":"0D_NWI_NSAL",

              "text":"Net Sales",

              "scalingFactor":0,

              "unitOfMeasure":"$",

              "formatString":"#,##0.00 $;'-'#,##0.00 $"

             }

            ]

Note that custom data sources are also responsible to create such field if needed - and the data buffer provides some help for it.

New Runtime JSON Properties

If you have a data-bound property of type ResultCellSet, it is quite difficult to create the 2-dimensional layout for the data, as you receive the data in a 1-dimensional array that was filled line by line. To break up the latter array into the correct rows, you need the number of columns - with the new JSON property rowCount. For completeness, there is also a columnCount JSON property. If your property is ResultCellList or ResultCell one or both of the JSON properties are 1.

Advanced Features

There are some new features that are quite tricky and complicated, but could be valuable for some advanced users and use cases.

Limited Require.JS Support

To support the CVOM SDK we needed a way to use require.js modules. Require.js is a module system for JavaScript. It allows to load JavaScript files asynchronously and informes you once the needed module is available. The best thing however is that you get rid of global variables. Anything a require.js module provides is injected into the caller's callback.

Design Studio was initially developed without require.js. However, many open source libraries detect if require.js is present and behave differently, for example by not exposing global variables and defining a require.js module.

Unfortunately, in Design Studio 1.3 it can happen that require.js is loaded. This happens if the page contains a chart: The CVOM libraries contain require.js - and if the open source library that comes with your SDK component is loaded after CVOM, it might behave strange. You may see require.js error messages and the expected global variables are missing.

In Design Studio 1.4 you can load all require.js/AMD enabled libraries with require.js instead of including them via <jsInclude>:

sap.zen.Dispatcher.instance.require(["path1/module1", "path1/module1"], function(module1, module2) {

  sap.designstudio.sdk.Component.subclass("com.sap.sample.coloredbox.ColoredBox", function() {

      // Your handler code here, using module1 and module2

  });

});

You need to use the function sap.zen.Dispatcher.instance.require instead of normal require to ensure that your handler is not used to early. The Design Studio JSON processing is automatically delayed util all modules are loaded. The module names/paths are relative to your handler file. If the name is unique, there is even a chance to load different versions of the same libraries without conflict. SAP would however not guarantee that this will always work.

Binding Events to Design Studio Script Methods

Normally, an SDK component can't modify data sources or other components, at least not directly. Of course, a component can expose an event and in the event handler the user of the component can write some Design Studio script that does some modification, for example, DS_x.setFilter, etc. But the SDK component so far has no direct access to the Design Studio script API.

Now this is possible, even if it is kind of indirect:

  1. Define an invisible property of type ScriptText.
  2. Define one or more visible or invisible properties that transport the arguments that you need for Design Studio scripting.
  3. In your contribution.ztl, define a private function. In the body you can call any Design Studio script function you want, including the full JavaScript language.
  4. Bind the event to the Design Studio script method.

The following snippets show how a component could call the Desing Studio script method clearFilters() with a given dimension name.

In the contribution.xml file we define an invisible even onclear and an invisible property for the dimension parameter called dimension.

<sdkExtension ...>

  <component ...

    <jsInclude>res/js/component.js</jsInclude>

    <property

      id="onclear"

      type="ScriptText"

      visible="false" .../>

     <property

      id="dimension"

      type="Script"

      visible="false" .../>

    <initialization>

      <defaultValue property="onclear">this.doClearFilter();</defaultValue>

    </initialization>

  </component>

</sdkExtension>

In the initialization section we bind the onclear event to the doClearFilter Design Studio script method.

The function itself is marked private so that it can't be called from normal Design Studio scripts. It also uses getDataSource() to access the bound data source and call the Design Studio scipt method clearFilters, passing in the value of the invisible field dimension.

@Visibility(private)

void doClearFilter() {*

    this.getDataSource().clearFilters(this.dimension);

*}

On Browser side, you can now invoke your Design Studio script method with this snippet:

this.dimension("Dim1");

this.firePropertiesChangedAndEvent(["dimension"], "onclick");

First you set the invisible dimension property to the value you like. Then you tell the server that the property value has changed and fire the invisible event.

Pseudo Event "onBeforeRender"

In conjunction with the Design Studio script event binding described before, there is another little powerful feature: the built-in pseudo event beforeRender.

This event happens always before the properties are send from server to browser. It allows you to call some Design Studio script methods to initialize some (invisible or visible) properties before they are sent to your handler JavaScript.

Imagine you want to implement a listbox that automatically displays all dimensions of a bound data source. Here is what you have to do:

  • Create a invisible property, for example, dimensions.
  • Bind the onBeforeRender event to a private Design Studio script method, for example, beforeRender.
  • In onBeforeRender call the Design Studio script method getDimensions(), stringify the result and assign it to your dimensions property.
  • In you handler JavaScript file receive the dimensions property, parse it to a JSON and fill you listbox.

Note that in the onBeforeRender event you are only allowed to perform "read-only" operations, like getDimensions(), getMembers(), getData(), etc., but not modifying operations like setFilter().

That's all for Design Studio 1.4. Let's see how long the list will be for coming releases. I'm looking forward to your comments, proposals, suggestions, etc.