Creating a new Custom Chart
To start building a custom chart, select the chart type you would like to use from the chart selection panel. Think of this as the type of visual you would like to use to visualize your custom data collection.
After selecting the chart type, the charts data panel will open.
Choose Custom Chart as the data source
Select the table you would like to build the script from. This can be changed in the script and does not need to be the only table from which data is pulled. It can also be referenced in the options object mentioned below.
After writing your script. Hit Save.
Fill out the relevant chart options on the options panel and hit Save to render your chart.
How it Works
Using the script field
The script field is where all the custom scripting happens. Within the script field you can write any code at all that you would be able to write in a script include. This includes GlideRecord and GlideAggregate scripts and using gs functions (including gs.info).
To aid and assist you there are three variables that the script utilizes as well as a whole class designed to work within the script. These variables can act as a link between the custom chart and the VividCharts UI.
Variables
options
This contains all the chart options values. This is a collection of all the chart’s configurations and choices including what is set in the options panel when building a chart. This can be modified in the script or used as a reference to pull items you would like to be configurable in the UI. This allows a VCDCS script to be written but has some no-code configurability. Allowing a user to update the limit of records returned in a custom script for example. To better see what is contained in each chart’s options values the options variable can be logged out in a gs.info.
filter
This contains the encoded query that is generated by the current filter built in the VividCharts editor. Since this is an encoded query, it can be used and manipulated within the VCDCS for many purposes. For example, we would like to be able to use the filter in the UI but would like to reuse the filter as part of our data collection. Simply reference the filter variable and apply the encoded query as needed in your Custom Script.
chartData
This variable begins as an empty array and is what is returned to the front end to render your charts. The chart’s data and the options variable are the 2 main pieces of data to be included. The chart’s data must also be in the form the front end expects. To see what data format the front end is expecting, you can call the default collector using VividCollector for the chart and see its format by logging it out using gs.info. The chartData variable must be in this format at the end of the data collection:
chartData = {
data: {the variable you used for the chart’s data goes here} ,
options: {either place the options variable here or your modified options}
};
Classes
VividCollector
A class designed to take options and filter values and produce a data object that matches the front end and options. This data object can then be modified to present something different to the front end.
How To Use the VividCollector
VividCollector has several functions associated with it to get your data ready to use and render the visual of the chart.
Functions
VividCollector(options, filter)
VividCollector is not a static class. It must be initialized using a new keyword with an options object as well as an optional filter object. For example:
var collector = new VividCollector(options, filter)
This options value is what will be used in data collection so make sure to modify the options you need before initializing a VividCollector class.
addOption(field, value)
If you need to modify the options after you have already initialized the object, you can do so using this function. you will modify the field provided (from the base options) with the provided value.
setFilter(encoded query)
If a new filter is needed after initializing with one, you may use setFilter to assign a new encoded query to be used for the filter.
associateTable(table)
This works similarly to addOption but will set the table used in collection to the given table.
setType(type)
Sets the type of data collection to do. Use the list of chart types to match to the type of data collection you are looking for.
fetchData()
This is where the data collection happens. If you have set up your VividCollector with an options value that is valid and a type minimally, you simply call fetchData to get a data object that matches what the front end expects. You can then manipulate that data object. You can keep modifying the inputs and calling this function as much as you like as well.
Chart Types For the VividCollector
This is a list of the chart types used in the setType() function on the VividCollector. These must be passed in as a string. For example:
collector.setType("line");
arc score
area
bar
bar matrix
calculated score
comparison score
cost plan trend
curved bar
diverging bar
donut
donut matrix
field selector
gantt
grouped bar
grouped timed bar
half donut
heatmap
key milestone timeline
line
list
list score
multi demand
multi line
nested list
nested score list
normalized bar
percent complete
percent score
percentage timed bar
pie
pie matrix
pivot
program heatmap
progress score
project heatmap
project status map
project timeline
ridac
score
single demand
spline
stacked bar
stacked timed bar
status map
timed bar
timed donut
timed half donut
timed pie
treemap
trend table
waffle
Examples
Here are some examples to get you started
Donut Chart Grouping by active off the incident table
// custom chart starts here
var collector = new VividCollector(options);
collector.addOption('groupBy', 'active');
collector.associateTable('incident');
collector.setType('donut');
var data = collector.fetchData();
chartData = {
data: data,
options: options
};
Pie Chart displaying RIDAC information
// if we are using this in a summary, the summaryPrimary option will be filled and will contain the sys_id of the project
if (options.summaryPrimary) {
options.record = options.summaryPrimary;
}
// otherwise, we are in testing mode, so just use a set record. In a more prod environment this might trigger a no data and bypass collection
else {
options.record = '9dce0ac0db8d881025c85a35dc9619cf';
}
// have a flag for no data so we can display VC no data even with all 0s, or in this case, a single result to indicate no data as it looks better than the warning
var noData = true;
// create a collector and collect a ridac instead
var collector = new VividCollector(options);
collector.setType('ridac');
collector.associateTable('pm_project');
var ridacData = collector.fetchData();
// initialize a holder for the data
var data = [];
// loop through the ridac converting it to more donut friendly data
for (var i = 0; i < ridacData.chartData.length; i++) { // get the value as we will be using it
value = Number(ridacData.chartData[i].data.score) // if we have even a single piece of data, set the flag to true
if (value > 0) {
noData = false;
} // push in the value alongside the title, we don't use clickthrough or percent so just give them any value
data.push({
name: ridacData.chartData[i].title,
value: value,
query: '^EQ',
percent: 1
});
}
// unused but shows an alternative version that displays the standard no data
/*
if (noData) {
data = 'VC no data'
}
*/
if (noData) {
// reset data
data = []
// push in the new no data format
data.push({
name: "No Data",
value: 1,
query: '^EQ',
percent: 1
});
}
// format the data in the chartData wrapper expected in pie
var formattedData = { chartData: data };
// set up that final return
chartData = {
data: formattedData,
options: options
};
Multi Table Chart
// custom script starts here
var collector = new VividCollector(options);
collector.associateTable('incident');
collector.setType('donut');
var data = collector.fetchData();
var collector2 = new VividCollector(options);
collector2.associateTable('change_request');
collector2.setType('donut');
var data2 = collector2.fetchData();
for (var i = 0; i < data.chartData.length; i++) {
for (var j = 0; j < data2.chartData.length; j++) {
if (data.chartData[i].name === data2.chartData[j].name) {
data.chartData[i].value = Number(data.chartData[i].value) * Number(data2.chartData[j].value);
if (data.chartData[i].value < 4) {
data.chartData[i].name = data.chartData[i].name + " (Number)";
}
}
}
}
chartData = {
data: data,
options: options
};