A dashboard presenting sample financial results of a company along with predictions, as well as revenue and costs compared to the budget.

"Date";"Budget";"Cost";"Revenue";"CostPredP";"RevPredP";"CostPredO";"RevPredO"
1546300800000;7000000;6200000;8200000;;;;
1548979200000;7500000;5800000;8700000;;;;
1551398400000;7000000;7500000;8200000;;;;
1554076800000;7000000;6400000;8200000;;;;
1556668800000;7500000;6700000;8700000;;;;
1559347200000;7000000;7300000;8200000;;;;
1561939200000;7500000;6900000;8700000;;;;
1564617600000;7000000;7100000;8200000;;;;
1567296000000;7500000;6800000;8700000;;;;
1569888000000;7000000;5900000;8200000;;;;
1572566400000;7000000;6300000;8200000;;;;
1575158400000;7500000;6500000;8700000;;;;
1577836800000;7000000;7200000;8200000;;;;
1580515200000;7000000;6600000;8200000;;;;
1583020800000;7500000;5700000;8700000;;;;
1585699200000;7000000;7000000;8200000;;;;
1588291200000;7500000;6300000;8700000;;;;
1590969600000;7000000;6800000;8200000;;;;
1593561600000;7500000;6200000;8700000;;;;
1596240000000;7000000;7400000;8200000;;;;
1598918400000;7500000;6900000;8700000;;;;
1601510400000;7000000;7100000;8200000;;;;
1604188800000;7500000;7300000;8700000;;;;
1606780800000;7000000;6800000;8200000;;;;
1609459200000;7500000;6200000;8700000;;;;
1612137600000;7000000;6500000;8200000;;;;
1614556800000;7500000;6700000;8700000;;;;
1617235200000;7000000;7200000;8200000;;;;
1619827200000;7500000;6400000;8700000;;;;
1622505600000;7000000;5900000;8200000;;;;
1625097600000;7500000;6100000;8700000;;;;
1627776000000;8000000;6300000;9200000;;;;
1630454400000;8500000;7000000;9700000;;;;
1633046400000;8000000;8500000;9200000;;;;
1635724800000;8500000;8000000;9700000;;;;
1638316800000;8000000;8300000;9200000;;;;
1640995200000;8500000;8600000;9700000;;;;
1643673600000;8000000;8800000;9200000;;;;
1646092800000;8500000;8500000;9700000;;;;
1648771200000;8000000;7500000;9200000;;;;
1651363200000;8500000;8700000;9700000;;;;
1654041600000;8000000;9500000;10200000;;;;
1656633600000;8500000;8200000;8700000;;;;
1659312000000;8000000;8900000;10700000;;;;
1661990400000;8500000;9200000;9200000;;;;
1664582400000;8000000;7800000;7800000;;;;
1667260800000;8500000;8500000;8000000;;;;
1669852800000;8000000;7800000;8000000;;;;
1672531200000;8500000;6900000;8700000;;;;
1675209600000;8000000;7100000;8900000;;;;
1677628800000;8500000;7200000;8000000;;;;
1680307200000;8000000;7400000;8000000;;;;
1682899200000;8500000;6900000;8700000;;;;
1685577600000;8000000;7100000;8900000;;;;
1688169600000;8500000;7500000;8000000;;;;
1690848000000;8000000;7300000;8700000;;;;
1693526400000;8500000;7600000;8900000;;;;
1696118400000;8000000;7600000;8900000;;;;
1698796800000;7500000;;;7900000;8200000;6900000;9000000
1701388800000;7600000;;;8000000;8300000;7000000;9200000
1704067200000;;;;7900000;8300000;7000000;9100000
1706745600000;;;;8000000;8000000;7400000;9200000
1709251200000;;;;8200000;8100000;7300000;9400000
1711929600000;;;;8100000;8400000;7400000;9200000
1714521600000;;;;7900000;8200000;7200000;9200000
1717200000000;;;;8100000;8200000;7300000;9000000
1719792000000;;;;8200000;8300000;7400000;9100000
1722470400000;;;;8400000;8500000;7500000;9200000
1725148800000;;;;8300000;8500000;7400000;9300000
1727740800000;;;;8200000;8200000;7500000;9300000
1730419200000;;;;8300000;8300000;7400000;9200000
1733011200000;;;;8100000;8400000;7500000;9300000
} }, chart: { type: 'column', className: 'highcharts-column-chart' }, credits: { enabled: false }, xAxis: { type: 'datetime', min: Date.UTC(currentYear), max: Date.UTC(currentYear, 11) }, yAxis: { tickInterval: 2e6 }, series: [{ name: 'Budget', id: 'budget-series', colorIndex: 1 }], tooltip: { format: `{x:%B %Y}
  {series.name}: {(divide y 1000000):.2f}M ` } }; const board = Dashboards.board('container', { dataPool: { connectors: [{ type: 'CSV', id: 'data', csv: document.getElementById('csv').innerHTML, dataModifier: { type: 'Math', columnFormulas: [{ column: 'Result', // I formula: 'D1-C1' }, { column: 'AccResult', // J formula: 'SUM(I$1:I1)' }, { column: 'CostPredA', // K formula: 'AVERAGE(E1,G1)' }, { column: 'RevPredA', // L formula: 'AVERAGE(F1, H1)' }, { column: 'AccResPredP', // M formula: 'J1+SUM(F$1:F1)-SUM(E$1:E1)' }, { column: 'AccResPredO', // N formula: 'J1+SUM(H$1:H1)-SUM(G$1:G1)' }, { column: 'ResPredA', // O formula: 'L1-K1' }, { column: 'AccResPredA', // P formula: 'J1+SUM(O$1:O1)' }] } }] }, gui: { layouts: [{ id: 'layout-1', rows: [{ cells: [{ id: 'kpi-layout-cell', layout: { rows: [{ cells: [{ id: 'rev-chart-kpi' }, { id: 'rev-forecast-kpi' }, { id: 'rev-goal-forecast-kpi' }] }, { cells: [{ id: 'cost-chart-kpi' }, { id: 'cost-forecast-kpi' }, { id: 'cost-goal-forecast-kpi' }] }, { cells: [{ id: 'res-chart-kpi' }, { id: 'res-forecast-kpi' }, { id: 'res-goal-forecast-kpi' }] }] } }, { id: 'stock-cell' }] }, { cells: [{ id: 'rev-chart' }, { id: 'cost-chart' }] }] }] }, components: [{ renderTo: 'rev-chart-kpi', type: 'KPI', chartOptions: Highcharts.merge(commonGaugeOptions, { title: { text: 'Revenue (YTD)' }, accessibility: { point: { valueDescriptionFormat: 'YTD revenue is {value} million $.' } }, yAxis: { max: 102, tickPositions: [73, 83, 92, 102], plotBands: [{ from: 0, to: 73, className: 'null-band' }, { from: 73, to: 83, className: 'warn-band' }, { from: 83, to: 92, className: 'opt-band' }, { from: 92, to: 102, className: 'high-band' }] } }) }, { renderTo: 'rev-forecast-kpi', type: 'KPI', title: `Revenue forecast for ${currentYear}:`, valueFormat: '${value}M' }, { renderTo: 'rev-goal-forecast-kpi', type: 'KPI', title: 'Revenue goal will be achieved at:', valueFormat: '{value}%' }, { renderTo: 'cost-chart-kpi', type: 'KPI', chartOptions: Highcharts.merge(commonGaugeOptions, { title: { text: 'Cost (YTD)' }, accessibility: { point: { valueDescriptionFormat: 'YTD cost is {value} million $.' } }, yAxis: { max: 86, tickPositions: [61, 70, 78, 86], plotBands: [{ from: 0, to: 61, className: 'null-band' }, { from: 61, to: 70, className: 'warn-band' }, { from: 70, to: 78, className: 'opt-band' }, { from: 78, to: 86, className: 'warn-band' }] } }) }, { renderTo: 'cost-forecast-kpi', type: 'KPI', title: `Cost forecast for ${currentYear}:`, valueFormat: '${value}M' }, { renderTo: 'cost-goal-forecast-kpi', type: 'KPI', title: 'Cost goal will be achieved at:', valueFormat: '{value}%' }, { renderTo: 'res-chart-kpi', type: 'KPI', chartOptions: Highcharts.merge(commonGaugeOptions, { title: { text: 'Result (YTD)' }, accessibility: { point: { valueDescriptionFormat: 'YTD result is {value} million $.' } }, yAxis: { max: 21, tickPositions: [6, 10, 16, 21], plotBands: [{ from: 0, to: 6, className: 'null-band' }, { from: 6, to: 10, className: 'warn-band' }, { from: 10, to: 16, className: 'opt-band' }, { from: 16, to: 21, className: 'high-band' }] } }) }, { renderTo: 'res-forecast-kpi', type: 'KPI', title: `Result forecast for ${currentYear}:`, valueFormat: '${value}M' }, { renderTo: 'res-goal-forecast-kpi', type: 'KPI', title: 'Result goal will be achieved at:', valueFormat: '{value}%' }, { renderTo: 'rev-chart', type: 'Highcharts', connector: { id: 'data', columnAssignment: [{ seriesId: 'budget-series', data: ['Date', 'Budget'] }, { seriesId: 'Revenue', data: ['Date', 'Revenue'] }] }, sync: { highlight: true }, chartOptions: { ...commonColumnOptions, title: { text: 'Revenue' } } }, { renderTo: 'cost-chart', type: 'Highcharts', connector: { id: 'data', columnAssignment: [{ seriesId: 'budget-series', data: ['Date', 'Budget'] }, { seriesId: 'Cost', data: ['Date', 'Cost'] }] }, sync: { highlight: true }, chartOptions: { ...commonColumnOptions, title: { text: 'Cost' } } }, { renderTo: 'stock-cell', type: 'Highcharts', chartConstructor: 'stockChart', connector: { id: 'data', columnAssignment: [{ seriesId: 'result', data: ['Date', 'AccResPredA'] }, { seriesId: 'pessimistically', data: ['Date', 'AccResPredP'] }, { seriesId: 'optimistically', data: ['Date', 'AccResPredO'] }] }, sync: { highlight: true }, tooltip: { useHTML: true }, chartOptions: { chart: { className: 'highcharts-stock-chart' }, title: { text: 'Accumulated Result with Forecast' }, subtitle: { text: 'From January 2019 to December 2024' }, accessibility: { point: { valuePrefix: ' } }, xAxis: { plotLines: [{ value: currentMonth, label: { text: 'current month' } }, { value: Date.UTC(currentYear, 0), className: 'year-plotline' }, { value: Date.UTC(currentYear, 11), className: 'year-plotline' }] }, rangeSelector: { buttons: [{ type: 'month', count: 6, text: '6m', title: 'View 6 months' }, { type: 'year', count: 1, text: '1y', title: 'View 1 year' }, { type: 'year', count: 3, text: '3y', title: 'View 3 years' }, { type: 'ytd', text: 'YTD', title: 'View year to date' }, { type: 'all', text: 'All', title: 'View all' }], selected: 2 }, tooltip: { formatter: function () { const { x, points } = this; const format = v => ' + (v / 1e6).toFixed(2) + 'M'; const color = (s, color) => ` ${s} `; const date = Highcharts.dateFormat('%B %Y', x); if (x <= currentMonth) { return `${date}
${color('●', 0)}  Result: ${color(format(points[0].y), 0)} `; } return ` Forecast for ${date}
${color('➚', 2)}  Optimistically: ${color(format(points[2].y), 2)}
${color('●', 0)}  Average: ${color(format(points[0].y), 0)}
${color('➘', 1)}  Pessimistically: ${color(format(points[1].y), 1)} `; } }, credits: { enabled: false }, series: [{ name: 'Result', id: 'result', zIndex: 2 }, { name: 'Pessimistically', id: 'pessimistically' }, { name: 'Optimistically', id: 'optimistically' }] } }] }, true); board.then(res => { const table = res.dataPool.connectors.data.getTable().getModified().columns; const revKPI = res.mountedComponents[0].component; const revForecast = res.mountedComponents[1].component; const revGoalForecast = res.mountedComponents[2].component; const costKPI = res.mountedComponents[3].component; const costForecast = res.mountedComponents[4].component; const costGoalForecast = res.mountedComponents[5].component; const resKPI = res.mountedComponents[6].component; const resForecast = res.mountedComponents[7].component; const resGoalForecast = res.mountedComponents[8].component; const firstRowID = table.Date.findIndex(d => d === Date.UTC(currentYear)); const lastRowID = table.Date.findIndex(d => d === currentMonth); const forecastRowID = table.Date.findIndex(d => d === Date.UTC(currentYear, 11)); let revYTD = 0, costYTD = 0; for (let i = firstRowID; i <= lastRowID; i++) { revYTD += table.Revenue[i] / 1e6; costYTD += table.Cost[i] / 1e6; } let revYearlyForecast = revYTD, costYearlyForecast = costYTD; for (let i = lastRowID + 1; i <= forecastRowID; i++) { revYearlyForecast += table.RevPredA[i] / 1e6; costYearlyForecast += table.CostPredA[i] / 1e6; } revKPI.update({ caption: `${Math.round(revYTD / revTarget * 100)}% of annual target` }); revKPI.chart.addSeries({ data: [revYTD] }); costKPI.update({ caption: `${Math.round(costYTD / costTarget * 100)}% of annual target` }); costKPI.chart.addSeries({ data: [costYTD] }); resKPI.update({ caption: `${Math.round( (revYTD - costYTD) / (revTarget - costTarget) * 100 )}% of annual target` }); resKPI.chart.addSeries({ data: [Math.round((revYTD - costYTD) * 10) / 10] }); revForecast.update({ value: revYearlyForecast.toFixed(2) }); revGoalForecast.update({ value: Math.round(revYearlyForecast / revTarget * 100) }); costForecast.update({ value: costYearlyForecast.toFixed(2) }); costGoalForecast.update({ value: Math.round(costYearlyForecast / costTarget * 100) }); resForecast.update({ value: (revYearlyForecast - costYearlyForecast).toFixed(2) }); resGoalForecast.update({ value: Math.round(( revYearlyForecast - costYearlyForecast ) / (revTarget - costTarget) * 100) }); });