Tableau Cnake – Playing with the JS API from ClojureScript
September 4, 2015
, , , , , , , , ,

Tableau Snake GameTL;DR – Yes, this is an interactive Nokia like Snake game using Tableau Javascript API. You can play with the game at

I have to confess: I never used Tableau’s JavaScript (Embedding) API as of now. When we had to use it I always asked someone from my team to deal with that part simply because I am not a huge fan of javascript, so I try to keep the distance whenever possible. But who said that the JS API works with Javascript only? You can control your wiz from ClojureScript which is one of my favorite – so why don’t give it a try?  Well, as you see I tried.

What is this all about?

I wanted to try different things in one round. This is why it has several, tightly connected features like storing the complete history of each users key presses or a standalone high score server with Rest API.

Some of the design decisions / requirements:

  1. Tableau part should work on Tableau Public (=no real time data refreshes on tableau side)
  2. Have an interactive gameplay experience. Considering Tableau’s refresh speed I decided to keep volatile parts (the snake) outside the Viz while the less changing parts (pills, hall of fame board) went to a Tableau Workbook
  3. Use ClojureScript (& Clojure) exclusively.
  4. Show visualization for the current & top 10 scores after game over. The challenge here to draw a dynamic chart with session related data using Tableau Public – which isn’t the tool for non-extracted data sets.
  5. It was not my original plan, but after Jeffrey Shaffer’s tweet regarding High Score handling I added that to my  TODO list.
  6. And if I start collecting data I wan’t to do it properly. So the Tableau Cnake game record your moves, key presses, pill eating moments along with these events related time stamps. I wrote a generic high score server in Clojure using Liberator providing a fancy REST API.
  7. To make this data available I wrote a Tableau Web Data Connector in ClojureScript to retrieve the “human generated data”. Right now I gather 10,000 events per hour, so it would be a good performance test for this new Tableau feature.
  8. Build some nice Tableau workbooks to analyze the data, like what is the average game time by country, how many moves required to eat a pill and so on. No so exciting but it’s enough to show case Tableau’s WDC feature.

Quite a lot, ehh? It is, but implementing the whole story takes only a few hours, not more. Whatever, let’s jump in it!

The Game part

Tableau Cnake Game Play

Tableau Cnake Game Play

Game Engine

This is the post of confessions. As you see it on the game page, the engine itself is a fork form Joakin’s cnake project. It calculates the cnake world which is basically the map of snake & pill coordinates.  I kept his git version history in my repo so you can see which piece is written by him. Basically I use game.cljs and some parts of ui.cljs and most of these codes are not mine (but public domain open source). The code itself is well designed like it should be in the 2010s’: the game engine and UI communicates with asynchronous messages – so there are no direct function calls between the namespaces. This was a huge help later when I started to replace the user interface.

UI – Pills Workbook

As I wrote earlier I kept the snake itself in HTML5 Canvas element while the pills are moved to the Tableau workbook. The workbook has a data source with 400 lines. It has only one column called location having integer numbers from 1 to 400. I calculate width, height and color (simple modulus) from this single column and put the results on a scatter plot using circles.

Cnake sheet - contains all possible pills locations

Cnake sheet – contains all possible pills locations

To be able to select the visible pills I added a filter for the location field. From Javascript ClojureScript I can simply change the filter selection according to the game’s state.

This is how it looks on public without any API call:

Controlling the Viz

During the game play we need two things: load the visualization and update the pills locations. All Tableau related codes are in the tableau.cljs, you can have a look in it in advance.

Loading the Viz

The Viz load process is very similar to how it is done in JavaScript. Just call new tableau.Viz  with the viz name and options, that’s it.

The code simply defines a few constants (remember, ClojureScript does not have variables: everything is immutable) and creates a new Viz object. The js/#  macro responsible for the javascript interoperability, e.g.: calling a function inside window while the js-obj  macro builds a native javascript object.

One interesting thing. Usually you have to implement a callback for notifying your application that the visualization has loaded. In JavaScript people tend to call their processing or UI logic directly from the onFirstInteractive  callback but that is a bad practice (=bad design).  I prefer asynchronous messaging everywhere. Thus, when Tableau finished the loading of the visualization it sends a message to the tableau-viz-ready-channel . Other modules can subscribe and read from this channel. This allows to keep the code clean: it reduces the cross dependencies between modules.

These go blocks are written in a synchronous style, and internally converted to a state machine that executes them asynchronously. The state machine ensures that even if the browser runs Javascript in a single thread we can still have multiple go blocks running in the same time waiting and blocking for messages. Remember: you can’t write any quality client *script code without a good state machine implementation under the hood.

Drawing the pills

In the workbook we have 400 pills on different locations. We just need to filter according to the game state.  The game engine has a function which invoked after a pill changes:

It gets the current coordinates of the pills and send it to the tableau viz control channel. On the other side, the tableau namespace waits for commands in a go-loop :

This is a beautiful tail recursive synchronous message receiver block with parameter deconstruction. When a :pills command arrives it calls  update-pills  function with the new locations.

The with-tab function ensures that inside its closure we are on the cnake tab (switch tab when necessary) and call the applyFilterAsync function with tableau friendly location parameters. That’s it.

High score

So Jeffery requested this high score feature which gave me a good use case to try out something on Tableau Public. I quickly built a REST high score server (with one of colleague) that can store and return high score information from ClojureScript.

Ben Jones - the guy behind Tableau Public - owns the leader board

Ben Jones – the guy behind Tableau Public – owns the leader board

The Hall of Fame Viz

After your tiny-little snake run into himself the following viz shows your score vs top 10 gamers:

Hard to beat the cnake masters

Hard to beat the cnake masters

Now the thing is that Tableau Public does not allow you to connect live sources. Thus, the only option is to show the current scores is to rely entirely on parameters. Yes, this view does not use any measures or dimensions, just parameters:

Parameter only Tableau Public Viz for dynamic values

Parameter only Tableau Public Viz for dynamic values

After game we simply update the parameters.

High Score server

After reading how to integrate Google Spreadsheet with Tableau I decided to write the whole stuff from scratch. Clojure has a beautiful library to build REST web services: liberator. If you familiar with Erlang’s web machine then you will find liberator very straightforward: it uses the same decision tree based approach.

After I told my colleague Gyula that I started to build a high score server he immediately stepped in and took over the project. His first move was to add Ruby/ActiveRecord like migrations with ragtime. (Once I was a big ruby fan but rails ruined everything).

Also, his version stores all key presses and score event with relative time stamps. This will be useful to visualize how guys are playing. The sources are here: If you are new to Ring/Liberator I would suggest to look into core.clj.

Web Data Connector & Usage reports

This post is already kilometers long, maybe next time. In advance, you will able to access the high score and event data directly from Tableau to analyze how people are playing with game.

Links & Additional info

And last but not least, Tableau API is an easy and fun way to extend Tableau’s (even Public’s) capabilities. Forget ugly JavaScript codes: you can do everything in ClojureScript, Coffee, Scala.js, Dart or TypeScript.

Tamás Földi

Related items

/ You may check this items as well

sync frelard

Tableau Extensions Addons Introduction: Synchronized Scrollbars

At this year’s Tableau Conference, I tried t...

Read more

Tableau External Services API: Adding Haskell Expressions as Calculations

We all have our own Tableau Conference habits.  M...

Read more
Scaling Tableau Image

Scaling out Tableau Extracts – Building a distributed, multi-node MPP Hyper Cluster

Tableau Hyper Database (“Extract”) is ...

Read more