This opportunity analysis report is an attempt to visualize a summary of the state of an opportunity, showing where in the process an opportunity is instead of showing just the sales stage, and displaying KPI’s using color instead of just a series of numbers.
Disclaimer: This is not a finished report and should not be considered as such. This is just a proof of concept to show what the reporting engine of CRM On Demand is capable of.
HTML5 Canvas and Javascript are not a required skill for normal CRM On Demand report generation at all! But using these techniques enable a wide range of unusual data visualizations.
Here is all you need to make this opportunity analysis report in CRM On Demand. But before you try this out, you might want to learn more about how narrative views actually work by checking out this video recording
Result Example
- Showing where the opportunity is in the sales process
- Showing a KPI value not just with a calculated value, but by adding a color that compares the value to a certain expectation
Criteria Fields
From the ‘Reporting’ subject areas, I used: ‘Opportunities’
Field Name | Calculated Field | Formula |
---|---|---|
Opportunity Name | Opportunity.Name | |
Sales Stage | Opportunity.”Sales Stage” | |
Probability | Opportunity.”Probability %” | |
Days till close date | ||
Expected Revenue | Yes | CAST(“Opportunity Metrics”.”Expected Revenue” / 1000 AS CHAR) |
Criteria Filters
- A filter to only evaluate opportunity of the same opportunity type. Mixing opportunity types will lead to having sales stages of different opportunity types mixed up into a flow that is not representable, unless that would be built in further into the narrative report.
- A filter to only show the opportunity matching 1 specific opportunity ID or name.
Data Formatting
Format the date till the table view looks something like the example below.
Hide the table once the narrative view is ready.
Narrative Warning
As this report relies on the use of multiple views, as many as you need, especially for the tiles, you need to make sure that the first few lines in the prefix contain a unique identifier for each of them:
<canvas id="tile1" width="800" height="50"></canvas> <script> var canvas = document.getElementById('tile1'); ...
<canvas id="tile2" width="800" height="50"></canvas> <script> var canvas = document.getElementById('tile2'); ...
<canvas id="tile3" width="800" height="50"></canvas> <script> var canvas = document.getElementById('tile3');
Narrative View Definition 1: Process Flow
Prefix
<canvas id="myCanvas" width="800" height="50"></canvas> <script> var canvas = document.getElementById('myCanvas'); var context = canvas.getContext('2d'); var flow = []; flow[0] = 'Qualified Lead'; flow[1] = 'Building Vision'; flow[2] = 'Short List'; flow[3] = 'Selected'; flow[4] = 'Negotiation'; flow[5] = 'Closed/Lost'; flow[6] = 'Closed/Won'; var params = []; params['canvasWidth'] = canvas.width; params['canvasHeight'] = canvas.height; params['stageWidth'] = Math.round(canvas.width / flow.length); function drawStage(i, salesStage, flowStage) { x = i * params['stageWidth']; y1 = i; y3 = canvas.height; y2 = y1 + Math.round((y3 - y1) / 2); w = params['stageWidth']; s = 12; context.beginPath(); context.moveTo(x, y1); context.lineTo(x + w - s, y1); context.lineTo(x + w, y2); context.lineTo(x + w - s, y3); context.lineTo(x, y3); context.lineTo(x + s, y2); if (salesStage == flowStage) { context.fillStyle = 'red'; } else { context.fillStyle = 'blue'; } context.fill(); context.font = '10pt Arial'; context.fillStyle = 'white'; context.textAlign = 'center'; context.textBaseline = 'middle'; context.fillText(flowStage, x + Math.round(w / 2), y2); } function drawFlow(salesStage) { for (i = 0; i < flow.length; i++) { drawStage(i, salesStage, flow[i]); } }
Narrative
drawFlow('@2');
Postfix
</script>
Rows to Display: empty
Narrative View Definition 2, 3, 4: KPI Tile
Prefix
<canvas id="myTile1" width="150" height="150"></canvas> <script> var canvas = document.getElementById('myTile1'); var context = canvas.getContext('2d'); var params = []; params['canvasWidth'] = canvas.width; params['canvasHeight'] = canvas.height; function drawText(text, order, size) { x = Math.round(canvas.width / 2); y = Math.round(params['canvasHeight'] / 3) * order; context.font = size + 'pt Arial'; context.fillStyle = 'white'; context.textAlign = 'center'; context.textBaseline = 'middle'; context.fillText(text, x, y); } function drawTile(label, value) { x = 0; y = 0; w = canvas.width; h = canvas.height; context.beginPath(); context.rect(x, y, w, h); context.fillStyle = 'green'; context.fill(); context.beginPath(); context.rect(x + 5, y + 5, w - 10, h - 10); context.lineWidth = 2; context.strokeStyle = 'white'; context.stroke(); drawText(label, 1, 10); drawText(value, 2, 30); }
Narrative
drawTile('Probability', '@3'+'%');
Postfix
</script>
Rows to Display: empty