SAPUI5 VIZ Charts event handling
This blog post is at the request of Abesh Bhattacharjee – blame him ๐
The SAPUI5 library includes chart controls based upon the VIZ charting library. You can see some samples of them in action at https://sapui5.hana.ondemand.com/sdk/test-resources/sap/viz/Charting.html
Once you start building charts you pretty soon want to implement some event handling when a user clicks on a chart element. For example the usual way of implementing drill-down is by having the user click on a chart element and then using that element as the context for subsequent processing – perhaps rendering another chart that shows a more granular representation of just the element selected.
The SAPUI5 eventing framework allows us to attach an handler to the selectData event to be called when a user clicks on a chart element. The framework passes a sap.ui.base.Event object to the handler that contains the details of the specific action and target that triggered the event. In a perfect world we would be able to extract from this object the context of the element we clicked on so we could use that for subsequent actions.
In simple charts that only have a single dimension and a single measure this is achievable – albeit not terribly easily. There is an example of how to do it
But when you are charting multiple measurements and/or multiple dimensions things become much more difficult. Take for example this stacked column chart.
If you want to follow along my example yourself here is the HTML/Javascript that created it.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Chart</title>
<script id="sap-ui-bootstrap" type="text/javascript"
src="resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.commons, sap.viz">
</script>
<script>
var oModel = new sap.ui.model.json.JSONModel({
data : [
{ country : 'China', product : 'Car', profit : 32 },
{ country : 'France', product : 'Car', profit : 43 },
{ country : 'Germany', product : 'Car', profit : 34 },
{ country : 'USA', product : 'Car', profit : 25 },
{ country : 'China', product : 'Truck', profit : 78 },
{ country : 'France', product : 'Truck', profit : 86 },
{ country : 'Germany', product : 'Truck', profit : 56 },
{ country : 'USA', product : 'Truck', profit : 76 },
{ country : 'China', product : 'Motorcycle', profit : 78 },
{ country : 'France', product : 'Motorcycle', profit : 86 },
{ country : 'Germany', product : 'Motorcycle', profit : 56 },
{ country : 'USA', product : 'Motorcycle', profit : 76 },
{ country : 'China', product : 'Bicycle', profit : 78 },
{ country : 'France', product : 'Bicycle', profit : 86 },
{ country : 'Germany', product : 'Bicycle', profit : 56 },
{ country : 'USA', product : 'Bicycle', profit : 76 }
]
});
sap.ui.getCore().setModel(oModel);
var dataset = new sap.viz.ui5.data.FlattenedDataset({
dimensions : [
{ axis : 1, name : 'Country', value : "{country}" },
{ axis : 2, name : 'Product', value : "{product}" }
],
measures : [
{ name : 'Profit', value : '{profit}' }
],
data : { path : "/data" }
});
new sap.viz.ui5.StackedColumn("oChart",{
width : "100%",
height : "200px",
title : { visible : true, text : 'Test Stacked Column Chart' },
dataset : dataset
}).placeAt("content");
</script>
</head>
<body class="sapUiBody">
<div id="content"></div>
</body>
</html>
Notice that we have two dimensions – Country and Product. We can select an individual element by clicking on it, we can select an entire column by clicking on the X-axis label, and we can select many elements together.
Each time we click a chart element we fire the selectData event which passes details of the element we clicked on to any event handlers. The challenge is to determine the context of this element for subsequent processing. What follows is one way you could do this by adding a few lines of javascript to the HTML page.
Step 1. Turn off all the user interaction that the chart library delivered with the exception of tooltips.
sap.ui.getCore().byId("oChart").setInteraction(
new sap.viz.ui5.types.controller.Interaction({
selectability: new sap.viz.ui5.types.controller.Interaction_selectability({
mode: sap.viz.ui5.types.controller.Interaction_selectability_mode.none
})
})
);
Step 2. Attach an event handler for the browser click event to the chart.
sap.ui.getCore().byId("oChart").attachBrowserEvent("click",chartClickHandler);
Step 3: Implement the event handler.
We are only interested in clicks on the x-Axis of the chart. The x-Axis markup is wrapped in a SVG tag that looks like <g class=”v-m-xAxis” …>. So firstly we test to see if the area clicked is not a descendant of his tag and return immediately.
if(!$(oEvent.srcElement).closest('.v-m-xAxis').length) return;
The x-Axis labels are rendered like the below sample. The <rect> tag is the source element of the click event.
<rect x=”301″ y=”1″ width=”301″ height=”35″ opacity=”0″ class=”v-labelarea” fill=”#808080″></rect>
<g fill=”#333333″ class=”v-label viz-axis-label” font-size=”12px” font-weight=”normal” font-family=”‘Open Sans’, Arial, Helvetica, sans-serif”>
<text pointer-events=”none” x=”452″ y=”18.2″ dominant-baseline=”middle” text-anchor=”middle”>France</text>
</g>
We can isolate the contents of the <text> tag into a variable called xAxisLabel like this.
var xAxisLabel=$($(oEvent.srcElement).next('.viz-axis-label').children('text')).text();
If I add a dialog box to confirm the x-Axis label that has been clicked the complete event handler looks like this.
function chartClickHandler(oEvent) {
if(!$(oEvent.srcElement).closest('.v-m-xAxis').length) return;
var xAxisLabel=$($(oEvent.srcElement).next('.viz-axis-label').children('text')).text();
new sap.ui.commons.Dialog({ title: xAxisLabel+" clicked" }).open();
}
It’s not a perfect solution but it works for our example. Obviously the more complex the chart the more challenging isolating the context of a user click event will be.
If, like me, you are amazed at what can be done with a few lines of Javascript I encourage you to check out JQuery.
And just for completeness here is the final version.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Chart</title>
<script id="sap-ui-bootstrap" type="text/javascript"
src="resources/sap-ui-core.js"
data-sap-ui-theme="sap_goldreflection"
data-sap-ui-libs="sap.ui.commons, sap.viz">
</script>
<script>
var oModel = new sap.ui.model.json.JSONModel({
data : [
{ country : 'China', product : 'Car', profit : 32 },
{ country : 'France', product : 'Car', profit : 43 },
{ country : 'Germany', product : 'Car', profit : 34 },
{ country : 'USA', product : 'Car', profit : 25 },
{ country : 'China', product : 'Truck', profit : 78 },
{ country : 'France', product : 'Truck', profit : 86 },
{ country : 'Germany', product : 'Truck', profit : 56 },
{ country : 'USA', product : 'Truck', profit : 76 },
{ country : 'China', product : 'Motorcycle', profit : 78 },
{ country : 'France', product : 'Motorcycle', profit : 86 },
{ country : 'Germany', product : 'Motorcycle', profit : 56 },
{ country : 'USA', product : 'Motorcycle', profit : 76 },
{ country : 'China', product : 'Bicycle', profit : 78 },
{ country : 'France', product : 'Bicycle', profit : 86 },
{ country : 'Germany', product : 'Bicycle', profit : 56 },
{ country : 'USA', product : 'Bicycle', profit : 76 }
]
});
sap.ui.getCore().setModel(oModel);
var dataset = new sap.viz.ui5.data.FlattenedDataset({
dimensions : [
{ axis : 1, name : 'Country', value : "{country}" },
{ axis : 2, name : 'Product', value : "{product}" }
],
measures : [
{ name : 'Profit', value : '{profit}' }
],
data : { path : "/data" }
});
new sap.viz.ui5.StackedColumn("oChart",{
width : "100%",
height : "200px",
title : { visible : true, text : 'Test Stacked Column Chart' },
dataset : dataset
}).placeAt("content");
//Step 1. Turn off all the user interaction stuff in the chart apart from tooltips.
sap.ui.getCore().byId("oChart").setInteraction(
new sap.viz.ui5.types.controller.Interaction({
selectability: new sap.viz.ui5.types.controller.Interaction_selectability({
mode: sap.viz.ui5.types.controller.Interaction_selectability_mode.none
})
})
);
//Step 2. Attach an event handler for when the user clicks on the chart.
sap.ui.getCore().byId("oChart").attachBrowserEvent("click",chartClickHandler);
//Step 3. Implementation of the event handler.
function chartClickHandler(oEvent) {
if(!$(oEvent.srcElement).closest('.v-m-xAxis').length) return;
var xAxisLabel=$($(oEvent.srcElement).next('.viz-axis-label').children('text')).text();
new sap.ui.commons.Dialog({ title: xAxisLabel+" clicked" }).open();
}
</script>
</head>
<body class="sapUiBody">
<div id="content"></div>
</body>
</html>
Cheers
Graham Robbo
Robbo, thanks so much for blogging this !
I am sure others will find it as useful as I have, without wasting the numerous hours chasing a solution to a feature missing in action !
YOU ROCK !!!
Thanks Abesh
Hi, thank you so much for acknowledging my simple solution into your wonderful blog. You are one of my most admired person and inspired me a lot.
Thanks
&
Best Regards,
Bibhas Das
Thanks Bibhas
this is great Graham. would be really helpful. ๐
Hi Graham,
Thank you for the wonderful Blog.
I am facing a problem while using the same on vbox. Is this not supposed to work if I put my chart inside a vbox and then call setinteraction?
I am getting
"Uncaught TypeError: Cannot call method 'setInteraction' of undefined "
Can you guide me what I might be doing wrong?
Hi Atul,
you have a javascript error - it looks like the object you are trying to call the setinteraction method on is not being found.
Jump into a javascript debugger and see what it really happening.
Hay Graham,
Interesting Blog.. can't blame Abesh ๐
By the way, How I can group the dimensions in X Axis ? You have any examples with you ?
Sree
Hi Graham,
Thank you for you blog, it is very usefull for me, I'm a beginner in SAPUI5.
When I perform your example I don't have the popup, the condition in the function doesn't pass. So I can't trigger the click in the X-axis label.
Do you have an idea about why ? Am I the only one this that problem ?
Hi Flavien,
this solution relies upon the DOM that is created by the VIZ Chart.
It appears this has changed slightly in the later versions of the SAPUI5 library.
I found changing the charClickHandler function, as follows, works with the latest version of the SAPUI5 library.
function chartClickHandler(oEvent) {
if(!$(oEvent.target).closest('.viz-axis-body').length) return;
var xAxisLabel=$($(oEvent.target).next('.viz-axis-label').children('text')).text();
new sap.ui.commons.Dialog({ title: xAxisLabel+" clicked" }).open();
Cheers
Graham Robbo
Thank's a lot, it works well.
Hi: off the topic, does sapui5 viz supports Hebrew language(arabic) right to left?
thanks
srini
No idea Srini - you will just have to find out. When you do please post the answer? ๐
Hi Graham,
Wonderful Blog. It helped me a lot to learn to create a column chart as i am new to UI5.
But i have one question that instead of clicking any axis, i want to attach an event with the column of column chart. Could you please help me in achieving it??
Hi Deepak,
I see no reason why you couldn't do this. The SAPUI5 library already supports this with simple charts. For more complex I encourage you to have a go and then blog about it to let everyone else know how to do it.
Cheers
Graham Robbo
Can we have source code view for the demos on the UI5 CVOM HTML5 Charts - sap.viz.ui5
All source code is included with the SDK. OpenUI5 is here, but of course it does not include the sap.viz components. ๐
SAPUI5 SDK is a bit harder to grab. I usually get latest from https://tools.hana.ondemand.com using Eclipse update wizard and then manually unpack the archives.
Cheers
Graham Robbo
Hi Graham,
Do you know the reason why sap.viz, docs and the examples are so hard to find? I'm not exactly sure how to jump through those hoops you mentioned...
David
Hi David,
things have moved around quite a bit since I wrote this blog. You can find some examples in the SDK at https://sapui5.hana.ondemand.com/sdk/#test-resources/sap/viz/demokit/VIZCharts.html and https://sapui5.hana.ondemand.com/sdk/explored.html#/entity/sap.viz.ui5.controls.VizFrame/samples
Cheers
Graham Robbo
Thanks Graham. I appreciate the pointer to the samples.
David
Hi,
I am trying to use this control in Mobile/Tablet. But no luck in my effort. can any one give your idea, how to implement this in mobile.
ref post : Problem in sap.viz ( only in Mobile/Tablet )
Thanks,
Karthik A
Hi Karthik,
if you want to use a mobile charting library you could try the one built on the Sybase MAKIT library. https://sapui5.hana.ondemand.com/sdk/test-resources/sap/makit/demokit/index.html
Cheers
Graham Robbo
Hi Graham Robinson,
Thanks for you reply.
i have some open questions on this sap.viz.
1. SAP.VIZ is it available for mobile run time library?
2. sap.ui.suite.commons.TimeLine also not available in Mobile run time library.
why SAP includes this two components in sap.Explored, i am little bit confused. ๐
If you have any ref link, please guide me on this controls, for mobile/Tablet.
for Desktop: this controls are working fine.
Thanks,
Karthik A
Hi Karthik,
these libraries are constantly being enhanced, updated and modified. You will have to sort out what works best for your particular needs. And remember there is no reason you can't also incorporate other non-SAP libraries and components as well if you want to - or enhance the ones that SAP delivers.
Cheers
Graham Robbo
Hi Graham Robinson ,
Thanks for your reply man ๐
Cheers
Karthik A
Hi Graham,
Thanks for a wonderful blog.
I wanted to know if it is possible to create a 3-dimensional graph using SAP Ui5. If yes, Do we have any Demo available illustrating it?
Regards,
Amit
Hi Amit,
the answer to your questions is really "yes" and "no". 😏
Firstly it is important to remember that the SAPUI5 framework is designed so that it can properly co-exist with other libraries you may wish to use in your application.
The sap.viz library I used for this example uses the open source D3.js library which can produce amazing data-driven visualisations. The sap.viz library only includes a limited list of 2D charts but there is no reason you couldn't use the D3.js library (or any other library you prefer) to visualise your data any way you like in a SAPUI5 application.
There are also other features of the SAPUI5 library designed to support SAP Visual Business, etc. and SAP deliver controls that provide charts using the MaKit library that have a more 3D look to them and are designed for mobile platforms. Demo here.
Cheers
Graham Robbo
Code is not working for me..Can anyone help me with this ??
I don't know - can they? 😏
Hi Graham,
Its a great blog with wonderful working sample. I appreciate for the post.
I have an requirement to create a sample dashboard with drill down and filter functionality using sapui5 and html , getting input data from information models created in Hana.
This post helps me to understand the base requirements for drill down feature.
Can you help with a working sample or suggest some blog, for drill down and filter functionalities getting input data from models created in Hana?
Thanks,
Naveen
Hi Nav,
everything you are after is documented in the Developers Guide.
Cheers
Graham Robbo
Thanks alot Graham Robinson
It is really nice article ....
Hi Graham,
currently i am using sap.viz.ui5.TimeBubble, my problem is when user click on one bubble, it is highlighted but if one more click on this bubble nothing happened. what i expect is dismiss highlight. do you know any event about this?
thanks in advance..
Hi Roger,
I haven't looked at this library in a while so I am unable to directly answer your question, but I note in the documentation for the TimeBubble control there are events for both selectData and deselectData.
You may be able to use these events to achieve what you want?
Cheers
Graham Robbo
it doesn't work, because selectData is just called once when clicks on a chart element. if click again on this chart element, nothing happened. What i wanna do is if second click happens on this chart element, this element change its status from highlight to normal.
i think it is general problem for all the viz chart.
You can try using the same technique I have done in this blog to catch the event. For example on the TimeBubble demo page at https://sapui5.hana.ondemand.com/sdk/test-resources/sap/viz/Charting.html I used the Chrome console to add an event handler like so....
$('.v-datashape').click(function(e){console.log('Bubble clicked')})
Cheers
Graham Robbo
definitely it should work, somehow it is not entire solution. See if one ".v-datashape" is selected, its css changed a little bit as following I marked in bold,
<g class="v-datashape" transform="translate(432.94955356928574,164.9029)"><path class="v-datapoint v-morphable-datapoint v-datapoint-selected" fill="#68cbe7" stroke-width="1" stroke="#498ea2" stroke-opacity="0.8" d="M-33.5,0 A33.5,33.5 0 1,0 33.5,0 A33.5,33.5 0 1,0 -33.5,0z" fill-opacity="0.8"></path></g>
and the other datashapes changed to ,
<g class="v-datashape" transform..........
<path class="v-datapoint-default v-datapoint v-morphable-datapoint" fill="#ffcd84" stroke-width="1" stroke="#ffffff" stroke-opacity="0.4" d="M-34.5,0 A34.5,34.5 0 1,0 34.5,0 A34.5,34.5 0 1,0 -34.5,0z" fill-opacity="0.4"></path></g>
for dismiss highlight, i don't want to loop all the v-datashapes to change their css. is there any build-in api to do that
Why would you loop through all the bubbles - aren't you only interested in the one that was clicked?
the one that clicked is highlighted, the other ones are gray out... i have to loop through to change the CSS back...that's the reason why i wanna find a elegant way.
๐
Hey,
I'm using xml-Views and try to attach a event to a column click inside a colum-chart.
I tried to use the "handlers"-Attribute, but it always states the given function is undefined.
<vtc:Interaction supportedEventNames="mouseup,mousedown,mousemove,mouseout,mouseover,touchstart" handlers="chartClick">
...
</vtc:Interaction>
Since im using as much in the XML-Views/Fragments as possible, I would like to avoid getting the id an attach browser events.
Is there a way to attach such handlers via xml?
Please post questions in the forums or on Stackoverflow.
Cheers
Graham Robbo
Hi Ruven.
Good Day.
Have you found any solution for it? Let me know the definition structure if you have done so? Share the solution thread if any.
I am trying to use the i5Charts in XML view but couldn't find any code samples on the same. Let me know if you have any clue.
Thanks
Venkatesh ๐
Hi Graham,
Thanks for this blog. I have an issue in SAP VIZ Pie Chart, Hope you could help me in this. Can u please have a look at this question. I would appreciated for your time.
http://scn.sap.com/thread/3723915
Thanks, Vinay
Hey
//Step 1. Turn off all the user interaction stuff in the chart apart from tooltips.
sap.ui.getCore().byId("priceByPaymentType").setInteraction(
new sap.viz.ui5.types.controller.Interaction({
selectability: new sap.viz.ui5.types.controller.Interaction_selectability({
mode: sap.viz.ui5.types.controller.Interaction_selectability_mode.none
})
})
);
//Step 2. Attach an event handler for when the user clicks on the chart.
sap.ui.getCore().byId("priceByPaymentType").attachBrowserEvent("click",chartClickHandler);
//Step 3. Implementation of the event handler.
function chartClickHandler(oEvent) {
if(!$(oEvent.target).closest('.viz-axis-body').length) return;
var xAxisLabel=$($(oEvent.target).next('.viz-axis-label').children('text')).text();
new sap.ui.commons.Dialog({ title: xAxisLabel+" clicked" }).open();
}
the above code i used for my application. Step1 works fine. but on click event action is not working.
Hi Ranajay,
this code depends on the underlying SAPUI5 libraries which are regularly updated - and each update potentially changes how the chart is rendered. This means you will need to adjust the code to match the rendered HTML. Check earlier comments for an example.
Cheers
Graham Robbo
So where can I check the library to see these changes.
Have you looked at the release notes? Or used the browser debugger to check out the DOM?
Hello,
thanks for your blog. But after searching a nicer way I found the solution to get data selected :
In selectedData handler :
This should be more flexible.
Regards
Hi Joseph,
could you please give a bit more details about your solution?
Given a following example, where to put selectData handler?
sap.ui.define([
...
...
], function(Controller,..) {
"use strict";
var PieController Controller.extend("my.namespace.PieChart", {
onInit : function(oEvent) {...},
onBeforeRendering : function() {},
onAfterRendering : function() {}
});
return PieController;
});
Kind regards,
Filip
Hello,
In the XML view :
<viz:ui5.controls.VizFrame id="idVizFramePie" selectData=".onSelectedDataPie"
uiConfig="{applicationSet:'fiori'}" vizType="column" width="1000px"></viz:ui5.controls.VizFrame>
In the controller :
Hope it will help you.
Regards,
Yes, it did! Thank you a lot Joseph for taking your time for replying and helping out.
Kind regards,
Filip
Thanks Graham for this blog post, it explains well how to achieve desired goal.
Following your example, I have wrote the handler that isolates the context of a user click event for PieChart. Maybe someone finds it useful.
var pieChartClickHandler = function(oEvent){
var target = oEvent.srcElement || oEvent.target;
if(!$(target).closest('.v-datapoint').length)
return;
var clickedElementId = target.parentElement.getAttribute("data-datapoint-id");
var clickedElementLabel = $(".v-datalabel[data-datapoint-id='" + clickedElementId +"']").children('text').text();
console.log("Clicked Data: " + clickedElementLabel);
};
Best regards,
Filip
Hi Filip,
I think you might have missed an important piece of information contained within the comments for this blog.
Please remember that this blog was written more than 2 years ago when trapping and interpreting events from the Viz charts was very rudimentary. Since then the libraries have been enhanced many times and now there is much better event handling interpretation built into the controls.
Joseph BERTHE has pointed to some of these new event handlers in his comments.
The key thing is that if the SAP delivered controls come with suitable event handling we should use it - and not build our own in the way I did originally with this example. That is because SAP will ensure these event handlers continue to work properly even if they make changes to the DOM representation of the controls.
When the controls change the way they are rendered jQuery-based queries, such as
$(target).closest('v-datapoint')
, may no longer work or might point to a different result. This is why my solution has required changes several times since it was first published to accommodate the newer SAPUI5 libraries.I have built a newer example based upon the "selectData" and "deselectData" events of the sap.viz.ui5.controls.Vizframe control. You can see it in action at http://embed.plnkr.co/U9lkJmNetAknLrSI1HFK/
Using the standard event handlers you can see how even selecting and deselecting columns of the chart in groups can be handled smoothly. The same principles can be applied to your pie chart example too - as users are able to select and deselect multiple segments at once.
onSelectData: function(oEvent) {
var aSelections = oEvent.getParameter("data");
var oModel = this.getView().byId('idList').getModel();
for (var i = 0; i < aSelections.length; i++) {
this._selectedData.push(aSelections[i].data);
};
oModel.refresh();
},
onDeselectData: function(oEvent) {
var aSelections = oEvent.getParameter("data");
var oModel = this.getView().byId('idList').getModel();
for (var i = 0; i < aSelections.length; i++) {
for (var j = 0; j < oModel.getData().length; j++) {
if (oModel.getData()[j] === aSelections[i].data) {
oModel.getData().splice(j, 1);
break;
}
};
};
oModel.refresh();
}
The below image shows it in action
I hope this helps.
Cheers
Graham Robbo
Hi Graham,
thank you a lot for this nice explanation and code example. It's easy to understand and suitable for UI5 beginners like me..your post made my life easier ๐ IMHO your example would be perfect for SAPUI5 Explored
Kind regards,
Filip
High praise indeed ๐ cc DJ Adams
Hi Filip,
I finally found the notice I was looking for to include in my previous comment.
As you can see the the control library I used in the original post 2 years ago has been deprecated and sap recommends using the VizFrame control instead. That is how I built the demo I linked to above.
Cheers
Graham Robbo
Hi Graham,
Wonderful Blog. It helped me a lot to learn to create a column chart as i am new to UI5.
Thanks
Karthik
Glad to be of assistance Karthik.
Hello Graham, greatย blog!
I have a requirement to develop a gauge chart, and i know that it's possible to do it with external libraries. My problem is that my application has to run on FIORI launchpad, and i do not found any post teaching how to use external libraries inside FIORI Launchpad.
Do you have any idea if is this possible?
Thanks!
Matheus Goulart
Hi Matheus,
you can certainly use external libraries in FLP apps. Go for it!
Cheers
Graham Robbo