<!doctype html>
<html>
<head>
<script src="//cdn.anychart.com/js/7.4.0/anychart.min.js"></script>
<style>
html, body, #container {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="container"></div>
<script type="text/javascript">
// Filters
var territoryFilter = null;
var platformFilter = null;
var categoryFilter = null;
// Charting objects
var unitsChart = null;
var territoryChart = null;
var platformChart = null;
var categoryChart = null;
var unitSeries = null;
var territorySeries = null;
var platformSeries = null;
var categorySeries = null;
var helpLabel = null;
// Colors
var unitSeriesColor = 'rgb(102, 143, 169)';
var barsSeriesColor = 'rgb(233, 234, 237)';
var hoverBarsSeriesColor = 'rgb(255, 225, 105)';
var barTitleColor = 'rgb(85, 85, 85)';
var helpTextColor = 'rgb(85, 85, 85)';
var helpBgStroke = 'rgb(221, 221, 221)';
var helpBgFill = 'rgb(249, 250, 251)';
// Raw dashboard data, see data format in the end of the file
var rawData = generateData();
anychart.onDocumentReady(function() {
var title;
// Create stage for all charting objects
stage = acgraph.create('container');
// Create area chart
unitsChart = anychart.area();
// Set chart to render on stage
unitsChart.container(stage);
// Set chart size and position
unitsChart.bounds(0, 0, '100%', '50%');
// Set chart title text
title = unitsChart.title();
title.text('Software Sales Dashboard Units per Day');
title.fontSize(16);
title.fontWeight('normal');
// Set chart title position
title.margin().top(10).bottom(10);
// Remove left chart padding
unitsChart.padding().left(0);
// Disable chart background
unitsChart.background().enabled(false);
// Set chart grid settings
var grid = unitsChart.grid();
grid.enabled(true);
grid.oddFill('none');
grid.evenFill('none');
var extraGrid = unitsChart.grid(1);
extraGrid.enabled(false);
var minorGrid = unitsChart.minorGrid();
minorGrid.enabled(false);
// Create yAxis
var yAxis = unitsChart.yAxis();
yAxis.title().text('Units');
yAxis.stroke('none');
yAxis.ticks().enabled(false);
yAxis.minorTicks().enabled(false);
yAxis.labels().padding().right(5);
// Create xAxis
var xAxis = unitsChart.xAxis();
xAxis.title().enabled(false);
xAxis.staggerMode(false);
var monthNames = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
xAxis.labels().textFormatter(function() {
var date = new Date(this.value);
return monthNames[date.getMonth()] + ' ' + date.getDate() + ' ' + date.getFullYear();
});
// Create step area series
unitSeries = unitsChart.stepArea();
unitSeries.color(unitSeriesColor);
unitSeries.tooltip().contentFormatter(function() {
return String(this.value);
});
// Create bar chart
territoryChart = anychart.bar();
// Set chart to render on stage
territoryChart.container(stage);
// Set chart size and position
territoryChart.bounds('1%', '52%', '33%', '30%');
// Set chart settings common for all bar charts in dashboard
setupBarChartSettings(territoryChart);
// Set chart title text
title = territoryChart.title();
title.text('Territory');
title.fontWeight('normal');
title.fontColor(barTitleColor);
title.fontSize('16px');
// Set chart title position settings
title.padding(0, 0, 0, 80);
title.align('left');
// Create bar series
territorySeries = territoryChart.bar();
territorySeries.name('territories');
// Set series settings common for all bar series in the dashboard
setupBarSeriesSettings(territorySeries);
// Create bar chart
platformChart = anychart.bar();
// Set chart to render on stage
platformChart.container(stage);
// Set chart size and position
platformChart.bounds('34%', '52%', '32%', '30%');
// Set chart settings common for all bar charts in the dashboard
setupBarChartSettings(platformChart);
// Set chart title text
title = platformChart.title();
title.text('Platform');
title.fontWeight('normal');
title.fontColor(barTitleColor);
title.fontSize('16px');
// Set chart title position settings
title.align('left');
title.padding(0, 0, 0, 40);
// Create bar series
platformSeries = platformChart.bar();
platformSeries.name('platforms');
// Set series settings common for all bar series in the dashboard
setupBarSeriesSettings(platformSeries);
// Create help label
helpLabel = platformChart.label();
//set label text settings
helpLabel.text('Click Bars to Filter');
helpLabel.fontColor(helpTextColor);
helpLabel.fontSize(10);
helpLabel.fontWeight('normal');
//set label position settings
helpLabel.position('centerbottom');
helpLabel.anchor('centerbottom');
helpLabel.offsetY(-20);
helpLabel.padding(3, 3, 3, 3);
// Set label background settings
var labelBackground = helpLabel.background();
labelBackground.enabled(true);
labelBackground.fill(helpBgFill);
labelBackground.stroke(helpBgStroke);
// Create bar chart
categoryChart = anychart.bar();
// Set chart to render on stage
categoryChart.container(stage);
// Set chart size and position
categoryChart.bounds('66%', '52%', '33%', '30%');
// Set chart settings common for all bar charts in the dashboard
setupBarChartSettings(categoryChart);
// Set chart title text
title = categoryChart.title();
title.text('Category');
title.fontWeight('normal');
title.fontColor(barTitleColor);
title.fontSize('16px');
// Set chart title position
title.align('left');
title.padding(0, 0, 0, '90px');
// Create bar series
categorySeries = categoryChart.bar();
categorySeries.name('categories');
// Set series settings common for all bar series in the dashboard
setupBarSeriesSettings(categorySeries);
updateData();
// Initiate all charts drawing
unitsChart.draw();
territoryChart.draw();
platformChart.draw();
categoryChart.draw();
});
// Setup same settings for all charts
function setupBarSeriesSettings(series) {
series.color(barsSeriesColor)
series.tooltip().contentFormatter(function() {
return String(this.value);
});
series.listen('pointClick', function(e) {
var series = e.target;
var seriesName = series.name();
var categoryName = e.iterator.get('x');
switch (seriesName) {
case 'territories':
territoryFilter = (territoryFilter && territoryFilter == categoryName) ? null : categoryName;
break;
case 'platforms':
platformFilter = (platformFilter && platformFilter == categoryName) ? null : categoryName;
break;
case 'categories':
categoryFilter = (categoryFilter && categoryFilter == categoryName) ? null : categoryName;
break;
}
updateData();
});
}
/**
* Set the same settings for all charts (assuming it is Bar Chart).
* @param {anychart.cartesian.Chart} chart Chart to set settings.
*/
function setupBarChartSettings(chart) {
// Disable axes titles
chart.xAxis().title().enabled(false);
chart.yAxis().enabled(false);
// Disable grids
chart.grid().enabled(false);
chart.grid(1).enabled(false);
chart.minorGrid().enabled(false);
// Set bar position
chart.barsPadding(.2);
chart.barGroupsPadding(0.5);
// Set background, padding and margin settings
chart.background().enabled(false);
chart.padding(0);
chart.margin(0);
chart.margin().bottom(20);
}
/**
* Apply filters to raw data.
* Set data to charts in the following format:
*
* var unitData = [
* //timestamp value
* [1409529600000, 100],
* [1409616000000, 200],
* [1409702400000, 300]
* ];
* var barData = [
* {x: 'Category Name 1', value: 100, fill: 'rgb(233, 234, 237)', stroke: 'anychart.color.darken(rgb(233, 234, 237))'},
* {x: 'Category Name 2', value: 200, fill: 'rgb(233, 234, 237)', stroke: 'anychart.color.darken(rgb(233, 234, 237))'},
* {x: 'Category Name 3', value: 300, fill: 'rgb(233, 234, 237)', stroke: 'anychart.color.darken(rgb(233, 234, 237))'}
* ];
*
*/
function updateData() {
var unitMap = {};
var territoryMap = {};
var platformMap = {};
var categoryMap = {};
for (var i = 0, count = rawData.length; i < count; i++) {
var dataItem = rawData[i];
var fitTerritoryFilter = !territoryFilter || (territoryFilter && territoryFilter == dataItem['territory']);
var fitPlatformFilter = !platformFilter || (platformFilter && platformFilter == dataItem['platform']);
var fitCategoryFilter = !categoryFilter || (categoryFilter && categoryFilter == dataItem['category']);
if (fitTerritoryFilter && fitPlatformFilter && fitCategoryFilter) {
var unitsMapItem = unitMap[dataItem.x];
if (unitsMapItem) {
unitMap[dataItem.x] = [dataItem.x, unitsMapItem[1] + dataItem.value];
} else {
unitMap[dataItem.x] = [dataItem.x, dataItem.value];
}
}
if (fitPlatformFilter && fitCategoryFilter) {
var territoryMapItem = territoryMap[dataItem.territory];
if (territoryMapItem) {
territoryMapItem.value += dataItem.value;
} else {
territoryMapItem = {x: dataItem.territory, value: dataItem.value};
territoryMap[dataItem.territory] = territoryMapItem;
}
territoryMapItem['fill'] = territoryMapItem.x == territoryFilter ? hoverBarsSeriesColor : undefined;
territoryMapItem['stroke'] = territoryMapItem.x == territoryFilter ? anychart.color.darken(hoverBarsSeriesColor) : undefined;
}
if (fitTerritoryFilter && fitCategoryFilter) {
var platformMapItem = platformMap[dataItem.platform];
if (platformMapItem) {
platformMapItem.value += dataItem.value;
} else {
platformMapItem = {x: dataItem.platform, value: dataItem.value};
platformMap[dataItem.platform] = platformMapItem;
}
platformMapItem['fill'] = platformMapItem.x == platformFilter ? hoverBarsSeriesColor : undefined;
platformMapItem['stroke'] = platformMapItem.x == territoryFilter ? anychart.color.darken(hoverBarsSeriesColor) : undefined;
}
if (fitTerritoryFilter && fitPlatformFilter) {
var categoryMapItem = categoryMap[dataItem.category];
if (categoryMapItem) {
categoryMapItem += dataItem.value;
} else {
categoryMapItem = {x: dataItem.category, value: dataItem.value};
categoryMap[dataItem.category] = categoryMapItem;
}
categoryMapItem['fill'] = categoryMapItem.x == categoryFilter ? hoverBarsSeriesColor : undefined;
categoryMapItem['stroke'] = categoryMapItem.x == territoryFilter ? anychart.color.darken(hoverBarsSeriesColor) : undefined;
}
}
var territoryData = getValues(territoryMap);
//console.log(territoryData); //uncomment to log data format
var platformData = getValues(platformMap);
//console.log(platformData); //uncomment to log data format
var categoryData = getValues(categoryMap);
//console.log(categoryData); //uncomment to log data format
var unitData = getValues(unitMap);
//console.log(unitData); //uncomment to log data format
territorySeries.data(territoryData);
platformSeries.data(platformData);
categorySeries.data(categoryData);
unitSeries.data(unitData);
}
/**
* Generate data in the following format:
* var data = [
* {x: Date.UTC(2014, 8, 1), value: 700, territory: 'Europe', platform: 'iPhone', category: 'Games'},
* {x: Date.UTC(2014, 8, 1), value: 200, territory: 'Europe', platform: 'iPad', category: 'Games'},
* {x: Date.UTC(2014, 8, 1), value: 400, territory: 'Europe', platform: 'Desktop', category: 'Games'}
* ];
* @return {Array.<Object>}
*/
function generateData() {
var data = [];
var dates = [
Date.UTC(2014, 8, 1), Date.UTC(2014, 8, 2), Date.UTC(2014, 8, 3),
Date.UTC(2014, 8, 4), Date.UTC(2014, 8, 5), Date.UTC(2014, 8, 6),
Date.UTC(2014, 8, 7), Date.UTC(2014, 8, 8), Date.UTC(2014, 8, 9)
];
var territories = ['Europe', 'Asia Pacific', 'USA and Canada'];
var platforms = ['iPhone', 'iPad', 'Desktop'];
var categories = ['Games', 'Social Networking', 'Photo & Video'];
for (var d = 0, datesCount = dates.length; d < datesCount; d++) {
for (var t = 0, territoriesCount = territories.length; t < territoriesCount; t++) {
for (var p = 0, platformsCount = platforms.length; p < platformsCount; p++) {
for (var c = 0, categoriesCount = categories.length; c < categoriesCount; c++) {
data.push({
x: dates[d],
value: Math.floor((Math.random() * 100) + 1),
territory: territories[t],
platform: platforms[p],
category: categories[c]
});
}
}
}
}
return data;
}
/**
* Return Object values as array.
* @param {Object} obj
* @return {Array}
*/
function getValues(obj) {
var res = [];
var i = 0;
for (var key in obj) {
res[i++] = obj[key];
}
return res;
}
</script>
</body>
</html>