1votos

Reloj Digital en JavaScript

por josejuan hace 5 años

Se implementa primero un display estilo LCD con colores. Luego un controlador de fuentes que importa archivos Unifont.hex. Luego un controlador que permite enviar mensajes. Finalmente un ejemplo de uso que muestra la hora solicitada y frases aleatorias. Puede ejecutarse directamente en la consola de Firefox.

Contruye un reloj digital creando los números a partir de un caracter de relleno, es decir, teniendo un array bidimensional, rellenar las posiciones necesarias para que al imprimirlo en pantalla simule la hora y fecha.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<html> 
<head> 
<script> 
 
    // puedes pegar sólo la parte de javascript en la consola y ejecutar la función: 
    // 
    //      loader() 
    // 
    // ¡probado sólo en Firefox 28.0! requiere lambdas!!!! 
 
    Array.range = (a, b) => Array(b + 1).join(' ').split('').map((_, i) => a + i); 
 
 
    // dibuja un display LCD con colores (cada píxel tiene su color) y permite "empujar" las columnas de der/izq 
    function LCD(o = {}) { 
        var cfg = {}; 
        cfg.e  = o.layer      || document.body; 
        cfg.w  = o.width      || 150; 
        cfg.h  = o.height     || 16; // si quiere hacerse coincidir con Unifont 
        cfg.cw = o.cellWidth  || 2; 
        cfg.ch = o.cellHeight || 2; 
        cfg.e.innerHTML = 
          '<table style="border-collapse: collapse"><tr>' + 
          Array.range(0, cfg.h).map(_ => Array.range(0, cfg.w).map(_ => '<td>&nbsp;</td>').join('')).join('</tr><tr>') + 
          '</tr></table>'; 
        var _cell = Array.prototype.slice.call(cfg.e.getElementsByTagName('td')); 
        _cell.map(c => c.style = 'width: ' + cfg.cw + 'mm; height: ' + cfg.ch + 'mm; background-color: white; border: 1px solid lightgray; font-size: 1px'); 
        var cell = (r, c) => _cell[ r * cfg.w + c ]; 
        return (colors /* [color] */ => { 
                for(var r = 0, i = 0, S1 = cfg.h, S2 = cfg.w - 1; r < S1; r++, i++) { 
                  for(var c = 0; c < S2; c++, i++) 
                    _cell[i].style.backgroundColor = _cell[i + 1].style.backgroundColor; 
                  _cell[i].style.backgroundColor = colors[r]; 
            }); 
 
 
    // Codifica una fuente Unifont (http://unifoundry.com/unifont.html) coloreada 
    function Unifont8x16(color) { // << puede hacerse x32 para las "partes bajas" 
       var source = // << directamente un archivo Unifont (cambiar EOL por ;) 
          "0020:00000000000000000000000000000000;0021:00000000080808080808080008080000;0022:00002222222200000000000000000000;0023:000000001212127E24247E4848480000;0024:00000000083E4948380E09493E080000;0025:00000000314A4A340808162929460000;0026:000000001C2222221C39454246390000;0027:00000808080800000000000000000000;0028:00000004080810101010101008080400;0029:00000020101008080808080810102000;002A:00000000000008492A1C2A4908000000;002B:0000000000000808087F080808000000;002C:00000000000000000000000018080810;002D:0000000000000000003C000000000000;002E:00000000000000000000000018180000;002F:00000000020204080810102040400000;0030:00000000182442424242424224180000;0031:000000000818280808080808083E0000;0032:000000003C4242020C102040407E0000;0033:000000003C4242021C020242423C0000;0034:00000000040C142444447E0404040000;0035:000000007E4040407C020202423C0000;0036:000000001C2040407C424242423C0000;0037:000000007E0202040404080808080000;0038:000000003C4242423C424242423C0000;0039:000000003C4242423E02020204380000;003A:00000000000018180000001818000000;003B:00000000000018180000001808081000;003C:00000000000204081020100804020000;003D:000000000000007E0000007E00000000;003E:00000000004020100804081020400000;003F:000000003C4242020408080008080000;0040:000000001C224A565252524E201E0000;0041:0000000018242442427E424242420000;0042:000000007C4242427C424242427C0000;0043:000000003C42424040404042423C0000;0044:00000000784442424242424244780000;0045:000000007E4040407C404040407E0000;0046:000000007E4040407C40404040400000;0047:000000003C424240404E4242463A0000;0048:00000000424242427E42424242420000;0049:000000003E08080808080808083E0000;004A:000000001F0404040404044444380000;004B:00000000424448506060504844420000;004C:000000004040404040404040407E0000;004D:00000000424266665A5A424242420000;004E:0000000042626252524A4A4646420000;004F:000000003C42424242424242423C0000;0050:000000007C4242427C40404040400000;0051:000000003C4242424242425A663C0300;0052:000000007C4242427C48444442420000;0053:000000003C424240300C0242423C0000;0054:000000007F0808080808080808080000;0055:000000004242424242424242423C0000;0056:00000000414141222222141408080000;0057:00000000424242425A5A666642420000;0058:00000000424224241818242442420000;0059:00000000414122221408080808080000;005A:000000007E02020408102040407E0000;005B:0000000E080808080808080808080E00;005C:00000000404020101008080402020000;005D:00000070101010101010101010107000;005E:00001824420000000000000000000000;005F:00000000000000000000000000007F00;0060:00201008000000000000000000000000;0061:0000000000003C42023E4242463A0000;0062:0000004040405C6242424242625C0000;0063:0000000000003C4240404040423C0000;0064:0000000202023A4642424242463A0000;0065:0000000000003C42427E4040423C0000;0066:0000000C1010107C1010101010100000;0067:0000000000023A44444438203C42423C;0068:0000004040405C624242424242420000;0069:000000080800180808080808083E0000;006A:0000000404000C040404040404044830;006B:00000000404044485060504844420000;006C:000000001808080808080808083E0000;006D:00000000000076494949494949490000;006E:0000000000005C624242424242420000;006F:0000000000003C4242424242423C0000;0070:0000000000005C6242424242625C4040;0071:0000000000003A4642424242463A0202;0072:0000000000005C624240404040400000;0073:0000000000003C4240300C02423C0000;0074:0000000010107C1010101010100C0000;0075:000000000000424242424242463A0000;0076:00000000000042424224242418180000;0077:00000000000041494949494949360000;0078:00000000000042422418182442420000;0079:0000000000004242424242261A02023C;007A:0000000000007E0204081020407E0000;007B:0000000C101008081010080810100C00;007C:00000808080808080808080808080808;007D:00000030080810100808101008083000;007E:00000031494600000000000000000000;00A0:00000000000000000000000000000000;00A1:00000000080800080808080808080000;00A2:0000000008083E494848493E08080000;00A3:000000000E1010107C1010103E610000;00A4:000000000042243C24243C2442000000;00A5:00000000412214087F087F0808080000;00A6:00000000080808080000080808080000;00A7:000000003C42403C42423C02423C0000;00A8:24240000000000000000000000000000;00A9:000000003C4299A5A1A1A599423C0000;00AA:00001C021E221E003E00000000000000;00AB:00000000001212242448242412120000;00AC:000000000000000000007E0202020000;00AE:000000003C42B9A5A5B9A9A5423C0000;00AF:00007E00000000000000000000000000;00B0:10282810000000000000000000000000;00B1:000000000808087F080808007F000000;00B2:00001C22021C20203E00000000000000;00B3:00001C22021C02221C00000000000000;00B4:00040810000000000000000000000000;00B5:000000000000000022222222362A2020;00B6:0000003E7A7A7A7A3A0A0A0A0A0A0E00;00B7:00000000000000001818000000000000;00B8:00000000000000000000000000000830;00B9:00000818280808080800000000000000;00BA:00001C2222221C003E00000000000000;00BB:00000000004848242412242448480000;00BC:00000000226224282812162A4E420000;00BD:000000002262242828141A22444E0000;00BE:00000000621224186812162A4E420000;00BF:000000000808000808304242423C0000;00C0:300C000018242442427E424242420000;00C1:0C30000018242442427E424242420000;00C2:1824000018242442427E424242420000;00C3:324C000018242442427E424242420000;00C4:2424000018242442427E424242420000;00C5:1824180018242442427E424242420000;00C6:000000001F2848487F484848484F0000;00C7:000000003C42424040404042423C0830;00C8:300C00007E4040407C404040407E0000;00C9:0C3000007E4040407C404040407E0000;00CA:182400007E4040407C404040407E0000;00CB:242400007E4040407C404040407E0000;00CC:180600003E08080808080808083E0000;00CD:0C3000003E08080808080808083E0000;00CE:182400003E08080808080808083E0000;00CF:242400003E08080808080808083E0000;00D0:0000000078444242F242424244780000;00D1:324C000042626252524A4A4646420000;00D2:300C00003C42424242424242423C0000;00D3:0C3000003C42424242424242423C0000;00D4:182400003C42424242424242423C0000;00D5:324C00003C42424242424242423C0000;00D6:242400003C42424242424242423C0000;00D7:00000000000000422418244200000000;00D8:000000023A44464A4A525262225C4000;00D9:300C00004242424242424242423C0000;00DA:0C3000004242424242424242423C0000;00DB:182400004242424242424242423C0000;00DC:242400004242424242424242423C0000;00DD:0C300000414122221408080808080000;00DE:00000040407844424244784040400000;00DF:00000000384444447C424242625C0000;00E0:0000300C00003C42023E4242463A0000;00E1:00000C3000003C42023E4242463A0000;00E2:0000182400003C42023E4242463A0000;00E3:0000324C00003C42023E4242463A0000;00E4:0000242400003C42023E4242463A0000;00E5:0018241800003C42023E4242463A0000;00E6:0000000000003E49093F4848493E0000;00E7:0000000000003C4240404040423C0830;00E8:0000300C00003C42427E4040423C0000;00E9:00000C3000003C42427E4040423C0000;00EA:0000182400003C42427E4040423C0000;00EB:0000242400003C42427E4040423C0000;00EC:0000300C0000180808080808083E0000;00ED:00000C300000180808080808083E0000;00EE:000018240000180808080808083E0000;00EF:000024240000180808080808083E0000;00F0:0000320C1422023E42424242423C0000;00F1:0000324C00005C624242424242420000;00F2:0000300C00003C4242424242423C0000;00F3:00000C3000003C4242424242423C0000;00F4:0000182400003C4242424242423C0000;00F5:0000324C00003C4242424242423C0000;00F6:0000242400003C4242424242423C0000;00F7:0000000000001800007E000018000000;00F8:0000000000023C464A4A5252623C4000;00F9:0000300C0000424242424242463A0000;00FA:00000C300000424242424242463A0000;00FB:000018240000424242424242463A0000;00FC:000024240000424242424242463A0000;00FD:00000C3000004242424242261A02023C;00FE:0000000020203C222222242830202020;00FF:0000242400004242424242261A02023C"; 
       var font = {}; 
       source.split(';').forEach(f => { 
         var q = f.split(':'), w = [], css = []; 
         for(var a = 0, b = 2, Q = q[1], S = Q.length; b < S; a += 2, b += 2) 
           w.unshift(parseInt('0x' + Q.slice(a, b))); 
         for(var c = 0, m = 128; c < 8; c++, m >>= 1) { 
           var cs = []; 
           for(var r = 0; r < 16; r++) 
             cs.unshift((w[r] & m) ? color : ''); 
           css.push(cs); 
         font[String.fromCharCode(parseInt('0x' + q[0]))] = css; 
       }); 
       return ((lcd, c) => (typeof font[c] === "undefined" ? font[' '] : font[c]).forEach(lcd)); 
 
 
    // permite escribir cadenas coloreadas y las envía al display en intervalos manteniendo un buffer queue 
    function LCDController(lcd, interval) { 
        var queue = [], fonts = {}; 
        var self = { 
            lcd: lcd, 
            write: (color, s) => s.split('').forEach(c => queue.unshift({color: color, c: c})), 
            font: f => (typeof fonts[f] === "undefined" ? (fonts[f] = Unifont8x16(f)) : fonts[f]), 
            render: c => self.font(c.color)(self.lcd, c.c), 
            isEmpty: () => queue.length === 0, 
            run: () => self.render(self.isEmpty() ? {color: 'black', c: ' '} : queue.pop()) 
        }; 
        window.setInterval(_ => self.run(), interval); 
        return self; 
 
 
    // un ejemplo de uso, imprime mensajes aleatorios y la fecha y hora a intervalos regulares 
    function loader() { 
        var controller = LCDController(LCD(), 500); 
        var msg = [{c: 'blue', m: "I'm blur"} 
                  ,{c: 'yellow', m: "I'm happy"} 
                  ,{c: 'pink', m: "I'm in love"} 
                  ,{c: 'red', m: "I'm angry"} 
                  ]; 
        window.setInterval(_ => { 
          if(controller.isEmpty()) { 
            controller.write('green', new Date().toLocaleTimeString('es') + ' ' + new Date().toLocaleDateString('es')); 
            var m = msg[Math.floor(Math.random() * msg.length)]; 
            controller.write(m.c, "  " + m.m + "  "); 
        }, 1000); 
 
</script> 
<body onload="loader()"> 
</body> 
</html> 
8 comentarios
0votos

Escrito por josejuan hace 5 años

(Por eso de mostrar una imagen reescalada)
0votos

Escrito por Victor hace 5 años

me ha encantado, se me ha ocurrido meterle un socket.io y queda muy divertido
0votos

Escrito por josejuan hace 5 años

¡Buena idea!, también se pueden obtener las fuentes de archivos directamente (con xhr por ejemplo), aunque para algo en producción sería mejor usar un canvas en lugar de tanto td :D :D :D
0votos

Escrito por adr hace 5 años

Bueno era rellenar con caracteres ><.
Aunque sin duda no te haré reescribir el código porque en vez de colorear el bg de las casillas sólo habría que añadir un caracter coloreado.
0votos

Escrito por josejuan hace 5 años

(Mmm... ¿que debo hacer?...)

El problema que comento con los td, es de rendimiento. Modificar el DOM puede llegar a ser tan lento en ciertos casos (como éste) que puede ser mejor incluso reescribir todo el elemento (no parecer ser el caso).

Sin duda en una solución más real sería renderizar sobre un canvas directamente un framebuffer en lugar de desplazar el color entre elementos (sean estos td o un carácter).

En cualquier caso, la solución seguiría sirviendo tal cual está, modificando únicamente el constructor LCD.
0votos

Escrito por adr hace 5 años

No hay que hacer nada, así está bien, pero el reto decía:

Contruye un reloj digital creando los números a partir de un caracter de relleno, es decir, teniendo un array bidimensional, rellenar las posiciones necesarias para que al imprimirlo en pantalla simule la hora y fecha

Todos los ejercicios que estoy proponiendo son básicos de matrices bidimensionales para que sean fáciles de resolver.

Tu rellenas con una tabla y coloreas el background. Hace lo mismo. Lo que si en vez de eso ponías un caracter y lo coloreabas cumplías lo que decía el reto, pero eran taaan insignificante lo que había que cambiar que consideré que así ya estaba bien.

Ahora bien, si insertas el mismo caracter, un caracter con el mismo ancho o declaras el estilo font-family:monospace; No veo necesidad de usar tablas.

Como hay muchas formas de hacerlo puse varios ejemplos,
incluso viendo que un usuario quizo hacerlo con Canvas pues también puse un ejemplo así.

En conclusión, que así es válido, aunque falto el caracter de relleno.
0votos

Escrito por adr hace 5 años

es más, de los publicados que no son propios, es el único que ha dado la solución sin errores y que realmente escribe el dato que se pasa.
0votos

Escrito por Api hace 5 años

Muy bueno :)

Comenta la solución

Tienes que identificarte para poder publicar tu comentario.