IV Congreso de Software Libre para Educación

Santiago de Compostela, 1 e 2 de xullo de 2015



Libros electrónicos con
HTML5, Javascript e CSS



Mario Rodríguez Riotorto

mario@edu.xunta.es

Confucio Oio e esquezo.
Vexo e lembro.
Fago e aprendo.

Confucio, s.IV AC.

Maneiras de facer:

  • Traballos de campo
  • Materiais manipulativos
  • O computador como laboratorio... Imos por aquí

As ferramentas de autor:

Outro enfoque:

  • Fóra capas intermedias
  • Falamos directamente a linguaxe da web:
    HTML, Javascript, CSS
  • Reivindicamos a figura do
    profesor-programador-creativo
  • Custe económico = cero
  • Custe en tempo = moito (pero divertido)
  • Beneficio = non hai límites...

... só a túa imaxinación !!!

As nosas linguaxes:

  • HTML: a linguaxe de marcas para indicar o que amosará o documento.
  • CSS: as follas de estilos para indicar como queremos ver a información do documento.
  • Javascript: a linguaxe de programación para indicar como queremos que o documento interactúe co usuario.

As nosas ferramentas:

  • Navegador de Internet
  • Editor de texto

A programación en secundaria

  • É unha volta ás raíces
  • Está nos novos currículos
  • GB: programación 5-16 anos
  • USA:
    “I want to make sure that kids know how to produce stuff using computers and not just consume stuff”.

Barack Obama

HTML

Estrutura da páxina

Ligazón non accesible.

Código: Estrutura da páxina


<!doctype html>
<html>

  <head>
    <meta charset="utf-8">
    <title>Título da miña páxina</title>
  </head>

  <body>
    <h1>Páxina web</h1>
    <p>Un parágrafo</p>
    <p>Outro parágrafo</p>
  </body>

</html>
    

HTML

Unha táboa

Ligazón non accesible.

Código: Unha táboa


<body>
 <table border="1">
  <tr> <th>País</th>     <th>Capital</th> </tr>
  <tr> <td>Francia</td>  <td>París</td>   </tr>
  <tr> <td>Alemania</td> <td>Berlín</td>  </tr>
 </table>
</body>
    

HTML

Viñeta non numerada

Ligazón non accesible.

Código: Viñeta non numerada

Unha viñeta non numerada


<body>
  <ul>
    <li>Cabeza</li>
    <li>Corpo</li>
    <li>Extremidades</li>
  </ul>
</body>
    

HTML

Inclusión dunha ligazón

Ligazón non accesible.

Código: Inclusión dunha ligazón


<body>
  <p>
    <a href="http://www.nasa.gov">Páxina da NASA</a>
  </p>
</body>
    

HTML

Inclusión dunha imaxe

Ligazón non accesible.

Código: Inclusión dunha imaxe


<body>
  <img src="confucio.jpg" alt="Kung Fu Tsé">
</body>
    

HTML

Inclusión dun vídeo

Ligazón non accesible.

Código: Inclusión dun vídeo


<body>
  <video src="robot.ogg" controls></video>
</body>
    

HTML

Inclusión dun son

Ligazón non accesible.

Código: Inclusión dun son


<body>
  <audio src="musica.wav" controls></audio>
</body>
    

HTML

Inclusión de páxina remota

Ligazón non accesible.

Código: Inclusión de páxina remota


<body>
  <object data="http://maxima.cesga.es"
          width="800" height="500">
  </object>
</body>
    

HTML

O lenzo (canvas)

Ligazón non accesible.

Código: Debuxando sobre a páxina


<canvas id="lenzo" width="200" height="200"></canvas>

<script>
var c=document.getElementById("lenzo");
var ctx = c.getContext("2d");

// o círculo
ctx.fillStyle = 'cyan';
ctx.beginPath();
ctx.arc(100,100,50,0,Math.PI*2,true);
ctx.closePath();
ctx.fill();

// o arco negro
ctx.beginPath();
ctx.arc(100,100,70,0,Math.PI/2,false);
ctx.lineWidth = 8;
ctx.stroke();

// o sector marrón
ctx.beginPath();
ctx.fillStyle = 'brown';
ctx.arc(100,0,75,1,2.4,false);
ctx.lineTo(100,0);
ctx.fill();

// polígono sen recheo
ctx.beginPath();
ctx.moveTo(190, 75);
ctx.lineTo(180, 180);
ctx.lineTo(0, 150);
ctx.lineTo(10,120);
ctx.closePath();
ctx.lineWidth = 5;
ctx.strokeStyle = '#123456';
ctx.stroke();

</script>
    

Información HTML

CSS

Formateando

Ligazón non accesible.

Código: Formateando dentro de html


<body>
  <h1 style="font-size:   200%;
             font-style:  italic;
             color:       blue;
             font-weight: bold;
             text-align:  center;">
         Páxina web</h1>
  <p style="color:       green;
            font-size:   70%;
            text-align:  right;">
         Un parágrafo</p>
  <p style="transform:        rotate(20deg);
	    transform-origin: left top 0;">
         Outro parágrafo</p>
</body>
    

Código para o ficheiro de estilo

estilo.css


h1 {font-size:   200%;
    font-style:  italic;
    color:       blue;
    font-weight: bold;
    text-align:  center;}
p.estilo1 {color: green;
           font-size:    70%;
           text-align:   right;}
p.estilo2 {transform:        rotate(20deg);
	   transform-origin: left top 0;}
    

Código para html con folla de estilo

ficheiro.html


<head>
  <link rel="stylesheet" href="estilo.css">
</head>

<body>
  <h1>Páxina web</h1>
  <p class="estilo1">Un parágrafo</p>
  <p class="estilo2">Outro parágrafo</p>
</body>
    

JS: Variables


<script>
  var a, b, c, d;
  a = 5.265;
  b = false;
  c = "Moi boas";
  d = [80, a, b];
  a = a + d[1];
  document.write(c + ", vou sumar: " + a);
</script>
    

JS: Aritmética


<script>
  var a = 25, b = -5.6, c = 7;
  a = b + c;
  b = a * c;
  c = a - (a/b);
  document.write("a+b+c = " + (a+b+c));
</script>
    

JS: Funcións matemáticas


<script>
var x = 3.5, y = Math.PI - Math.E;
document.write(
  "sen(3.5)·√ (π-e)+34= " +
  (Math.sin(x)*Math.sqrt(y)+ Math.pow(3,4)));
</script>
    

JS: Procesando arrays


<script>
var a = [2, 4, 6, 8, 10];
document.write(
 "Número de elementos: " + a.length + "<br>" +
 "Concatena arrays: "    + a.concat(12,14,16) + "<br>" +
 "Elimina o último: "    + a.pop() + "<br>" +
 "Valor actual: "        + a );
</script>
    

JS: Procesando texto


<script>
var t = "A Coruña, Santiago, Ferrol";
document.write(
  "Número de caracteres: "    + t.length        +"<br>"+
  "Escribe en maiúsculas: "   + t.toUpperCase() +"<br>"+
  "Carácter en posición 20: " + t.charAt(20)    +"<br>"+
  "Cidades ó revés: "         + t.split(',').reverse());
</script>
    

JS: Control, if-else


<script>
var chove = true;
if (chove)
  {document.write("Colle o paraugas" ); }
else
  {document.write("Disfruta do paseo." ); }
</script>
    

JS: Control, for


<script>
  var s = 0;
  for (var i=1; i<=5; i++) {s = s + i;}
  document.write("Suma = ", s);
</script>
    

JS: Control, switch


<script>
  var  n = 2;
  switch (n) {
    case 1:  document.write("Un")    ; break;
    case 2:  document.write("Dous")  ; break;
    default: document.write("Moitos"); }
</script>
    

Información Programación JS

JS: Formulario

Campo de texto e botón

Expresión numérica:

Resultado:

Código: Texto e botón


<body>
 <script>
   function evalua(form) {
     form.resultado.value = eval (form.expr.value); }
 </script>

 <form>
   Expresión numérica:
   <input type="text" name="expr" size="25"><br>
   <input type="button" value="ti dálle aquí" 
          onclick="evalua(this.form)"><br>

   Resultado:
   <input type="text" name="resultado" size=15>
 </form>

</body>
  

JS: Formulario

Botóns de radio

Como vai hoxe o tempo?:
Chove a rabiar
Quenta o sol

Código: Botóns de radio


<body>
 <script>
   function quefago(form) {
     if (form.chove.value == "0")
      {form.fai.value = "Colle o paraugas!";}
     else
      {form.fai.value = "Disfruta do paseo!";}}
 </script>

 <form>
   Como vai hoxe o tempo?:<br>
   <input type="radio" name="chove" value="0"
          onchange="quefago(this.form);">Chove a rabiar<br>
   <input type="radio" name="chove" value="1"
          onchange="quefago(this.form);">Quenta o sol<br>
   <input type="text" name="fai" size=15>
 </form>

</body>
  

JS: Formulario

Listados

Cidade:

Código: Formulario


<body>
 <script>
 function habitantes(form) {
   var opcion = form.cidade.value;
   switch (opcion) {
     case "1": form.dato.value = "246.056 hab.";
               break;
     case "2": form.dato.value = "95.671 hab." ;
               break;
     case "3": form.dato.value = "70.389 hab." ; }  }
 </script>

 <form>
   Cidade:
   <select name="cidade"
           onchange="habitantes(this.form)">
     <option value="1">A Coruña</option>
     <option value="2">Santiago</option>
     <option value="3">Ferrol</option>
   </select><br>
   <input type="text" name="dato" size="15">
 </form>

</body>
  

Información formularios JS

JS: Notación matemática

MathJax

O perímetro do rombo é \(P=4l\) a a súa área \[A = \frac{D \cdot d}{2}.\]

Código: Notación matemática


<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>

<p>
O perímetro do rombo é \(P=4l\) a a súa área
\[A = \frac{D \cdot d}{2}.\]
</p>
  

JS: Notación matemática

MathJax

A variable aleatoria \(X\) ten distribución normal de parámetros \(\mu\) e \(\sigma\) se a súa función de densidade é \[ f(x)= \frac{1}{\sqrt{2 \pi} \sigma} e^{- \frac{(x-\mu)^2}{\sigma^2}}, \forall x \in \mathbb{R}, \] sendo \(\mu = \int_{-\infty}^\infty x f(x) dx\) a súa esperanza.

Código: Notación matemática


<p>
A variable aleatoria \(X\) ten distribución
normal de parámetros \(\mu\) e \(\sigma\)
se a súa función de densidade é

\[
f(x)= \frac{1}{\sqrt{2 \pi} \sigma}
      e^{- \frac{(x-\mu)^2}{\sigma^2}},
      \forall x \in \mathbb{R},
\]

sendo \(\mu = \int_{-\infty}^\infty x f(x) dx\)
a súa esperanza.
</p>
  

Información MathJax

JS: Presentacións

reveal

Levades un rato mirando para el !!


<script src="js/reveal.js"></script>

<section>
  <h2>JS: Presentacións</h2>
  <p>reveal</p>
  <p>Levades un rato mirando para el !!</p>
</section>
  

JS: Presentacións

reveal

Diferentes formas de facer as transicións:
Nigunha - Fade - Slide (por defecto) - Convex - Concave - Zoom

JS: Presentacións

reveal

Temas dispoñibles:
Black (por defecto) - White - League - Sky - Beige - Simple
Serif - Night - Moon - Solarized

JS: Presentacións

reveal

Podemos cambiarlle a cor de fondo a unha diapositiva.


<section data-background="cyan">
  

JS: Presentacións

reveal

Podemos poñer unha imaxe de fondo a unha diapositiva.


<section data-background="hercules.jpg">
  

JS: Presentacións

reveal

Podemos utilizar unha imaxe para formar un mosaico.


<section data-background="hercules.jpg"
         data-background-repeat="repeat"
         data-background-size="100px">
  

JS: Presentacións

reveal

Xa postos, un vídeo de fondo.

<section data-background-video="robot.ogg">

Información reveal

Outro proxecto: impress.js

JS: Xeometría dinámica

jsxgraph

(Se non se ven as figuras, pulsade F5)

Ligazón non accesible.

Código: Xeometría dinámica


<script src='http://jsxgraph.uni-bayreuth.de/distrib/jsxgraphcore.js'></script>

<div id="box" class="jxbox"
     style="width:450px; height:450px;"></div>

<script>
 var brd = JXG.JSXGraph.initBoard('box',
            {boundingbox: [-10, 10, 10, -10]);
 var a = brd.create('point', [-2, 1]);
 var b = brd.create('point', [-4, -5]);
 var c = brd.create('point', [3, -6]);
 var p = brd.create('polygon', [a, b, c],
                    {hasInnerPoints: true});
</script>
  

Información jsxgraph

Librerías para gráficos 2D

JS: mapas

openlayers.js

Ligazón non accesible.

JS: mapas

openlayers.js


<script src="http://www.openlayers.org/api/OpenLayers.js"></script>

<div id="map" style="width:600px;
                     height:450px;"></div>

<script>
var proj= new OpenLayers.Projection("EPSG:4326");

map = new OpenLayers.Map(
           'map',
           {controls:[new OpenLayers.Control.Navigation(
                                     {zoomWheelEnabled : true}),
                      new OpenLayers.Control.MousePosition(),
                      new OpenLayers.Control.Scale()],
            displayProjection: proj } );

map.addLayer(new OpenLayers.Layer.OSM());

map.zoomToMaxExtent();
</script>
  

Información openlayers.js

JS: sintetizador de son

riffwave.js

Toca unha nota:

LA 3ª octava ( 220 Hz)
LA 4ª octava ( 440 Hz)
LA 6ª octava (1760 Hz)

JS: sintetizador de son

riffwave.js


<script src="plugin/sound/riffwave.js"></script>

<script>
function toca(form) {
  var opcion=form.nota.value, frec;

  switch (opcion) {
    case "0": frec = 220.0 ; break;
    case "1": frec = 440.0 ; break;
    case "2": frec = 1760  ; } 

  var sr = 8000;
  var t  = 1;
  var n  = Math.round(t * sr);
  var dospifd = 2 * Math.PI * frec / sr;
  var seno = [];
  for (var i=0; i<n; i++)
    seno[i] = 128+Math.round(127*Math.sin(dospifd * i ));
  var wave = new RIFFWAVE(seno);
  var audio = new Audio(wave.dataURI);
  audio.play(); }
</script>

<form>
  Toca unha nota:<br>
  <input type="radio" name="nota" value="0" 
         onchange="toca(this.form);">LA 3ª octava ( 220 Hz)<br>
  <input type="radio" name="nota" value="1"
         onchange="toca(this.form);">LA 4ª octava ( 440 Hz)<br>
  <input type="radio" name="nota" value="2"
         onchange="toca(this.form);">LA 6ª octava (1760 Hz)<br>
</form>
  

JS: Modelado 3D

three.js

Ligazón non accesible.

Código: Modelado 3D


<script src="three/three.min.js"></script>

<script>
  // Prepara a escea
  var scene = new THREE.Scene();

  // Define a cámara
  var ancho = 400, alto = 400;			
  var camera = new THREE.PerspectiveCamera(
                   75, ancho/alto, 0.1, 1000);
  camera.position.z = 5;

  // Define a luz
  var light = new THREE.PointLight(0xffffff);
  light.position = camera.position;
  scene.add(light);

  // Define o lenzo
  var renderer = new THREE.WebGLRenderer();
  renderer.setSize( ancho, alto );
  renderer.setClearColor( 0xffffff, 1);
  document.body.appendChild(renderer.domElement);

  // Define o cubo
  var geometry1 = new THREE.BoxGeometry(3,3,3);
  var material1 = new THREE.MeshPhongMaterial(
                      {color: 0x00ff00,
                       transparent:true,
                       opacity:0.7} );
  var cubo = new THREE.Mesh(geometry1,material1);
  scene.add( cubo );

  // Define o cilindro
  var geometry2 = new THREE.CylinderGeometry(
                               0.4,0.4,6,50);
  var material2 = new THREE.MeshPhongMaterial(
                      {color:0x00ffff});
  var cilindro = new THREE.Mesh(geometry2,material2);
  scene.add( cilindro );

  // Programa o movemento dos corpos
  var render = function () {
                 requestAnimationFrame(render);
                 cubo.rotation.x += 0.01;
                 cubo.rotation.y += 0.01;
                 cilindro.rotation.z += 0.07;
                 renderer.render(scene, camera);};

  render();
</script>

Información three.js

JS: procesamento de imaxes

Negativo

HTML5 non soportado. HTML5 non soportado.

JS: procesamento de imaxes

Código: Negativo


<canvas id="negativo1"></canvas>
<canvas id="negativo2"></canvas>

<script>
  // garda imaxe no primeiro canvas (só para comparar)
  var imga1 = new Image();
  imga1.src = "aux/hercules2.png";
  var ca1 = document.getElementById("negativo1");
  var ctxa1 = ca1.getContext("2d");
  ctxa1.canvas.width = imga1.width;
  ctxa1.canvas.height = imga1.height;
  ctxa1.drawImage(imga1, 0, 0);

  // garda imaxe no segundo canvas (para procesar)
  var imga2 = new Image();
  imga2.src = "aux/hercules2.png";
  var ca2   = document.getElementById("negativo2");
  var ctxa2 = ca2.getContext("2d");
  ctxa2.canvas.width  = imga2.width;
  ctxa2.canvas.height = imga2.height;
  ctxa2.drawImage(imga2, 0, 0);

  // le os píxeles do segundo canvas
  var nega = ctxa2.getImageData(0, 0, imga2.width, imga2.height);

  // transforma píxeles e actualiza no segundo canvas
  for (var i = 0; i < nega.data.length; i += 4)
    { nega.data[i]   = 255 - nega.data[i];
      nega.data[i+1] = 255 - nega.data[i+1];
      nega.data[i+2] = 255 - nega.data[i+2];
      nega.data[i+3] = 255;  }
  ctxa2.putImageData(nega, 0, 0);
</script>

JS: procesamento de imaxes

Transición gradual

HTML5 non soportado. HTML5 non soportado. HTML5 non soportado.

JS: procesamento de imaxes

Código: Transición gradual


<canvas id="transicion1"></canvas>
<canvas id="transicion2"></canvas>
<canvas id="transicion3"></canvas>

<script>
  // garda imaxe no primeiro canvas (só para comparar)
  var imga1 = new Image();
  imga1.src = "aux/fragas.png";
  var ca1 = document.getElementById("transicion1");
  var ctxa1 = ca1.getContext("2d");
  ctxa1.canvas.width = imga1.width;
  ctxa1.canvas.height = imga1.height;
  ctxa1.drawImage(imga1, 0, 0);

  // garda imaxe no segundo canvas (só para comparar)
  var imga2 = new Image();
  imga2.src = "aux/hercules2.png";
  var ca2 = document.getElementById("transicion2");
  var ctxa2 = ca2.getContext("2d");
  ctxa2.canvas.width = imga2.width;
  ctxa2.canvas.height = imga2.height;
  ctxa2.drawImage(imga2, 0, 0);

  // garda imaxe no terceiro canvas (para procesar)
  var imga3 = new Image();
  imga3.src = "aux/fragas.png";
  var ca3 = document.getElementById("transicion3");
  var ctxa3 = ca3.getContext("2d");
  ctxa3.canvas.width = imga3.width;
  ctxa3.canvas.height = imga3.height;
  ctxa3.drawImage(imga3, 0, 0);

  // le os píxeles do segundo (Torre de Hércules) e 
  // terceiro canvas (Fragas do Eume)
  var frag = ctxa3.getImageData(0, 0, imga3.width, imga3.height);
  var herc = ctxa2.getImageData(0, 0, imga2.width, imga2.height);
  var c;

  // transforma píxeles e actualiza no terceiro canvas
  for (var i = 0; i < frag.data.length; i += 4)
    { c = i / frag.data.length;
      frag.data[i]   = Math.round(c * frag.data[i]   + (1-c) * herc.data[i]);
      frag.data[i+1] = Math.round(c * frag.data[i+1] + (1-c) * herc.data[i+1]);
      frag.data[i+2] = Math.round(c * frag.data[i+2] + (1-c) * herc.data[i+1]);
      frag.data[i+3] = 255;  }
  ctxa3.putImageData(frag, 0, 0);
</script>

Non podía faltar:

<canvas id="despedida" width="900" height="200"
    style="border:2px solid blue; border-radius: 20px;">

<script>
  var can, ctx, step, steps = 0,
      delay = 20;
 
  function saluda() {
    can = document.getElementById("despedida");
    ctxs = can.getContext("2d");
    ctxs.fillStyle = "orange";
    ctxs.font = "40pt Verdana";
    ctxs.textAlign = "right";
    ctxs.textBaseline = "middle";
    step = 0;
    steps = can.width + 600;
    RunTextLeftToRight();  }
 
  function RunTextLeftToRight() {
    step++;
    ctxs.clearRect(0, 0, can.width, can.height);
    ctxs.save();
    ctxs.translate(step, can.height / 2);
    ctxs.fillText("Grazas !!", 0, 0);
    ctxs.restore();
    if (step == steps)
      step = 0;
    if (step < steps)
      var t = setTimeout('RunTextLeftToRight()', delay);}

    saluda();
</script>
Licencia de Creative Commons

Esta obra está baixo unha licenza de Creative Commons Recoñecemento-CompartirIgual 4.0 Internacional.