Initial Objective statements


This post is about getting D3 connected as an extension to Thingworx.

There are a number of existing extensions using D3 but I wanted to explore a simple use case to make it easier to get into and bring out 2 additional points

  • Using an infotable as data input
  • Resize

The output looks like the image below


and the data was generated by a Timer based random value generator that set the values on a Thing every minute.

The data into the Widget is from a core service QueryHistory (a wrapped service that uses QueryProperyHistory)


In this example I will use temp as the variable in focus


If you have never created an extension take a look at Widget Extensions Introduction which provides a start to understanding the steps defined below, which are the core points to keep it relatively short.

The extension will be called d3timeseries and will use the standard design pattern


Create a folder called d3timeseries and create a subfolder ui and a add a metadata.xml file to the d3timeseries

From there create the files and folder structure


define the metadata.xml using CDN url for

D3 url url=""

legend url = ""


Also check out which provides documentation and examples for D3

For the initial set of Properties that control the D3 will use


DataAsINFOTABLE (Data coming into d3)









Note: we are not using Width and Height as in previous articles but setting 'supportsAutoResize': true,


Below shows the general structure will use for the d3timeseries.ide.js properties

After deploying the extension  (take look at Widget Extensions Introduction to understand the how) we can see its now possible to provide Data input and some layout controls as parameters


From there we can work in the d3timeseries.runtime.js file to define how to consume and pass data to D3.


There a 4 basic function that need to be defined


  • this.renderHtml
  • this.afterRender
  • this.updateProperty
  • this.resize








The actual D3 worker is drawChart which I will break down the highlights

I use an init function to setup where the SVG element will be placed

The init is called inside drawChart

Next inside drawChart the rowData incoming parameter is checked for any content we can consume the expected rows object


Next the x and y ranges need to be defined and notice that I have hardcoded for d.timestamp and d.temp these 2 are returned in the infotable rows

The last variable inputs are the layout properties


Now we have the general inputs defined the last piece is to use D3 to draw the visualization (and note we have chosen a simple visualization timeseries chart)



Define a svg variable and use D3 to select the div element defined in the init function. Also remove any existing elements this helps in the resize call.

Get the current width and height as before




Now do some D3 magic (You will have to read in more detail the D3 documentation to get the complete understanding)


Below sets up the x and y axis and labels


Next define x and y scale so the visualization fits in the area available and actually add the axis's and ticks, plus the definition for the actual line const line = d3.line()



Now we are ready for the row data which gets defined as data and passed to the xScale and yScale using in the const line = d3.line()



After zipping up and deploying and using in a mashup you should get a D3 timeseries chart.








Code for the QueryHistory


logger.debug("Calling "+ + ":QueryHistory");



// result: INFOTABLE

var result = me.QueryPropertyHistory({

maxItems: undefined /* NUMBER */,

startDate: undefined /* DATETIME */,

endDate: undefined /* DATETIME */,

oldestFirst: undefined /* BOOLEAN */,

query: undefined /* QUERY */



Thing properties example




Random generator code


me.hum = Math.random() * 100;

me.temp = Math.random() * 100;


message = message + "Hum=" + me.hum+ " ";

message = message + "Temp=" +me.temp+ " ";


logger.debug( + "  RandomGenerator values= " + message );


result = message;





Previous Posts