Dibujando a tiempo real con Canvas, Node.js y Socket.io

Desde hace unos meses vengo haciendo pequeñas pruebas con Node.js y realmente me llama bastante esta tecnología, ver Javascript desde el lado del servidor es algo tan raro como atrayente para mi.

Nunca he destacado usando Javascript, en alguna ocasión estudie por mi cuenta las particularidades de este lenguaje pero es que Jquery te facilita tanto el trabajo al realizar acciones en las Webs que me parecía perder el tiempo profundizar en el. Gran error por mi parte.

Luego llego Html 5 y con la etiqueta Canvas se abría ante mi un mundo nuevo, así que decidí empezar a aprender Javascript y Canvas. Y en eso sigo, aprendido Javascript y Canvas poco a poco.

A medida que aprendo me gustaría dejar constancia de mis avances, y se me ha ocurrido realizar una “Pizarra” (si, como la de tu colegio cuando niño/a) que permita a varios usuarios interactuar con ella al mismo tiempo. Como servidor he usado* Node.js* con el framework Express.js, y la librería de Websockets socket.io. En el lado del cliente solamente esta el elemento Canvas y Javascript (y socket.io para el cliente).

Dejo un vídeo de ejemplo:

En el vídeo solamente se ve como lo pruebo en local, pero lo cierto es que probé a hacer yo de servidor mientras varios usuarios accedían desde remoto a la aplicación y la latencia era imperceptible.

El código de la aplicación lo he publicado enhttps://github.com/Nazariglez/pizarra-node para todo el que quiera verlo, destriparlo y criticarlo. He intentado comentarlo de la forma mas clara posible así que explicar aquí paso a paso que hace el código es repetir lo mismo y aburrir al personal.

Lo que si puedo es hablar sobre los problemas que me encontré haciéndolo, los cuales realmente no son problemas, sino falta de conocimientos y experiencia.

La parte del servidor se puede decir que es tan sencilla que no hay nada que destacar, simplemente espera los eventos startLine, closeLine, draw con las coordenadas del ratón y los reenvía a todos los usuarios conectados, el evento clean simplemente envía una señal al cliente para que dibuje un rectángulo verde sobre el tapiz.

En el lado del navegador fue diferente, mi primer fallo fue usar los callback de los eventos que escuchan las acciones del ratón para alterar directamente el canvas, porque cuando llego el momento de escuchar lo que llegaba por websockets debía repetir código para poder dibujar, fallo de novato, para algo existen las funciones ;). Así que extraje todas las acciones a funciones que reciben las coordenadas donde actuar para poder usarlo indistintamente si la orden llegar desde el cliente o desde el servidor.

Lo próximo con lo que me encontré es que al dibujar (desde el cliente), el servidor me enviaba la orden de dibujar nuevamente el mismo trazo, y entonces los trazos se hacían ‘mas gruesos’ en los cambios de dirección, además aunque se diera el caso de que el trazo se viera exactamente igual, esto no es aceptable desde el punto de vista del rendimiento, ¿Por que dibujar dos trazos (o un trazo con el doble de puntos) pudiendo dibujar uno?. La solución es fácil, cuando dibujas solamente debe de llegar una orden a el cliente, yo decidí que al usuario que dibuja se ejecuten las funciones de dibujo sobre la marcha en el cliente, y cuando el servidor envía la señal de dibujo a todos los usuarios, compruebe que tu eres el que esta dibujando y no repita las ordenes. No se si lo logre explicar de una forma entendible.

El siguiente y ultimo “problema” es que al intentar dibujar dos usuarios a la vez, osea dando clicks de manera simultanea sobre el tapiz (cada cual desde su ordenador claro), el trazo se distorsiona. En realidad no se distorsiona sino que el script entiende que es el mismo trazo y no dos trazos separados, por lo tanto la linea que surge es un garabato, la forma en la que lo solucione no es una “solución” propiamente, lo que hice fue bloquear las acciones dentro de los eventos del ratón en el cliente cuando otro usuario esta dibujando, por lo tanto para que uno dibuje otro debe de “soltar” el click del ratón, es algo un tanto rudimentario pero de momento no se dibujar dos trazos por separado y a la vez.

Espero que los errores que cometí y el código sirvan al menos de ejemplo. Seguiré trasteando con estas tecnologías y publicando los avances!