Boardgame in CRM On Demand

This boardgame like any type of gamification visualization tries to create some competition between participants.

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 boardgame 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

boardgame

Concepts

  • The base report is one where activities per salesrep are counted, but anything could be counted
  • The activity count is capped at 20
  • The incentives can be entered in the narrative view prefix definition.  The colors and center image can be changed there too

Criteria Fields

From the ‘Reporting’ subject areas, I used: ‘Activities’

Field Name Calculated Field Formula
Salesrep Account.Owner
# Activities Yes CASE WHEN “Activity Metrics”.”# of Activities” > 20 THEN 20 ELSE “Activity Metrics”.”# of Activities” END
Rep # Yes RSUM(COUNT(DISTINCT 1))
# Reps Yes SUM(COUNT(DISTINCT 1))

Criteria Filters

  • Any filter to count activities in a certain timeframe
  • Any filter that limits the count of activities to only a specific type of activities

Data Formatting

Format the date till the table view looks something like the example below.

boardgame table

Hide the table once the narrative view is ready.

Narrative View Definition

Prefix

<canvas id="myCanvas" width="800" height="800"></canvas>
<script>
   var canvas = document.getElementById('myCanvas');
   var context = canvas.getContext('2d');

   var params = [];
   params['tilesPerXSide'] = 6;
   params['tilesPerYSide'] = 6;
   params['boardBorder'] = 5;
   params['tileBorder'] = 3;
   params['maxWidth'] = canvas.width;
   params['maxHeight'] = canvas.height;
   params['countTiles'] = 2 * params['tilesPerXSide'] + 2 * params['tilesPerYSide'] - 4;

   var board = [];

   for (var i = 1; i <= params['countTiles'] ; i++) {
      board[i] = [];
      board[i]['reward'] = '';
      board[i]['players'] = [];
      board[i]['tileColor'] = 'white';
      board[i]['tileEdgeColor'] = 'red';
      board[i]['tileNumberColor'] = '#F0F0F0';
      board[i]['tileRewardColor'] = 'white';
      board[i]['tilePlayerColor'] = 'blue';
   }
   setReward(5, '1 x Champagne');
   setReward(10, '6 x Champagne');
   setReward(15, '12 x Champagne');
   setReward(20, 'City trip for 2');

   context.beginPath();
   context.rect(0, 0, canvas.width, canvas.height);
   context.lineWidth = 1;
   context.fillStyle = 'white';
   context.fill();
   context.strokeStyle = 'black';
   context.stroke();

   var image = new Image();
   image.onload = function() {
      context.drawImage(image, canvas.width / 2 - 128, canvas.height / 2 - 128 - 50);
   };
   image.src = 'http://www.technogist.com/wp-content/uploads/2014/05/Oracle-logo.png';

   context.font = '20pt Calibri';
   context.textAlign = 'center';
   context.textBaseline = 'middle';
   context.fillStyle = 'red';
   context.fillText('Score small deals in FY15 (less than $100k)', canvas.width / 2, canvas.height / 2 + 100);

   function setReward(tileID, reward) {
      board[tileID]['reward'] = reward;
      board[tileID]['tileColor'] = 'red';
      board[tileID]['tileEdgeColor'] = 'red';
      board[tileID]['tileNumberColor'] = '#FF8181';
      board[tileID]['tileRewardColor'] = 'white';
      board[tileID]['tilePlayerColor'] = 'blue';
   }

   function drawTiles(params, tileID, board) {
      var tileWidth = Math.round((params['maxWidth'] - (2 * params['boardBorder']) - (2 * params['tileBorder'])) / params['tilesPerXSide']);
      var tileHeight = Math.round((params['maxHeight'] - (2 * params['boardBorder']) - (2 * params['tileBorder'])) / params['tilesPerYSide']);

      if (tileID <= params['tilesPerXSide']) {
        x = params['tileBorder'] + params['boardBorder'] + ((tileID - 1) * tileWidth);
        y = params['tileBorder'] + params['boardBorder'];

      } else if (tileID <= params['tilesPerXSide'] + params['tilesPerYSide'] -1) {
        x = params['tileBorder'] + params['boardBorder'] + ((params['tilesPerXSide'] - 1) * tileWidth);
        y = params['tileBorder'] + params['boardBorder'] + ((tileID - params['tilesPerXSide']) * tileHeight);

      } else if (tileID <= 2*params['tilesPerXSide'] + params['tilesPerYSide'] -2) {
        var offsetX = tileID - params['tilesPerXSide'] - params['tilesPerXSide'] + 1;
        x = params['tileBorder'] + params['boardBorder'] + ((params['tilesPerYSide'] - offsetX - 1) * tileWidth);
        y = params['tileBorder'] + params['boardBorder'] + ((params['tilesPerYSide'] - 1) * tileHeight);

      } else if (tileID <= 2*params['tilesPerXSide'] + 2*params['tilesPerYSide'] -4) {
        var offsetY = tileID - 2*params['tilesPerXSide'] - params['tilesPerYSide'] +2;
        x = params['tileBorder'] + params['boardBorder'];
        y = params['tileBorder'] + params['boardBorder'] + ((params['tilesPerYSide'] - offsetY - 1) * tileHeight);
      }

// draw Tile
      context.beginPath();
      context.rect(x, y, tileWidth, tileHeight);
      context.fillStyle = board[tileID]['tileColor'];
      context.fill();
      context.lineWidth = params['tileBorder'];
      context.strokeStyle = board[tileID]['tileEdgeColor'];
      context.stroke();

// write tile number
      context.font = '60pt Calibri';
      context.textAlign = 'center';
      context.textBaseline = 'middle';
      context.fillStyle = board[tileID]['tileNumberColor'];
      context.fillText(tileID, x + tileWidth/2, y + tileHeight/2);

// write reward
      context.font = '12pt Calibri';
      context.textAlign = 'center';
      context.fillStyle = board[tileID]['tileRewardColor'];
      context.fillText(board[tileID]['reward'], x + tileWidth/2, y + 10);

      var k = board[tileID]['players'].length;
      if (k > 0) {
         for (var i = 0; i < k; i++) {
            context.font = '12pt Calibri';
            context.textAlign = 'center';
            context.fillStyle = board[tileID]['tilePlayerColor'];
            context.fillText(board[tileID]['players'][i], x + tileWidth/2, y + 10 + 14 * (i+2));
         }
      }
   }

Narrative

var j = board[@2]['players'].length;
board[@2]['players'][j] = '@1';

Row separator: empty

Postfix

for (var i = 1; i <= params['countTiles'] ; i++) {
 drawTiles(params, i, board);
 }
 </script>

Rows to Display: empty

Leave a Reply

Your email address will not be published. Required fields are marked *