Peloton Engineering
Peloton-Engineering
3 min readOct 7, 2015

--

Using HTML5 Canvas to Post Directly to Facebook

Facebook Share Modal on Peloton.com

From Static to Rich : The Obstacles

Within Peloton’s webapp, we provide our users the ability to see their performance for each class they take. Included within this report is a chart that maps their cadence, power, distance, calories burned, and heart beat. Users can opt to “Share” this report to Facebook, but doing so simply provides a link back to our webapp, with no visual representation of the workout, just a static brand image that we feared was becoming redundant.

While brainstorming ways to extend our features abilities, we proposed a system that allowed the user to share a “snapshot” of this graph — the only problem was, the graph wasn’t an image, but a living-breathing SVG based data representation that had no home on a server. Thus, no URL to access with an image MIME type.

As far as Facebook’s JavaScript SDK documentation goes, the only mention of sharing images to a user’s feed assumes the passing of a URL where said image resides. Facebook will then transload the image, run their own compression processes, and publish it accordingly. As such, the initial proposal for our post-graph-to-Facebook process included creating our own PNG snapshot and uploading it to S3, then returning that newly-created image URL to Facebook. That sounded perfectly fine, but we knew there had to be a better, faster way.

Leveraging Technologies : Canvas to the Rescue

“[The HTML5 canvas element] is part of HTML5 and allows for dynamic, scriptable rendering of 2D shapes and bitmap images. It is a low level, procedural model that updates a bitmap and does not have a built-in scene graph.” This element has many uses including: web game development, graph and chart rendering, and interactive applications, to name a few.

Though our performance graphs are SVG-based (vector) and not drawn in canvas, we knew we could load SVG’s onto canvas or use a similar process to extract our Base64 encoded image data. The first step was getting that Base64 encoded data from our canvas element:

var canvas = document.getElementById(‘canvas’);
var dataURI = canvas.toDataUrl();

Then, we needed to find what we cared about:

var imgdata = dataUrl.match(/data:(image\/.+);base64,(.+)/);

From there, we converted the data to a Blob: “A Blob object represents a file-like object of immutable, raw data. Blobs represent data that isn’t necessarily in a JavaScript-native format. The File interface is based on Blob, inheriting blob functionality and expanding it to support files on the user’s system.”

function dataURItoBlob(dataURI, mime) {
var byteString = window.atob(dataURI);
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
var blob = new Blob([ia], { type: mime });
return blob;
}
var blob = dataURItoBlob(imgdata[2], imgdata[1]);

Once our data was represented as a Blob, the last step was to use the the FormData object which we could send to Facebook in our POST:

var fd = new FormData();
fd.append(‘access_token’, $scope.facebook.authToken);
fd.append(‘source’, blob);
fd.append(‘message’, $scope.canvas.background.getCaption());

Above, you might notice Angular $scope variables as we used AngularJS for this application. Below, is the final piece that uses Angular’s $http to POST and pull the thread through:

$http.post(‘https://graph.facebook.com/me/photos?access_token=' + $scope.facebook.authToken, fd, {
transformRequest: angular.identity,
headers: {
‘Content-Type’: undefined
}
})
.success(function (res) { // Success logic })
.error(function (res) { // Error logic });

The Prototype : Precursor to Implementation

As with any new feature, we thought it best to test the waters and see how this approach would work in the wild, without a complete rewrite our our existing implementation. It just so happened with Valentine’s Day around the corner, our social and marketing teams were dreaming up ways to engage our users on social media. The idea was to create an interactive Valentine’s Day app that allowed the user to customize a Peloton-themed candy heart, as well as tag their friends, and share their own message.

--

--