Preview only show first 10 pages with watermark. For full document please download
Learning Pentaho Ctools
Learning Pentaho CTools
-
Rating
-
Date
August 2017 -
Size
4.4MB -
Views
11,208 -
Categories
Transcript
[1] www.ebook3000.com Learning Pentaho CTools Acquire finesse with CTools features and build rich and custom analytics solutions using Pentaho Miguel Gaspar BIRMINGHAM - MUMBAI www.ebook3000.com Learning Pentaho CTools Copyright © 2016 Packt Publishing All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews. Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book. Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information. First published: May 2016 Production reference: 1250516 Published by Packt Publishing Ltd. Livery Place 35 Livery Street Birmingham B3 2PB, UK. ISBN 978-1-78528-342-0 www.packtpub.com www.ebook3000.com Credits Author Project Coordinator Miguel Gaspar Sanchita Mandal Reviewers Proofreader Dan Keeley Safis Editing Sadakar Pochampalli Indexer Umang Shah Monica Ajmera Mehta Commissioning Editor Dipika Gaonkar Graphics Disha Haria Acquisition Editor Production Coordinator Sonali Vernekar Arvindkumar Gupta Content Development Editor Kirti Patil Cover Work Arvindkumar Gupta Technical Editor Jayesh Sonawane Copy Editor Ameesha Smith-Green www.ebook3000.com About the Author Miguel Gaspar started working at Webdetails about 3 years ago, some time before the acquisition of Webdetails by Pentaho. He was a consultant in the Implementation team and his work involved developing dashboard solutions as part of services. He is now acting as the technical owner of some of the Implementations projects as part of the Webdetails team in Pentaho. He likes to be as professional as possible, but in an informal way. One of his favorite hobbies is learning and his particular areas of interest are: business analytics, predictive analysis and big data, augmented reality, and cloud computing. He likes to play and is a huge martial arts fan and also one of the worst soccer players ever. He is married and a parent of two young and lovely daughters, who would like to spend more time playing like crazies with him. He also likes to spend time with friends or just having a drink and a good talk with someone else, if possible with his family at his side. He really hates liars. I am really grateful to my wife for all the support and also to my daughters for letting me compensate them for the time I spent writing the book while I should be spending the time with them, playing and laughing. I also want to thank all the reviewers and the team that worked on the book to make it better. www.ebook3000.com About the Reviewers Dan Keeley is an open source analytics advocate who has been working with Pentaho for nearly 10 years. He is now running his own company, building a team specializing in fast turnaround analytics. He has reviewed books on Pentaho Reporting and Pentaho Data Integration. Sadakar Pochampalli has been working as a BI consultant, and has around 4 years of experience with the Pentaho BI suite (all the modules) and the Japsersoft BI suite (all the modules). He is a postgraduate with a masters in computer applications from Bankatlal Badruka College for IT, Hyderabad, Telangana. He was awarded by Badruka (BBCIT) college with E.Balagurusamy gold medal for his outstanding performance during his postgraduation. He has been involved in end-to-end BI solutions using the Pentaho BI suite to meet the customers' expectations. He is passionate about learning open source and enterprise BI technologies as well an enthusiast of working on big data technologies. He often says to his friends, colleagues, and family that learning things never exhausts the mind. He has successfully delivered around 20 end-to-end BI projects using Pentaho and Jaspersoft. He has also trained more than 200 folks, from freshers to the CEOs of companies. This is the first book he has reviewed. He is the author of two active blogs: http:// pentaho-bi-suite.blogspot.in/ (Pentaho BI Suite) and http://jasper-bisuite.blogspot.in/ (Jaspersoft BI Suite). I would like to express my special thanks to the author of this book Miguel Gaspar and Packt Publishing for giving me this wonderful opportunity to review the content of book to make me part of this project. I enjoyed doing it as I have been working on the same technology for the past few years. Hope you find this book very useful and you will also enjoy learning CTools. www.ebook3000.com Umang Shah did his MSc (IT) at the Dhirubhai Ambani Institute of Information and Communication Technology (DA-IICT), which is among India's top tier institutes. After completing his masters of science, he worked in a startup firm, Cogbooks, as a BI-ETL developer and has working here for the last 3 years. As a startup culture, he worked on multiple roles and with multiple technologies. Pentaho, Amazon-EC2, and Cassandra are major parts of them. He writes a blog for helping Pentaho community: https://shahumang.wordpress.com. This is the very first book I am reviewing, so I want to thank Packt Publishing for giving me this opportunity. www.ebook3000.com www.PacktPub.com eBooks, discount offers, and more Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub. com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details. At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters and receive exclusive discounts and offers on Packt books and eBooks. TM https://www2.packtpub.com/books/subscription/packtlib Do you need instant solutions to your IT questions? PacktLib is Packt's online digital book library. Here, you can search, access, and read Packt's entire library of books. Why subscribe? • Fully searchable across every book published by Packt • Copy and paste, print, and bookmark content • On demand and accessible via a web browser www.ebook3000.com www.ebook3000.com This book is dedicated to all the Pentaho Community contributors, and to the excellent Webdetails team for the excellent work they do. I hope all of you can keep the contributions coming and hope that the book can bring new ones. www.ebook3000.com Table of Contents Preface vii Chapter 1: Getting Started with CTools 1 Introducing the CTools Considerations before creating a dashboard The first steps in creating a dashboard Getting the right requirements Creating a mock-up or dashboard design Team and project management Developing a dashboard Installing CTools Installing the CTools using Pentaho Marketplace Installing the CTools using the CTools installer Manually installing the CTools 2 4 7 7 9 10 10 11 12 15 17 Concepts and frameworks used 17 Summary 19 Chapter 2: Acquiring Data with CDA Introduction to CDA Creating a new CDA data source Available types of CDA data sources SQL databases Mondrian cubes Pentaho metadata Kettle transformations Scripting data sources XPath over XML Compound queries [i] 21 22 24 28 28 29 31 31 33 35 35 Table of Contents Common properties Making use of parameters 36 37 Editing and previewing Manipulating the output of a data source CDA cache Managing the cache and the scheduler Cache keys 43 45 45 45 47 Parameters on SQL queries Parameters in MDX queries Parameters on kettle queries Private parameters Configuring local cache keys Configuring system-wide cache keys 38 39 41 42 47 48 Web API reference 48 getCdaList 48 listQueries 49 listParameters 49 doQuery 49 clearCache 50 previewQuery 50 editFile 51 manageCache 51 Hands-on dashboards 51 Summary 54 Chapter 3: Building the Dashboard Using CDF Understanding the basics of a CDF dashboard Lifecycle of dashboards and components Creating a CDF dashboard Hands-on dashboards Using components inside the dashboards Defining data sources for components Creating and using parameters in data sources The importance of listeners inside the components Interaction between components Using preExecution and postExecution Understanding how to work with postFetch Using preChange and postChange Priority of component execution Available components and properties [ ii ] 55 56 56 62 66 66 68 72 75 77 82 85 87 89 90 Table of Contents Adding resources – JavaScript and CSS Using internal modules Defining and including new modules Including CSS files Dashboards utilities Formatting numbers Numbers Currency Abbreviation Percentages Languages and locales Multiple formats Formatting and manipulating dates Internationalization of numbers and dates 92 92 94 95 95 95 97 97 97 98 98 98 99 100 Dashboard storage 101 Dashboard context 104 Useful functions of the CDF API 107 Functions from the dashboards module: 107 Functions from the logger module: 109 Functions from the components module: 109 Summary 109 Chapter 4: Leverage the Process with CDE A brief introduction to CDE Working with the editor Operational toolbar 111 112 113 115 New 115 Save and Save as 115 117 Reload Settings 117 The perspectives toolbar 121 The layout perspective The data sources perspective The components perspective 122 142 145 Parameter, parameters, and listeners, again Putting it all together Creating your first CDE dashboard 156 157 159 Summary 167 Creating the layout Define the data sources Add the parameters and components Overall improvements [ iii ] 159 161 164 166 Table of Contents Chapter 5: Applying Filters to the Dashboard The select component The multi-select component The filter component Expected data layout Specific properties Making use of add-ins Advanced options and configurations Changing default messages Showing values 169 170 174 177 178 179 180 185 185 186 Date range input component 186 The multi-button component 189 Summary 190 Chapter 6: Tables, Templates, Exports, and Text Components Table component Table pagination Internationalization and localization Draw function Column formats, types, width, and headers Expanding content Making use of add-ins groupHeaders clippedText sparkline dataBar trendArrow circle cccBulletChart formattedText localizedText hyperlink 191 192 194 195 196 196 200 203 206 207 207 209 210 213 215 215 217 220 Template component 221 Automatically generated model and root element 225 Template and engine 226 Model handler 227 Formatters 229 Add-ins 230 Events 242 Extendable options 244 Export button component 245 Export Popup button component 245 Text component 248 Summary 249 [ iv ] Table of Contents Chapter 7: Advanced Concepts Using CDF and CDE 251 Chapter 8: Visualizations Using CCC 287 References to components, parameters, and layout elements 252 The query and freeform components 253 The query component 254 257 The freeform component Creating add-ins 257 260 The template add-in Extending CDF and CDE with new components 263 Extending CDF 263 268 Extending CDE Extending or creating new dashboard types 274 276 Creating a new dashboard style/template Extending styles for CDF dashboards 276 Extending styles for CDE dashboards 278 Bookmarkable parameters 279 Internationalization and localization 280 The dashboard component 283 Summary 285 Some background on CCC 288 Making use of the CCC library in a CDF dashboard 288 Mandatory and desirable properties 291 Mapping data 291 Crosstab 292 The crosstabMode property 293 The seriesInRows property 294 The timeSeries and timeSeriesFormat properties 295 Making use of CCC in CDE 295 Changing properties in preExecution or postFetch 297 Handling the click event 298 Internationalization of CCC Charts 299 What are extension points and how do you use them? 301 Formatting a basis axis label based on the scale 302 Customizing tooltips 304 Pie chart showing the value in the center 307 Dimensions 308 Readers 309 Visual roles 310 Debugging the CCC charts 311 [v] Table of Contents CGG – Community Graphics Generator 314 References 315 Summary 315 Chapter 9: Pentaho App Builder Understanding Pentaho App Builder Installing Pentaho App Builder Create a new plugin Creating a new endpoint Creating a job/transformation Creating a dashboard Folder structure Making use of Kettle endpoints on a dashboard 317 318 318 319 321 322 327 328 329 How do I make the plugin available on the marketplace? 332 Summary 333 Chapter 10: Embed, Deploy, and Debug 335 Embedding dashboards 336 Avoiding cross-domain requests 336 Embedding a CDF dashboard 337 Embedding a CDE dashboard 340 Dashboard, component, and parameter events 341 Debugging 343 Browser compatibility 344 Debugging with developer tools 344 Short tips 347 Delivering a solution 348 Version control and deploying projects 349 Documentation 350 Knowledge transfer 350 How to get help and help others 351 Summary 353 Index 355 [ vi ] Preface Using Pentaho allows you to build a complete analytics solution, and CTools brings an advanced flexibility to creating custom reports and making the most out of Pentaho. You can build your analytics dashboards/reports in an advanced and remarkable way. I can not avoid saying that Pentaho and CTools are two of the fastest and most amazing tools for building a complete solution that really takes your business to another level, and you probably would not be able to do with any other tool on the market. CTools provides a way to use web technologies to deliver astounding data visualizations that are proven to create a huge visual impact, but the the learning curve can be quite slow; the documentation can be dispersed and sometimes not easy to obtain. So, this book will help overcome the problem, getting you up to speed and giving you basic and advanced concepts so that you can acquire all the knowledge you need. By reading the book, you can learn not only how to understand how CTools work, but also the best way to make use of them. You will learn how to create custom dashboards to build incomparable analytics solutions. Throughout the book, your knowledge will increase, and at the end, you will be capable of creating your own custom and advanced analysis. [ vii ] Preface What this book covers Chapter 1, Getting Started with CTools, gives a brief introduction to the history of CTools. It will also introduce the reader to the purpose of the tool and teaches the user what methods are needed to install Community Tools. It is important to take some time getting an introduction to some concepts before you start building dashboards with Community Tools, so this chapter is not optional. When developing a dashboard, the first step is to interact with the client and get the requirements. There is a need to understand what is the best way to display data on the dashboard, and of course, there are some techniques that can be used to have a clean and simple dashboard that is, at the same time, very informative and intuitive. Navigation inside the dashboard should respect the requirements, but should be easy to understand. There is also a need to use standard components with a custom style so that it can be a unique dashboard while being quick to develop. Understanding this and other concepts will make the difference when developing the dashboard, so this chapter exposes some considerations that should be taken into account while creating dashboards. Chapter 2, Acquiring Data with CDA, is focused on the use of Community Data Access (CDA). Readers will find what kinds of Pentaho data sources we can use to acquire data using CDA, and also how to do it. How we can use parameters and all the other properties to get the desired results and how to manipulate the output that will be exposed to the dashboards or to the exports will also be covered. Chapter 3, Building the Dashboard Using CDF, will cover the two ways to build Community Dashboards. To build a dashboard, readers can avoid the use of CDF, but to achieve better results and build incredible dashboards, users should know how it works. One of the most important parts when building a CTools dashboard is the life cycle, so readers will have the chance to know how the life cycle of the dashboards and the components works. Pentaho uses the CDF framework inside the platform, so some concepts will become clear to you. Readers will also be challenged to create their first dashboard using CDF to better understand the concepts of Community Dashboards Editor. [ viii ] Preface Chapter 4, Leverage the Process with CDE, will be focused on the advantages and disadvantages of using Community Dashboards Editor (CDE) and why to use CDE to build a dashboard. Here, we will learn how to create dashboards without writing code or leveraging the work without the need to write code. The reader will also learn how to build a responsive and interactive dashboard, starting with the main concepts, and how to use the available graphical interface. Among the other concepts, you will learn how to create a layout, use components, and set some queries to be used inside the components. The chapter will also teach what needs to be changed to quickly build dashboards when using CDE. An important part is how to add more resources to the dashboard, and include them in the execution of the dashboard. Chapter 5, Applying Filters to the Dashboard , will show how to work with the most important and commonly used components. This chapter will cover filters and selectors that can be applied to the dashboard as one way to create interaction by filtering data for the full dashboard, or just some sections of it. A dashboard is meant to be easy to use and give good insights to get results at the first look. We can filter the information being displayed. This chapter covers the components we can use so that the user can have access to all the information, keeping it simple to understand and only providing information for the selected context. Chapter 6, Tables, Templates, Exports, and Text Components, covers add-ins for both table and template components. An important part of building a dashboard is to find the best way to represent data on the dashboard. We should not focus on only showing a table, a chart, or any other component, but how to represent the data using that same component. So, this chapter covers the most commonly used components. There is also another component such as the exports and the text component. There are some tips on how to avoid performance issues in the dashboards. Chapter 7, Advanced Concepts Using CDF and CDE, covers the advanced concepts when building dashboards with both CDF and CDE dashboards. CDF and CDE provide some really cool components that have more flexibility and allow you to build your own visualizations. So, we will also need to cover these components. You will face some requests to internationalize/localize dashboards, so we will also be covering it. There are some tips and advanced concepts that new CTools developers may not find easy to understand at first glance, but that more advanced users will find useful. The chapter also reinforces the concepts of references to components, parameters, and layout elements. [ ix ] www.ebook3000.com Preface Chapter 8, Visualizations Using CCC, may be one of the most expected chapters. A dashboard is really useful and desirable when a user looks at it and can understand what is going on with the business without the need of having to look for quite a large amount of information. This is where visualizations become very useful. This chapter will teach the reader how to make customizations on the available charts produced by the Community Charts Components (CCC). This book will show how to apply properties that can be shared between multiple charts. Readers will get a better knowledge of how to customize charts, where to look for information, and see some more advanced features useful inside dashboards. I would like to cover all the aspects, concepts, and properties, but that's almost impossible. CCC is a huge tool with infinite customizations that can be applied, so we would need to focus on giving you what you really need to keep learning about CCC by yourself. Chapter 9, Pentaho App Builder, talks about the one new feature created for Pentaho— the ability to create plugins without the need to create Java code. I would say this is one of the most interesting plugins created for Pentaho. By this time, readers already know how to create a dashboard. So, if you already know how to create jobs and transformations using Pentaho Data Integration, you should also be able to create plugins. We will need to understand the Community Plugin Kick-starter (CPK) and its relation with the Pentaho App Builder, and this chapter will explain it. Chapter 10, Embed, Deploy, and Debug, will explain how to embed both CDF and CDE dashboards into third-party applications. Usually, one request from customers is how to embed a dashboard into one application. Using RequireJS, this is simple and very flexible. You can build mini dashboards that you easily embed into your application without interfering with its default behavior. This chapter will provide information on how you can do debugging on the dashboard using the developer's tools of your browser. What you need for this book The only requirements are to have a Pentaho 5.X installed, but it's recommended to install 6.X. When installing Pentaho, there is the option to include some sample data, so please do it. Most of the samples make use of it, so to properly make use of samples, you will need to include them. It is known as the Steelwheels sample data. This includes a database of Metadata and Mondrian schemas. [x] Preface To make proper use of Pentaho Builder Application Server, you will need a browser. Even if Pentaho, in some of its versions, supports Internet Explorer 8, we just can't use this version when building responsive dashboards or making use of CSS3. You will need to have a higher version, such as Internet Explorer 9 or even better, make use of Chrome, Firefox, or Safari. The reader should have knowledge of JavaScript, JQuery, and Cascading Style Sheets (CSS). Not that it's mandatory to know the technologies, but it's the way the user will take the most out of some CTools. Who this book is for If you are a CTools developer and would like to expand your knowledge and create attractive dashboards and frameworks, this book is the go-to-guide for you. A basic knowledge of JavaScript and Cascading Style Sheets (CSS) is highly recommended. Conventions In this book, you will find a number of text styles that distinguish between different kinds of information. Here are some examples of these styles and an explanation of their meaning. Code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles are shown as follows: "We can include other contexts through the use of the include directive." A block of code is set as follows:My first dashboard!
[ 79 ]
Building the Dashboard Using CDF
CTools Book Samples!
Your dashboard will be wrapped by this element @CONTENT@
@FOOTER@
[ 118 ]
Chapter 4
Defining a new style is just creating an HTML page where we need to add the following strings, which will be replaced by the HTML and JavaScript code needed for the dashboard: °°
@HEADER@: This will be replaced by the scripts to include the JavaScript and CSS needed for the execution of the dashboard.
°°
@CONTENT@: This will be replaced by the HMTL with the structure defined in the Layout panel and the JavaScript code generated by CDE to run the dashboard, using as a base the components and data sources defined and the components panels.
°°
@FOOTER@: This will be replaced by some supplementary code to render some content that may be needed for the dashboard.
The styles should be uploaded to the repository and should be placed inside the folder /public/cde/styles. The styles inside the dropdown will have the name of the file, but two files should exist. One when creating legacy dashboards, not using RequireJS, and another when using RequireJS. The file name containing the style to be applied when using RequireJS should be appended by the text Require. For instance, create an HTML page with the name customStyleRequire.html containing the previous code and upload it to the folder /public/cde/styles folder. By creating your own styles, you can add content that will be used in all the dashboards where the style is applied. Refresh the CDE plugin When uploading files into the folder /public/cde/*, we should refresh the CDE, and to do this, you need to make a call to the following URL: http://'+value+'
'; } }; myself.setAddInOptions("colType", "formattedText", options); });
We also need to add some CSS similar to the following line: .formattedText .negative {color: red;}
You will find on the JavaScript code the textFormat function returning a div element with the formatted value, which will use the mask specified on the columns format of the table. We can get the specified format from the st.colFormat from the st object. This way we could execute the sprint function and format the value with that mask. The div element will have a CSS class that will be negative if the value is less than zero, and positive otherwise, so that we can apply some CSS and turn the negative values to red. All of the code is wrapped by a require function because we need the sprintf library to be included and available when executing the code.
[ 216 ]
Chapter 6
localizedText
The localizedText add-in allows the table to display content based on a language that is set for the browser. Using this add-in you may delegate to i18n the translations of the values returned from the query. If the range of values returned is not too big, and if they are not changing over time, it's fine to use this add-in; otherwise, we have a drawback because you need to have all the translations in one file, and if there is no translation for the current value being displayed, i18n will not be able to do it. When adding new rows in the database, we would also need to add them on the property files that are going to be used by i18n. So, if the range of values is too big and change over time, maybe you should consider doing it on the back end, using a Dynamic Schema Processor, SQL Generator, or any other technique available in Pentaho; but that is not the purpose of this book, so let's skip this option. So, if you have to meet the requirements to use the add-in, or for any other reason you need to use it, let's see how to do it. We have not yet discussed how to use i18n on the dashboards but we will do it later, but we need to have a brief introduction. When building a dashboard that needs to handle internationalization and localization, and they all should, you must specify a file with the name messages_ supported_languages.properties, which should be in the same folder as the dashboard. That's the way i18n will read the message files and their content will be key/value pairs where: • key: will be the Sales by territory:
- EMEA: $168479
- APAC: $601606
- Japan: $168479
- NA: $1821247
Sales by territory:
' + '- ' + ' {{#territory}}' + '
- {{name}}:{{sales}} ' + ' {{/territory}}' + '
Sales by territory:
' + '- ' + '<% _.each(model.territory, function(elem) { %>' + '
- <%= elem.name %>: $ <%= elem.sales %> ' + '<% }); %>' + '
Sales by territory:
' + '- ' + '{{ _.each(model.territory, function(elem) { }}' + '
- {{=elem.name}}: $ {{=elem.sales}} ' + '{{ }); }}' + '
' + '<% _.each(items, function(elem) { %>' + '
'; return template; }
The template creates a parent element that will wrap all other elements. Since each row is the same as one element of items, the root key of the model, the template generates a '+ ' <%= elem[0] %>: $<%= elem[1] %> '+ '
' + '<% }); %>' + ' <%= addin("3,5,7,3,4,2", "sparkline", "sparkline") %>
'+ ' that's going to have the name of the territory and the value. You should have noticed that we are using CSS classes, the bootstrap CSS classes that will make this content responsive to screen size changes.
[ 226 ]
Chapter 6
Model handler
We already covered in earlier chapters and/or sections the fact that we can use Pentaho Data Integration (Kettle) transformations to return data to the dashboard. When using MDX, we may return some more complex value parsed in a string and, when this happens, you may also need to manipulate the model so that it will let you build a really advanced visualization. Let's suppose that you are returning the sales for each territory and country, and you want to display a card by territory where you will include all countries' sales, such as in the following image:
What we need to do is to group the result by territory, because if we can have an object for each one of the territories then we can have all countries inside it. It's easy to build a template that can bring those results to the screen: function(data){ if (data.queryInfo.totalRows > 0) { var model = {}; var territories = _.groupBy(data.resultset, function(elem){ return elem[1]; }); model[this.rootElement] = territories; return model; } else { return null; } }
[ 227 ]
Tables, Templates, Exports, and Text Components
On the previous code, first we are checking whether we get results from the query, otherwise we want to return null to notify the component that it will not have data to display. If we have data on the result, then we will use the groupBy function to group all rows based on the second column (index one) that contains the territory. What we are getting is an object where the key will be the territory and the value will be the array of countries/values that belong to that same territory. After getting the result object we also need to put it on a root key, which is represented by this. rootElement, so we are using the property that has been set on the component (default value is items) so that we can iterate on each territory inside of it. An example of the model that is returned to the component is: { items: { APAC: [["Australia", "APAC", 630623, "0,49637,0,…,0,37905"], …, ["New Zealand", "APAC", 535584,"0,0,36409,…,0,102523"]], EMEA: [[…],…,[…]], Japan: [[…],…,[…]], NA: [[…],…,[…]] }
Based on the model, we can now build the template. We will need to iterate on each element of items, getting each one of the territories, where we will iterate on each one of the arrays inside it. When inside each country we can access the value by using the proper index such as 0 to get the country, 1 to get the territory, or 2 to get the value for sales: function() { var template = '
' + '<% _.each(items, function(tVal, tKey) { %>' + '
'; return template; }
[ 228 ]
Chapter 6
You will see two loops that are coded using the _.each function. First, iterate for each one of the territories and then for each one of the countries. When on the territory, we are using the key to create an element that will have the category or territory. When on the country, we will build three elements to display the name of country, the sale of the year, and a sparkline that represents the value for each one of the months for that same year. You will notice two function formatters and add-ins, but don't worry; we are going to cover them now.
Formatters
Formatters are very useful because, most of the time, we can't get the value formatted from the query, as we want it to be displayed on the dashboard. Let's suppose you have a query that can be used to get data to more than one component, taking advantage of the already cached data. If that's the case and if you want to display the values on a different format, then you need to handle it on the clientside. It's also easier changing the format on the client-side than on the queries, which can also be used by another dashboard or application. The template component has the concept of formatters, which are functions that we can define on the component and later use them inside the template. The values here can be numeric, a date, or a string. This can be done using the following property of the component: • Formatters: Used to define the formats that we may need to apply to the values returned from the dashboard and that will be displayed on the dashboard. When you click on the property you will get a popup where you will have to define the identifier/name for the formatter and the function that receives an argument, the value, and returns the already formatted value. Let's suppose you wanted to display the numbers, not to eight decimal places but just one. For that we would create a formatter with the identifier/name floatFormatter and a function such as: function(value, id){ return Utils.numberFormat(value, '$0.0a') }
Formatters are defined as a property. When you click on the property, you have the ability to add as many as you want.
[ 229 ]
Tables, Templates, Exports, and Text Components
To make use of the formatter inside the template, we need to use a function that is a formatter and receives two arguments: the value to be formatted, and the identifier/name of the formatter to use. This is because you can define and use multiple formatters on a template. One example of a template that would make use of the formatter would be as follows: function() { var template = ' '+ '
' + '<% }); %>' + ' <%=tKey%>
'+ ' <% _.each(tVal, function(cVal, countryKey) { %>' + ' '+ '
' + ' <% }); %>' + ' <%=cVal[0]%>
'+ ' <%=formatter(cVal[2],"sales")%>
'+ ' <%=addin(cVal[3],"sparkline"%>
'+ ' ' + '<% _.each(items, function(elem) { %>' + '
'; return template; }
You can see in the code that this way we are displaying all the sales by territory, but the values of sales are being formatted to have only one decimal place. The formatter function is being used and called from the template.
Add-ins
We already covered the use of add-ins in the table component. They are really useful and easy to create on the tables, and here on the template component this is also very easy. We can create new add-ins or make use of the ones that are already there by default. The way to apply add-ins that already exist is a bit different from tables. Here on the template component, since we are defining the layout for our visualization you also need to define it on the template. You can make use of it by using the addin function that receives three arguments, the data to be used by the add-in that will create the visualization, the name of the add-in to use, and the name of the column that comes from the query because the add-in may need to access the column. Another reason to specify the ID is because, when using the same add-in on the same template but for a different purpose, you may want to have a different format, as is possible on the table component. Let's suppose you want to display sparklines but using lines and bars for different purposes. By including the id, you may do so. Just don't forget that the id must match the column name that is returned from the query.
[ 230 ]
Chapter 6
Let's suppose you want to display sparklines like you can do on the table component. For that you should have the string with comma-separated values, and let's suppose that the third column of your query is returning it for you. You would need to apply a template as follows: function() { var template = ''+ ' <%=elem[0]%><%=formatter(elem[1],"floatFormatter","")%> '+ '
' + '<% }); %>' + '' + '<% _.each(items, function(elem) { %>' + '
'; return template; }
You can see the addin function being used, passing as arguments elem[2] where the string containing the values separated by commas is, and another argument with the name of the add-in to use. We may also want to change the default options for add-ins, and here it's the same as on the table component. We need to use the setAddInOptions function to override the default values. The function should be placed on the preExecution function of the component: function f(){ var opts = { type: 'bar', height: 20, barWidth: 6 }; this.setAddInOptions("templateType","sparkline", opts); }
[ 231 ]
Tables, Templates, Exports, and Text Components
The result of the add-in would be something similar to that displayed in the following image:
You need to be sure that the add-in that you are using is registered, otherwise it will not work. The add-ins that are available for the template component are not the same; some will be available and others will not. During the writing of this book I also created approximately ten add-ins, some of them almost a copy of add-ins used in the table component. The following image is an example of the add-ins that can already be used inside the template component:
[ 232 ]
Chapter 6
You can see on the image some numbers pointing to the add-ins; let's cover them and use the numbers so that you can easily identify them. The add-ins that we are covering for the template component are very similar to the ones on the table component so you already have most of the information. Don't forget that these options should be set inside the preExecution function of the component: 1. clippedText: The same as the table add-in plugin used when we have text larger than the space we have to display it. It will show the full text when we hover over it. The options available are: °°
showTooltip: To show a tooltip when hovering over the text. The default value is true.
°°
useTipsy: Use the Tipsy JQuery plugin to show a fancy and customizable tooltip. The default value is true.
°°
applyFormat: This is a function that receives an argument that is the
value to show on the tooltip and returns the formatted value. One example would be:
var options = { showTooltip: true, useTipsy: true, applyFormat: function(value) { return value; } } this.setAddInOptions("templateType","clippedText", options);
2. trendArrow: This add-in is very similar to the trend arrow of the table component using the exact same behavior and properties. It will display an arrow up/down and red/green depending on whether it's up/below and whether it's a good/bad value. This is the same behavior as the trendArrow table add-in, so please refer to the documentation. The properties are the same: °°
good: This property says that a good value is above the threshold
°°
thresholds: Defines the up and down thresholds. The default for up
upper interval. The opposite applies if we set a value of false. The default value is true. and down thresholds is zero:
{up: 0, down: 0}.
[ 233 ]
Tables, Templates, Exports, and Text Components
°°
includeValue: Used to specify that we will also see the value side by side with the arrow. The default value is false. Here the difference
to the add-ins available on the table component is that I have used font icons to display the arrow. Color and sizes can be changed just by changing/overriding some CSS. By opening the trendArrow.css file when debugging your dashboard, you will find the CSS classes that you need to override and customize the size, icon, and color. The following image is an example of the template add-in showing the trendArrow pointing down or up depending on a negative or positive trend compared to the sibling period:
3. formatted: I consider this a multiuse add-in because you can use it to easily apply some formatting or even customize, and have complete control over, what you will display. You can use the add-in to send HTML to the dashboard, so it gives you great flexibility. By default, the add-in format will be applied using one of two functions. You can format numbers and/or dates. This is quite different from the one we have discussed for the table component; it's simpler to use but powerful as well. The three main properties are: °°
formatFunction: Here you should specify a string with the name of the function that you want to use from Utils. Use numberFormat to format a number or dateFormat to format a date. The default value is numberFormat.
°°
formatMask: You should remember from the section where you covered the Utils number and date formatting functions that we also
need to specify the format mask, so this property is used to specify it. You should set a string with the format to use on the function that you specified as formatFunction. The default value is #,#.#. To get more information, please refer to the date and number formatting of the CDF chapter, Chapter 3, Building the Dashboard Using CDF.
[ 234 ]
Chapter 6
°°
applyFormat: By default, the functions used are the formatFunction and formatMask properties, so it will do the formatting based on
what you have specified for those properties. But if you want to customize the content to display, you can overwrite this function. If so, you need to define your own function, which needs to receive the value as the argument and return the text/HTML to be presented on the dashboard:
var options = { applyFormat: function(value) { return ' '+ '
' + '<% }); %>' + ' <%= elem[0] %>
'+ ' <%=formatter(elem[1], "sales", "sales")%>
'+ ' <%=addin(elem[2], "sparkline", "sparkline")%>
'+ ' '+value+'
'; } }; this.setAddInOptions("templateType","formatted", options);
The previous code is an example of the code to be placed on the preExecution function of the component to extend the options, if we want to customize the content to return to the dashboard when applying the formatted add-in inside the template component. 4. sparkline: Allows you to use the JQuery Sparkline Plugin just like we covered on the table component. Options should be the ones available on the plugin; just make sure the value returned is a string, represented with comma-separated (,) numbers. This is the only property that you will need to define, but you can use more. You can go to the Try It Out section of the Sparkline Plugin to check that the properties will differ from chart type to chart type: °°
type: It's a chart type and also a property that is passed from the
add-in to the Sparkline Plugin. Here the default is bar.
Per instance, if you need to display bars to represent the values chart and change some of the properties you would use code such as: var options = { type: 'bar', barWidth: 6}; this.setAddInOptions("templateType", "sparkline", options);
[ 235 ]
Tables, Templates, Exports, and Text Components
Please refer to the sparkline add-in section of the table component. You will find all the information you need, which will also work on the template component. The following images are also examples of what you can achieve when using the add-in:
The previous image uses the bullet chart options, while the following image uses the bar chart options to represent the values that should be represented:
5. hyperlink: hyperlink is an add-in that can provide links to any URI that is recognized by the HTML and the browser. You need to return a string with a valid URL from the query. The use is exactly the same as on the table component, so please refer to that section to get more information. The options are: °°
openInNewTab: Used to open the URI on a new tab of the browser.
By default, it is set to true. When set to false it will be opened on the same tab.
[ 236 ]
Chapter 6
°°
prependHttpIfNeeded: Used to tell the add-in to prepend the string http:// to the URL provided when the URI does not include one.
We should avoid it when providing an e-mail address as the URI. °°
regexp: We can provide a regular expression to check whether
°°
pattern: This is the regular expression that will extract the strings to use as the label and as the URI.
°°
labelReference: Used to tell from which group index we get the label. By default, its value is set to 0.
°°
urlReference: Used to tell from which group index we get the
the provided URL is valid. The regular expression is just to check whether it's valid or not. If it's valid then the add-in can create the link. By default, it's set to null, avoiding the validation.
URI. By default, its value is set to 1. To use the add-in, the value returned can be something such as: [Pentaho Website][http:// www.pentaho.com], and if that's the case you will need to apply the following options to the add-in: var options = { pattern: /\[(.*?)\]/g }; this.setAddInOptions("templateType","hyperlink", options);
6. localized: This is similar to the localizedText add-in on the table component. Please refer to the documentation on the table component section. 7. bubble: This add-in will draw a bubble where the size of the bubble is the relation between the value and the minimum and maximum values for all the rows on that same column, where the biggest bubble will be the highest value of all. The available properties are: °°
containerSize: Sets the size of the parent container where the
bubble will be. The default value is 30. The size of the bubble should be returned as a percentage, which will be the relative size for the bubble inside the parent container.
[ 237 ]
Tables, Templates, Exports, and Text Components
°°
valuesArray: This is the function used to return the array of values
where we should be searching for the max and min values, so that we can calculate the size of the bubble. By default, it will use the id passed when applying the add-in on the template, where the id should match the name of the column that we want to use to get the max and min values. Therefore, it's very important to have the id of the column passed when making the call of the add-in on the template. Based on the modelHandler function and the model you are returning to the component, the valuesArray function may need to be changed to get the proper array of values from the returned model. The function receives an argument that is the status but, as it's called from the radius and/or color functions that we also may override, you may include more arguments on it:
function(st) { var colNames = _.map(st.data.metadata, function(elem){ return elem.colName; }); var colIdx = _.indexOf(colNames, st.id); var values = st.data.resultset.map(function(e){ return Number(e[colIdx]); }); return values; }
°°
radius: The default value is a function that will calculate the size
based on the value for this same element. It accepts a function that receives the status as an argument. From the status, we can get the value that should be represented by the bubble, the data returned from the query, and the id for the add-in, which should identify the name of the column that should be used to find the min and max values that can be used to calculate the size of the bubble. If there are some add-ins that can work without the id being passed, this is not the case. By default, the following code is applied:
function(st) { var values = this.valuesArray(st); var tblMax = _.max(values), tblMin = _.min(values); var value = Number(st.value), size = (value-tblMin)/(tblMax-tblMin); return size*100; },
[ 238 ]
Chapter 6
°°
color: The color to be used for the bubble. This option accepts a
function that receives as an argument the status, where we can find the value, all the data returned from the query, and an id that identifies that unique add-in. The default function is:
function(st) { return "rgba(200, 200, 200 , 0.6)"; }
°°
showTooltip: To show a tooltip when hovering over the bubble. The default value is true.
°°
useTipsy: Use the Tipsy JQuery plugin to show a fancy and customizable tooltip. The default value is true.
°°
applyFormat: This is a function that receives an argument that is the
value to show on the tooltip, and returns the formatted value. The default value is:
function(st, opt) { return "Value:" + Utils.numberFormat(st.value, '#,#.#'); }
°°
tipsyOptions: The options to be passed to the Tipsy JQuery plugin.
This way Tipsy can be customized. The default value is:
{ gravity: 's', html: false }
The following image is an example of the result of applying the Bubble add-in:
[ 239 ]
Tables, Templates, Exports, and Text Components
8. bulletChart: This is used to represent a bullet chart with the values that come from the query for that same cell. Here you need to return all the values to use on the bullet chart, separated by a comma. The options that you have available are all those available for CCC charts, which we are going to cover later. The options for the chart should be set inside the chartDefinition object. The following code is an example of how to set the properties: var options = { chartOpts: { compatVersion: 2, height: 60, orientation: "horizontal", } } this.setAddInOptions("templateType","bulletChart", options);
When using the default properties, you get a bullet chart similar to the ones in the following image:
9. cccChart: This add-in allows you to display any CCC chart, but it's tricky. We will see later in this book, when we cover CCC charts, that CCC can receive from the query any result set and still display the chart. You may need to change some properties to have data displayed as expected. This is the tricky part here. What is the best way to represent the data so that we can have it represented correctly? Depending on the chart and on the properties that you set for the chart to represent it, you may need to adapt the result set. It would be easier to set the query, choose the chart to represent it, and then just adapt some of the options to adapt the chart to the data format that is returned. You may be a little bit confused with this, but do not worry, you will get the information to understand it. For now, let's focus on the properties that can be used to customize the behavior of the add-in:
[ 240 ]
Chapter 6
°°
type: Used to set the kind of chart to represent data. Possible values are: BarChart, LineChart, PieChart, DotChart, StackedLineChart, StackedAreaChart, HeatGridChart, WaterfallChart, BoxplotChart, MetricLineChart, TreemapChart, SunburstChart, and BulletChart. You won't need the last one since you have an
add-in capable of doing the same thing. The default value is set to PieChart.
°°
chartOptions: Used to set the options for the chart; you should take
a look at the CCC documentation pages and check what properties are available. You can also directly change some of the properties of the chart and check the results. Those are the options/properties that you can set here. One example would be:
chartOptions: { compatVersion: 2, height: 100, animate: false, crosstabMode: false, seriesInRows: false, timeSeries: false }
The crosstabMode, seriesInRows, and timeSeries properties are the ones that will make the difference when CCC is interpreting the results. This will definitely change the data you are displaying. The compatVersion is used to inform CCC that the chart should be rendered using version 2, which has a lot of improvements and fixes. In this case there is a property that's really mandatory, the height for the chart. Without this one the chart will not be rendered. °°
transformData: A function that receives the data as an argument and returns the complete result containing the metadata and resultset. Please refer to the Chapter 2, Acquiring Data with CDA to
get more information if you can't remember the format expected. You won't need to include the queryInfo: function(data) { var result = { metadata: [], resultset: []}; try { data = JSON.parse(data); var colMetadata = []; _.each(data, function(row, index) { if (index == 0) { _.each(row, function(col, index) { result.metadata.push({ [ 241 ]
Tables, Templates, Exports, and Text Components colIndex: index, colName: "Col"+index, colType: "String"}); }); } result.resultset.push(row); }); } catch(e) { return null; } return result; }
The following code accepts as an argument an array of arrays. For each row we need to add it to the new result set, and in the case of the first row, we also need to add the metadata to it. The following image is one example of a pie chart being displayed inside the template component:
Events
It's also possible to handle clicks on the elements created by the template component. You can use events to expand a particular section, to make a fireChange creating interaction between components, or to get details for the clicked section. Since you are creating a function, you can do whatever you need inside. To create an event, you need to use the Events property of the component. For the right-most value you will need to define the event that you want to handle, followed by the selector of the element from where you want to handle the event separated by a comma (,). On the left you will need to define the function and write the code (it can only be a fireChange) so that other components can be notified and updated. [ 242 ]
Chapter 6
Let's suppose that you wanted to get details for a particular territory, the one that is clicked; the template would be like: function() { var template = '' + '<% _.each(items, function(elem) { %>' + '
'; return template; }
You can see that for each of the items/territories, we are creating a parent container that includes data-territory attribute with the name of the territory and a CSS class where the value set is the clickable value. The data-territory attribute will be used to get the territory we are clicking on, and the CSS class will be used to get the HTML element where we will attach the event. To handle the event, we will need to add an event handler on the events property of the component. To do it you will need to use the left field click , .territory and the following function on the right field of the dialog that pops up: function(event) { var $elem = $(event.currentTarget); var selected = $elem.data('territory'); $elem.toggleClass('selected'); this.dashboard.fireChange('selectedParam', selected); }
Inside the function this will refer to the add-in, so on the first line we are getting the element that we clicked on. After that, we are using the JQuery data function to get the data from the attribute data category from where we will know which value should be used to set the parameter value. But first, we also need to toggle the CSS class to know which territories are selected. At the end we add a fireChange so that the value is written to the parameter, and the components that are listening it can be notified about the change. Don't forget that, for this to work, you will need to create the parameter to store the selected territory name. In our example the name is selectedParam. Besides fireChange, you can expand the container you are clicking on and display some more information. This doesn't need to be an element outside, as in the samples provided with the book. [ 243 ]
Tables, Templates, Exports, and Text Components
Extendable options
On the template component it's possible to customize the messages that you get in the event of an error, and for that we can use the following property: Extendable options: Accepts a function that returns the JSON object structure with all the messages to override it. The function to return the messages, which is used by default, is the following: function() { var opts = { messages: { error: { noData: "No data available.", invalidTemplate: "Invalid template.", invalidTemplateType: "Invalid template type.", generic: "Invalid options defined…." }, config: { style: { error: {icon: "remove-sign", type: "danger"} }, template: ""+ " '+ '
'; '<% }); %>' + ' <%=elem[0]%>
'+ ' <%=addin(elem[4],"trendArrow")%>
'+ ' " + " " + " <%=msg%> " + "
" } }, }; return opts; }
The function will return an object with customized error messages but also the Underscore template that is used to build the error message that will be displayed. If you look deeper into the template, you will find that I used a Bootstrap alert component and also made use of the icons to display on the alert. The alert type to use and the icons are defined inside messages.config.style. It will work as a template model where the template will act as the template and the style as the model. If needed, you can also overwrite the processMessage function that takes care of building the message. The function accepts two arguments, the message and the type, and returns a string with the HTML to be displayed as a message.
[ 244 ]
Chapter 6
If you have no row to display, by default, the following will be shown:
As you can see, the template component needs to be improved, mainly by making it easier to use, but without losing the flexibility to adapt and create new and impacting visualizations. We are in an era where the request to have prescriptive solutions and real-time prescriptive solutions is already a reality. I will be working on a similar component that can have real-time results presented on a dashboard using your custom visualization, so I am expecting to be able to have a real-time template component in the near future.
Export button component
When presenting content on a dashboard, which uses a query to present the content, we can make the export of the data to a specific format. It can be done only for a component, so the results of only a query and not the full dashboard will be exported. When using this component, you can export data to one of two formats, csv or xls; no other format is available on this component. The properties that you need to set are: • Label: The label that will be displayed on the button. • Component name: The name of the component from where to export the data. This should be the name that you gave to the component. Since you need to export the data from a component, you should already have a component set and ready to be used. • Output type: The format to export data to. Available options are the ones already mentioned, csv or xls.
Export Popup button component
The Export Popup button component is more flexible and will let you have more options. When using this component, the final user will have a link available where he can click to do the exporting. When clicking on the link, the user will get a popup with the options to export to different formats, and one option should be selected to make the export. The formats available are the same that are available in CDA, so you are able to export data to csv, xls, json, and xml. Besides that, if you have a chart, the final user will also be able to export the chart to svg or png format.
[ 245 ]
Tables, Templates, Exports, and Text Components
The options that you have available are: • Title: This is the text that will be displayed on the dashboard, where the final user can click. • Gravity parameter: This is used to set the position where the popup will jump. • Chart component to export: This is the name of the chart to export. Here you can click on the down arrow key to get the list of values and select the component name. • Chart export label: This is used to set the text that will be displayed and to make possible the export of the chart. • Chart export type: Here we need to specify the format to export the chart to. Available options are svg or png. • Data component to export: This is the name of the component from where data will be exported. Here you can click on the down arrow key to get the list of values and select the component name. • Data export label: This is used to set the text that will be displayed and to enable exporting the data. • Data export type: Here we need to specify the format to export the data to. Available options are csv, xls, json, or xml. • Name for data export attachment: This is name of the file that will be exported. The format will automatically be appended to the name of the file. • Content linking: This an advanced option to present the options and set the links that will enable the export. Per instance, when you want to be able to export to CSV and XLS. Using the previous properties you can only specify one format. The content linking property will allow you to specify the text to be displayed and a function that will be executed when the respective link is clicked. Inside this function you will be able to define the component from where to export, the format, and the filename to export to. When using this property, you will get a dialog where you will be able to add options. Each new line will be an option, and for each line you need to specify an argument and a value. On the text more to the left, you need to specify the text to display as the link. On the text more to the right, you will need to specify the function. Per instance, on the text to display you would set Export to CSV and the function would be as follows: function() { var comp = dashboard.getComponentByName('${c:myTable}');
[ 246 ]
Chapter 6 var cd = comp.chartDefinition || comp.queryDefinition; var query = dashboard.getQuery(cd); query.exportData('csv', {}, {filename: "filename.csv"}); }
The first line of code will get the instance of the component with the name myTable, whereas on the second line we get chartDefinitions or queryDefinitions. Depending on the component, it will return the correct option, because if one is not available we will use the other. The third line gets the information about the query, and by using this last one we can export the data. For that we need to make use of the exportData function that should be available for all the components that run a query. This function accepts three arguments; the first is the export type, the second is the overwrite options, and here you can return an empty object, and finally the third one is an object where we can specify the filename and extension for the file that will be exposed. The following image is an example of what can be produced, out-of-the-box:
When doing the export, the CDA query will run again, using the same parameters that are selected on the dashboard, and at that time it's already cached. Anyway, you can play around a little with this. It's not unusual to have a request to have quite a different export than we are seeing on the dashboard, so you can imagine a scenario where you will have a component that is hidden and is not executed until an export is requested.
[ 247 ]
Tables, Templates, Exports, and Text Components
Referring to component, parameters, and to the layout If you go to the developer tool of your browser and inspect a CDE dashboard code, you can see that, to the names of the components that we set when editing the dashboard, we always prepend with render_. So when you want to refer to the name of the component, you should refer to the complete name such as render_myComponentName. When you use code inside the dashboard, which is not valid for code on external files, you can refer to the component as ${c:myComponentName}. This will be translated when the code is sent to the browser, as it's already referring to the correct name of the component. This is also valid for parameters ${p:myParameterName} and for elements on the layout by using ${h:myPlaceholderName}. The syntax difference is the letter before the name and inside the {}. You can use c for components, p for parameters, and h for elements on the layout.
Text component
The text component is another component that is really simple to use. It allows you to display text on the dashboard. This component will not trigger a query, but is still executed as part of the lifecycle of the dashboard, so it's very useful. It can be used, per instance, to display the user that is logged in. Besides the properties that you already know and that are common to the remaining components, there can also be: • Expression: A function that should return the text/HTML to be displayed on the element of the layout associated to this component. One example would be: function() { return this.dashboard.context.user; }
The previous code is returning the username of the user that is using the dashboard, but we could have returned HTML to display.
[ 248 ]
Chapter 6
Summary
By reading this chapter, you should have learned how to use the table component, template component, export buttons, and text component. You should be able to use the table component to display details for each one of the rows, or just trigger some changes to other components when the user clicks on a row. You also should have learned to apply add-ins and customize tables, understand the capabilities provided by functionality on the server-side, or just customize what we see displayed (and the how of it). You have also learned how to use the template component to display data the way you need to. The template component provides many ways to display the results of a query, customize messages, or just apply some functions to customize formatting. Besides the fact of learning how to use the components, you should be able to make the most of them and be able to find the best way to present data to the user using these two components. Hopefully you also understand what you should use, or should avoid, so as to not decrease the performance of the dashboard, or even queries triggered. Performance is very important. At the end of the chapter, besides learning how to use the text component, you also learned how to export data and the way to do it. We have covered the way to export an image from a chart. There is a dedicated chapter for charts, as they are one of the best ways to represent data on the dashboard. The next chapter will cover some advanced concepts that you can use in both CDF and CDE dashboards.
[ 249 ]
Advanced Concepts Using CDF and CDE Today, when we are requested to build a dashboard, most of the time we find ourselves faced with customers who want you to make the dashboard available in multiple languages, and to be honest, this makes sense. Why would you have a dashboard available only in your language and not in other languages? In this chapter, we will teach you how you can do this. CDF and CDE provide you with some really cool components that are more flexibility then others, and allow you to build your own visualizations, so we will also cover these components. But for now let's suppose that you are working with a customer who has hired you to build a dashboard but also to train his team to build the remaining dashboards. If there is a visualization that you need to implement/develop, you will certainly be capable of creating a delivery that includes a custom component that they can use/reuse later. This is possible, and we are going to cover how to do it, as well as how to extend template and table components by creating new add-ins. In one of the sections of the book, we also provided some information about reusing templates and styles, and we already showed you how to create a new template, save it, and reuse it. But we also may want to create a style, and this is the chapter where we are going to do that. A very interesting possibility is building a dashboard and embedding it in another one. Do you realize how cool this could be? Just imagine creating a dashboard that can be used a section of another dashboard, and reusing it multiple times. You must be having some ideas already, so let's start with the chapter.
[ 251 ]
Advanced Concepts Using CDF and CDE
The topics covered include: • Creating new add-ins for table and template components • Making use of the template add-in for table and template components • Creating and changing the style of the dashboards • Using the dashboard component to reuse dashboards • Creating new add-ins and new components • Making use of bookmarkable parameters
References to components, parameters, and layout elements
First, I want to start by covering one important concept in CDF, and don't forget that concepts in CDF also extend to CDE. If you open the developer tools in your browser and start inspecting some CDE dashboard code, you will see that the names of the components are always prepended with render_ with the name of the components that we set when editing the dashboard. This way, when you want to refer to a component using its name, you should use the complete name of the component such as: this.dashboard.getComponentByName('${c:myComponentName}');
This would be the same as: this.dashboard.getComponentByName('render_myComponentName');
When you use this code line inside a dashboard, where it is not valid for code in external files, you can refer to the component as ${c:myComponentName}. This is possible because, when using this syntax, it will be translated and replaced by the full name of the component, so you don't need to worry about the name that CDE may have given to it. This is also valid for the parameters or elements created in the layout perspective. When you use a dashboard embedded in a dashboard, like we are going to see later, and you take a look at the code, you will see that the name will not be exactly the same as the one you gave it. You should worry about this, because you can use the syntax previously referred to.
[ 252 ]
Chapter 7
Since this is also valid for components, parameters, and layout elements, we should have a way to distinguish them. This is done by changing the letter before :. You should use a p for parameters, a c for components, and an h (from HTML) for the layout elements, like the following: • Components, which has already been covered: this.dashboard.getComponentByName('${c:myComponentName}');
• Parameters: this.dashboard.getParameterValue('${p:myParameterName}');
• Layout elements: $('.${h:myLayoutLementName}').text('Hello World');
When you select the name of parameters, the elements of the layout, and the component's name using the drop-down, CDE will automatically create a reference to the proper object of the dashboard, using the correct syntax. It won't work, if you type the name yourself nor when writing your own code. For this reason, I always advise you to select the values using the drop-down, and select the value from the list, otherwise you might be creating issues.
The query and freeform components
The components we have covered will give you the freedom to do almost everything you need to do to build an amazing dashboard. However, sometimes we need to go further, and we might be able to do this just by using the available components. To build custom visualizations, you can also make use of the query and freeform components, but what's the difference between them? A very frequently asked question is where to use one or the other. So now let's answer this question and learn how to use these components.
[ 253 ]
Advanced Concepts Using CDF and CDE
The query component will trigger a query, but you want to display some custom content inside your dashboard. Here you can't avoid setting a valid query, so the freeform component is useful here. The freeform component will not trigger any query so you can use it as you want/need. You may be thinking, If it does not do anything, why would I use it? Well, it's because sometimes you have the need to execute some code that respects the lifecycle (a good example can be internationalization/ localization, or just adding static HTML to the page/dashboard) of the dashboard; as with any other component, these two components have their own lifecycle. When using require, if you add HTML elements with text directly to the layout of the dashboard, you will see that text displayed in the first place, will give you a bad look and feel. You can use a text component to add the HTML, which will just be added to the page when the dashboard is being rendered. For both, query and freeform components, you will be able to specify the priority of execution and the preExecution and postExecution functions, as well as the component that should be executed at the start of the dashboard, by setting true or false in executeAtStart. For the query component, we are also able to specify the properties datasource, parameters, and the postFetch function, which will be executed as soon as the component gets the results, just after the preExecution function and before the postExecution function. So the difference between the query and the freeform components, is that, for the query component, a data source will be used and, for the freeform, it will not. Just use them when you need to present content that you are not able to present with any other component provided by CDF and CDE.
The query component
As already said, we can use the query component to present custom content to the dashboard. The properties that are available along with the common ones are: • Result var: This is the name of the dashboard parameter that is going to be used to store the result set from the query. This will not include the metadata, but just the resultset itself. It will store a multidimensional array with all the rows and columns returned. There is no default value—you should specify the name of a parameter. When you leave it blank, no parameter will be set. To access the parameter that could be named myResultset, you should use the same methods as for any other parameter in the dashboard, as in the following code: var data = this.dashboard.getParameterValue('${p:myResultset}');
[ 254 ]
Chapter 7
• Asynchronous mode: This tells us that the component should work in an asynchronous way. The default value is true and, when set to false, only after the component's rendering is complete, the components with a low priority (higher values) will be executed. My advice is to always use the default value. Pretty much, the property is there to retain compatibility with older versions of dashboards/components, so keep this property set to true. You can also get more details on Pedro Alves' blog at the following links: • http://pedroalves-bi.blogspot.co.uk/2012/11/making-cdf-callsasynchronous.html
• http://pedroalves-bi.blogspot.co.uk/2013/01/cdf-async-support. html
Let's suppose that you wanted to display the product line to be displayed as an accordion, where for each product line item we display the products and sales for that same line. There is no component, out of the box, that would build what was described in last sentence. Anyhow, you can build a custom component if you want to use it multiple times in multiple dashboards; otherwise you can just use the query component. The reason for using the query component is because the results that are going to be displayed come from a query, and we still don't have them in the dashboard.
[ 255 ]
Advanced Concepts Using CDF and CDE
We could use the query component in one of two ways. The first way is to use the variable to create and write the elements to the page on the postExecution function, only after postFetch. The following code is an example of creating the accordion with the accordion from JQuery UI (more information is available at: https:// jqueryui.com/accordion/): function() { var data = this.dashboard.getParameterValue('${p:myResultset}'); var $placeholder = this.placeholder(), $accordion = $(''), productLines = _.groupBy(data, function(elem) { return elem[0]; }); _.each(productLines, function(products, line) { $accordion.append(''+line +'
'); var $content = $(''); _.each(products, function(product) { var values = product[1] + ': ' + Utils.numberFormat(product[2], '$#,###.0'); $content.find('p').append('
'+ values + '
'); }); $accordion.append($content); }); $accordion.accordion({ heightStyle: "content" }); $placeholder.empty().append($accordion); }
In the previous code, we are getting the result of the query and iterating on each product line, and for each line we are also iterating on the products. This way, we can write the elements to the page. At the end of the code, we are using the accordion plugin and rendering it in the dashboard. The other way is to use postFetch directly, making use of the argument that is passed. If that was the case, then you will not need to define the variable data, just specify it as argument of the function; where you have data, it will be data. resultset. Don't forget that, when in postFetch, we should return data to the component.
[ 256 ]
Chapter 7
The freeform component
If you have a component that already has the result of a query that fits your need or you just want to render some content in the dashboard that does not depend on the result of a query, you can use the freeform component. The advantage is that the component has its own lifecycle and will be perfectly synced with the lifecycle of the dashboard. You can change the priority of execution, and add code for preor post execution. A property that is different from the other components is: • Custom script: This will accept a function with the code to be executed, just after preExecution and before postExecution. For this case, and supposing that you had a query component execution before this one, you could use the same code here in the custom script. This would grab the result from the parameters and the same code would be used to build the content for the dashboard. Even simpler would be a case where you needed to have the freeform component performing fireChange to a parameter based on some actions that can be controlled by the lifecycle of the dashboard. As the component will not make use of a query, you should already have figured out that it will not make a call to postFetch.
Creating add-ins
We have seen that both the table and template component can make use of add-ins. We can also extend CDF and create new add-ins that can be added to the dashboard. You should always be aware that when using it on a table component the add-in will be used for the cell of the table, so be cautious about what you are showing for each cell, so that the table does not become hard to read due to excessive information. Just because dashboard users get information from a dashboard does not mean you should present excessive information. To add a new add-in you just need to write a few lines of code and some properties, create a new instance of an add-in, and register it to the dashboard. The definition of the add-ins will be set using a JSON structure with the following elements: • name: This is the name/identifier given to the add-in, which will be used to reference it. This field is mandatory and accepts a string. • label: This will be the description of the add-in. It accepts a string.
[ 257 ]
Advanced Concepts Using CDF and CDE
• defaults: Here we need to set another JSON structure with the default properties of the add-in. These properties are the ones that may be overwritten later when setting the properties of the add-in. For example, for the sparkline add-in, it may have the type set as line but later we may want to use a bar. • init: This is used to execute some code once the add-in is requested. Some preparation code can be executed here. When defining an add-in that will be applied to a table, we also need to specify the sort functions, and the right place to do it. It accepts a function and accepts no arguments. • implementation: This is a function where the code of the implementation will be added. The function receives three arguments: • target or tgt: As you will see in the following example, it's a reference to the HTML element where we will be rendering the content to be displayed. • status or st: As you will see in the following example, it's an object where we can find the value to be used. The information that will be available inside this argument will depend on the component that is using the add-in. For instance, when used in a table, we may have access to the index of the column (colIdx) and the index of the row index (rowIdx) being processed. Since in some cases we may be using a hierarchical structure, we will have access to the add-in identifier (id) that is being passed when the add-in is used in the template. For both cases, independently of the component, we will have access to the complete dataset or model (data when in the table component and model when in the template component). • options or opt: Like you will see in the following example, these are the options set by the developer to customize the appearance and/or behavior of the add-in. We should use them if we want to extend the default options. Let's see what the code would be for an add-in created to be used in a table and another for the template component. Let's suppose you want to create an add-in to format the values that are going to be displayed in the dashboard. For this, you need to use the numberFormat function under the CDF utilities, which was already referred to in this book as Utils. We should not forget to include the module. To create and include a new add-in in your dashboard, you will need to add a new resource, using the layout perspective, and give it a name. After setting the name, you should place the code inside it, something like: define(['../../../AddIn','../../../Dashboard', '../../../dashboard/Utils','../../../Logger', '../../../lib/jquery','amd!../../../lib/underscore', 'amd!../../../lib/datatables'],
[ 258 ]
Chapter 7 function(AddIn, Dashboard, Utils, Logger, $, _) { var formatted = { name: "numberFormat", label: " numberFormat", defaults: { formatMask: '#,#.#' }, init: function() { $.fn.dataTableExt.oSort[this.name+'-asc']= $.fn.dataTableExt.oSort['string-asc']; $.fn.dataTableExt.oSort[this.name+'-desc']= $.fn.dataTableExt.oSort['string-desc']; }, implementation: function(tgt, st, opt) { var opts = $.extend(true, this.defaults, opt), Value = Utils.numberFormat(st.value, opts.formatMask); $(tgt).empty().text(Value); } }; var addin = new AddIn(numberFormat); Dashboard.registerGlobalAddIn("Table", "colType", addin); return formatted; });
In the previous code, first we are using require to create the add-in, including all the modules (JavaScript and CSS). When all modules are there, we need to start creating the code for the add-in. We start by creating a JSON structure, the name, label, and defaults as well as the init and implementation functions. The name will be the identifier of the add-in, in this case the formatter. For the defaults, we are defining the format mask, which will be applied when no other format is passed to the add-in. The init function is being used to define the sort functions of the jQuery Datatables plugin. This will only be used by the add-ins that we create and apply for the tables. It will not break if applied to the template; it will just not be used. The implementation function has the code that will be executed every time it's called by the table or by the template components. On the first line of the implementation function, we are extending the default options with the options that may be passed to the add-in on the pre-execution of the component. On the second line, we are setting a variable with the format, which is defined in the options and applied to the value that we can grab from the status. Here, using jQuery, we are cleaning the actual content that might be there and writing the already formatted value.
[ 259 ]
Advanced Concepts Using CDF and CDE
After this is complete, and now that we have the formatted JSON with the definition of the add-in, it's time to create a new instance of the add-in. And last, we are registering the add-in in the dashboard and as available as a column type of the table. When developing the add-in for the template component, there are two main differences between the add-in for the table component. One difference is that we would not need to define the sort function inside the init function, because that may not make sense when applying a template. That way, we would also not need the datatables module. The other difference is when registering the add-in for the dashboard. As you can see in the following code line, we are registering it to be used for the template component. Just look at the first two arguments of the function. We are using Template and not Table, as we are also using templateType and not colType: Dashboard.registerGlobalAddIn("Template", "templateType", addin);
The template add-in
There is one other add-in that was not covered, and it's available for the template component but also in the table component. The way it works is pretty much the same as the template component. There are three ways for the add-in to use the data being processed. The first one is by working on the query to return a string with the JSON structure that will be parsed by the default modelHandler function. There is another way: overwriting the modelHandler function by writing your own code and returning a custom and valid JSON structure as the model. If none of the earlier options return valid JSON, then the value will be treated as a string. Please refer to: http://www.json.org for more information. Just use the method that you are most comfortable with, prepare everything in the query/backend, or use the available function to return a valid model that can be applied to the template being defined. The way to apply options to the add-in is the same as already covered for the other add-ins, and the ones available are: • templateType: You must select the template engine to use. Those currently available are underscore and mustache. The last one is the default value. • template: This is the template to be used. • rootElement: This is the name/key that will wrap the model/value being processed. [ 260 ]
Chapter 7
• formatters: This accepts a multidimensional array. Each formatter will be represented by an array that will have two elements. The first element will be a string with the name of the formatter and the second will be the function that accepts two arguments: the value to be formatted and the identifier of the add-in being executed. It should return the formatted value. • events: This is similar to the last option, and here it accepts a multidimensional array. Each event will be an array with two elements. The first element is a string that has the event being handled and the selector of the element, separated by a comma (,). The second element is a function with the code to execute when the event is triggered in the selected element. The function accepts one argument that is a reference to the event itself, just like writing a function such as a regular JavaScript event. • modelHandler: This is a function that accepts data being processed by the component. The function is used to return a valid model to be rendered in the template of the add-in. • postProcess: This is a function where you can write some code after the elements are rendered on the page. For any of these functions, please refer to the template component documentation to get more information: var templateOpts = { templateType: 'underscore', template: '<% _.each(items, function(value, idx) { %>' + ' '+ ' Hello World HelloWorld Hello OTHERCOMPONENTS Others PalleteEntry 1.0 title executeAtStart htmlObject xActionArrayParameter dataSource preExecution [ 268 ]
Chapter 7 postExecution postFetch parameter tooltip listeners message Library mesage BaseProperty Hello World Model Handler Message to display. String String 0 false 1.0
You will get a lot of examples in your Pentaho solutions folder, under the CDE plugin folder, and inside the following folder: /pentahosolutions/system/pentaho-cdf-dd/resources/custom/components. This is where CDE components are placed, so you can have access to all the sources of all the CDE components.
[ 269 ]
Advanced Concepts Using CDF and CDE
Based on the knowledge that you have about using the lifecycle and the CDE components, the example code we just gave is almost self-explanatory. An important part is that we have a main tag where we set all the other definitions. Inside it we will have headers and content. In the tag we are setting the name, description, and category/group for the component, where the following properties are being used: • Name: The name of the component. • Iname: The interface name of the component, which is very useful for a legacy dashboard. It should not have any special characters or blank spaces. It would be a good practice to set it with the same name as the RequireJS module. • Description: This is just a description of the component. • Category: This is the ID of the group where the component will become available. Another way to say this is to set the group of the layout perspective where we can select this component from. • CatDescription: This is the description of the category where the component will be available. • Version: This is just a number that you can use to specify the version of the component. In the tag, we are setting: • Model: This is where we have defined the properties that will become visible when using the layout perspective and when the component has been selected. In the previous example, you will find the following properties that you already know: title, executeAtStart, htmlObject, parameters, preExecution, postExecution, postFetch, tooltip, listeners, and chartDefiniton, where you can find the dataSource to be used. If defining a select component, it would also make sense to have preChange and postChange.
[ 270 ]
Chapter 7
A property that you don't really know is the message property, which we need to specify in the tag , which we will cover as follows: • Implementation: Here you will find the definition of the component. The previous example code shows two properties in the tag; the first one supportsLegacy is used to make the component available for a legacy dashboard. Since it's not the purpose of this book to cover legacy but only a RequireJS dashboard, we have set this property to false. As the component should work in RequireJS dashboards, we have set supportsAMD to true. The renaming tags are: °°
Code: This property is where we specify the path and filename of the JavaScript file where the code for the component will be placed.
°°
Styles: This is a tag where you will have all the styles (CSS files) that should be loaded with the dashboard. The . This will instruct CDF to make use of a particular template/style for our dashboard. By default, the templates are inside a folder in the filesystem, in the plugin itself. The folder is /pentaho-solutions/system/pentaho-cdf. When we create styles/templates, we need to have them in one place that is accessible for multiple projects, if needed; however, if we place them in the same folder as the default ones, they will be overwritten on the next update of the plugin. To avoid this, it's possible to place our own templates in a folder, inside the Pentaho Repository, that will not be lost when updating the plugins. It should be created in a folder as: /public/cdf/ templates, and all the styles/templates will become available for the dashboards. The name of the file should be: dashboard-template-myTemplate.html; when setting it in the XCDF file dashboard, we should exclude the prefix dashboardtemplate. The tag inside the XCDF will be . [ 276 ]
Chapter 7
But how should we define the template? To answer that, let's look at the following example, which is exactly the same as the clean template: Ctools Book Samples {content}
You can see that this is pretty much an HTML page where you can also add CSS and JavaScript files, and CSS code—well, everything you can have on an HTML page you can also have here. The magic is the expression {content}, which represents the area where the specific code for each one of the dashboards will be placed. This expression will be replaced by the HTML, again including JavaScript and CSS code, from the file that is defined in the template element, such as myFirstDashboard.html. So the code inside myFirstDashboard.html will be replacing the referred expression, generating a complete HTML page for your dashboard, the file that will be used by the browser to render the web page with the dashboard. So, when creating our first dashboard with the example code we saw previously, the browser would render similar to the following code: Ctools Book Samples
[ 277 ]
Advanced Concepts Using CDF and CDE
Extending styles for CDE dashboards
It's also possible to extend CDE with new styles/templates. The way to create them is pretty much the same, except for the name and the folder where they should be saved. CDE templates should be saved inside /public/cdf/templates and the names are simple. As we can have legacy and require dashboards, we may need to specify two different files, one for the legacy and the other one to be used when building a require dashboard. The name should be appended by Require before the extension, for instance, myCustomStyleRequire.html. Otherwise on a legacy dashboard, which we are not covering in this book, it would just be myCustomStyle.html. The tags that will be replaced also change a bit, so here we need to make use of: • @header@: This is used to include some initialization scripts, such as the dashboard context. It should be part of the header. • @content@: This is use to be replaced by the content of the dashboard. This is where the dashboard will be rendered. All the layout and code for the execution of the dashboard are placed here. • @footer@: This is used to include some scripts. It can be part of the footer template. The way to apply a style/template to a CDE dashboard is to just choose it from the setting dialog of the dashboard. You will see a dropdown where the available styles/templates will be selectable. You just need to select the one for your dashboard and save it. Next time the dashboard is rendered, it will make use of that style/template.
[ 278 ]
Chapter 7
The CleanRequire.html style looks like the following code. You can see a clean file where the header, content, and footer will be placed: @HEADER@ @CONTENT@ @FOOTER@
Bookmarkable parameters
You have already seen that we are able to create a dashboard that uses filters to be interactive. But let's suppose you want a dashboard to jump to a particular state using some values that could be specified using the URL. That's also possible out of the box using the bookmarkable parameters. A great usage of this is for you to share the status of a dashboard with someone else. When you are exploring data through the dashboard, you may find some insights or just some warnings that you want to send to someone else. You can even send an e-mail with that information to someone else in the company. So now let's see how you can get them working. When you create parameters, by using the components perspective, you may create a parameter by expanding the Generic group, choosing the type of parameter (also covered in this book). Three properties will become available: one for the name, a second one for the default value, and a checkbox to make the parameter a bookmarkable one. If you make a parameter available, and when you start using the dashboard in such a way the parameter value is changed, you will notice that the URL changes and some more information has been added. The changes that you will find in the decoded URL will look like the following, depending on the parameters and the values being sent to them: bookmarkState={"params":{"filterParam":"[Product].[Trains]"}} [ 279 ]
Advanced Concepts Using CDF and CDE
This line shows that the value that is selected is Trains. What this means is that, if you use the entire URL like we are getting in the browser, opening another tab or window for your browser and pasting the complete URL will filter your dashboards and show only trains. If you use the dashboard URL without bookmarkState in the URL, then you will get the dashboard filtered with the default value, which in the sample provided is Classic Cars. You will find a short and simple example in the chapter samples of a dashboard that presents a button that will send an e-mail with the URL containing the selection applied. In that case, you could send a message to a particular department or person, providing some insights. The code in the button would resemble: function() { var dashboardPath = window.location.href; // send email with path to dashboard }
This just gets the current URL with the bookmark state and sends it by e-mail. Bookmarkable parameters in CDF The Bookmarkable parameters are a CDE functionality, so you can also use them in CDF dashboards as well, if you include the module, cdf/Dashboard.Bootstrap.
Internationalization and localization
We can have internationalized and localized dashboards, and these are based on the i18n jQuery plugin. When we need to translate a dashboard, we need to create multiple files in the same folder as the dashboard, all of the .properties files. The first one is messages_supported_languages.properties, where we need to specify the languages that will be supported. This will dictate the files and languages that should be read. If we want to be able to provide transactions in Portuguese (pt) and English (en), we use: pt en
Here we should have and/or _, where is the lowercase code for the language and is the uppercase country code.
[ 280 ]
Chapter 7
The i18n properties files will be key/value pairs where the names will dictate the language that will be used. We can also make use of a fallback file, but the fallback file doesn't need to be defined in the supported languages file. We can delegate i18n messages to three specific files, which need to be placed in the same folder as the dashboard. The standard in Pentaho is to have the names using the following rules: messages__.properties
These files are the ones that will contain the translations for a particular country for a language, where should be replaced by the lowercase language code and should be replaced by the uppercase country code (for instance: messages_en_US.properties, messages_en_UK.properties, messages_pt_ PT.properties and messages_pt_BR.properties): messages_.properties
These files contain the translations for a particular language, not specifying the country, where should be replaced by the lowercase language code (for instance: messages_en.properties and messages_pt.properties): messages.properties
That's the fallback file, where no language or country is specified. Here we will not need to specify a language or country. Messages or translations can and should be shared by the different files; whenever that happens, the following rule applies: The message keys placed in messages__.properties will override similar ones placed in messages_.properties, which will overwrite messages.properties. A hierarchical structure of the messages properties files would be: + messages.properties ++ messages_en.properties ++++ messages_en_US.properties ++++ messages_en_UK.properties ++ messages_pt.properties ++++ messages_pt_PT.properties ++++ messages_pt_BR.properties
[ 281 ]
Advanced Concepts Using CDF and CDE
Each one of these files is a pair of key/value, where the key and value are separated by an equals sign (=). The key will represent the identifier for the transactions while the value will be the translation itself, the text that will be displayed on the dashboard. Let's suppose that we are creating a dashboard that can translate English and Portuguese. The first step is to create the fallback properties file. From there, we need to create new files for language and country, and just include the keys that need translation. The messages.properties file would look like: DASH.TITLE: Internationalization and localization DASH.DESC: Internationalization and localization, sample dashboard
The messages_en.properties file could be empty, because the translation will be the same. When there is no key/value for the requested key, the priority (as explained before) is taken into consideration, so the text from the fallback file would be shown. The messages_pt.properties file would look like this: DASH.TITLE: Internacionalização e localização DASH.DESC: Exemplo de internacionalização e localização
To make use of the translations inside a dashboard, we need to make use of the CDF API, calling the prop function from i18nSupport. The following line of code grabs the translation from the correct language file and returning it. This is done through a line of code: this.dashboard.i18nSupport.prop('DASH.TITLE');
The previous examples do not specify the messages for the countries but, as already covered, you should be able to do it; the content will also be based on key/value pairs. We can avoid repeating the key/value pairs that are similar and use the hierarchical priority rules to specify only the key/value pairs that are different from file to file.
[ 282 ]
Chapter 7
To apply this to the DOM using postExecution of the components, you can use jQuery or a text component. There are some places such as charts or tables where you can also use the function, but make sure you also have a way to return the transactions for the result of a query. This can be achieved using a metadata schema, a dynamic schema processor on Mondrian, or with Kettle (PDI), but it may be harder with a simple SQL query where we can't use parameters to change the column returned.
The dashboard component
Using RequireJS allows great flexibility for the integration of CDE and CDF dashboards in third-party applications. That said, you could start asking: Is there a way to have dashboards inside another dashboard? This way, we could develop mini-dashboards that we can reuse inside the same dashboard and/or for multiple dashboards. Later, we will cover, in Chapter 10, Embed, Deploy, and Debug, how we can integrate/embed dashboards into third-party applications, because now reusing a CDE dashboard inside another CDE dashboard is really easy. We can use the dashboard component that you can find inside the Custom group of the Components panel. The component will only be available when building RequireJS and not a legacy dashboard and, as we said before, the CDF and CDE chapters of this book are really focused on building dashboards using RequireJS. The dashboard component is really easy to understand and use, and in my opinion it's one of the most desired components for developers and teams who want to reuse code and build more complete and complex solutions with less effort. One of its advantage is that you can make use of a mini-dashboard in multiple dashboards. If you find a problem or just want to make a change, you just need to apply it to the mini-dashboard, and instantly you will see those changes applied to all the dashboards making using of that mini-dashboard.
[ 283 ]
Advanced Concepts Using CDF and CDE
The available properties when using this component are: • Dashboard path: This is the path to the dashboard you want to embed inside your main dashboard. Here you can point to a mini-dashboard that in reality is a dashboard. That mini-dashboard will be called and rendered inside the main dashboard. • Parameter mapping: If you want to synchronize some of the parameters between both dashboards, you can do this using this property. You can choose the parameters from the list of available parameters; when entering the name, you just need to click on the down arrow. On the left, you will find the parameters of the main dashboard, and on the right are the parameters that are public on the dashboard that is being instantiated. The following screenshot shows the mapping between the parameters from the main instantiated dashboard:
But you should now be asking, why am I referring to a public parameters? Well, it is possible to define the parameter mapping using the parameters of the dashboard being instantiated, and it's necessary that you make them public. When you are creating/editing a parameter, you need to change the Public property to True. This will make the parameter available to the outside world. The following screenshot is an example of this:
You will see that the Public property is set to true, so the parameter will become available when instantiated in the dashboard component. [ 284 ]
Chapter 7
• Datasource mapping: Interesting? Yes, definitely interesting. This can be used to overwrite a data source being used on the instantiated dashboard. This means that we can replace the data source and use one defined in the main dashboard. When you create a mapping between dashboards, that data source will be replaced everywhere. So if you have multiple components using the same data source on the instantiated dashboard, this means that those components will use the data source from the main dashboard being mapped. In the examples from this chapter that you can import to your repository, you will find inside the chapter 7 folder an example on the use of the dashboard component. There you will find two dashboards. On one main dashboard we use the mini-dashboard four times, displaying different titles, data, and even different chart types. You can use the dashboard component to create navigation between dashboards, reuse dashboards, and create what in a more limited way CDE made available as widgets (with the use of RequireJS, this does not make sense anymore). I find the dashboard component much more flexible and easy to use, with the advantage that it is possible to define a dummy data source for the mini-dashboards and really use the data sources defined in the main-dashboard.
Summary
In this chapter, you learned some advanced features, tricks, and tips that you can use to build fancier dashboards, just save time developing dashboards, or extend the CDF and CDE capabilities by creating new components. We also covered some important features such as internationalization and localization. You should also now know how to use the bookmarkable parameters to initiate a dashboard from a particular state or just call new dashboards, passing some values to replace the default values for the parameters. If you create a new dashboard template that will be used to standardize the look and feel of all your dashboards, this topic is also covered in this chapter. This may be one of the most complex chapters and hard to understand, but it is important when you start to get more complex and advanced requirements for the dashboards. This is really useful when you want to deliver advanced and custom features to your customers or developers. There is no need for everyone to know every single feature and possibility in CDF and CDE so, if you have a team that does not have that knowledge but you want them to be able to reuse some of your code and/or dashboards, you now have the knowledge to make it possible.
[ 285 ]
Advanced Concepts Using CDF and CDE
Don't forget that is fine to use the query component, but if you are using the same code twice, you may need to consider the development of a custom component and make it easier to reuse. In the next chapter, you will come to understand the CCC properties and how they can be used for visualization.
[ 286 ]
Visualizations Using CCC The Charts Component Library is not really a Pentaho plugin, but instead is a Chart library that Webdetails created some years ago and that Pentaho started to use on Analyzer visualizations. It allows a great level of customization by changing the properties that are applied to the charts and perfectly integrates with CDF, CDE, and CDA. The dashboards that Webdetails creates make use of CCC charts, usually with a great level of customization. Customizing them is a way to make them fancy and really good-looking and, even more importantly, it is a way to create a visualization that best fits the customer/end user's needs. We really should be focused on having the best visualizations for the end user, and CCC is one of the best ways to achieve this, but to do this you need to have a very deep knowledge of the library, and know how to get amazing results. I think I could write an entire book just about CCC, and in this chapter I will only be able to cover a small part of what I like, but I will try to focus on the basics and give you some tips and tricks that could make a difference. I'll be happy if I can give you some directions for you to follow, and then you can keep searching and learning about CCC. An important part of CCC is understanding properties such as series in rows or crosstab mode, because that is where people usually struggle at the start. When you can't find a property to change chart styling/functionality/behavior, you might find a way to extend the options by using something called extension points, so we will also cover them. I also find interaction within the dashboard to be an important feature. So we will look at how to use it, and you will see that it's very simple.
[ 287 ]
Visualizations Using CCC
In this chapter, you will learn how to: • Understand the properties needed to adapt the chart to your data source results • Use the properties of a CCC chart • Create a CCC chat by using the JavaScript library • Make use of the internationalization of CCC charts • See how to handle clicks on charts • Scale the base axis • Customize tooltips
Some background on CCC
CCC is built on top of Protovis, a JavaScript library that allows you to produce visualizations just based on simple marks, such as bars, dots, and lines, among others, which are created through dynamic properties based on the data to be represented. You can get more information on this at: http://mbostock.github. io/protovis/. If you want to extend charts with some elements that are not available you can, but it would be useful to have an idea about how Protovis works. CCC has a great website, http://www.webdetails.pt/ctools/ccc/, where you can see some samples including the source code. On the page, you can edit the code, change some properties, and click the Apply button. If the code is valid, you will see your chart update. As well as that, it provides documentation for almost all of the properties and options that CCC makes available.
Making use of the CCC library in a CDF dashboard
As CCC is a chart library, you can use it as you would on any other web page. But CDF also provides components that you can implement to use a CCC chart on a dashboard and fully integrate with the life cycle of the dashboard. To use a CCC chart on the CDF dashboard, the HTML that is invoked from the XCDF file would look like the following (as we have already covered how to build a CDF dashboard, I will not focus on that, and will mainly focus on the JavaScript code):
The most important thing here is the use of the CCC chart component that we have covered in an example as a bar chart. We can see by the object that we are instantiating, CccBarChartComponent, and also by the type, cccBarChart. The previous dashboard will execute the query specified as dataAccessId for the CDA file set on the property path, and render the chart on the dashboard. The dashboard code also refers to the crosstab mode for the result set, but the base axis should not be a timeSeries. There are series in the columns, but don't worry about this as we'll be covering this topic later.
[ 289 ]
Visualizations Using CCC
The existing CCC components that you are able to use out of the box inside CDF dashboards are as follows. Don't forget that CCC has plenty of charts, so the sample images that you will see in the following table are just one example of the type of charts you can achieve. CCC Component
Chart Type
Sample Chart
CccAreaChartComponent
cccAreaChart
Not available
CccBarChartComponent
cccBarChart
http://www.webdetails. pt/ctools/ccc/#type=bar
CccBoxplotChartComponent
cccBoxplotChart
http://www. webdetails.pt/ctools/ ccc/#type=boxplot
CccBulletChartComponent
cccBulletChart
http://www. webdetails.pt/ctools/ ccc/#type=bullet
CccDotChartComponent
cccDotChart
http://www.webdetails. pt/ctools/ccc/#type=dot
CccHeatGridChartComponent
cccHeatGridChart
http://www. webdetails.pt/ctools/ ccc/#type=heatgrid
CccLineChartComponent
cccLineChart
http://www. webdetails.pt/ctools/ ccc/#type=line
CccMetricDotChartComponent
cccMetricDotChart
http://www. webdetails.pt/ctools/ ccc/#type=metricdot
CccMetricLineChartComponent
cccMetricLineChart
Not available
CccNormalizedBarChartComponent
cccNormalizedBarChart
Not available
CccParCoordChartComponent
cccParCoordChart
Not available
CccPieChartComponent
cccPieChart
http://www.webdetails. pt/ctools/ccc/#type=pie
CccStackedAreaChartComponent
cccStackedAreaChart
http://www. webdetails.pt/ctools/ ccc/#type=stackedarea
CccStackedDotChartComponent
cccStackedDotChart
Not available
CccStackedLineChartComponent
cccStackedLineChart
http://www. webdetails.pt/ctools/ ccc/#type=stackedline
CccSunburstChartComponent
cccSunburstChart
http://www. webdetails.pt/ctools/ ccc/#type=sunburst
CccTreemapAreaChartComponent
cccTreemapAreaChart
http://www. webdetails.pt/ctools/ ccc/#type=treemap
[ 290 ]
Chapter 8 CCC Component
Chart Type
Sample Chart
CccWaterfallAreaChartComponent
cccWaterfallAreaChart
http://www. webdetails.pt/ctools/ ccc/#type=waterfall
In the sample code, you will find a property called compatMode that has a value of 2 set. This will make CCC work as a revamped version that delivers more options and a lot of improvements, and makes it easier to use.
Mandatory and desirable properties
Among other properties such as name, datasource, and htmlObject, other chart properties are mandatory. The height is really important, because if you don't set the height of the chart, you will not fit the chart in the dashboard. The height should also be specified in pixels. If you don't set the width of the component, or to be more precise, then the chart will grab the width of the element where it's being rendered it will grab the width of the HTML element with the name specified in the htmlObject property. The seriesInRows, crosstabMode, and timeseries properties are optional but, depending on the kind of chart you are generating, you might want to specify them. The use of these properties becomes clear if we can also see the output of the queries we are executing. We need to go deeper into the properties that are related to the data mapping to visual elements.
Mapping data
We need to be aware of the way that data mapping is done in the chart. You can understand how it works if you can imagine data input as a table. CCC can receive the data as two different structures: relational and crosstab. If CCC receives data as a crosstab query, it will translate it to a relational structure. You can see this in the following examples.
[ 291 ]
Visualizations Using CCC
Crosstab
The following table is an example of the crosstab data structure: Column Data 1
Column Data 2
Row Data 1
Measure Data 1.1
Measure Data 1.2
Row Data 2
Measure Data 2.1
Measure Data 2.2
Creating crosstab queries To create a crosstab query, usually you can do this with the group when using SQL; or just use MDX, which allows us to easily specify a set for the columns and for the rows.
Just by looking at the previous and following examples, you should be able to understand that, in the crosstab structure (the previous example), columns and rows are part of the result set, while in the relational format (the following example), column headers or headers are not part of the result set, but are part of the metadata returned from the query. The relational format is as follows: Column
Row
Value
Column Data 1
Row Data 1
Measure Data 1.1
Column Data 2
Row Data 1
Measure Data 2.1
Column Data 1
Row Data 2
Measure Data 1.2
Column Data 2
Row Data 2
Measure Data 2.1
The preceding two data structures represent the options when setting the crosstabMode and seriesInRows properties.
[ 292 ]
Chapter 8
The crosstabMode property
To better understand these concepts, we will make use of a real example. This property, crosstabMode, is easy to understand when comparing the results of two queries. Non-crosstab (Relational):
Crosstab:
Markets
Sales
Markets
2003
2004
2005
APAC
1281705
APAC
3529
5938
3411
EMEA
50028224
EMEA
16711
23630
9237
Japan
503957
Japan
2851
1692
380
NA
3852061
NA
13348
18157
6447
In the previous tables, you can see that on the left-hand side you can find the values of sales from each of the territories. The only relevant information is relative to the values presented are the territories. We can say that we are able to get all the information just by looking at the rows, where we can see a direct connection between markets and the sales value. In the table presented on the right, you will find a value for each territory/year, meaning that the values presented, and in the sample provided in the matrix, are dependent on two variables, which are the territory in the rows and the years in the columns. Here we need both the rows and the columns to know what each one of the values represents. Relevant information can be found in the rows and the columns, so this is a crosstab. Crosstabs display the joint distribution of two or more variables, and are usually represented in the form of a contingency table in a matrix. When the result of a query is dependent only on one variable, then you should set the crosstabMode property to false. When it is dependent on two or more variables, you should set the crosstabMode property to false, otherwise CCC will just use the first two columns like in the non-crosstab example.
[ 293 ]
Visualizations Using CCC
The seriesInRows property
Now let's use the same two where we have a crosstab:
The previous figure shows two charts: the one on the left is a crosstab with the series in the rows, and the one on the right is also crosstab but the series are not in the rows (the series are in the columns). When the crosstab is set to true, it means that the measure column title can be translated as a series or a category, and that's determined by the property seriesInRows. If this property is set to true, then it will read the series from the rows, otherwise it will read the series from the columns. If the crosstab is set to false, the community chart component is expecting a row to correspond exactly to one data point, and two or three columns can be returned. When three columns are returned, they can be a category, series and data, or series, category and data and that's determined by the seriesInRows property. When set to true, CCC will expect the structure to have three columns such as category, series, and data. When it is set to false, it will expect them to be series, category, and data. A simple table should give you a quicker reference: crosstabMode
seriesInRows
Description
true
true
The column titles will act as category values while the series values are represented as data points of the first column.
true
false
The column titles will act as series value while the category/category values are represented as data points of the first column.
false
true
The column titles will act as category values while the series values are represented as data points of the first column.
false
false
The column titles will act as category values while the series values are represented as data points of the first column. [ 294 ]
Chapter 8
The timeSeries and timeSeriesFormat properties
The timeSeries property defines whether the data to be represented by the chart is discrete or continuous. If we want to present some values over time, then the timeSeries property should be set to true. When we set the chart to be timeSeries, we also need to set another property to tell CCC how it should interpret the dates that come from the query. Check out the following image for timeSeries and timeSeriesFormat:
In the example provided with the book, you will find a dashboard that presents data as a timeSeries property. The result of one of the queries has the year and the abbreviated month name separate by -, such as 2015-Nov. For the chart to understand it as a date, we need to specify the format by setting the property timeSeriesFomart, which in our example would be %Y-%b, where %Y is the year is represented by four digits, and %b is the abbreviated month name. The format should be specified using the Protovis format, which follows the same format as strftime in the C programming language, aside from some unsupported options. To find out what options are available, you should take a look at the documentation, which you will find at: https://mbostock.github.io/protovis/ jsdoc/symbols/pv.Format.date.html.
Making use of CCC in CDE
There are a lot of properties that will use a default value, and you can find out about them by looking at the documentation or inspecting the code that is generated by CDE when you use chart components. By looking at the console log of your browser, you should also able to understand and get some information about the properties being used by default and/or see whether you are using a property that does not fit your needs.
[ 295 ]
Visualizations Using CCC
The use of CCC charts in CDE is simpler, just because you may not need to code. I am only saying may because, to achieve quicker results, you may apply some code and make it easier to share properties among different charts or type of chart. To use a CCC chart, you just need to select the property that you need to change and set its value by using the drop-down or by just setting the value:
The previous screenshot shows a group of properties with the respective values on the right. One of the best ways to start to get used to CCC properties is to use the CCC page available as part of the Webdetails page: http://www.webdetails.pt/ctools/ ccc. There you will find samples and the properties that are being used for each of the chart. You can use the dropdown to select different kinds of charts from all those that are available inside CCC. You also have the ability to change the properties and update the chart to check the result immediately. What I usually do, as it's easier and faster, is to change the properties here, check the results, and then apply the necessary values for each of the properties in the CCC charts inside the dashboards. In the following samples, you will also find documentation about the properties, see where the properties are separated by sections of the chart, and after that you will find the extension points. On the site, when you click on a property/option you will be redirected to another page where you will find the documentation and how to use it.
[ 296 ]
Chapter 8
Changing properties in preExecution or postFetch
We are able to change the properties for the charts, as with any other component. Inside preExecution, the keyword this, refers to the component itself, so we will have access to the chart's main object, which we can also manipulate and add, remove, and change options. For instance, you can apply the following code: function() { var cdProps = { dotsVisible: true, plotFrame_strokeStyle: '#bbbbbb', colors: ['#005CA7', '#FFC20F', '#333333', '#68AC2D'] }; $.extend(true, this.chartDefinition, cdProps); }
What we are doing is creating an object with all the properties that we want to add or change for the chart, and then extending the chartDefinitions (where the properties or options are). This is what we are doing with the JQuery function. Use the CCC website and make your life easier This way to apply options makes it easier to set the properties. Just change or add the properties that you need, test it, and, when you're happy with the result, you just need to copy them into the object that will extend/overwrite the chart options. Just keep in mind that the properties you change directly in the editor will be overwritten by the ones defined in the preExecution function, if they match each other of course.
Why is this important? It's because not all the properties that you can apply to CCC are exposed in CDE, so you can use preExecution to use or set those properties.
[ 297 ]
Visualizations Using CCC
Handling the click event
One important thing about charts is that they allow interaction. CCC provides a way to handle some events in the chart and click is one of those events. To have it working, we need to change two properties: clickable, which needs to be set to true, and clickAction where we need to write a function with the code to be executed when a click happens. The function receives one argument that usually is referred to as a scene. The scene is an object that has a lot of information about the context where the event happened. From the object you will have access to vars, another object where we can find the series and the categories where the click happened. We can use the function to get the series/categories being clicked and perform a fireChange that can trigger updates on other components: function(scene) { var series = "Series:"+scene.atoms.series.label; var category = "Category:"+scene.vars.category.label; var value = "Value:"+scene.vars.value.label; Logger.log(category+" & "+value); Logger.log(series); }
In the previous code example, you can find the function to handle the click action for a CCC chart. When the click happens, the code is executed, and a variable with the click series is taken from scene.atoms.series.label. As well as this, the clicked category scene.vars.category.label and the value that crosses the same series/category in scene.vars.value.value. This is valid for a crosstab, but you will not find the series when it is a non-crosstab. You can think of a scene as describing one instance of visual representation. It is generally local to each panel or section of the chart and it's represented by a group of variables that are organized hierarchically. Depending on the scene, it may contain one or many datums. And you must be asking what a a datum is. A datum represents a row, so it contains values for multiple columns. We also can see from the example that we are referring to atoms, which hold at least a value, a label, and the key of a column. To get a better understanding of what I am talking about, you should perform a breakpoint anywhere in the code of the previous function and explore the object scene.
[ 298 ]
Chapter 8
In the previous example, you would be able to access the category, series labels, and value, as you can see in the following table:
Value
Category
Series
Corosstab scene.vars.value.label
Non-crosstab scene.vars.value.label
or
or
scene.getValue(); scene.vars.category.label
scene.getValue(); scene.vars.category.label
or
or
scene.getCategoryLabel(); scene.atoms.series.label
scene.getCategoryLabel();
or scene.getSeriesLabel()
For instance, if you add the previous function code to a chart that is a crosstab where the categories are the years and the series are the territories, if you click on the chart, the output would be something like: [info] WD: Category:2004 & Value:23630 [info] WD: Series:EMEA
This means that you clicked on the year 2004 for the EMEA. EMEA sales for the year 2004 were 23,630. If you replace the Logger functions with fireChange as follows, you will be able to make use of the label/value of the clicked category to render other components and some details about them: this.dashboard.fireChange("parameter", scene.vars.category.label);
Internationalization of CCC Charts
We already saw that all the values coming from the database should not need to be translated. There are some ways in Pentaho to do this, but we may still need to set the title of a chart, where the title should be also internationalized. Another case is when you have dates where the month is represented by numbers in the base axis, but you want to display the month's abbreviated name. This name could be also translated to different languages, which is not hard.
[ 299 ]
Visualizations Using CCC
For the title, sub-title, and legend, the way to do it is to use the instructions on how to set properties on preExecution and the instructions that we already covered in an earlier Chapter 6, Tables, Templates, Exports, and Text Components about i18n. First, you will need to define the properties files for the internationalization and set the properties/translations: var cd = this.chartDefinition; cd.title = this.dashboard.i18nSupport.prop('BOTTOMCHART.TITLE');
To change the title of the chart based on the language defined, we will need to define a function, but we can't use the property on the chart because that will only allow you to define a string, so you will not be able to use a JavaScript instruction to get the text. If you set the previous example code on the preExecution of the chart, you will be able to do so. It may not only make sense to change not only the titles, but for instance it may also be advisable to internationalize the month names. If you are getting data such as 2004-02, this may correspond to a time series format as %Y-%m. If that's the case and you want to display the abbreviated month name, then you may use the baseAxisTickFormatter and the dateFormat function from the dashboard utilities, also known as Utils. The code to write inside the preExecution would be: var cd = this.chartDefinition; cd.baseAxisTickFormatter = function(label) { return Utils.dateFormat(moment(label, 'YYYY-mmm'), 'MMM/YYYY'); };
The preceding code uses baseAxisTickFormatter, which allows you to write a function that receives an argument, identified on the code as a label, because it will store the label for each one of the base axis tick marks. We are using the dateFormat method and moment library function to format and return the year followed by the abbreviated month name. You can get information about the language defined and being used by running the following instruction moment.locale();
If you need to, you can change the language. If so, please refer to the CDF chapter, as we already covered it there.
[ 300 ]
Chapter 8
What are extension points and how do you use them?
One great thing about the options that you can use is that they are are already implemented. If not, and if they are available as part of Protovis but just not in CCC, you are able can make use of the extension points. So, with extension points you are able to use properties/options that are not implemented directly in CCC. They are one of the great features of CCC charts, because they provide almost direct access to the underlying Protovis marks. When setting an extension point, we should specify its name and value. The name is a combination of a CCC identification and the Protovis property name separated by an underscore (_). For instance, to define the fill style for the legend, you would need to define legendArea_fillStyle and set a color. First you need to set the visual element, followed by (_) and by the extension point property. There are no ways to handle the right-click action in CCC, nor is there the possibility to directly listen to the context menu in a Protovis mark, so we can make use of extension points. A good example is: bar_event: [ ['contextmenu', function(s) { … }], ['mouseover', function(s) { … }], ['mouseover', function(s) { … }] ]
For each chart type, you will find at the bottom of each chart type the extension points that are available. For instance, the extension points that are available for line charts can be found at: http://www.webdetails.pt/ctools/ ccc/#type=dot&anchor=extension-points. The image on the left is an example of it.
[ 301 ]
Visualizations Using CCC
When you click on a visual element name such as baseAxisGrid_, you will be redirected to another page where you can select the mark, which is the image at the center. Let's suppose that you choose to change the label, you need to add the mark to the visual element like baseAxisGrid_label. Finally, after clicking on the marker, you get a list of extension points, which is the image on the right, where you can select the extension point. Let's suppose you have chosen to change the font. It will also need to be added to the property and will end up as baseAxisGrid_labelFont.
For the provided extension point, we would need to specify the font and size, as specified at: http://www.w3.org/TR/CSS2/fonts.html#font-shorthand.
Formatting a basis axis label based on the scale
When you are working with a time series chart, you may want to set a different format for the base axis labels. Let's suppose you want to have a chart that is listening to a time selector. If you select one-year old data to be displayed on the chart, certainly you are not interested in seeing the minutes on the date label. However, if you want to display the last hour, the ticks of the base axis need to be presented in minutes. There is an extension point we can use to get a conditional format based on the scale of the base axis. The extension point is baseAxisScale_tickFormatter, and it can be used like in the code as follows: baseAxisScale_tickFormatter: function(value, dateTickPrecision) { switch(dateTickPrecision) { case pvc.time.intervals.y:
[ 302 ]
Chapter 8 return format_date_year_tick(value); break; case pvc.time.intervals.m: return format_date_month_tick(value); break; case pvc.time.intervals.H: return format_date_hour_tick(value); break; default: return format_date_default_tick(value); } }
It accepts a function with two arguments: the value to be formatted and the tick precision, and should return the formatted label to be presented on each label of the base axis. The previous code shows how the function is used. You can see that a switch based on the base axis scale will perform a different format, calling a function. The functions in the code are not pre-defined—we need to write the functions or code to create the formatting. One example of a function to format the date is using the utils dateFormat function to return the formatted value to the chart. The following table shows the intervals that can be used when verifying which time intervals are being displayed on the chart: Interval
Description
Number representing the interval
y
Year
31536e6
m
Month
2592e6
d30
30 days
2592e6
d7
7 days
6048e5
d
Day
864e5
H
Hour
36e5
m
Minute
6e4
s
Second
1e3
ms
Milliseconds
1
[ 303 ]
Visualizations Using CCC
Customizing tooltips
CCC provides the ability to change the default tooltip format, and can be changed using the tooltipFormat property. We can change it, making it look like the following image, on the right. You can also compare it to the one on the left, which is the default one:
The tooltip default format might change depending on the chart type, but also on some options that you apply to the chart, mainly crosstabMode and seriesInRows. The property accepts a function that receives one argument, the scene, which will be a similar structure as already covered for the click event. You should return the HTML to be shown on the dashboard when we hover the chart. In the previous image, you will see on the chart on the left side the defiant tooltip, and on the right a different tooltip. That's because the following code was applied: tooltipFormat: function(scene){ var year = scene.atoms.series.label; var territory = scene.atoms.category.value; var sales = Utils.numberFormat(scene.vars.value.value, "#.00A"); var html = '' + :/pentaho/plugin/cgg/api/
services/draw?script=/public/Ctools+Book+Samples/Chapter+8/CGGSample/ CGGSample_chart.js&outputType=png.
This URI uses two parameters, the script and the output type. The first one is used to point to where the script to generate the chart is located. This script is only generated when you enable the checkbox in the CGG dialog box and just after saving the dashboard. When you save the dashboard, the script is generated and you can make use of it. Using CGG, charts can be exposed as a PNG or SVG image. Let's see how we can make this happen. We can change the outputType parameter and set the string png to get a PNG image or set svg to get an SVG image. I always prefer to use SVG but, if you have some incompatibilities, you can use the other option. By default, CGG uses PNG.
[ 314 ]
Chapter 8
References
Other good sources of additional information and examples are the following links: • http://jsfiddle.net/user/duarteleao/fiddles/ • http://forums.pentaho.com/showthread.php?161089-CCC-FAQFrequently-Asked-Questions-About-CCC
Summary
In this chapter, we provided a quick overview of how to use CCC in CDF and CDE dashboards and showed you what kinds of chart are available. We covered some of the base options as well as some advanced options that you might use to get almost a fully custom visualization. Might be that some of the properties are not available in the CDE GUI, but the properties and respective values might be used in the preExecution or postFetch function of the CCC component being used. You should now know about internationalization and how to customize tooltips, and even how to deal with the click event, creating interaction with new components. When starting out using CCC, you might not be interested in debugging, but if you are or are intending to be an advanced user, you should start looking into it. We also covered what an extension point is and how to use it. In the next chapter, we are going to cover the Pentaho App Builder and you'll see how to build a Pentaho plugin with it.
[ 315 ]
Pentaho App Builder Pentaho App Builder is one plugin you can use to build your Pentaho plugins. The most interesting part of it is that you don't need to create any code to get it working. Yes, you heard right, no code. In this chapter, you will learn about: • Pentaho App Builder • Community Plugin Kick-starter • Creating a dashboard • Making a plugin available on the marketplace By the end of this chapter, you will understand Pentaho App Builder and how to work with it. There was a time when you would have needed to know how to write Java code for the back end of the plugin, but now it's much more simple and more accessible to many more people. You will also know what the Community Plugin Kick-starter (CPK) is and its relationship with Pentaho App Builder. You really need to understand the concepts behind CPK, because that's where most of the magic happens. Pentaho App Builder is just a graphical interface that leverages the work. You will also see that with CPK, you are able to make use of jobs directly, and not just transformations like in CDA. We'll give you some tips and tricks that you will find very useful.
[ 317 ]
Pentaho App Builder
Understanding Pentaho App Builder "Sparkl, or Pentaho App Builder, is a plugin creator instrument that sits on 2 major cornerstones of Pentaho: CTools and PDI, aiming to leverage as much as possible of our existing stack." – Pedro Alves The main idea is to use both of the two most amazing tools in Pentaho: the CTools and Kettle (also known as Pentaho Data Integration). If you know how to build Kettle jobs and transformations and also know how to build a dashboard, you should be able to build a Pentaho plugin. If not, it's about time to learn. I can recommend you two books: https://www.packtpub.com/big-data-and-
business-intelligence/pentaho-data-integration-beginners-guidesecond-edition and https://www.packtpub.com/big-data-and-businessintelligence/pentaho-data-integration-4-cookbook.
If you didn't know Java code, it would be hard for you to create a plugin, but that's not the case anymore as you are able to do it without the need to write Java code. You can also create a CTools dashboard without writing a line of code; however, as I already told you earlier in the book, you will need to write some JavaScript to build remarkable dashboards. Not that you need to know a lot of JavaScript; you just need to understand it and adjust some code in the book or in the included samples. We are making the absolute most of the existing skills of data developers. When we talk about building a web application, usually we will talk about having a back end and a front end. Pentaho App Builder works on top of CPK. CPK provides a way to simplify the structure of a Pentaho package application, where the UI can be built as a CDE dashboard and the back end as a Kettle transformation/job. There are other options, such as making the back end using JavaScript or Java code. However, there is no need to do this if you can use Kettle.
Installing Pentaho App Builder
You can install Pentaho App Builder using Marketplace, and you just need to refer to the instructions in the first chapter. Pentaho App Builder has some dependencies, so make sure you have them installed: • CPF: Community Plugin Framework • CDE: Community Dashboard Editor • CDF: Community Dashboard Framework • CDA: Community Data Access [ 318 ]
Chapter 9
Create a new plugin
Open Pentaho App Builder using the PUC menu, or directly from http:// localhost:8080/pentaho/plugin/sparkl/api/main. When you start Pentaho App Builder, you will be in the following dashboard. I referred to the dashboard, because Pentaho App Builder is itself dashboard:
In the preceding image, you will find the following buttons/options: 1. Sort plugins by: This is to sort the plugins that are available in your Pentaho instance. Here, you only see the plugins that were built using Pentaho App Builder or CPK. 2. Refresh: This refreshes the list of available plugins. 3. Create a new Plugin: Click this plus sign to be able to create new plugins. You will learn more about this later in the chapter. 4. Play: This will open/execute the main dashboard of the plugin. 5. Edit: You will be redirected to another window where you can edit the metadata of the plugin, or create/edit/remove end points. 6. Remove: This deletes the plugin from the system folder. The files will be removed from the system folder of the server. When you create a new plugin using option 3, you need to enter the name of the plugin and click on the Create plugin button. You will get a message to restart the server. So please proceed. In future versions of Pentaho 6.X and new releases of Pentaho App Builder for Pentaho 6.X, it will be possible to generate a new plugin that becomes immediately available. [ 319 ]
Pentaho App Builder
After the restart, you need to go into Pentaho App Builder and edit your plugin. If you didn't set the metadata of the plugin, it's a good time to do it. Just fill out the form data and click on Apply Changes. The following image is an example of what you will get:
You will see two tabs: About and Elements. About is the information/metadata of the plugin. Elements is about the endpoints of the plugin:
[ 320 ]
Chapter 9
In the preceding image, we can identify the following sections: 1. Plugin name: The plugin's ID/name. 2. Add new element: You can click on this plus button to add a new endpoint. It can be a dashboard or a Kettle job/transformation. We will cover these separately in this chapter. 3. Display options: You can select the type of add-in you want to be displayed. It can be a dashboard or a Kettle transformation/job, or both at the same time. In the image, you can see a dashboard that can be used as the front end and a Kettle transformation/job as part of the back end. 4. Refresh button: This will let you refresh the endpoints available. You can add a dashboard or transformation/job to the endpoints folder in the plugin system folder, and you can then refresh the plugin to see the endpoints listed, so there is no need for a restart. 5. Available endpoints: Here you will get a list of the available endpoints. The list will include the name, type, and permissions. The type will give you information about whether it's a dashboard or Kettle endpoint.
Creating a new endpoint
An endpoint can be considered as a URI and HTTP method that directly gets a response from the server. For instance, when invoking the URI, we might get a dashboard or the result from a Kettle job/transformation. It does not need to be invoked from the plugin itself, as you can run a Kettle endpoint from another application, but of course one of the use cases it to use the end points inside the plugin itself. We saw in Chapter 2, Acquiring Data with CDA, that we can use CDA to get data from a Kettle transformation, but using Pentaho App Builder to do so, you can also use jobs to execute some actions and return success or error messages, download a file/multiple files, or have a custom format. Note that you should use Pentaho App Builder only if you're building one application/plugin, otherwise you might build a normal dashboard or use CDA endpoints to get data. If you can't do this with a regular dashboard and CDA data sources, then use Pentaho App Builder. Like we have already covered, there are two kinds of endpoints that you can use in Pentaho App Builder/CPK. When creating a new element, you need to specify its name and type: • A Pentaho Data Integration (Kettle) job/transformation • A CDE dashboard [ 321 ]
Pentaho App Builder
Creating a job/transformation
To create a new Kettle endpoint, you will need to specify the name and the type Kettle Endpoint. You will also need to choose from Clean Job or Clean Transformation. You can also create a Kettle transformation that can be executed only by an administrator:
After the endpoint has been created, you will see it as shown in the following image:
There are two buttons here you can use for each Kettle endpoint: 1. Execute the endpoint: This will trigger the execution of the endpoint. 2. Remove/delete the endpoint: This removes the endpoint, and will ask for confirmation. You don't have a button to edit the Kettle transformation/job, and that's because it's not possible to open Data Integration in the browser.
Starting to learn about CPK
Like we covered earlier, CPK is where almost all the magic exists. In reality, the plugins that you create with Pentaho App Builder are CPK plugins that might be created by Pentaho App Builder, the web interface that allows you to do so easily. CPK lets you expose the Kettle jobs, transformations, and dashboards as a REST endpoint. You can call them using either of the following calls: • http://://plugin//api/ {kettleFileName}
• http://://plugin//api/ {dashboardFileName}
Here: • host: This is the hostname or IP of the server. It can be localhost when you have Pentaho installed on the same machine as the request. • port: This is the port we can use to access the Pentaho server. It is 8080 by default. [ 322 ]
Chapter 9
• webapp: This is the web app's name, which by default is pentaho. • cpkPluginId: This is the ID of the plugin that you specified when creating the plugin. • kettleFileName or dashboardFileName: This is the name of the endpoint you are requesting. You can specify the name of the dashboard or the name of a Kettle transformation or job. When we create a Kettle transformation or job using Pentaho App Builder, as explained earlier, you will get the following parameters automatically created for the job or transformation you have created: Parameter #cpk.cache.isEnabled #cpk.cache. timeToLiveSeconds
Default value false
Description
3,600
This shows how many seconds a result will be cached for. Setting this value to 0 means the result will be cached forever.
This enables/disables the caching of results.
#cpk.executeAtStart
This indicates whether the transformation is to be executed when the plugin is initialized or not.
#cpk.plugin.dir
This is the plugin folder.
#cpk.plugin.id
This is the ID of the plugin.
#cpk.response. attachmentName
This is the attachment name used when downloading a file from a result.
#cpk.response.download
false
This shows whether or not to mark the HTTP response body as an attachment.
#cpk.response. kettleOutput
This is the output format to be used by default. The possible values are: Infered, Json, SingleCell, ResultFiles, and ResultOnly.
#cpk.response.mimeType
This is the mimeType of the HTTP response. If this value is not set, the plugin will try to determine it from the file extension.
#cpk.result.stepName
OUTPUT
This is the default output step where the rows will be fetched for the result.
#cpk.session. [sessionVarName]
This is the value of the session variable named [sessionVarName]. It will be automatically injected when the variable is enabled.
#cpk.session.roles
These are the roles of the username executing this transformation. [ 323 ]
Pentaho App Builder
Parameter
Default value
Description
#cpk.session.username
This is the username that is executing this transformation.
#cpk.solution.system. dir #cpk.webapp.dir
This is the pentaho-solutions folder. This is the webapp folder.
By default, all the parameters are disabled. To enable the parameter, you should remove the # from the beginning of its name. Otherwise, it will be seen as a comment.
Specifying the step of where to get results from
A Kettle endpoint (job or transformation) may have multiple steps or job entries where we can get the results from. You are able to choose which step to retrieve data from. This can be done by setting the name of the step/job entry to start with OUTPUT. Just prefix the name of your step with the referred string and see the results returned to the caller of the endpoint. There is also another way. It is possible to specify which step entry we want to fetch the row results from—we just need to include the stepName parameter in the query string of the request. To make it easier to identify the step name where to pull the information from, we need to add to our URI ?stepName=OUTPUT: http://://plugin//api/ {dashboardName}?stepName=OUTPUT
By default, CPK will try to find an OUTPUT step name. A bit later on, we will cover how you can change the step name directly in the jobs/transformations using the cpk.result.stepName property.
Specifying parameters' values
It's very useful that you can pass parameters to a transformation/job. To do so, you need to prefix the name of the parameter with param. If the parameter name is called territory, you need to use paramterritory, as shown here: http://:/pentaho/plugin//api/{dashboardName} ?paramterritory=EMEA
[ 324 ]
Chapter 9
Changing the output format type
CPK will try to guess the output type; however, you can specify the output type you desire. We may want to return data to the caller, or just return a file that can be downloaded. The available options are as follows: • Json: This returns the result rows in a standard CDA-like result set format (metadata / queryinfo / resultset), just like a CDA data source. • ResultFiles: This gets the files that were set in the result. For this to be enabled, we need to set the option Add filename to the result set. • SingleCell: This returns the content of the first cell of the first row in the result. This allows us to return other format types, for instance XML. • ResultOnly: This returns status information about the execution. This is usually the output of the executions of a job. We can select the desired format by setting a query string parameter like in the following link. The query string name is kettleOutput: http://:/pentaho/plugin//api/{dashboardName} ?paramterritory=EMEA
You want to avoid the use of the query string parameter, and you also have the transformation/job parameter cpk.response.kettleOutput that you can change. When the parameter cpk.response.kettleOutput isn't used, CPK will try to infer it. Take a look at the following diagram:
[ 325 ]
Pentaho App Builder
The previous diagram is the decision logic to determine which will be the result returned from the endpoint. When the option resultFiles is used, CPK will compress all the files inside a .zip file, which is returned, but keep in mind that if the result only includes one file, CPK will not zip it and will return the files, so if you're using a browser, the browser will try to determine the mime type from the file extension. If the mime type is known, the browser will try to render the file and not download it. You can also force the file to be downloaded if it's a single file. This can be achieved by setting cpk.response. download to true. If you also want to specify the mime type so that the browser can understand its content, you can do this by setting the parameter cpk.response.mimeType to the desired value (for example, an application/XML). Specify the filename for the downloaded file To specify the filename, you can use the parameter cpk.response. attachmentName, or set the query string parameter name attachmentName.
Returning a single cell
Let's suppose you want to return your own JSON or XML structure. How would you do so? To achieve that you need to return a single cell. You should follow the same behavior as for the result file. This will also behave as defined by the use of the parameters cpk.response.download, cpk.response.mimeType and cpk. response.attachedName.
Other considerations
Each CPK plugin has its own cache to store the results obtained from the execution of its endpoints. By default, caching is disabled and to enable it, you set the value of the transformation/job parameter cpk.cache.isEnabled to true. The length of time that the results will remain cached can be set by setting the time in seconds using the parameter cpk.cache.timeToLiveSeconds.
[ 326 ]
Chapter 9
Creating a dashboard
To create a new dashboard, just add the name of your dashboard and select the type Dashboard. You will also need to select its style between a clean dashboard or a Pentaho App Builder template dashboard. I advise you to use the clean dashboard and apply your own styles, or create your own style (similar to what was explained in Chapter 7, Advanced Concepts using CDF and CDE):
There is also a checkbox you can check if the dashboard should only be accessible only to Pentaho administrators. When you create a new endpoint, the dashboard will become available. The following image is an example of a row displaying a dashboard endpoint. After the endpoint has been created, you will see the following image:
There are three buttons you can use for each frontend endpoint (dashboard): 1. Open the dashboard: This will trigger the execution of the dashboard. 2. Edit the dashboard: This will open the dashboard in edit mode. 3. Remove / Delete the endpoint: This removes the endpoint, and will ask for confirmation. A dashboard is used like the Kettle endpoints are. The URL to call is basically the same, and the only change is the name of the endpoint, which should point to the name of the dashboard. You can invoke dashboards using the following calls: • http://://plugin//api/ {dashboardFileName}
• http://://plugin//api/ {dashboardFileName}?mode=edit
In the second call, you will see ?mode=edit, meaning that we want to open the dashboard in edit mode, while the first one will open it in render mode.
[ 327 ]
Pentaho App Builder
There are some default endpoints already defined that you can use so you don't give the same name to the dashboards or transformations/jobs. The endpoints are as follows: • status: Displays the status of the plugin and all its endpoints • refresh or reload: Reloads all the configurations, endpoints, and dashboards, and also clears the endpoints cache • version: Returns the plugin version (defined in the plugin's version.xml file or through the control panel) • getSitemapJson: Returns a JSON object with the plugins sitemap (for dashboards only!) • getElementsList: Returns a JSON object with the whole list of elements present in the plugin (dashboards and Kettle endpoints)
Folder structure
The folder structure of the plugins is as follows: dashboards | endpoints | static | resources | lib | plugin.xml
Where, they are explained as follows: • dashboards: Inside the folder are all the dashboards that have been created and that should be accessible to all users. Any dashboard that is placed inside the admin folder will only be available for administrators. • endpoints: All backend endpoints, Kettle jobs, and transformations should be placed inside a kettle folder. When the name of a Kettle job or transformation is prefixed by _, the endpoint will not become available as an external endpoint. This makes it possible to have private endpoints that can only be used by another job and/or transformation. • static: All CSS, JavaScript, and images can be placed here, and will be available to be used inside the dashboard. • lib: This is where the Java libraries can be placed. • plugin.xml: This is the file where all the configurations are set. Here you may uncomment the menu-item tag and make a menu item available to open the dashboard when the option is clicked: [ 328 ]
Chapter 9
Making use of Kettle endpoints on a dashboard
You may use some of the Kettle endpoints you have created for each of the plugins available on the server. When creating the dashboard, in edit mode of course, if you go to the data sources perspectives, you will find some data sources groups that are new to the list of data sources types. Inside each one of those groups, you will find a list of endpoints that you have created for your plugin, but also can be used in other plugins. Each plugin will have its own group, and the data sources inside are the data sources for each of them, as shown here:
The previous image is one example of the groups that will become available, and you will also see your own data sources or the data sources you have created for your plugin. You can see in the following image two plugins: myPlugin and d3ComponentLibrary. There are two endpoints that belong to myPlugin: getData and removeMe:
[ 329 ]
Pentaho App Builder
You can make use of this endpoint as another data source, except that you will have fewer options. The preceding image shows you that an endpoint provides three properties: • Name: Used the same as with other data sources. This is the name of the data source that can be set on a component. • Output step: This is where you can set the name of the step where you want to extract data from. • Output type: This sets the output type of the data source. The available options that you can select from the dropdown when you start typing or clicking down are as follows: °°
Inferred: This lets CPK infer the result, as explained earlier.
°°
JSON: The result will be a Json object like any other CDA data source.
°°
ResultFiles: This will return a file, which may be the only one, or a .zip file with all the files that are being used in the dashboard. You will need to check the option add filename to the result set for the steps where the option is available. Doing so is not mandatory for all the steps but only for the ones where the files will be exported from. The filenames are used to identify the files to export.
°°
ResultOnly: This is usually used when the endpoint is a job.
°°
SingleCell: This is used when you want to get a custom result. You set the output that you wish for a single cell as a string. The result of the string of a single cell will be returned.
But how about parameters? Can't we use parameters and pass them to a transformation/job? Yes, you can, but you need to define them in the parameters of the component that is using the data source. Using another plugins endpoint When using another plugin transformation from another Pentaho App Builder plugin, you need to take care, because there will be an endpoint that belongs to another plugin, and that's a dependency. There is no problem doing so, you just need to make sure that you include the plugin as a dependency, so that users installing your plugin know that another plugin needs to be included.
[ 330 ]
Chapter 9
When you use a data source (that is, a plugin endpoint) in a component, you may specify the parameters to pass to the transformation/job. Check the following image:
Let's suppose you have a parameter in your little transformation called myKettleParameter. You can send a value to the transformation by creating a mapping with the parameter of the dashboard. When using a table component, for instance, you may define the data source and the parameters to be sent to the data source. The preceding image is one example of the image you will get when setting the parameters. On the left, you will need to specify the name of the parameters of the transformation, and on the right, the name of the parameter of the dashboard. This will create a mapping between both, and that's the way we can send a value to a Kettle parameter. You can add as many parameters as you need. Just don't forget that if you are adding too many parameters, you may be doing something wrong. When creating a plugin, you don't always want a job/transformation to be used as a way to get data for the front end. You may want the dashboard of the plugin to perform some action. For that purpose, you can use a Kettle transformation or job. You can use your own code to do so, or you can use the button component. The button component has a property called Action Datasource, where you can choose one of the data sources to execute when clicking the button. The action parameters property is where we can specify the parameters mapping between the Kettle job/transformation and the dashboard parameters. There are two callbacks you can use when setting Action Datasource: • Success Callback: This will be executed when the job/transformation is executed with success. • Failure Callback: This will be executed when the job/transformation fails to execute.
[ 331 ]
Pentaho App Builder
The functions that can be defined are as follows: function(result) { … // Make use of the result returned to the dashboard. … }
The function receives one argument, which is the result returned to the dashboard. Inside the function, you will need to write the code to parse the information and display it, or just interpret it.
How do I make the plugin available on the marketplace?
As soon as the plugin is developed and in a stable state, it is ready to be shared to the community. CPK is able to generate a .zip file with metadata information so it is able to be published to the marketplace. Of course, if you are building the plugin for a customer, you don't want to make it public, so you don't need to go through these steps. To submit the plugin, you need to follow the instructions provided at the following link: https://github.com/pentaho/marketplace-metadata. The following instructions assume that you have the git command line installed and available. As you can see, there are three main steps: 1. Clone the repository: To do this, you first need to create a GitHub account, which can be created for free. Go to https://github.com/pentaho/marketplace-metadata and click on the fork button, which will create a fork of the repository in your account. You will then be able to clone the fork in your account. There are many ways to clone the repository, and one of these ways is to execute a line, as follows: git clone [email protected]:mfgaspar/marketplace-metadata.git
This will create a folder with all the files needed. The file you will need to change is marketplace.xml. These steps are required to make it possible to perform the submit request.
[ 332 ]
Chapter 9
2. Update the marketplace.xml file with your market-entry: You should edit the file and add an entry as explained in the instructions provided on the Pentaho marketplace metadata link we just mentioned. After you've filled out all the necessary information, you can proceed with the pull request, but first you will need to commit the changes to your repository. To do so, you can run the following in the command line: git add marketplace.xml git commit –m "Adding myPlugin to the marketplace"
3. Submit a pull request to have your plugin reviewed for inclusion on both the marketplace plugins and the Pentaho Marketplace website. To submit the pull request, you need to go back to your Pentaho Marketplace fork page, add click on Pull Request, and include a message. Pentaho will need to categorize and approve the plugin before it becomes available on the marketplace.
Summary
As you can see, it's pretty simple to create a new plugin for Pentaho. I really hope you can have a brilliant idea that we can use, that becomes available on the marketplace. In this chapter, you learned that you can build a plugin just by creating endpoints that are accessible from the browser, and this can be very useful when integrating Pentaho with third-party applications. In the next chapter, we will cover what we have missed until now, for example, how to embed a CDF/CDE dashboard in a third-party application and how to perform debugging.
[ 333 ]
Embed, Deploy, and Debug Usually, one of the request from customers is to embed dashboards in a third party application. Using RequireJS, doing so is simple and very flexible. You can build mini dashboards that you can easily embed into your application without interfering with the dashboard's default behavior. In this chapter, you will learn how to embed both CDF and CDE dashboards into third-party applications and will explore some considerations. In all the earlier chapters, you learned how to build a dashboard using CDF and/or CDE. But when we are developing them, we may face some problems, and it would be great to know what should we be looking for. In this chapter, you will get information on how you can debug the dashboard using the developer tools in your browser. One of the last phases of a project is delivery to the customer or internally to a department, or any other issue that you find. In this chapter, you will also learn some concepts that will help you deploy a project and you'll explore some considerations when delivering a project to a customer. You may also know, if you've been paying close attention, that there are some CTools that have Pentaho support. If you are a Pentaho customer who has paid for support, you may raise a support case for CDA, CDF, CDE, and CGG, which are the supported tools. Otherwise, if you are a community user, you have other options that may not be as good and quick as support, but we will explore the options so you can find some help if you need it. In this chapter, you will learn how to: • Embed CDF and CDE dashboards • Avoid cross-domain references problems • Handle events from outside the dashboard • Debug dashboards when developing them [ 335 ]
Embed, Deploy, and Debug
Embedding dashboards
A frequent question or request that I get from customers is how to embed the dashboards in another application. To be honest, the process before RequireJS was introduced into CDF was quite hard and was not interesting. The possibilities, and I will not get into details of them, were to use an HTML iframe, but this came with a lot of problems later on, it was not really suitable for mobiles, and it was bad from the usability point of view. Another option would be to use html div integration, but that created conflicts in JavaScript libraries and in the CSS, so it might create a mess when styling your pages. With the use of RequireJS, the process is much more simple and flexible, and does not cause big issues. Of course, you might find some minor issues, but they can be easily identified and fixed. The process of embedding a CDF and a CDE dashboard is different, even if the base concepts are quite similar. Of course, the first step before embedding a dashboard, is to create that same dashboard. This is valid when embedding a CDE dashboard, because a CDF dashboard is created at the same time you are embedding it. The good news, which you should be expecting, is that you don't need to do anything different from what we've covered up to now to create a dashboard that can be embedded. A really good advantage is that you can embed the same dashboard multiple times in your application. And you may build a kind of mini dashboard that you can use multiple times.
Avoiding cross-domain requests
Before you start embedding your dashboards, you need to be aware of how to avoid cross-domain request issues. When embedding dashboards in other applications and in earlier versions of CDF and CDE, you needed to have a reverse proxy working to avoid cross-domain request issues. Nowadays, the process is really simple. You can turn on an extra setting for CDF and CDE. To properly allow embedding, which usually requires cross-domain requests, you will need to add the following XML tag, and that's valid for both CDF and CDE. Edit the settings.xml file of CDF and/or CDE, which you will find in your pentaho-solutions folder: system/pentaho-cdf-dd/settings.xml and system/ pentaho-cdf/settings.xml. Then add the following property: true
[ 336 ]
Chapter 10
Depending on the configuration of your server, you may need to restart the server. If you don't know what I am talking about, just restart it and you will see it working without cross-domain request problems. So now let's start embedding some dashboards.
Embedding a CDF dashboard
A CDF dashboard can be easily embedded in any HTML page hosted anywhere— you just need to include a script to embed CDF in your web page/application. The script will ask for CDF, and the request should be made to a Pentaho Server that has CDF installed. The script to include is as follows:
Where: • : This should be replaced by the server name or IP and the port number when different from 80. • : This should be replaced by the web app name. By default, it's Pentaho, but this can be changed. If your Pentaho server is hosted on the same machine as your application and the web app is the default one, your request would be:
That's it … Okay, you must be asking, but how do I include the dashboard in my application/site, because I only saw how to call CDF's embedded capabilities? Well, a CDF dashboard is nothing more than JavaScript code you have built, so you can include it on your web page/application now and it will work. From the Chapter 3, Building the Dashboard Using CDF you must remember that we had at least two files, but one of them was just to be used by Pentaho.
[ 337 ]
Embed, Deploy, and Debug
The main one is the .xcdf file, which is an xml file that identifies the dashboard when you double-click on it. It reality, it will be rendering a web page with the dashboard inside. This file will point to two more files, both HTML pages. The first one is the dashboard itself, which is an HTML page where you can also include scripts (JavaScript and CSS, among others) and it is where the code of your CDF dashboard should be. The second one is just a wrapper for the first one. If you want more details, please refer back to Chapter 3, Building the Dashboard Using CDF. Please check whether the code of your dashboard (the code that .xcdf is pointing to) is like the following:
If so, the code of your web page/application should be like this: mySample
[ 338 ]
Chapter 10
As you can see, one of the ways to embed the dashboard is really simple—just embed CDF by calling it as a script and include the code to create your CDF dashboard. You have a mini dashboard that you want to reuse, so you can wrap it with RequireJS and reuse it as many times as you need—just don't forget that you also need the HTML elements on the page. I believe that, at this time, you should be able to find a way to do it. You have all the concepts, or you just need some more JavaScript and RequireJS knowledge, but that's not really the purpose of this book.
[ 339 ]
Embed, Deploy, and Debug
Embedding a CDE dashboard
Embedding a CDE dashboard can be quite simple. You really need to create your own dashboard using CDE in Pentaho. When you have your dashboard working, you just need to request it. To make it possible to embed a CDE dashboard, we first need to embed CDE, just like we saw for CDF, but this time we request CDE to be embedded:
You can now embed a dashboard in one of two different ways. Using RequireJS in your web page/application, you will be able to include a dashboard as a module. The two ways to do this are: 1. Directly point to the getDashboard endpoint available in CDF: '/pentaho/plugin/pentaho-cdf-dd/api/renderer/ getDashboard?path=/public/dash/sample.wcdf'
2. Use the dash! RequireJS loader plugin: 'dash!/public/dash/sample.wcdf'
So, let's explore how to use it. The first step is to create a CDE dashboard. Only after you have a dashboard, do you need to include the dashboard in your web page/application. Your dashboard and/or web page/application just needs to include the following code: require([ '/pentaho/plugin/pentaho-cdf-dd/api/renderer/getDashboard?path=/ public/dash /sample.wcdf' ], function(SampleDash) { var sampleDash = new SampleDash("content1"); sampleDash.render(); });
[ 340 ]
Chapter 10
Or it could include: require([ 'dash!/public/dash/sample.wcdf' ], function(SampleDash) { var sampleDash = new SampleDash("content1"); sampleDash.render(); });
If you look at both examples, you will notice a difference: the link to the module required. Both options will have a RequireJS module that contains a class for a specific dashboard. You can create new instances of that class, just to provide an element ID, or the element itself. The returned class extends the Dashboard class and adds some new methods: • render(): This is used to render the dashboard, by first setting up the DOM, adding the components and parameters to the dashboard, and finally calling the init() function • setupDOM(): This is used to set up a predefined layout inside its element • renderDashboard(): This adds the components and the parameters to the dashboard, and then initializes it You may use render() to render the dashboard; or, for better control, you may use setupDOM() followed by some logic of yours to manipulate the DOM, and finally call element.renderDashboard(). When embedding a CDE dashboard, your page does not need to provide all the HTML elements needed for the dashboard, because you have created them. You just need to have one element where all the other elements will be placed.
Dashboard, component, and parameter events
One interesting feature that embedded CDE provides is the ability to manage events from the outside. For instance, we can create a link between dashboards. The way to do this is using dashboard events.
[ 341 ]
Embed, Deploy, and Debug
Let's suppose you have one instance for each of two dashboards. Both dashboards have one parameter in common, productLine. The first dashboard has one selector that allows you to change a product line, and the second dashboard has a chart that is listening to a parameter with the same name. The parameters from each of the dashboards will not automatically be linked, so we need to specify that connection: require([ 'dash!/public/dash/selectorDash.wcdf'], 'dash!/public/dash/lineChartDash.wcdf'], function(SelectorDash, LineChartDash) { var selectorDash = new SelectorDash("selector"); selectorDash.render(); var lineChartDash= new LineChartDash("lineChart"); lineChartDash.render(); selectorDash.on("productLine:fireChange", function (evt) { lineChartDash.fireChange("productLine", evt.value); }); });
Looking at the code, you will see that, in the first dashboard, the productLine parameter is being watched, and a change is triggered by the fireChange function. For instance, when the user makes a selection, the code inside the function will trigger a change for the productLine parameter of the second dashboard. This creates a link between both dashboards. This feature is nothing more than an extension of Backbone.Events, so you can learn to use it to the fullest at http://backbonejs.org/#Events. The events can be triggered by the dashboard or by the components. The following events are available: • The events triggered by dashboards are as follows: °°
Parameter changes: When a parameter changes its value, the event :fireChange is triggered
°°
Dashboard pre-initialization: When the dashboard finishes running the pre-initialization scripts, the event cdf:preInit is triggered
°°
Dashboard post-initialization: When the dashboard finishes running the post-initializations scripts, the event cdf:postInit is triggered
°°
User not logged in error: When CDF detects that a user is no longer logged in, the event cdf:loginError is triggered
°°
Server error: If a call to the server returns an error, the event cdf:serverError is triggered [ 342 ]
Chapter 10
• The events triggered by components are as follows: °°
Pre-execution of the component: After the call to the preExecution function, the event cdf:preExecution is triggered.
°°
Post-execution of the component: After the call to the postExecution function, the event cdf:postExecution is triggered.
°°
Error: If an error happens during the execution of the component, the event cdf:error is triggered. This can be applied for each one of the components.
Managing events is important inside the dashboard, but the ability to manage events outside the dashboard becomes very important when we are embedding dashboards.
Debugging
When we are developing a dashboard, we may face problems and we need to know where to look for solutions. Many of the problems we face when developing a dashboard can be identified using the developer tools in your browser. I usually use Chrome, so the examples here are based on the developer tools of this browser. The version that was used while writing this was 46.0.2490.86 (64-bit). Anyhow, if you are using Firefox, you also have developer tools, or you can install Firebug, a developer tool that does not come installed by default. To be honest, I find the developer tools of Internet Explorer to be very poor, even if they are getting better in the latest versions of the browser. Anyhow, we must use them when we are debugging problems that only exist in this browser. Do not forget to test your dashboard on all of the browsers.
[ 343 ]
Embed, Deploy, and Debug
Browser compatibility
Like any other web page, a dashboard can work in one browser and fail to execute in another browser. Every browser has an engine, and they can be quite different. To check what each browser supports and does not support, and for which version, you can use the following site: http://caniuse.com. For instance, if you want to check which ones support SVG images, just search for SVG and you will see something like this:
The preceding screenshot shows browsers and their versions; a red rectangle means that SVG is not supported and a green rectangle shows the versions that are supported.
Debugging with developer tools
Among other features, developer tools allow you to inspect, edit, and monitor CSS, HTML, JavaScript, and network requests in any web page. If you want to know more, the following links show how developer tools work: • https://developer.chrome.com/devtools • https://developer.apple.com/safari/tools/ • https://developer.mozilla.org/en-US/docs/Tools • https://msdn.microsoft.com/en-us/library/dd565628.aspx
[ 344 ]
Chapter 10
When a dashboard is rendered, the CSS and JavaScript files are minified; thus, when you are debugging the dashboard, you must add a parameter to your URL. The parameter to be added is debug and it needs to be set to true. You can add it as ?debug=true if no other parameter exists or as &debug=true if another parameter already exists. Please look at the following two examples: • http://localhost:8080/pentaho/api/repos/%3Apublic%3Asample. wcdf/generatedContent?debug=true
• http://localhost:8080/pentaho/api/repos/%3Apublic%3Asample. wcdf/generatedContent?paramcountry=Portugal&debug=true
Both examples will allows you to debug the dashboard the only difference is that one has a parameter and another one does not, so one uses the & to set the debug to true, and the other one uses a ? to set the debug mode to true. This will make CDF and CDE return non-minified versions of the code, and you will be able to check and understand the code. It will even be possible to add some breakpoints. It is not the purpose of this book to teach you how to use developer tools, but I will give you some hints about the main and basic concepts to start with. This doesn't mean you should forget about your need to have a better understanding of developer tools for different browsers. On Chrome, open the developer tools using Ctrl + Shift + I (or command + option + I on the Mac) to open them. You will get something like the following screenshot:
[ 345 ]
Embed, Deploy, and Debug
In the preceding screenshot, you can see three numbers: 1: This is where you can get details about HTML elements, the network, and sources. 2: This is where you display the CSS of each element you can select in panel 1 when you are in the Elements tab. • When you're in the Elements tab, you can to evaluate HTML and CSS, and you can also change HTML and CSS and preview the changes in real time. The changes are not saved to the dashboard, nor to file. • When you're in the Network tab, you can get information about the requests made to the server. On the highest level, there are two types of errors you can expect here when using developer tools: the front end and the back end. When you get errors executing queries, it means that something went wrong when executing queries. You should first look at the request that is being executed; if it all looks fine, then you need to find the errors on the server side, and here the browser's developer tools can't help you. In these cases, you need to look at the errors on the server side and, if you're not getting the necessary information, you might need to increase the log level, but on the server side. • When you're in the Sources tab, you can display each of the files loaded and needed for the execution of the dashboard. This is where is you can add breakpoints and pause the execution so that you can evaluate the code at a specific time. When the errors happening in the dashboard are not at the back end, then the Source tab is where you might need to look and to also interpret the logs being showed in the Console shown in 3. 3: The console is where you can get the messages being sent from the dashboard. This is where you need to search for errors. If they're not shown, you can press on the Esc key. We covered some examples of logs in Chapter 8, Visualizations Using CCC. Don't forget to learn a bit more about developer tools.
[ 346 ]
Chapter 10
Short tips
Keep one eye on the console, as it provides you with a lot of information. You can see the order of execution of the components, which part of the dashboard is being executed, and even errors and which file we get the logged information from.
The previous screenshot also shows one error. If you click on the error, you will be redirected to the place where the error is coming from. If it's a JavaScript error, the code will be displayed in the source tab. If it's a network request, it will display details in the request. You can create a breakpoint there.
The preceding screenshot shows the details of one of the queries being executed. Before looking at the server-side logs, make sure all the parameters are correct, as the full request.
[ 347 ]
Embed, Deploy, and Debug
When using the Source tab, to create a breakpoint in the code you just need to click on the left side of the line where you want to stop. You will see a blue sign that identifies that there is a breakpoint, and the code execution will be stopped when that part of the code is being executed. You need to make sure that the code is executed so that the execution can be paused. You can then control the flow of the process by jumping into functions, to the next line, or to the next breakpoint. When hovering over the variable, its current value will be displayed.
The preceding screenshot shows the code paused during the execution of the dashboard, and the mouse is hovering over the this variable, so we also see its value. In the top-right corner, you can see a toolbar, where you can jump to the next breakpoint, jump to the next line, jump into the next function, or jump out from current functions. You will also be able to disable breakpoints from pausing, among other options.
Delivering a solution
Before delivering a solution, you need to consider some aspects of the project. In reality, and as we saw earlier, they should be considered at the start of the project when everything is being planned. There are some phases of the project that are usually part of a successful project and can save you some time, but they can also help you create a better relationship with the customer and achieve a greater level of satisfaction. The documentation and knowledge transfer are two of those tasks, and another one is deploying a project and version control for our code.
[ 348 ]
Chapter 10
Version control and deploying projects
You can't afford to lose your work, do you? Can you also spend most lots of lying changes for development to quality acceptance tests or production environment? It's an important part of development that you keep all the code in a version control system. All content developed with or for Pentaho should be treated as a software artefact and tested and controlled as such. This is true even if we are talking about reports, such as the ones you can build with the standard Pentaho tools. For instance, a Pentaho Analyzer file is just an XML file that you can push into version control. The dashboards and CDA files that you produce with CTools are also files that you should push to the repository. This also applies to the version of configuration files from your Pentaho system, and some custom extensions that are not deployed to the repository can be controlled via a external version control system. Finally, even though the DI repository does have version control, it lacks an advanced version control system (VCS) feature such as branching or tagging. For this reason, Pentaho recommends managing all artefacts with a VCS such as GIT or SVN. The following diagram shows a conceptual architecture to deploy and test in different environments. Developers have the complete Pentaho stack on their development systems, or they might be developing on top of the development server. As artefacts are created and developer-tested, they get checked into VCS. Once a set of functionalities are completed and checked, they are pushed from development to the quality acceptance (QA) server that is used for integration and testing. When QA is done, the artefacts are checked into a production environment using VCS. Here, you can use a specific branch and/or tags for an upcoming version or a patch. Finally, when a production release is ready, the branch or tag can be used to check out all of the artefacts.
[ 349 ]
Embed, Deploy, and Debug
In order to isolate the developer work, it is useful to have a full copy of the development stack. Even some customers do not provide or allows to have a QA environment; the production and development environment should be exactly the same. Believe me, you won't deploy solutions from a development environment to QA or production if they do not match. There is an issue with the way .cdfde files are saved to disk—the files are rewritten in such a way that the VCS will get confused and identify a lot of changes when in reality there was a small change. This can turn the process of merging files into a nightmare. When working as a team and working on the same file, there are merges that will be required, so be careful when committing changes and make sure you are doing the right thing.
Documentation
One important part of delivery to the customer is documentation. For you to be successful in your deliveries to the customer, you definitely need to include proper documentation. I agree that it's hard to create proper documentation, and that it's better to create interesting and useful stuff. Anyhow, it's not useful if people do not know how to make use of it or how to make it work. You should train yourself to create documentation during some phases of the project. If you are not creating any documentation at the end of each completed phase of your work/tasks, you are doing something wrong. If you need to, you can break down your tasks into smaller tasks and schedule/spend some time building the documentation. The truth is that it will save you time in the future, and it will also provide a better delivery for the customer, and enable you to reach the highest level of satisfaction for your customers. I'm sure you would prefer to select the most interesting projects and say, "I can't do it" or "I have no time" to a customer, rather than not being engaged again because the customer isn't truly happy with your work.
Knowledge transfer
Even if you are delivering proper documentation to the customer, it's possible and common that the customer will ignore it and archive it before even reading it. A good way to pass some knowledge is to make a knowledge transfer. And if you are asking why on earth you are building documentation, the answer is: because you are a good professional doing a great job and you wouldn't fail to deliver an important part of the project just because the customer probably won't give it any attention.
[ 350 ]
Chapter 10
You won't need to spend a lot of time on the knowledge transfer, but you need to make sure that the customer has the necessary information to make proper use of your solutions and deliveries. This is a good opportunity to make it clear to the customer that the knowledge transfer does not replace the documentation and that reading the documentation is a prerequisite to the knowledge transfer. That said, we should never schedule a knowledge transfer before we can deliver the documentation. I believe that it is also an advantage to request a list of questions regarding the documentation that the customer would like to be covered during the knowledge transfer. This removes their right to complain later about missing knowledge. Of course, that does not excuse you from creating proper documentation and preparing a proper knowledge transfer. Some topics that you should cover during the knowledge transfer will be related to the project and the team you are delivering the project to. It's quite different when delivering a solution to an IT department than it is to a final customer, and your documentation and knowledge transfer should reflect this.
How to get help and help others
If you are an enterprise user, you have access to support (CDA, CDF, CDE, and CGG, which are the supported tools), but when you are not, how should you proceed? Well, you have multiple ways to solve your problem, and of course that will also be dependent on the problem you have found, the way you phrase the question, and how much information you are requesting. When you're not an enterprise user, you have some options. You will probably get a quick answer, but don't be disappointed if you don't—just try again. For any and each of the ways to get help (even if it's enterprise support), you should always provide the most information you can. This includes the context of the problem that's happening. You should provide a good and clear description of the problem, a sample when ever possible (even if you need to create it with sample data), and/or screenshots when it makes sense to do so. You should also provide the configurations that are not there by default, because they might be important to replicate the problem. You should always bear it in mind that people who are looking at your request or even trying to answer it might not guess what it's in your mind; alternatively, they may not be seeing the same as you. This might be the difference between getting a quick solution/response and not getting an answer.
[ 351 ]
Embed, Deploy, and Debug
When you want to get some help, you may want to ask the community, and you can use the forum to do so. You will find the forum at http://forums.pentaho. com and more specifically http://forums.pentaho.com/forumdisplay.php?80Community-Tools-CTools. The first step is to register as a user on the forum, so that you can create your own posts. First, you should search for your question/problem, which is also a good way to learn more. You might also want to search for JIRAs that are already closed and have a solution to your issue. If there is none, you can create a new post and wait for answers. If you find some questions that you know the answer to, or have an idea how to solve them, you should reply with an answer, because you might be helping another user. This is the way you can help to build a strong community. If you find that the problem is a bug, you should raise a JIRA. Go to http://jira. pentaho.com/secure/Dashboard.jspa and create a user. When you have a new issue, you need to select the project, so please ensure you select the right project. As said before, you should provide all the information that you are able to. You can see the selection of a project in the following screenshot:
The issues that you can create are not only bugs, but also improvements and new features. Improvements and new features are well received, and by suggesting these, you are contributing to a better product—a product that you are using. For the JIRAs that you open, you will get notifications, so you will know their status. There is also a button that enables you to start watching some issues that you might be interesting on getting updates for. You can also find some blogs that provide you with a lot of good content on how to use solutions and solve challenges. You should also be aware that having a good knowledge of the full Pentaho solution will be an advantage when trying to overcome some challenges. So don't discard any blog, help pages, or forums that might not be related to CTools, but that can provide information and knowledge about Pentaho, or even about front-end development, JavaScript, CSS, and so on.
[ 352 ]
Chapter 10
A good way to get updates about new features or bug fixes is to look at the CTools change log at http://www.webdetails.pt/ctools-changelog. You will be redirected to the last change log, but you can select earlier versions. You can click on each of the lines displayed to get more information about it. You will even be able to get the code that was changed.
Summary
In this chapter, you learned how to embed CFD and CDE dashboards in third-party applications. You saw that we must first embed CDF or CDE and then embed the dashboards. When embedding a CDE dashboard, there are two ways to do it. When embedding, it might also be important to receive information from, and send it to, the dashboard or create links between dashboards, and for that we can make use of events. We also talked about some aspects of the delivery of dashboards, which should also include documentation and knowledge transfers. Depending on who we are delivering the solution to, the technical level of the knowledge transfer and documentation might be quite different. Version control is an important part of the process when developing a dashboard; this is not part of the delivery, but it might be part of the deployment, so we discussed it in this chapter. Finally, we covered where and how you can get help or a solution to your problems when developing dashboards using CTools. You can use the community to get help, report bugs, suggest improvements, and request new features. Now that you have learned about CTools and how to create dashboards and Pentaho plugins, you should apply this knowledge to the dashboards that you already have, or just create new ones. Keep this book by your side while creating them, and you will see that it can be useful when you don't yet have a good knowledge of CTools. You should go through the examples provided with the book, as this is important for you to get a better understanding of components, parameters, listeners, and so on. This book does not provides examples for all of the components, but now that you have an understanding of CDA, CDF, and CDE, you can take a look at the examples included when you install CDF and CDE. This way, you will develop knowledge of the available components, their properties, and how they can be used. You will also need to keep an eye on the backlog updates to the CTools, because they are getting better and better day by day, with new functionalities and improvements.
[ 353 ]
Index A add-ins creating 257-259 add-ins, filter component about 180 group selection add-ins 181 group sorting add-ins 181 item selection add-ins 181 item sorting add-ins 181 post update add-ins 181 root footer add-ins 181 root header add-ins 181 root selection add-ins 181 add-ins, table component cccBulletChart 215 circle 213, 214 clippedText 207 dataBar 209, 210 formattedText 215, 216 groupHeaders 206 hyperlink 220, 221 localizedText 217, 219 sparkline 207, 208 trendArrow 210, 211 using 204, 205 add-ins, template component 230-241 Asynchronous Module Definition (AMD) 62
B Backbone URL 18
basis axis label formatting, scale based 302, 303 Blueprint URL 18, 274 bookmarkable parameters 279 Bootstrap URL 18, 275 bootstrap-select plugin URL 172
C Cascade Style Sheets (CSS) 5 CCC (Community Charts Components) about 2 background 288 charts, debugging 311-313 charts, internationalization 299, 300 component 290 library, using in CDF dashboard 288-291 references, URL 315 URL 18, 288, 311 using, in CDE 295, 296 cccBulletChart add-in 215 CDA about 21, 22 cache 45 data sources 23 editing 43, 44 previewing 43, 44 CDA cache and scheduler 45-47 keys 47 managing 45-47 system-wide cache keys, configuring 48 [ 355 ]
CDA data source creating 24-27 ID attribute 26 output, manipulating 45 Type attribute 26 types 28 CDA data source, types about 28 compound queries 35, 36 data sources, scripting 33, 34 Kettle transformations 31, 32 mondrian cubes 29-31 Pentaho metadata 31 SQL databases 28, 29 XPath, over XML 35 CDE (Community Dashboard Editor) about 2, 55, 112, 318 CCC, using 295, 296 extending 263, 268, 269, 270, 272, 274 CDE, dashboard about 159, 276 components, adding 164, 165 data sources, defining 161-163 embedding 340, 341 layout, creating 159 overall improvements 166, 167 parameters, adding 164, 165 styles, extending 278 CDF (Community Dashboard Framework) about 2, 22, 318 55 component lifecycle 56-61 dashboard 55 dashboard lifecycle 56-61 extending 263-267 CDF API, functions about 107 from components module 109 from dashboards module 107, 108 from logger module 109 CDF dashboard about 56, 66 building, files for 62 CCC library, using 288-291 creating 62-65
embedding 337-339 styles, extending 276, 277 Chosen URL 18, 172 circle add-in 213, 214 clearCache endpoint 50 click event handling 298, 299 clippedText add-in 207 Community Build Framework (CBF) 2 Community Data Access. See CDA Community Data Generator (CDG) 3 Community Data Validation (CDV) 3 Community Distributed Cache (CDC) 3 Community Edition (CE) 12 Community File Repository (CFR) 3 Community Graphics Generator (CGG) 314 Community Plugin Framework (CPF) 318 Community Plugin Kick-starter (CPK) 317 Community Text Editor (CTE) 66 components available 90, 91, 109 data sources, defining 68-71 execution, priority 89, 90 interacting between 77-81 listeners 75 references to 252, 253 using, inside dashboards 66, 68 components perspective, perspectives toolbar about 145-147 components toolbar 147 dashboard parameters 147-149 scripts 149 visual components 149-156 Content Delivery Network (CDN) files 195 Cron URL 44 cross domain requests avoiding 336 crosstabMode property 293 crosstab property 292 CSS files 172 CTools about 2, 157, 158 change log, URL 353 [ 356 ]
installing 11 installing, CTools used 15-17 installing, Pentaho Marketplace used 12-14 manual installation 17 URL 2 CTools installer URL 15 used, for installing CTools 15, 17
D dashboard about 7, 51, 107, 108, 283 and components 341 and parameters events 341 CDE dashboard, embedding 340, 341 CDF dashboard, embedding 337-339 components, using 66-68 context 104-106 cross domain requests, avoiding 336 dashboard path 284 Datasource mapping 285 design, creating 9 developing 10, 11 embedding 336 mock-up, creating 9 parameter mapping 284 prerequisites 4-6 requisites, getting 7, 8 storage 101 team and project management 10 utilities 95 dashboard style/template CDE dashboards style, extending 278 CDF dashboards style, extending 276, 277 creating 276 dashboard types Blueprint 274 Bootstrap 275 clean 274 creating 274, 275 extending 274, 275 dashboard, utilities abbreviation 97 about 95
currency 97 dates, formatting 99 dates, manipulating 99 languages and locales 98 multiple formats 98 numbers 97 numbers and dates, internationalization 100, 101 numbers, formatting 95, 96 percentages 98 data crosstabMode property 293 mapping 291, 292 seriesInRows property 294 timeSeriesFormat property 295 timeSeries property 295 Data Access Cache property 36 Columns property 37 common properties 36, 37 Name property 36 Output property 37 Parameters property 37 Query property 37 Data AccessID 23 dataBar add-in 209 data sources defining, for components 68-71 parameters, creating 72-75 parameters, using 72-75 URL 4 data sources perspective, perspectives toolbar about 142, 143 data sources, properties 144, 145 new data sources, creating 143, 144 DataTables types 203 URL 18, 192 date range input component about 186-188 properties 186, 187 debugging about 343 browser compatibility 344
[ 357 ]
short tips 347, 348 with developer tools 344-346 dimensions about 308, 309 readers 309, 310 URL 308 visual roles 310, 311 Document Object Model (DOM) 60, 262 doQuery method 49, 50 Draw function property 196
E editFile method 51 editor operational toolbar 115 working with 113-115 Enterprise Edition (EE) 5 events, template component 242, 243 export button component about 245 component name property 245 label property 245 output type property 245 export popup button component about 245, 247 chart component to export option 246 chart export label option 246 chart export type option 246 content linking option 246 data component to export option 246 data export label option 246 data export type option 246 gravity parameter option 246 name for data export attachment option 246 title option 246 extendable options, template component 244 extension point URL 302 Extract, Transform, and Load (ETL) 31
F Fancybox URL 18 filter component about 177 add-ins, usage 180-185 configurations, advanced 185 data layout, expected 178 default messages, changing 185 options, advanced 185 properties, specific 179, 180 values, displaying 186 Font-awesome URL 18 formattedText add-in 215, 216 formatters, template component 229, 230 forum URL 352 frameworks 17 freeform components 253, 257
G getCdaList endpoint 48 Git repository URL 3 Graphical User Interface (GUI) 27, 111 groupHeaders add-in 206
H help 351, 352 HTML 62 Hynds URL 172 hyperlink add-in 220, 221 Hypertext Markup Language (HTML) 5
I icon fonts URL 212 identifier (ID) 23 internationalization 280-283
[ 358 ]
internationalization and localization, table component Language property 195
J JavaScript 5 JIRA URL 352 jQuery URL 18 jQuery i18n URL 18 jQueryUI URL 18 JSON URL 260 JSON object URL 195
layout toolbar 122-134 responsive dashboards, building considerations 139-141 line charts URL 301 listeners inside components 75 listParameters endpoint 49 listQueries endpoint 49 localization 280-283 localizedText add-in 217-219 logger module 109
M
Kettle URL 104 Kettle endpoint buttons 322 creating 322 parameters values, specifying 324 results, getting 324 using, on dashboard 329-332 Kettle transformations about 31 KtrFile property 32 variables property 32 Key Performance Indicators (KPIs) about 5 components, using 66
manageCache method 51 Marketplace URL 12, 13, 17 Modernizr URL 18 Moment URL 18 MomentJS URL 99, 101 Mondrian cubes 29-31 Mozilla Public License URL 3 multi-button component about 189 Datasource 189 ultiple selection 189 value as ID 189 values array 189 multi-tenancy URL 47 Mustache URL 18
L
O
layout elements references to 252, 253 layout perspective, perspectives toolbar about 122 Bootstrap, used for creating responsive dashboard 136-139 considerations 134-136
Object-Oriented Programming (OOP) languages 263 open formula URL 37 operational toolbar, editor about 115 new 115
K
[ 359 ]
reload 117 save and save as 115, 116 settings 117-120
P parameters about 37, 156 in MDX queries 39, 40 on kettle queries 41, 42 on SQL queries 38, 39 private 42 references to 252 Pedro Alves blog post URL 17, 255 Pentaho App Builder about 3, 318 installing 318 new plugin, creating 319-321 URL 318 Pentaho Data Integration (Kettle) transformations 227 Pentaho Data Integration (PDI) 3 Pentaho Marketplace used, for installing CTools 12-15 Pentaho Metadata Schema about 31 DomainId 31 XmiFile 31 Pentaho Repository Synchronizer (PRS) 3 Pentaho User Console (PUC) 12, 43, 62 perspectives toolbar, editor about 121 components perspective 121, 145, 147 data sources perspective 121, 142 layout perspective 121, 122 layout toolbar 122-130 preview the dashboard 121 pie chart value, displaying in center 307 plugin creation, Pentaho App Builder availability, in marketplace 332, 333 CPK 322-324 dashboard, creating 327, 328 folder structure 328 GitHub account, URL 332
job/transformation, creating 322 Kettle endpoint 322 Kettle endpoints, using on dashboard 329-331 new endpoint, creating 321 other considerations 326 output format type, changing 325, 326 single cell, returning 326 submission, URL 332 plugins minified version 173 postChange using 87, 89 postExecution using 82, 84 postFetch properties, changing in 297 working with 85-87 preChange using 87-89 preExecution properties, changing in 297 using 82-84 previewQuery method 50 properties available 90, 91 mandatory 291 Protovis URL 18, 288
Q quality acceptance (QA) server 349 query components 253-256
R Raphael URL 18 Require URL 18 RequireJS URL 94 resources (JavaScript and CSS), adding about 92 CSS files, including 95 [ 360 ]
internal modules, using 92, 93 new modules, defining 94 new modules, including 94
S scale based basis axis label, formatting 302 Select2 URL 18, 172 select component about 170-173 JQuery plugin 172 value as array 171 value as ID 171 select multi-component 174-177 seriesInRows property 294 solution delivering 348 documentation 350 knowledge transfer 350 version control and deploy 349, 350 Sparkl 3, 318 sparkline add-in about 207, 208 URL 18 Stream Line Data Refinery (SDR) 4 Structured Query Language (SQL) databases 28, 29
T table component about 192-194 add-ins, using 203-205 column formats 196-199 column headers 196-199 column types 196-199 column width 197-199 content, expanding 200-203 Draw function 196 internationalization and localization 195 table pagination 194 table component, properties info filter 192 length change 193
page length 193 paginate 193 paginate on server-side 193 pagination type 193 searchable cols 192 show filter 192 sortable columns 193 sort data 193 style 193 template add-in about 260, 262 options, applying 260 template component about 221-224 add-ins 230-241 events 242, 243 extendable options 244 formatters 229, 230 model, automatically generated 225 model handler 227-229 root element, automatically generated 225 template and engine 226 template engines URL 221 text component about 248 expression function 248 timeSeriesFormat property 295 timeSeries property 295 tooltips customizing 304-307 trendArrow add-in 210-212 Try It Out section URL 207
U Underscore URL 18 URI string URL 220 User Interface (UI) 8
V version control system (VCS) 349 [ 361 ]
W Web API, reference about 48 clearCache 50 doQuery 49, 50 getCdaList 48 listParameters 49 listQueries 49 manageCache 51 previewQuery 50, 51 Webdetails page URL 296
X xAction URL 71 XCDF 62 XPath over XML 35
[ 362 ]
<%= value[1] %> : '+ '
' + '<% }); %>', formatters: [["abbreviation",function(value, id) { return Utils.numberFormat(value, '$0.0A'); }]], events: [["click, clickable.productLine", function(event){ alert('You clicked: '+$(this).data('id')); }]], modelHandler: function(data, opt) { var model = {}; model.items = data; return model; [ 261 ]
Advanced Concepts Using CDF and CDE }, }; this.setAddInOptions("templateType","template", templateOpts);
You may also apply the options and use this add-in in the template component so you just need to apply the options in the template and make a call to the add-in of the template using the following instruction: this.setAddInOptions("templateType", "template", options);
In this code, you will see that we are setting the options to be used by the template add-in. First we are setting the template type, which for our case is underscore. You will also see the template and, inside it, you will find a call to the formatter. We are passing two arguments to the formatter: the value to be formatted and the name of the function to be used. We could and should also specify another argument (a third one) that is the identifier and is useful when we want some conditional formatting. We can have multiple formatters, so we need to define them as a multidimensional array. Each element of the parent array will have two elements: the first one is the name of the function and the second one is the function that is executed when the formatter is used inside the defined template. The second element, the function, accepts two arguments: the value to be formatted and one identifier. The identifier is really useful if we need to define a formatter that can be used multiple times with different options for the same template. We can also see that we are specifying an event, and to do so we are specifying one array with one event and one Document Object Model (DOM) element. The events will also accept a multidimensional array and, once again, each element of the main/parent array will have another two elements. The first element is the event and the selector, which identify the target in the HTML, while the second one is the handler function triggered when the event is fired. The first and second elements of the array should be separated by a comma (,). In the previous sample code, we are just showing an alert message with the product line where we are clicking. The last option is modelHandler, where we are returning the array wrapped in a JSON structure where the root element is items, used in the template. The last instruction registers the options for the add-in. Take a look at the examples of dashboards provided with the book, and you can get a clear idea of how it works. Anyhow, it's the concept that we covered earlier for the template component, but applied to a table add-in.
[ 262 ]
Chapter 7
Extending CDF and CDE with new components
When we covered the query component, you must have been asking: If I want to use this for multiple dashboards, do I need to apply my own code over and over again for every dashboard? The answer is, no. With the custom components, you are perfectly able to create components that can be reusable in CDF or in CDE. What changes between CDE and CDF, is that, for CDE, you also need to include a XML file with the information about what should we see in the dashboard editor. Let's see how can you create your custom components.
Extending CDF
I would like you to consider two different kinds of components: those that allow filtering and those that allow you to display data in the dashboard. Of course, the ones that display information can also be used as selectors, but just add functionality to those that are really to allow visualizations of data on the dashboard. You should remember from Chapter 3, Building the Dashboard Using CDF, that components can run asynchronously among those with the same priority of execution. If they have different priorities of execution, then they will run synchronously. It's important to realize that, when I am talking about asynchronous execution, what I am really saying is that simultaneous AJAX requests will be executed, but the browser only allows a limited amount of concurrent calls, so they may be divided into multiple batches. That will depend on the number of components and the limit of simultaneous calls for the browser being used. To be able to take advantage of some concepts of the Object-Oriented Programming (OOP) languages, CDF makes use of libraries that ease the pain of OOP in JavaScript. One of them is Base, which can be found at http://dean.edwards.name/ weblog/2006/03/base/. This is a simple class and extends the object Object by adding two instance methods and one class method.
[ 263 ]
Advanced Concepts Using CDF and CDE
When creating a new component, you should be sure to create it in a way that it can run synchronously or asynchronously. This can be achieved by extending from existing classes. The UnmanagedComponent class is one of those cases. It already inherits from BaseComponent, which also inherits from Base class, so a lot of properties and methods/behaviors can be inherited. To take advantage of the existing base classes, we need to use UnmanagedComponent. This means that UnmanagedComponent is an advanced and more complete version of BaseComponent. It allows you to have control over the lifecycle when implementing components. When using UnmanagedComponent, the class will make the calls to preExecution, postExecution, and even to postFetch when triggering a query. This will also make sure the listeners are handled and that the parameters are sent to the queries when the component is executed. This way, the calls to these functions are entirely the responsibility of CDF, and the component doesn't need to worry about them. There are three functions that we can use when creating a component, and one of them needs be used. They are: • synchronous: This implements a synchronous lifecycle identical to the core CDF lifecycle • triggerQuery: This implements a simple interface to a lifecycle built around query objects • triggerAjax: This implements a simple interface to a lifecycle built around AJAX calls Creating a Hello World! component would be something like: define(['cdf/components/UnmanagedComponent','amd!cdf/lib/underscore'], function(UnmanagedComponent, _) { HelloWorldComponent = UnmanagedComponent.extend({ update: function() { var render = _.bind(this.render,this); this.synchronous(render); }, render: function(data) { var message = this.message || 'Hello World!'; this.placeholder().empty().text(message); } }); return HelloWorldComponent; });
[ 264 ]
Chapter 7
This example code doesn't make use of a query, so this.synchronous(render) should be used. Managed automatically by the CDF lifecycle, the render function will be called just after preExecution and before postExecution. In the example, the render function is being called using the synchronous function. The render function will show the Hello World text if a property message is not defined in the component. In the following example, we are making use of a query to show the result of the query. Here this.triggerQuery(this.queryDefinition, render) will be used, so postFetch will be also called, just before the render function, where we are making use of the data that we fetched. Inside the call of the query function, you can see that we are making use of the definitions of the data source/query for this component, so the definitions will be used to trigger the correct data source/query. define(['cdf/components/UnmanagedComponent','amd!cdf/lib/underscore'], function(UnmanagedComponent, _) { ShowResultComponent = UnmanagedComponent.extend({ update: function() { var render = _.bind(this.render,this); this.triggerQuery(this.queryDefinition, render); }, render: function(data) { this.placeholder().empty().text(JSON.stringify(data)); } }); return ShowResultComponent; });
The queryDefiniton object should look like the following, where dataAccessId is the identifier of the CDA datasource defined, and file will by default point to the same name and folder as the dashboard: { dataAccessId: 'myQuery', file: '/path/to/my/datasourceDefinition.cda' }
Since the methods (synchronous, triggerQuery, and triggerAjax) expect a callback that handles the actual component rendering, the conventional style is to have that pointing to a redraw/render function. Also, to follow the standards we should use the bind function, as you can see in the two previous examples. This function will ensure that, inside the redraw/render callback, these point to the component itself.
[ 265 ]
Advanced Concepts Using CDF and CDE
Now let's suppose you want to create some kind of a select component and you may want developers to be able to make use of a values array and not a query. If that's the case, you can switch between static values and the result of a query: define(['./UnmanagedComponent', 'amd!../lib/underscore'], function(UnmanagedComponent, _) { ShowResultComponent = UnmanagedComponent.extend({ update: function() { var render = _.bind(this.render, this); if(this.valuesArray && this.valuesArray.length > 0) { this.synchronous(render, this.valuesArray); } else { this.triggerQuery(this.queryDefinition, render); } } render: function(data) { this.placeholder().text(JSON.stringify(data)); } }); return ShowResultComponent; });
In reality, we have been acting on modules where the components are defined. We can include the component in the dashboard, or we can make it available for CDF in such a way that all dashboards will have access to it. You can have your custom components inside the Pentaho Repository—just create a folder such as /Public/ cdf/components, and place your components there. For instance, you should save the code of the first example provided for this section, Hello World, in a file called HelloWorldComponent.js, so you can use it later in dashboards. Now let's take a look at how you can make use of that same component, the custom Hello World. You will need to build a CDF dashboard like the one you can see here:
You will see that we are requiring a resource using the Pentaho Repository API, and from there we just use any other component. Don't forget that , as it's a CDF component, you could also define and make use of the preExecution and postExecution functions, like you can for any other component. When creating a component that acts like a filter, when an action is triggered (such as a click on the Apply button), it will change the parameter to store the selected values. We should make use of the following code: this._value = selectedValues; this.dashboard.processChange(this.name);
In this code, we can see the first line where we are setting the selected values of an internal variable _value, which will be used later to get the values that were selected. The processChange function accepts an argument that is the name of the component making the call, and it's responsible for grabbing the selected values. This is done by calling the getValue function, so this function should also be defined in the component code. Here is one example of the getValues function: getValue: function() { return this._value; },
You can see that the getValue function is just returning the values that were selected, so that the processChange function can proceed with its work. The processChange function now knows the values that have been selected, so it will make a call to preChange from the component if it exists, do the fireChange function using the parameter defined for the component, and call the postChange function. We don't need to worry about calling preChange, fireChange, and postChange; we just need to define the getValue function and call the processChange function. The dashboard lifecycle will take care of the rest for you.
[ 267 ]
Advanced Concepts Using CDF and CDE
Extending CDE
Now that we have a component working as a CDF component, we can also extend CDE to use that same component. We already saw that CDE is provided by a friendly interface that allows you to build the dashboard. But CDE needs to know what components are available, what properties may be used, and which types of values are accepted for each one of the properties. The big difference between a CDF and a CDE component is that a CDE component is also provided with some kind of a metadata file that should be specified using XML. Reading this XML file is the way that the server knows how to build the editor HTML page that will be rendered by the browser. You should give the same name to the file as for the component; that way, if you have multiple components inside the same folder, you will know which component belongs to which file. Another reason is because you can use different folders for the XML and JavaScript/CSS files. You have names that can identify them and will make your life easier, not only for you, but also for someone in your team who needs to understand them. For our example, we will show you the folder structure that we can have. But you should find out what the best approach is for you. The XML file with the definition of the component should also be placed inside the folder /Public/cde/components. The main structure of the file will be similar to: <%= formatter(value[2], "abbreviation") %>
'+ '
My first dashboard!
[ 288 ]
Chapter 8
Sales for '+year+' at '+territory+':'+sales+'
' + ''; return html; }
The code is pretty self-explanatory. First we are setting some variables such as year, territory, and the sales values, which we need to present inside the tooltip. Like in the click event, we are getting the labels/value from the scene, which might depend on the properties we set for the chart. For the sales, we are also abbreviating it, using two decimal places. And last, we build the HTML to be displayed when we hover over the chart.
[ 304 ]
Chapter 8
You can also change the base axis tooltip Like we are doing to the tooltip when hovering over the values represented in the chart, we can also use baseAxisTooltip; just don't forget that use the baseAxisTooltipVisible property must be set to true (the value by default). Getting the values to show will be pretty similar.
It can get more complex, though not much more, when we also want, for instance, to display the total value of sales for one year or for the territory. Based on that, we could also present the percentage relative to the total. We should use the property as explained earlier.
The previous image is one example of how we can customize a tooltip. In this case, we are showing the value but also the percentage that represents the hovered over territory (as the percentage/all the years) and also for the hovered over year (where we show the percentage/all the territories): tooltipFormat: function(scene){ var year = scene.getSeriesLabel(); var territory = scene.getCategoryLabel(); var value = scene.getValue(); var sales = Utils.numberFormat(value, "#.00A"); var totals = {}; _.each(scene.chart().data._datums, function(element) { [ 305 ]
Visualizations Using CCC var value = element.atoms.value.value; totals[element.atoms.category.label] = (totals[element.atoms.category.label]||0)+value; totals[element.atoms.series.label] = (totals[element.atoms.series.label]||0)+value; }); var categoryPerc = Utils.numberFormat(value/totals[territory], "0.0%"); var seriesPerc = Utils.numberFormat(value/totals[year], "0.0%"); var html = '' + ''+sales+'
' + 'Sales for '+territory+' in '+year+'
' + ' ' + ' ' + ''; return html; }
The first lines of the code are pretty similar except that we are using scene. getSeriesLabel() in place of scene.atoms.series.label. They do the same, so it's only different ways to get the values/labels, and then the total calculations that are calculated by iterating in all the elements of scene.chart().data._datums, which return the logical/relational table, a combination of the territory, years, and value. The last part of code is just to build the HTML with all the values and labels that we already got from the scene. There are multiple ways to get the values you need; for instance to customize the tooltip, you just need to explore the hierarchical structure of the scene and get used to it. The image that you are seeing also presents a different style, and that should be done using CSS. You can add CSS for your dashboard and change the style of the tooltip, not just the format.
[ 306 ]
Chapter 8
Styling tooltips When we want to style a tooltip, we may want to use the developer tools to check the classes or names and CSS properties already applied, but it's hard because the popup does not stay still. We can change the tooltipDelayOut property and increase its default value from 80 to 1000 or more, depending on the time you need.
When you want to apply some styles to the tooltips for a particular chart you can do by setting a CSS class on the tooltip. For that you should use the property tooltipClassName and set the class name to be added and later used on the CSS.
Pie chart showing the value in the center
There are features that CCC presents and that we don't yet know about, so you should keep an eye on the CCC forum (http://forums.pentaho.com/showthread. php?161089-CCC-FAQ-Frequently-Asked-Questions-About-CCC) and Duarte Cunha fiddles (http://jsfiddle.net/user/duarteleao/fiddles). The following example has been generated with some simple options that can make a difference. Of course, you also could achieve this with CSS, but it would make your life harder.
To get the result just shown, for each one of the charts we could apply the following options: function() { var cd = this.chartDefinition; var options = { valuesVisible: true, valuesLabelStyle: 'inside', valuesFont: '35px sans-serif', valuesMask: '{value.percent}', label_visible: function() { return !this.index; }, label_left: null, label_top: null, label_textAngle: 0, label_textAlign: 'center', [ 307 ]
Visualizations Using CCC label_textBaseline: 'middle', slice_innerRadiusEx: '70%', legend: false } $.extend(true, cd, options); }
Dimensions
It's important to know that a dimension in CCC is not an MDX dimension. Here it is represented by a subset of atoms. When you want to achieve more advanced results, you can change the behavior of CCC. Well maybe I shouldn't say change the behavior, but help CCC behave in a different way than the default behavior. What we can do is change one dimension, but not change the rest of them; CCC will apply the default options to just those dimensions. Don't forget that these changes are optional and you only want to apply them to change the default behavior of CCC. When dimensions are not defined, the default dimensions, with the default options, are generated to satisfy the needs of the chart. Anyhow, the data dimensions can be explicitly defined. When defining dimensions, you can define them partially. You will be able to define just one and let the others be automatically generated. The list of dimension options is defined at: http://www.webdetails.pt/ctools/ ccc/charts/jsdoc/symbols/pvc.options.DimensionType.html, where you can
also get more details.
We have made a table with a complete list and default values and a brief description of them: Name
Type
Short description (from the CCC website)
label
string
The name of the dimension type as it is shown to the user.
format
string
The dimension type's format provider.
function object isHidden
Boolean
This indicates whether the values of this dimension type should be hidden from the user.
isDiscrete
Boolean
This indicates whether a dimension type should be considered discrete or continuous.
valueType
function
This is the type of value that dimensions of this type will hold. [ 308 ]
Chapter 8
Name
Type
Short description (from the CCC website)
rawFormat
string
This is a Protovis format string that is to parse the raw value.
comparer
function
This is a function that compares two different and non-null values of the dimension's valueType.
converter
any
This converts a non-null raw value, as read from the data source, into a value of the dimension's valueType.
key
string
This is a function that converts a non-null value of the valueType into a string that (uniquely) identifies the value in the dimension.
formatter
function
This is a function that formats a value, possibly null, of the dimension's valueType.
For instance, if we want to have the dimension, category to be a date, but represented on a discrete and not continuous axis, we would need to specify the following options: dimensions: { category: {valueType: Date, isDiscrete: true} }.
Readers
One of the options that we have to apply to the dimension is readers. Readers allow you to declare the mapping of columns to dimensions. As it was not always possible to use colName, there was a need to invent readers. This will only happen after parsing the data structure and when CCC is already making use of a relational data structure (this could be the result of a data structure parsing from a crosstab). We can set readers using two different approaches: • Using visual role names or visual row prefix names: category, series, measure, value, and multiChart. Depending on the chart type, there might be other dimension types available such as median, lowerQuartil, upperQuartil, minimum, and maximum. They are applied on the box plot chart. °°
For instance: readers: ['category', 'series', 'value']: this would make CCC interpret the columns as specified, the measure, series, category and at least the value, slightly changing the way it interprets the columns by default
[ 309 ]
Visualizations Using CCC
• By using business names instead of defining measures, series, categories, and value. °°
For instance: readers: ['Markets', 'Years', 'Sales']
°°
When doing this, we also need to define the mapping for the visual roles: visualRoles: { value: 'Sales', // <-- mapping defined here series: 'Years', // <-- mapping defined here category: 'Markets' // <-- mapping defined here }
When defining readers, we might use the same visual role names or visual row prefix names that are not defined. These column values will not be mapped to visual roles automatically, but we are still able to use them on, for instance, tooltip customization or event handling. It can be very. Another way to define readers is using the indexes of the columns being mapped: readers: [ {names: 'Sales', indexes: 2}, {names: 'Years', indexes: 1}, {names: 'Markets', indexes: 0} ] visualRoles: { value: 'Sales', series: 'Years', category: 'Markets' }
In the previous example, the first column (index 0) of the data source feeds the Markets dimension, while the second column (index 1) feeds the Years dimension and so on.
Visual roles
You might use visual roles even if you are not using the business names as readers. For instance, they might be used to represent a second plot in the chart. Anyhow, the visualRoles option allows you to declare the mapping from CCC dimensions to visual roles.
[ 310 ]
Chapter 8
If you want to represent a second plot that should be a boxplot, then you will the code as follows: plots: [ // Main plot - bars { name: 'main', dotsVisible: true }, // Second plot - boxes { type: 'box', visualRoles: { // Comment the ones you don't want represented median: 'value', lowerQuartil: 'value2', upperQuartil: 'value3', minimum: 'value4', maximum: 'value5' } } ]
You can see that we are mapping the visual roles median, lowerQuartil, upperQuartil, minimum, and maximum, using the row prefix names value, value2, value3, value4, and value5. This will make it possible to have a second chart using box plot representations for each of the categories. You are able to check the example provided on the CCC web page at the following link: http://www.webdetails.pt/ctools/ccc/#type=line&anchor=line-with5-number-statistics. The available visual roles are: category, series, multiChart, value, dataPart, and
measures.
Debugging the CCC charts
When you want to customize your options a bit more, you may be entering some advanced features, where it's hard to understand what's being done or what changes we should apply. CCC provides some debugging modes that allow you to have a better understanding and knowledge of what these advanced features are doing.
[ 311 ]
Visualizations Using CCC
We will cover how to use developer tools to perform debugging later, but for now just be aware that you have specific debugging levels for CCC. You will see later that you can perform debugging on a dashboard if you add a parameter of your URL (debug=true). If you have a URL that is http://localhost:8080/pentaho/api/ repos/%3Apublic%3Asample.wcdf/generatedContent, you need change it to: http://localhost:8080/pentaho/api/repos/%3Apublic%3Asample.wcdf/ generatedContent?debug=true. Or if you have http://localhost:8080/ pentaho/api/repos/%3Apublic%3Asample.wcdf/generatedContent?paramcou ntry=Portugal, you need to change it to:http://localhost:8080/pentaho/api/ repos/%3Apublic%3Asample.wcdf/generatedContent?paramcountry=Portugal& debug=true. To debug a CCC chart and get extra information you can add &debugLevel=5. You need to use it like: http://localhost:8080/pentaho/api/
repos/%3Apublic%3Asample.wcdf/generatedContent?paramcountry=Portugal& debug=true&debugLevel=5.
When you do this, you will get a lot more information that is really important. This information will be available on the console in the developer tools of the browser you are using. The following examples are screenshots taken from Chrome for Mac OS X, version 46.0.2490.80 (64-bit). The image to the left shows the output on the console regarding the options being used to render the chart. The one to the right shows one example of the data source summary that CCC provides. Some examples are as follows:
[ 312 ]
Chapter 8
The following image is also part of the output that we get from debugging CCC. The image on the left gives you information about the Logical Table and how CCC parses the result set of the query seriesInRows and crosstabMode, or for readers:
Looking at the table on the right, you will find the Visual Roles Mapping that is being used as the default for the options used or as set by you, as explained earlier in this chapter. If, instead of using a value of 5 for the CCC debugging level, you use a value of 16 (&debugLevel=16), when displaying the chart you will be able to see some borders that identify all the panels of the chart. The following screenshot is an example of this. Among other things, it's useful to check whether it's being used as padding or margins for the panels. You can see those margins in the following image:
[ 313 ]
Visualizations Using CCC
CGG – Community Graphics Generator
CGG is a plugin that allows you to export CCC charts in CDE dashboards as images. CGG will generate the image on the server side, and that's the reason why you will see some JavaScript files related to the charts to be exported. Every time you set a chart to be exportable, it will be provided with a URL that you can use to export the image. This means you can see the generated images of the charts you can embed inside any other dashboard/report/page. When editing a CDE dashboard, you can press Shift + G, which is a shortcut to get to a dialog with a list of charts in the dashboard. By selecting a chart, you will be enabling the option to export the chart using CGG. You can see this in the following image:
The previous image also shows the URL button, which you can click to get the link to use for the export. For example, for one of the examples provided with the book, the link to the chart will be: http://