Exportar (0) Imprimir
Expandir todo

Cómo crear una presentación de imágenes en una página web

Los sitios web que incluyen muchas imágenes, como sitios de arte o galerías de fotos, pueden beneficiarse de mostrar algunas o todas las imágenes con un formato de presentación. Aquí te contamos cómo usar y crear un archivo de JavaScript compatible entre exploradores (slideShow.js) que crea una presentación en la que las imágenes realizan el fundido de entrada y salida de la forma especificada por una lista de elementos <img> determinada.

Nota  Puesto que se usa addEventListener, este contenido solo se aplica a Windows Internet Explorer 9 y versiones posteriores. Para versiones anteriores a Internet Explorer 9, se debe usar attachEvent. Para más información, consulta el tema sobre cómo crear estrategias de reserva efectivas.

Este tema está dividido en dos partes principales:

  • Cómo usar slideShow.js para crear una presentación a partir de una lista de etiquetas img
  • Detalles de la implementación de slideShow.js

Uso de slideShow.js

Este ejemplo muestra el marcado más sencillo que se necesita para crear una presentación de este tipo:


<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <!-- For intranet testing only, remove in production. -->
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <title>Slide Show</title>
</head>

<body>
  <div id="slideShowImages">
    <img src="images/slide1.jpg" alt="Slide 1" />
    <img src="images/slide2.jpg" alt="Slide 2" />
    <img src="images/slide3.jpg" alt="Slide 3" />    
    <img src="images/slide4.jpg" alt="Slide 4" />
  </div>  
  <button id="slideShowButton"></button> <!-- Optional button element. -->
  <script src="slideShow.js"></script>
</body>

</html>

Para usar slideShow.js para crear una presentación, el siguiente marcado debe estar presente:

  • Un contenedor <div> cuyo identificador es exactamente slideShowImages y contiene los elementos <img> que señalan a las imágenes que quieres para la presentación.
  • Un elemento script que señala a slideShow.js.

Nota  

Este ejemplo incluye un botón de alternancia opcional para mostrar u ocultar la presentación. Si usas este botón de alternancia, su identificador debe ser slideShowButton. Si no usas este botón de alternancia, el usuario puede parar o iniciar la presentación haciendo clic en cualquiera de las imágenes cíclicas de la presentación.

Además, si usas slideShow.js, puedes aplicar fácilmente estilos al contenedor <div> de la presentación, así como a sus imágenes secundarias, tal y como se muestra en esta muestra de código:


<!DOCTYPE html>
<html>

<head>
  <meta http-equiv="X-UA-Compatible" content="IE=Edge"> <!-- For intranet testing only, remove in production. -->
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <title>Slide Show</title>
  <style>
    #slideShowImages { /* The following CSS rules are optional. */
      border: 1px gray solid;
      background-color: lightgray;
    }   
  
    #slideShowImages img { /* The following CSS rules are optional. */
      border: 0.8em black solid;
      padding: 3px;
    }   
  </style>
</head>

<body>
  <div id="slideShowImages">
    <img src="images/slide1.jpg" alt="Slide 1" />
    <img src="images/slide2.jpg" alt="Slide 2" />
    <img src="images/slide3.jpg" alt="Slide 3" />    
    <img src="images/slide4.jpg" alt="Slide 4" />
  </div>  
  <button id="slideShowButton"></button> <!-- Optional button element. -->
  <script src="slideShow.js"></script>
</body>

</html>

Una de las mejores características de slideShow.js es que las imágenes de diferentes tamaños se centran automáticamente en el contenedor <div>, y la transición entre imágenes de distintos tamaños presenta un aspecto razonable porque mientras una diapositiva realiza el fundido de salida, la siguiente realiza el fundido de entrada simultáneamente.

Ahora puedes usar slideShow.js para crear una presentación a partir de una lista de elementos <img>. El resto de este tema está dedicado a explicar los detalles de implementación de slideShow.js.

Nota  Para cambiar la velocidad de la presentación o el texto del botón de alternancia, consulta la sección Globals.

Detalles de implementación

Como podemos observar al revisar slideShow.js, este archivo de JavaScript se compone esencialmente de dos elementos, la línea window.addEventListener('load', slideShow, false) y su función de retorno de llamada asociada slideShow.

Debido a que la función slideShow hace referencia a <div id="slideShowImages"> (y posiblemente a <button id="slideShowButton">), debemos asegurarnos de que estos elementos estén disponibles en el DOM antes de hacerlo. Para ello se utiliza window.addEventListener('load', slideShow, false). En otras palabras, solo se llama a slideShow cuando el marcado de la página web está disponible desde el DOM. Otra ventaja de colocar la mayor parte del código de slideShow.js en una única función es que protege el espacio de nombres de los usuarios de slideShow.js.

Ahora que comprendemos cuándo invocar a slideShow, vayamos a los detalles del propio slideShow, comenzando por su algoritmo principal:

Algoritmo principal

En el corazón del algoritmo de slideShow está el diseño CSS de <div id="slideShowImages"> y sus elementos <img> secundarios. Este diseño CSS se define en la función initializedSlideShowMarkup de slideShow.js. En particular, initializedSlideShowMarkup:

  • Establece la position CSS de <div id="slideShowImages"> en relative. Esto permite que cualquiera de sus elementos secundarios, que tienen posiciones absolutas, se posicionen con relación a su contenedor. Si <div id="slideShowImages"> se estableció en una posición static (valor predeterminado), sus elementos secundarios que tienen posiciones absolutas se posicionarían con relación al elemento <body> y no a <div id="slideShowImages">.
  • Establece posiciones absolutas para todos los elementos <img> de la presentación. Esto hace que todos estos elementos <img> se apilen unos encima de otros dentro de su contenedor <div id="slideShowImages">. Piensa en las diapositivas como una pila vertical de imágenes con la primera diapositiva (el primer elemento <img> de la lista) en la parte inferior de la pila y la última diapositiva (el último elemento <img> de la lista) en la parte superior de la pila.
  • Cambia la opacidad de todas las diapositivas (de la pila) a 0 para que sean completamente transparentes. A continuación, la opacidad del primer elemento <img> se establece en 1. Esto hace que la diapositiva situada en la parte inferior de la pila se pueda ver a través de todas las diapositivas transparentes que están situadas encima de ella.

Una vez completado este diseño inicial, ahora nos movemos por la pila de diapositivas, comenzando por la parte inferior (la primera diapositiva) hacia la parte superior (la última diapositiva):

  1. Haz que la diapositiva actual (de la pila) sea la diapositiva situada más al fondo (el primer elemento <img>).
  2. Pasa a la diapositiva siguiente de la pila. Si después de ella no hay otra diapositiva, haz que esta diapositiva sea la primera.
  3. Establece el valor de la opacidad de la diapositiva actual en 1 (visible) y el valor de la opacidad de la diapositiva siguiente en 0 (transparente).
  4. De forma simultánea y "lentamente" cambia el valor de la opacidad de la diapositiva actual de 1 a 0 y el valor de la opacidad de la diapositiva siguiente de 0 a 1. De esta manera, la diapositiva actual realiza el fundido de salida "lentamente" mientras la diapositiva siguiente realiza el fundido de entrada.
  5. Haz que la diapositiva actual sea la diapositiva siguiente.
  6. Ve al paso 2 hasta que el usuario indique que la presentación debe detenerse.

Una vez comprendido este algoritmo principal, podemos continuar con los detalles de los componentes principales de la función slideShow, que incluye estos componentes:

Globals

El primer elemento de slideShow es un literal de objeto denominado globals. Este objeto se usa para contener todas las "variables globales" de slideShow en un lugar obvio y práctico. Por ejemplo, para acceder a slideDelay desde cualquier lugar de slideShow, simplemente invoca globals.slideDelay.

Las seis primeras de estas "variables globales" son de especial interés:


slideDelay: 4000,
fadeDelay: 35,
wrapperID: "slideShowImages",
buttonID: "slideShowButton",
buttonStartText: "Start Slides",
buttonStopText: "Stop Slides",


El primer elemento, slideDelay, determina la cantidad de tiempo, en milisegundos, que una diapositiva determinada será visible en la pantalla. En este caso, cada una de las diapositivas será visible durante un total de 4 segundos.

Para describir fadeDelay, hacemos referencia de nuevo al algoritmo principal usado en slideShow.js. Considera nuestra pila de imágenes de diapositiva. La diapositiva situada en la parte inferior de la pila tiene un valor de opacity de 1 (es visible) mientras que todas las demás tienen un valor de opacidad de 0 (transparente). Para llevar a cabo la operación de fundido entre la primera diapositiva y la siguiente, disminuimos la opacidad de la primera diapositiva de 1 a 0 mientras que, al mismo tiempo, aumentamos la opacidad de la segunda de 0 a 1. Justo a mitad de camino de esta operación, ambas diapositivas tendrán una opacidad de 0,5. Al finalizar esta operación, la primera diapositiva tiene un valor de opacidad de 0 (transparente) y la segunda un valor de opacidad de 1 (visible). Una vez comprendido esto, fadeDelay representa la cantidad de tiempo entre los cambios individuales de opacidad. Por ejemplo, si fadeDelay es 35, transcurrirán 35 milisegundos entre cada cambio de opacidad. La cantidad que cambia la opacidad es el recíproco de este valor que, en este caso, es 0,0286. Debido a que el valor de incremento de la opacidad es 1/35, tardará 35 de estos valores en aumentar de 0 a 1 (y, de forma similar, 35 de estos valores en disminuir de 1 a 0). Por lo tanto, la cantidad de tiempo total que tarda en completarse en una operación de fundido es de 35 milisegundos por 35, o 352 = 1225 milisegundos= 1,225 segundos. De igual modo, si fadeDelay fuera 45, tardaría 452 = 2,025 segundos en completarse una operación de fundido entre dos diapositivas consecutivas. En pocas palabras, ajusta slideDelay y fadeDelay como quieras pero haz que fadeDelay sea siempre bastante más pequeño que slideDelay.

Pasando a otro tema, wrapperID y buttonID deben coincidir con los valores de identificador usados en el marcado: <div id="slideShowImages"> y <button id="slideShowButton">.

buttonStartText y buttonStopText definen el texto que se utilizará en el botón de alternancia opcional de la presentación. Puedes cambiar estas etiquetas (cadenas) por unas que se ajusten a tu aplicación.

Para obtener información sobre las demás "variables globales", consulta los comentarios en el archivo slideShow.js.

Principal

Ahora, describiremos el bloque de código "principal" de la función slideShow:


initializeGlobals();  

if ( insufficientSlideShowMarkup() ) {
  return;
}

 // Assert: there's at least one slide image.

if (globals.slideImages.length == 1) {
  return;
}

// Assert: there are at least two slide images.

initializeSlideShowMarkup();

globals.wrapperObject.addEventListener('click', toggleSlideShow, false);

if (globals.buttonObject) {
  globals.buttonObject.addEventListener('click', toggleSlideShow, false);
} 

startSlideShow();

Este bloque de código principal se puede describir de la siguiente manera:

  1. initializeGlobals inicializa globals y proporciona acceso al elemento contenedor <div>, sus elementos secundarios <img> y el botón de alternancia (si está presente).
  2. insufficientSlideShowMarkup devuelve false si el marcado esperado por slideShow.js parece estar presente; en caso contrario, devuelve true. Como puedes ver en la muestra de código, si se devuelve true, la función slideShow termina inmediatamente y termina slideShow.js en silencio (por diseño).
  3. Si globals.slideImages.length == 1 es true, solo hay un elemento <img> de presentación en el marcado y ya está en pantalla; simplemente terminamos slideShow.js, dejando esta única imagen en pantalla.
  4. initializeSlideShowMarkup prepara el marcado de la presentación (como se describe en la sección del algoritmo principal) para la siguiente presentación.
  5. A continuación, agregamos una escucha de eventos toggleSlideShow para que, cuando se haga clic en el elemento contenedor <div>, la presentación se desactive (si su valor es on) o se active (si su valor es off).
  6. A continuación, si globals.buttonObject es true, el botón de alternancia de la presentación está presente en el código y le asociamos la misma función de escucha de eventos (toggleSlideShow).
  7. Por último, llamamos a startSlideShow para iniciar realmente la presentación.

Aquí se explica con más detalle cada una de las funciones aquí descritas, así como las demás funciones contenidas en slideShow.

initializeGlobals

Este es el código para la función anidada initializeGlobals:


function initializeGlobals() {   
  globals.wrapperObject = (document.getElementById(globals.wrapperID) ? document.getElementById(globals.wrapperID) : null);
  globals.buttonObject = (document.getElementById(globals.buttonID) ? document.getElementById(globals.buttonID) : null);   
  
  if (globals.wrapperObject) {
    globals.slideImages = (globals.wrapperObject.querySelectorAll('img') ? globals.wrapperObject.querySelectorAll('img') : []);
  }
}


En función de los valores de identificador contenidos en globals (es decir, gloabals.wrapperID y globals.butonID), obtenemos una referencia a ellos si están presentes en el marcado. Después usamos querySelectorAll para llenar una matriz con objetos <img> de diapositiva. Esta matriz, globals.slideImages, funciona como nuestra pila metafórica describa en la sección del algoritmo principal.

insufficientSlideShowMarkup

Este es el código para la función anidada insufficientSlideShowMarkup:


function insufficientSlideShowMarkup() {
  if (!globals.wrapperObject) { 
    if (globals.buttonObject) {
      globals.buttonObject.style.display = "none"; 
    }
    return true;
  }

  if (!globals.slideImages.length) { 
    if (globals.wrapperObject) {
      globals.wrapperObject.style.display = "none"; 
    }
  
    if (globals.buttonObject) {
      globals.buttonObject.style.display = "none"; 
    }
  
    return true;
  }
  
  return false; 
} 

La principal finalidad de esta función es devolver false si todo el marcado esperado está presente, y true en caso contrario. Como puedes ver en este código, si se determina que no todo el marcado esperado está presente, el código intenta limpiar el marcado de la presentación asociado (es decir, establece el valor de la propiedad CSS display en "none") antes de devolver true.

initializeSlideShowMarkup

Este es el código para la función anidada initializeSlideShowMarkup:


function initializeSlideShowMarkup() {  
  var slideWidthMax = maxSlideWidth(); 
  var slideHeightMax = maxSlideHeight();
  
  globals.wrapperObject.style.position = "relative";
  globals.wrapperObject.style.overflow = "hidden"; 
  globals.wrapperObject.style.width = slideWidthMax + "px";
  globals.wrapperObject.style.height = slideHeightMax + "px";
  
  var slideCount = globals.slideImages.length;
  for (var i = 0; i < slideCount; i++) { 
    globals.slideImages[i].style.opacity = 0;
    globals.slideImages[i].style.position = "absolute";
    globals.slideImages[i].style.top = (slideHeightMax - globals.slideImages[i].getBoundingClientRect().height) / 2 + "px";   
    globals.slideImages[i].style.left = (slideWidthMax - globals.slideImages[i].getBoundingClientRect().width) / 2 + "px";               
  }
  
  globals.slideImages[0].style.opacity = 1; 
      
  if (globals.buttonObject) {
    globals.buttonObject.textContent = globals.buttonStopText;
  }
}

Esta función lleva a cabo varias acciones, entre ellas:

  • Establece los valores de position CSS de <div id="slideShowImages"> y sus elementos <img> secundarios, tal y como se describe en la sección del algoritmo principal.
  • Ajusta los valores de width y height del contenedor <div id="slideShowImages"> para que las imágenes que tengan el ancho y el alto mayores quepan exactamente en él (si las imágenes tienen dimensiones diferentes).
  • Ajusta la posición absolute de las imágenes para que estén centradas en el contenedor <div id="slideShowImages"> (de nuevo, si las imágenes no tienen dimensiones homogéneas). Para ello, las imágenes más pequeñas se alejan de la esquina superior izquierda de su contenedor ½ desde el margen hacia abajo y hacia la derecha de las mismas:

    Cómo centrar una imagen

  • Por último, si el botón de alternancia está presente en el marcado, la función establece el texto "detener la presentación" en el botón de alternancia (si la ejecución de la presentación se inicia de forma predeterminada).

maxSlideWidth y maxSlideHeight

Estas dos funciones devuelven el ancho de la imagen de diapositiva más ancha y el alto de la imagen de diapositiva más alta (pueden ser dos imágenes diferentes). Como ambas funciones son casi idénticas, solo examinaremos maxSlideWidth:


function maxSlideWidth() {
  var maxWidth = 0;
  var maxSlideIndex = 0;
  var slideCount = globals.slideImages.length;
  
  for (var i = 0; i < slideCount; i++) {
    if (globals.slideImages[i].width > maxWidth) {
      maxWidth = globals.slideImages[i].width;
      maxSlideIndex = i;
    }
  }

  return globals.slideImages[maxSlideIndex].getBoundingClientRect().width;
}

El método getBoundingClientRect siempre devuelve un valor en píxeles e incluye todas las propiedades CSS especificadas, como bordes, márgenes, etc. De esta forma se garantiza que el ancho y el alto de <div id="slideShowImages"> sea suficiente para acomodar todas las adiciones CSS aplicadas a las imágenes de diapositiva.

startSlideShow

El código de la función anidada startSlideShow es muy sencillo:


function startSlideShow() {
  globals.slideShowID = setInterval(transitionSlides, globals.slideDelay);                
}

Aquí, simplemente solicitamos que se llame a la función transitionSlides cada gloabls.slideDelay milisegundos hasta que se detengan estas invocaciones repetitivas mediante una llamada a clearInterval(globals.slideShowID).

haltSlideShow

Como ya habrás adivinado, el código de haltSlideShow se compone de una sola línea:


function haltSlideShow() {
  clearInterval(globals.slideShowID);   
}

Esto borra las invocaciones previamente solicitadas de transitionSlides, cada globals.slideDelay milisegundos, y detiene la presentación.

toggleSlideShow

Este es el código para la función anidada toggleSlideShow:


function toggleSlideShow() {
  if (globals.slideShowRunning) {
    haltSlideShow();
    if (globals.buttonObject) { 
      globals.buttonObject.textContent = globals.buttonStartText; 
    }
  }
  else {
    startSlideShow();
    if (globals.buttonObject) { 
      globals.buttonObject.textContent = globals.buttonStopText; 
    }            
  }
  globals.slideShowRunning = !(globals.slideShowRunning);
}

Recuerda las dos llamadas a addEventListener realizadas en el bloque de código principal:


globals.wrapperObject.addEventListener('click', toggleSlideShow, false); 
  
if (globals.buttonObject) {
  globals.buttonObject.addEventListener('click', toggleSlideShow, false);
}

Por lo tanto, toggleSlideShow se invoca cada vez que se hace clic en <div id="slideShowImages"> o <button id="slideShowButton"> (si está presente).

Como globals.slideShowRunning se estableció inicialmente en true en la primera invocación de toggleSlideShow, ahora se llama a haltSlideShow y (si está presente) se cambia el texto del botón de alternancia a su forma "iniciar la presentación". A continuación, se niega globals.slideShowRunning, que indica el estado actual de la presentación (desactivada, en este caso).

Cuando se vuelve a llamar a toggleSlideShow (al hacer clic en una imagen de la presentación o en el botón de alternancia), globals.slideShowRunning es false, por lo que se invoca startSlideShow, el texto del botón cambia a la forma "cerrar la presentación" y se niega globals.sideShowRunning (lo que indica que la presentación está activada o en ejecución).

De forma más resumida, toggleSlideShow hace justo eso: activa y desactiva la presentación mediante llamadas a startSlideShow y haltSlideShow, según determine el estado actual de globals.slideShowRunning.

transitionSlides y fadeActiveSlides

El algoritmo principal se implementa principalmente en la función transitionSlides:


function transitionSlides() {
  var currentSlide = globals.slideImages[globals.slideIndex];
  
  ++(globals.slideIndex);
  if (globals.slideIndex >= globals.slideImages.length) {
    globals.slideIndex = 0;
  }
  
  var nextSlide = globals.slideImages[globals.slideIndex];
  
  var currentSlideOpacity = 1;
  var nextSlideOpacity = 0;
  var opacityLevelIncrement = 1 / globals.fadeDelay;
  var fadeActiveSlidesID = setInterval(fadeActiveSlides, globals.fadeDelay);
  
  function fadeActiveSlides() {
    currentSlideOpacity -= opacityLevelIncrement;
    nextSlideOpacity += opacityLevelIncrement;
    
    // console.log(currentSlideOpacity + nextSlideOpacity);
    
    if (currentSlideOpacity >= 0 && nextSlideOpacity <= 1) {
      currentSlide.style.opacity = currentSlideOpacity;
      nextSlide.style.opacity = nextSlideOpacity; 
    }
    else {
      currentSlide.style.opacity = 0;
      nextSlide.style.opacity = 1; 
      clearInterval(fadeActiveSlidesID);
    }        
  }
}

Recuerda que globals.slideImages es una matriz de objetos de imagen de diapositiva y que globals.slideIndex se establece inicialmente en 0. Teniendo esto en cuenta, este es el seudocódigo de transitionSlides:

  1. Haz que la diapositiva actual sea la que indica globals.slideIndex:
    
    var currentSlide = globals.slideImages[globals.slideIndex];
    
    
  2. Pasa a la diapositiva siguiente y, si no hay una dispositiva siguiente, comienza desde el principio:
    
    ++(globals.slideIndex);
    if (globals.slideIndex >= globals.slideImages.length) {
      globals.slideIndex = 0;
    }
    
    
  3. Haz que la diapositiva siguiente sea la que indica globals.slideIndex:
    
    var nextSlide = globals.slideImages[globals.slideIndex];
    
    
  4. Prepara las variables locales usadas para realizar el fundido de salida de la diapositiva actual y el fundido de entrada de la diapositiva siguiente:
    
    var currentSlideOpacity = 1;
    var nextSlideOpacity = 0;
    var opacityLevelIncrement = 1 / globals.fadeDelay;
    
    
  5. Llama a la función local fadeActiveSlides cada globals.fadeDelay milisegundos hasta que ambas diapositivas hayan realizado el fundido. Es decir, se invoca fadeActiveSlides cada globals.fadeDelay milisegundos durante currentSlideOpacity >= 0 y nextSlideOpacity <= 1. Si una de ellas fuera false, a todos los efectos prácticos ambas diapositivas han realizado el fundido, por lo que establecemos explícitamente sus valores de opacidad y terminamos las invocaciones repetitivas de fadeActiveSlides en la cláusula else:
    
    currentSlide.style.opacity = 0;
    nextSlide.style.opacity = 1; 
    clearInterval(fadeActiveSlidesID);
    
    

Como muestra el código de fadeActiveSlides, la opacidad de la diapositiva actual disminuye la misma cantidad que aumenta la opacidad de la diapositiva siguiente, y como los valores de la opacidad siempre son de 0 a 1, resulta que la suma de estos dos valores de opacidad siempre será 1 (o al menos un valor muy próximo a 1, teniendo en cuenta los errores de redondeo). Esto es así y se puede comprobar llamando a console.log(currentSlideOpacity + nextSlideOpacity) como se sugiere en el comentario de la muestra de código anterior, y se repite aquí:


// console.log(currentSlideOpacity + nextSlideOpacity);

Para obtener más información sobre console.log, consulta Cómo usar las herramientas de desarrollo F12 para depurar las páginas web.

Papel de CSS en la implementación de slideShow.js

Paradójicamente, es CSS quien permite la implementación de esta biblioteca de presentaciones de JavaScript (slideShow.js). En particular, cuando se establece el valor CSS position de <div id="slideShowImages"> en relative y todos sus elementos <img> secundarios en un valor position de absolute, se obtiene una "pila" de imágenes de diapositiva transparentes. Después solo hay que retocar los valores de opacidad de las diapositivas adyacentes para crear una presentación con fundido.

Por último, hay muchas maneras diferentes de implementar una biblioteca de presentaciones basada en JavaScript, incluidos varios complementos jQuery. Con una explicación detallada de al menos una de estas implementaciones, te resultará más fácil escribir su propia biblioteca de presentaciones personalizada o modificar slideShow.js para que se ajuste a tus necesidades específicas (cuando sea necesario).

Temas relacionados

Galería de fotos Contoso Images

 

 

Mostrar:
© 2014 Microsoft