First wave of Uptred products released!

During the past few weeks, my team has been working on Uptred, a highly ambitious project that aims to give its users a set of tools that help them to manage and upload their videos from any of their devices to their favorite online providers. The first stage of this project finished last month with the releases of the first versions of Uptred Source and Uptred Shell on the Xamarin Component Store and on the Uptred website.

Continue reading

Collaborative Whiteboard Tutorial, Part Two

Part one of this tutorial focused on the description of the project and the server-side code. In this part, we write the client side code that is supposed to handle the drawing operations on an HTML canvas element.

As previously discussed, our web service is supposed to handle multiple separate whiteboards (which we call rooms). Therefore the client needs to know which room it is working on. To specify this, we pass the room name via a query string parameter, room. This parameter can then be read using a simple function (taken from the web via a quick Google search) that extracts the value of a parameter in the query string:

function get_param(name) {
var url = location.href;
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(url);
return results == null ? null : results[1];
}

The client side needs to store variables such as the room name, brush color, brush radius, and other objects in the memory for later use:

var ROOM = "0";
var COLOR = "black";
var RADIUS = 5;
var socket, canvas, context;

The layout of the app is fairly basic. It is made out of a full screen canvas with virtual dimensions of 1000×1000, a button for sending a clear signal, and a few buttons to change the brush color:

<canvas id="canvas" width="1000" height="1000"></canvas>
<div id="panel_tools">
<center>
<button class="action_button" onclick="clear_room();">Wipe</button>
<button class="color_button" style="background-color:black" onclick="change_color('black');">&nbsp;</button>
<button class="color_button" style="background-color:white" onclick="change_color('white');">&nbsp;</button>
<button class="color_button" style="background-color:green" onclick="change_color('green');">&nbsp;</button>
<button class="color_button" style="background-color:red" onclick="change_color('red');">&nbsp;</button>
<button class="color_button" style="background-color:blue" onclick="change_color('blue');">&nbsp;</button>
<button class="color_button" style="background-color:purple" onclick="change_color('purple');">&nbsp;</button>
<button class="color_button" style="background-color:orange" onclick="change_color('orange');">&nbsp;</button>
</center>
</div>

The color buttons simply call the change_color function with the specified color, which sets the brush color to the chosen one:

function change_color(color)
{
COLOR = color;
}

The wipe button calls the clear_room function which sends a clear signal to the server:

function clear_room() {
socket.emit("message", {
"room": ROOM,
"command": "clear"
});
}

As a response to the clear command, the server also sends its own clear command to all clients, telling them to wipe their canvas if they belong to this room:

function get_clear() {
context.clearRect(0, 0, canvas.width, canvas.height);
}

The first time the page is loaded, the client sends the server a join command, resulting in the serve sending the client a snapshot of the room. This message is handled by the get_room function, which iterates through the room data and draws everything in the room:

function get_room(room_data)
{
room_data.forEach(function (e, i) {
get_draw(e);
});
}

Also whenever someone draws, the server sends the clients the information of that brush. So to summarize, here are the commands that are handled by the clients:

if (msg["command"] == "draw") get_draw(msg["data"]);
if (msg["command"] == "clear") get_clear();
if (msg["command"] == "send_room") get_room(msg["data"]);

The get_draw function is responsible for drawing on the canvas. It assumes that the drawing data contains information such as the position of the object (in percentages, i.e. between 0.0 and 1.0), the radius of the brush, its color and the shape. Currently we only support circle for the shape:

function get_draw(draw_data)
{
if (draw_data["shape"] == "circle")
{
draw_data["x"] = (draw_data["x"] / 1000.0) * canvas.width;
draw_data["y"] = (draw_data["y"] / 1000.0) * canvas.height;
context.beginPath();
context.arc(draw_data["x"], draw_data["y"], draw_data["radius"], 0, 2 * Math.PI, false);
context.fillStyle = draw_data["color"];
context.fill();
}
}

Now we need to map the mouse event handlers to functions that will allow the client to send draw messages to the server. The user can enable draw mode by clicking the mouse button, and disable it by releasing the mouse button. Draw signals containing brush data and click position in percentages are sent to the server on mouse move:

var draw_enabled = false;
function mouse_paint(event)
{
if (!draw_enabled) return;
var rect = canvas.getBoundingClientRect();
var x = event.x - rect.left;
var y = event.y - rect.top;
socket.emit("message", {
"room": ROOM,
"command": "draw",
"data": {
"shape": "circle",
"x": 1000.0 * (x / rect.width),
"y": 1000.0 * (y / rect.height),
"radius": RADIUS,
"color": COLOR
},
})
}

function mouse_down(event)
{
draw_enabled = true;
mouse_paint(event);
}

function mouse_move(event)
{
mouse_paint(event);
}

function mouse_up(event)
{
draw_enabled = false;
}

The last step is to initialize everything and send a join message to begin the session:

function initialize() {
ROOM = get_param("room");
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");

canvas.addEventListener("mousedown", mouse_down, false);
canvas.addEventListener("mousemove", mouse_move, false);
canvas.addEventListener("mouseup", mouse_up, false);

socket = io();
socket.on("servermessage", handle_message);
socket.emit("message", {
"room": ROOM,
"command": "join"
});
}
window.addEventListener("load", initialize);

Collaborative Whiteboard Tutorial, Part One

This tutorial aims to demonstrate how to build a real-time communication channel between one server and multiple clients (i.e. browsers), simply by using JavaScript. This project uses Node.js for its server-side backend, and targets Google Chrome for the client side. However, the outcome also works well on other browsers, including Internet Explorer. We call this application QuickDraw.

The end result is supposed to be a web service that stores multiple whiteboards in different rooms, and each client can simply type in a room name and observe or modify the contents of the whiteboard. In case a room does not exist, it will be created automatically.

This tutorial is split into different steps. First, I will show how to create a simple communication channel between the server and clients, and afterwards we transmit user input to the server and receive drawing data from the server to the clients.

The Web Server

We use Node.js on the server side as a web server to send static HTML files as well as the client side JavaScript files, and also to handle the main logic of the program. The express library is used to power the web server and send the files in the client folder to the clients. All the code regarding the web server is stored in the server/web.js folder. Here we do not plan to explain how to run a web server with Node.js, and will simply use this file to start a web server on port 8081:

var web = require("./server/web.js");
web.start(8081);

web.js automatically creates a Socket.io object which is later used to power the communications between the server and clients.

The Communication Protocol

The server is responsible for storing whiteboards (rooms) and their content, and also broadcasting their data to the clients upon request. Therefore it needs to hold a list of rooms, their names and their content.

var rooms = [];
var roomIds = {};
function getRoom(roomId)
{
if (!(roomId in roomIds))
{
roomIds[roomId] = rooms.length;
rooms.push([]);
}
return rooms[roomIds[roomId]];
}

function sendRoom(roomId)
{
web.io.emit("servermessage", {
"room": roomId,
"command": "send_room",
"data": getRoom(roomId)
});
}

The sendRoom function receives a room name (according to the diagram above,) and sends the data associated with that room to the clients. This function can be called every time a client joins in order to receive a copy of what is currently on the whiteboard. We handle incoming messages on the server in the handleMessage function, so we can hook sendRoom to a join message:

function handleMessage(msg)
{
if (msg["command"] == "join") join(msg);
}

Now we need to handle the actual drawing task. Once a user clicks on their canvas, the client side sends the drawing data which contains information such as the position of touch, the brush color and the brush radius, in JSON format. The server side receives this data with a draw command, and adds this information to the room data. After storing the information, it rebroadcasts the same data so that every client receives this drawing information:

function draw(msg)
{
var room = getRoom(msg["room"]);
room.push(msg["data"]);
web.io.emit("servermessage", {
"room": msg["room"],
"command": "draw",
"data": msg["data"]
});
}

The draw method needs to be hooked to the draw command handled by the handleMessage function:

function handleMessage(msg)
{
if (msg["command"] == "join") join(msg);
if (msg["command"] == "draw") draw(msg);
}

Finally, the users should be able to clear a room. This is done by sending a clear command to the server. The server erases all the data stored in that room, and tells all clients to do the same on their canvas:

function clear(msg)
{
var room = getRoom(msg["room"]);
while (room.length) room.pop();
web.io.emit("servermessage", {
"room": msg["room"],
"command": "clear"
});
}

Again, we need to connect this method to the handleMessage function. To prevent crashes due to unknown commands, we surround our code with a try/catch block:

function handleMessage(msg)
{
try
{
//check if message is valid
if (!("room" in msg && "command" in msg))
return;

if (msg["command"] == "draw") draw(msg);
if (msg["command"] == "join") join(msg);
if (msg["command"] == "clear") clear(msg);
}
catch (err)
{
console.log(err);
}
}

And lastly, we need to tell Socket.io to call handleMessage every time a message arrives from a client:

web.io.on('connection', function (socket) {
console.log((new Date()) + ' Connection established.');
socket.on("message", handleMessage);
});

The server side code of our collaborative whiteboard project is done. You can study the full code on QuickDraw’s GitHub repository. The next post will cover the client side code which deals with mouse clicks as input, and draws received data from the server!

Magnetic Interaction with Mobile Games

I have been working on this for a while now, but now it’s time to finally reveal it.

In these videos, you can see the novel mobile interaction method I invented, called the “Magnetic Joystick”. The algorithm allows different objects to be used to wirelessly control mobile games like a joystick. For details, you can refer to our publication at NORDICHI 2014: http://dl.acm.org/citation.cfm?id=2670186

For more information on how to implement this in your games, please contact me via email at saeed[at]saeedoo[dot]com.

VimeoDotNet 3 on GitHub

Concerning this new Vimeo API version 3, I have managed to implement the functionality that allows you to:

    • Generate an authorization URL.
    • Get an access token.
    • Call an API method and get a deserialized JSON response in form of a Dictionary<string,object>.

The source code is available under MIT license on GitHub. For more information on using it, take a look at the Readme.txt file in the project. Meanwhile I will be working on implementing some straightforward upload functionality like the previous version of VimeoDotNet.

Also if you found this project useful, please don’t forget to donate using the link on the top of my blog! I appreciate all the support and pizza it will allow me to consume!