This documentation targets the API shipped with Pentaho 8.1. Click here for the updated version shipped with Pentaho 8.3.
Step 6 - Adding interactivity to the view
Visualizations can be much more fun and useful if the user is able to interact with them. The Visualization API defines two standard types of actions: execute and select. Most container applications handle these in some useful way.
On data actions and filters…
Visualization API data actions carry information that identifies the visual element with which the user interacted in terms of the subset of data that it visually represents. This is conveyed in their dataFilter property.
In this visualization, because each bar represents a category of the data, and the Category visual role is mapped to a single field, then each bar corresponds to a distinct value of the mapped field.
Implementing the execute action
The execute action is typically performed in response to a double-click event on the main visual elements,
in this case, the bars.
Declare the dependency on the execute action
The execute action type module needs to be loaded with the view module.
Modify the factory declaration of the view-d3.js file to the following:
define([
"module",
"d3",
"pentaho/visual/scene/Base",
"css!./css/view-d3",
], function(module, d3, Scene) {
return [
"pentaho/visual/base/view",
"./model",
"pentaho/visual/action/execute",
function(BaseView, Model, ExecuteAction) {
// ...
}
];
});
Handle the dblclick event
Now, you’ll handle the dblclick event of the SVG rect elements — the bars.
Add the following code to the _updateAll method:
// view-d3.js
// _updateAll:
function() {
// Part 1 & 2
// ...
// Part 3
var view = this;
bar.on("dblclick", function(scene) {
// A filter that would select the data that the bar visually represents
var filter = scene.createFilter();
// Create the action.
var action = new ExecuteAction({dataFilter: filter});
// Dispatch the action through the view.
view.act(action);
});
}
Remarks:
- The scene object knows how to create a filter for the data it represents (see createFilter).
- The action is being dispatched through the view, where action listeners can handle it.
Handling of the execute action event
The execute action event is already being handled on the sandbox side,
helping you to easily check that the action is being dispatched.
In the sandbox.html file you can find the following statements:
view.on("pentaho/visual/action/execute", {
"do": function(action) {
alert("Executed " + action.dataFilter.$contentKey);
}
});
Remarks:
- Actions emit events whose type is the id of the action’s type.
- Actions emit structured events, composed of multiple phases; you’re handling its
dophase. - Action listener functions receive the action as argument.
- The filter’s $contentKey property provides an easy way to get a human-readable description of a filter.
What are you waiting for?
Refresh the sandbox.html page in the browser, and double-click a bar!
Implementing the select action
The select action is an auxiliary action.
Its goal is to mark a subset of data on which, later, a real action, such as drilling-down, is performed.
The current set of selected data is stored in the model’s
selectionFilter
property.
For each select action that is performed,
its dataFilter,
may be removed from, be added to, replace or toggled in the model’s current selectionFilter,
according to the action’s
selectionMode.
Visualizations typically highlight visual elements that represent data that is selected. Container applications typically expose actions, from which the user can choose, to be performed on the currently selected subset of data.
You’ll let the user select bars by clicking on them.
Declare the dependency on the select action
The select action type module needs to be loaded with the view module.
Modify the type factory declaration of the view-d3.js file to the following:
define([
"module",
"d3",
"pentaho/visual/scene/Base",
"css!./css/view-d3",
], function(module, d3, Scene) {
return [
"pentaho/visual/base/view",
"./model",
"pentaho/visual/action/execute",
"pentaho/visual/action/select",
function(BaseView, Model, ExecuteAction, SelectAction) {
// ...
}
];
});
Handle the click event
Now, you’ll handle the click event of the SVG rect elements, the bars.
Add the following code to the _updateAll method:
// view-d3.js
// _updateAll:
function() {
// Part 1 & 2 & 3
// ...
// Part 4
bar.on("click", function(d) {
// A filter that would select the data that the bar visually represents
var filter = scene.createFilter();
// Create the action.
var action = new SelectAction({
dataFilter: filter,
selectionMode: event.ctrlKey || event.metaKey ? "toggle" : "replace"
});
// Dispatch the action through the view.
view.act(action);
});
}
Remarks:
- Each time a bar is clicked, the current model’s
selectionFilterwill be replaced with the data filter associated with the clicked bar, or toggled if the ctrl/cmd key is pressed.
Handling of the select action event
The select action event is also being handled on the sandbox side.
In sandbox.html you can analyze this block of code:
view.on("pentaho/visual/action/select", {
"finally": function(action) {
document.getElementById("messages_div").innerText =
"Selected: " + view.model.selectionFilter.$contentKey;
}
});
Remarks:
- You’re handling the
finallyphase of theselectaction, the last phase, that is called whatever happens. - The
selectaction’s default action automatically processes the action’sdataFilterandselectionModeand applies it to the model’sselectionFilter. We are using the content’s of the model’sselectionFilterproperty for displaying the final result.
Refresh the sandbox.html page in the browser, and click a bar!
You should see a text under the visualization showing the selected data’s filter.
Render selected bars differently
It would be much nicer if bars where highlighted with a different color when selected. Let’s do that.
Edit the CSS file
Edit the view-d3.css file. Append the following rules to it:
.pentaho-visual-samples-bar-d3 .bar.selected {
stroke-opacity: 0.4;
fill-opacity: 0.6;
}
.pentaho-visual-samples-bar-d3 .bar.selected:hover {
stroke-opacity: 0.8;
}
Change the render code
Finally, add the following code to the _updateAll method:
// view-d3.js
// _updateAll:
function() {
// Part 1 & 2 & 3 & 4
// ...
// Part 5
bar.classed("selected", function(scene) {
var selectionFilter = model.selectionFilter;
return !!selectionFilter && dataTable.filterMatchesRow(selectionFilter, scene.index);
});
}
Refresh the sandbox.html page in the browser, and click a bar!
You should see the selected bar exhibiting different colors.
Conflicting Click and Double-click events
You might have noticed that when double-clicking, apart from the dblclick event,
two other click events are being triggered.
This is a known issue of DOM events and there are multiple workarounds.
Check the code at the sample repository for a possible solution, based on Distinguishing click and double-click in D3.
Continue to Adding a default configuration.