Clon de Spritz en AngularJS: Fast Reader

Durante estas semanas ha salido a la luz un método de lectura en el ordenador y dispositivos móviles que parece estar llamado a revolucionar la forma de leer textos: presentan el texto palabra por palabra en un cuadro, centrando cada palabra en una posición. De este modo se evita perder tiempo en enfocar la vista en la siguiente palabra. Se puede encontrar más información en muchas noticias, como por ejemplo aquí, o en su sitio oficial: http://www.spritzinc.com/

La parte mala es que todavía no está disponible, más allá de una simple demo. Así que como me gustaría utilizarlo ya mismo, y no voy a apuntarme a su cartera de beta-testers, he decidido usarlo como excusa para hacer una webapp usando AngularJS  y Bootstrap.

Si queréis probar mi implementación, lo podéis hacer en http://rusizate.com/reader/ y como siempre el código fuente en el respositorio de GitHub: https://github.com/4lberto/FastReader

lectura

En cuanto a la parte técnica es muy sencilla. Sigue estos pasos:

  1. Lee el texto del textarea, que se guarda en una variable.
  2. Lo transforma a un array de palabras
  3. Va mostrando cada cierto tiempo las palabras en pantalla, calculando dos cosas:
    1. Qué letra se va a iluminar en rojo: mediante un switch case, dependiendo de la longitud de la palabra.
    2. Cuántos espacios se va a insertar delante de la palabra para que quede centrada respecto de la letra iluminada.

Otros dos aspectos destacables:

  • Control del tiempo en AngularJS: mediante el componente $timeout, que es como el window.setTimeout de Javascript. Es decir, espera una serie de milisegundos para llamar a una función. Metido en un bucle y mientras haya palabras por mostrar se va ejecutando. es muy importante usar $timeout y no window.setTimeout en AngularJS. El método tradicional no funciona.
$timeout(loop, Math.floor(((palabra.length+2)/4)*$scope.speed));
  • Necesitamos mostrar una palabra que tiene código HTML dentro. Para pintar de rojo la letra, debemos rodearla con un span. Para ello , en angular se puede usar $sce.trustAsHtml(palabra) y luego en el atributo de la vista podemos usar: ng-bind-html=”palabraActual”
<h3 ng-bind-html="palabraActual">{{palabraActual}}</h3>

 

$scope.palabraActual=$sce.trustAsHtml('pal<span class="rojo">a</rojo>bra');

En cambos casos tenemos que inyectar $timeout y $sce en el controlador de AngularJS


function TodoCtrl($scope, $timeout, $sce) {

El controlador al final queda de este modo:

</pre>
function TodoCtrl($scope, $timeout, $sce) {

var textoSplit;
 $scope.palabraActual=$sce.trustAsHtml("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a-word");
 $scope.indicePalabra=0;
 $scope.textoArea = "There is something at the bottom of every new human thought, every thought of genius, or even every earnest thought that springs up in any brain, which can never be communicated to others, even if one were to write volumes about it and were explaining one's idea for thirty-five years; there's something left which cannot be induced to emerge from your brain, and remains with you forever; and with it you will die, without communicating to anyone perhaps the most important of your ideas. - Fyodor Dostoyevsky, The Idiot"
 $scope.speed = 120;
 $scope.speedFactor = 10;
 $scope.leyendo = false;

$scope.startReading = function()
 {
 $scope.leyendo = true;

if(!((textoSplit)&&(textoSplit.length>0)))
 {
 $scope.indicePalabra=0;
 textoSplit = $scope.textoArea.split(" "); //Separa el texto
 }

loop();

}

$scope.stopReading = function()
 {
 $scope.leyendo = false;
 }

var loop = function()
 {
 console.log("Han llamado a loop:" + textoSplit.length + " - indicePalabra" + $scope.indicePalabra);

if(textoSplit.length>$scope.indicePalabra)
 {

var palabra = textoSplit[$scope.indicePalabra];
 var puntoCentral = calculaPuntoCentral(palabra);

$scope.palabraActual = $sce.trustAsHtml(generaEspacios(puntoCentral)+colorea(palabra, puntoCentral));

$scope.indicePalabra++;
 if($scope.leyendo)
 $timeout(loop, Math.floor(((palabra.length+2)/4)*$scope.speed));
 }
 else
 {
 console.log("Fin lectura...");
 }
 }
 $scope.speedUp = function()
 {
 $scope.speed += $scope.speedFactor;
 }

$scope.speedDown = function()
 {

$scope.speed = Math.max(0,$scope.speed-$scope.speedFactor);
 }

$scope.clearTextArea = function()
 {
 $scope.textoArea="";
 textoSplit = [];
 $scope.indicePalabra=0;
 $scope.palabraActual=$sce.trustAsHtml("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a-word");
 $scope.leyendo = false;
 }
 var calculaPuntoCentral = function(palabra)
 {

var puntoCentral = 1;

switch ( palabra.length) {
 case 1:
 puntoCentral = 1;
 break;
 case 2:
 case 3:
 case 4:
 case 5:
 puntoCentral = 1;
 break;
 case 6:
 case 7:
 case 8:
 case 9:
 puntoCentral = 2;
 break;
 case 10:
 case 11:
 case 12:
 case 13:
 puntoCentral = 3;
 break;
 default:
 puntoCentral = 4;
 };

return puntoCentral;
 }
 var generaEspacios = function(puntoCentral)
 {
 var espacios = 10;
 espacios = espacios - puntoCentral;
 var esp = "";
 for(var i = 0;i<espacios;i++)
 {
 esp+="&nbsp;"
 }

return esp;
 }
 var colorea = function(palabra, indice)
 {
 if (palabra.length <2)
 return '<span class="rojo">' + palabra + '</span>'
 else
 return palabra.substr(0,indice-1) + '<span class="rojo">' + palabra.substr(indice-1,1) + '</span>' + palabra.substr(indice,palabra.length);

}

}
<pre>

El código fuente completo está en el respositorio de GitHub: https://github.com/4lberto/FastReader y la demo en http://rusizate.com/reader/

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s