Posted 03/13/2009 - 13:36 by jeremy.pitten
Extending Mashlet Maker with Custom Mashlets using a Custom BubbleChart Mashlet
Introduction
We decided to prepare a new sample Mashlet to showcase how you can extend Mashlet Maker in Presto 2.6.x using custom Mashlets as well as the capabilities of the BubbleChart chart type. First let's have a look at building the custom Mashlet.
A rich set of FusionChart chart types are bundled with Presto, only a few of them are used by the current set of sample mashlet types, such as the Bar, Line and Pie charts.
A sample Bubble Chart is provided on the FusionCharts web site, here.
The bubble chart enables us to plot 3 dimensions, the x and y axis coordinates together with the 3rd dimension represented by the bubble size.
This bubble chart screenshot is a plot of the top 20 stock movers.
- x axis plots the actual stock quote.
- y axis plots the change in stock quote
- z axis (bubble size) is the percentage change in quote.
- Colour is used to represent positive and negative values.
Notice that the bubbles are settling around the y-axis origin indicating little movement.
The large bubbles indicate big percentage changes in quote.
The bubbles further down the x-axis indicate higher the stock quotes.
Our attention tends to be drawn towards the isolated bubbles.
Requirements and Design Issues
The general requirement is to design a BubbleChart mashlet type which is capable of being configured with a single Presto service operation. The mashlet should allow the service operation request and response details to be configured using the mashlet Preferences.
The service operation can have one or more comma seperated non-complex input parameters asscoaited with it. So if complex parameter data is required, the service will have to be virtalized using Wires.
The service operation must return an array of complex data items, from which we will select 4 parameters to plot:
- x-axis
- y-axis
- bubble size
- bubble label
The mashlet will allow the user to specifiy the XPath location of the repeating elements in the operation response, together with relative XPath locations for each of the parameters.
We'll allow the user to specify x and y axis labels.
Leading on from the example illustrated in the screenshot above, here is an example of a service response which is suitable for plotting with a bubble chart.
The service is an XIgnite GetTopMovers Service Operation which has been virtualized using Presto Wires.
<?xml version="1.0" encoding="UTF-8"?>
<GetTopMoversResponse xmlns="http://www.xignite.com/services/"
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<GetTopMoversResult>
<Top>
<Outcome>Success</Outcome>
<Identity>Header</Identity>
<Delay>1.078125</Delay>
<Symbol>QQQQ</Symbol>
<Exchange>NASDAQ</Exchange>
<Type>Most Active</Type>
<Name>PowerShares Exchange-Traded Fun</Name>
<Last>29.91</Last>
<Change>0.04</Change>
<PercentChange>0.13</PercentChange>
<Volume>175756936</Volume>
</Top>
<Top>
<Outcome>Success</Outcome>
<Delay>0</Delay>
<Symbol>CSCO</Symbol>
<Exchange>NASDAQ</Exchange>
<Type>Most Active</Type>
<Name>Cisco Systems, Inc.</Name>
<Last>15.84</Last>
<Change>0.22</Change>
<PercentChange>1.41</PercentChange>
<Volume>95723109</Volume>
</Top>
...
...
...
We need to transform this service response into an xml chart document of the following form:
<chart xAxisName='Last Quote' yAxisName='Change [Percentage Change]' numberPrefix=''>
<dataset color='ee3020' showValues='0'>
<set alpha='70' x='14.16' y='-0.52' z='3.54' name='CMCSA [-3.54]' />
<set alpha='70' x='1.54' y='-0.25' z='13.97' name='FITB [-13.97]' />
<set alpha='70' x='6.61' y='-0.18' z='2.65' name='NWSA [-2.65]' />
....
....
</dataset>
<dataset color='20dd20' showValues='0'>
<set alpha='70' x='29.91' y='0.04' z='0.13' name='QQQQ [0.13]' />
<set alpha='70' x='15.84' y='0.22' z='1.41' name='CSCO [1.41]' />
<set alpha='70' x='13.88' y='0.29' z='2.13' name='INTC [2.13]' />
....
....
</dataset>
</chart>
Mashlet Implementation
Step 1 : Create the Mashlet Class
Implementing a Custom Mashlet Type provides a detailed description of how to create a new mashlet type.
Define the Sample namespace, then define the Sample.BubbleChart class, which must extend the mashlet Ema.BoxMashlet base class.
As a minimum our mashlet must provide an implementation of the render function.
Ema.namespace("Sample");
Sample.BubbleChart = Class.create(Ema.BoxMashlet, {
render: function(){
}
});
Step 2 : Implement Mashlet Render function
The render function must do the following:
- build the jump request, using mashlet preferences:
- sid, service id
- oid, service operation id
- params, optional comma seperated parameter data - get a presto connection and invoke the jump request
- on receiving the response, attempt to render the bubble chart using the response data.
- if an error occurs invoking the request, log an error with the console.
render: function(){
var paramString = this.getPreference('params');
var request = {
header: {
resultFormat: 'xml'
},
sid: this.getPreference('sid'),
oid: this.getPreference('oid'),
params: paramString ? paramString.split(',') : []
};
this.getConnection().request(request, {
onSuccess: function(response){
this.renderChart(response.response);
},
onFailure: function(error){
console.error('error invoking request ', request, error);
},
scope: this
});
},
renderChart: function(responseData){
}
Step 3 : Implement renderChart function
In the renderChart function we extract all the necessary service data from the raw XML JUMP response, using XPath expressions defined as Mashlet Preferences. Rather than building the FusionChart XML document directly, we extract the service data from the JUMP response and create an intermediate data object, which we then pass to an instance of Presto.BubbleChart, which will build the Fusion Chart XML document.
So the following mashlet preferences are used:
- record, defines an XPath expression which identifies the repeating XML element.
- x, defines the XPath expression relative path to the x-axis element
- y, path to the y-axis element
- z, path to the bubble size element
- label, path to the element used to compose a bubble tooltip
We convert the xml response string into a DOM object and then use the Ext.DomQuery utility to populate an array of data objects, one for each item we will plot, which will take the form:
var data = [
{ x:123, y:456, z:789, label:ABC },
{ x:123, y:456, z:789, label:DEF },
{ x:123, y:456, z:789, label:GHI },
...
...
]
We keep the Presto.BubbleChart class implementation seperate from the Sample.BubbleChart implementation for a couple of reasons:
- Seperate how we access the service from how we present the service data.
- So Presto.BubbleChart can be reused elsewhere.
We instantiate the Presto.BubbleChart object and pass in a single parameter specifying a relative URL path with which it will locate the BubbleChart SWF file. Notice we make use of the mashlet this.resolveUrl method which will convert the #{prestoResources} token to construct an absolute Url, see Mashlet Path Tokens, for an explanation of the use of tokens such as #{prestoResources}.
We invoke the Presto.BubbleChart render method to perfom the actual chart rendering, we pass in the following parameters:
- A reference to the DOM parent element to which the chart will be appended.
- The data array.
- A parameter object, containing a few other rendering preferences such as axis labels.
renderChart: function(responseData){
var repeatingElement = this.getPreference('record');
var x = this.getPreference('x');
var y = this.getPreference('y');
var z = this.getPreference('z');
var label = this.getPreference('label');
var data = [];
var doc = Presto.Util.parseXml(responseData);
var items = Ext.DomQuery.select(repeatingElement, doc);
items.each(function(item){
data.push({
x: Ext.DomQuery.selectValue(x, item),
y: Ext.DomQuery.selectValue(y, item),
z: Ext.DomQuery.selectValue(z, item),
label: Ext.DomQuery.selectValue(label, item)
});
});
var params = {
xAxisLabel: this.getPreference('xAxisLabel'),
yAxisLabel: this.getPreference('yAxisLabel'),
showLabels: this.getPreference('showLabels')
}
var el = Ext.get(this.bodyEl).dom;
var bubbleChart = new Presto.BubbleChart({
home: this.resolveUrl('#{prestoResources}/common/js/')
});
bubbleChart.render(el, data, params);
}
Step 4 : Presto.BubbleChart Implementation
Final part of the implementation is the Presto.BubbleChart class, which will build the XML document required by the FusionCharts implementation. Notice how we pass in a reference to the Bubble.swf file which you should find under .
We could deploy this javascript file to a shared area so that it is available for use by other mashlet developers, but for now we'll keep things simple and deploy it to the same directory as the mashlet implemenation.
Ema.namespace("Presto");
Presto.BubbleChart = function(config){
config = config || {};
var homeUrl = config.home || '';
return {
render: function(el, data, params) {
var xAxisName = params.xAxisLabel || '';
var yAxisName = params.yAxisLabel || '';
var numberPrefix = params.numberPrefix || '';
var showValues = params.showValues ? '1' : '0';
var xmlData = [""];
xmlData.push("");
for(var i=0; i < data.length; i++){
var record = data[i];
var label = record.label + ' ['+record.z+']';
if(record.z < 0){
var z = - record.z;
xmlData.push(" ");
}
}
xmlData.push(' ');
xmlData.push("");
for(var i=0; i < data.length; i++){
var record = data[i];
if(record.z >= 0){
var label = record.label + ' ['+record.z+']';
xmlData.push(" ");
}
}
xmlData.push(' ');
xmlData.push(' ');
var width = el.offsetWidth;
var height = el.offsetHeight;
var chartId = el.id + '_bubble';
var myChart = new FusionCharts(homeUrl+"FusionCharts/Charts/Bubble.swf", chartId, width, height, "0", "0");
myChart.setDataXML(xmlData.join(""));
myChart.render(el);
return true;
}
};
};
Step 5 : Define Mashlet Type Configuration
The mashlet type configuration is shown below.
The resources section must detail the 3 javascript files required by the Mashlet:
- main.js which will contain the mashlet class implementation, Sample.BubbleChart extending Ema.BoxMashlet.
- bubbleChart.js, which will contain the Presto.BubbleChart implementation.
- FusionCharts.js, which will render the chart.
Each of the js resource entries includes a property definition, these are used internally by the mashlet framework to verify that the javascript contained within the resource file has been fully loaded. See Adding a Mashlet Type for more details.
"Sample.BubbleChart": {
"type": "Sample.BubbleChart",
"title":"Sample Bubble Chart Rendering",
"description": "A Fusion Bubble Chart displaying a dataset with x, y and size data items.",
"width":"300",
"height":"300",
"properties": {
"sid": "",
"oid":"",
"params":"",
"xAxisLabel":"",
"yAxisLabel":"",
"showLabels":"false",
"record":"",
"x":"",
"y":"",
"z":"",
"label":""
},
"properties-meta":{
"sid": {
"type": "string",
"description": "Service ID"
},
"oid": {
"type": "string",
"description": "Operation ID"
},
"params": {
"type": "string",
"description": "Comma separated operation parameters."
},
"xAxisLabel": {
"type": "string",
"description": "X Axis Label"
},
"yAxisLabel": {
"type": "string",
"description": "Y Axis Label"
},
"showLabels": {
"type": "boolean",
"description": "Show bubble Labels"
},
"record": {
"type": "string",
"description": "Response Repeating Element XPath"
},
"x": {
"type": "string",
"description": "X Data Item"
},
"y": {
"type": "string",
"description": "Y Data Item"
},
"z": {
"type": "string",
"description": "Z (Bubble Size) Data Item"
},
"label": {
"type": "string",
"description": "Bubble Label Data Item"
}
},
"resources": {
"libs": {
"presto_ext": true
},
"js": [
{
"property":"FusionCharts",
"script":"#{prestoResources}/common/js/FusionCharts/JSClass/FusionCharts.js"
}, {
"script":"bubbleChart.js",
"property":"Presto.BubbleChart"
}, {
"script":"main.js",
"property":"Sample.BubbleChart"
}
]
}
}
Implementing a Custom mashlet Type explains how to introduce a new mashlet type.
Mashlet Deployment
The general procedure for mashlet type deployment is as follows:
- Create a new folder under
mashlets/which matches the type of the new mashlet, in our caseSample.BubbleChart. - Add the mashlet type configuration to
mashlets/mashlet.json
A full description can be found here, Implementing a Custom Mashlet Type
Having updated mashlet.json, launch MashletMaker and you should see the new mashlet type listed as shown in the screenshot below.

We are now ready to create a mashlet instance.
Mashlet Instantiation
Assuming the new mashlet type is listed by MashletMaker, we now need to gather the mashlet preference data to be used.
Prepare Mashlet Preference Data
I created a Mashup of the XIgnite GetTopGainers Web Service, as described at the begining of this blog entry. So my service details are simply:
- sid TopGainers
- oid runMashup
No parameter data is required to invoke this mashup.
Then the presentation preferences are:
- record -
/GetTopGainersResponse/GetTopGainersResult/Top - x -
Last - y -
Change - z -
PercentChange - label -
Symbol
and we'll define axis label preferences:
- xAxisLabel - Last Quote
- yAxisLabel - Change [Percent Change]
Instantiate the Mashlet
Having collected our preference data we are now ready to create our mashlet:
- Launch Mashlet Maker
- Select Create From Type
- Select the Sample.BubbleChart type and click next.
- Enter our preferences under the Additional Preferences section.
- Click Preview Changes button and we should see something like the screenshot below.
- Finally, click the Publish Mashlet button to make the mashlet available for use.

Which brings us to the end of the process.
Sample Attachment
A zip file containing the Sample.BubbleChart mashlet is attached at the bottom of this page. It was developed and tested using Presto 2.6.1 and 2.6.2.
- Unzip the contents into your
webapps/mashlets/directory, which will create the new directorywebapps/mashlets/Sample.BubbleChart. - You will then need to cut & paste the
"Sample.BubbleChart"property and object value from themashlet.jsonfile, into your ownwebapps/mashlets/mashlet.jsonfile. - Launch Mashlet Maker and you should see the new Mashlet type listed as described in the above article.
- jeremy.pitten's blog
- Login or register to post comments
- Email this page
