Digital Signage With HTML Javascript (PWA Example)

Welcome to a tutorial on how to create digital signage with HTML and Javascript. Yes, anyone can make simple web pages these days. Then just access it on a smart TV, call it “digital signage”, the end. But that is not what we are making in this guide. Let us walk through something that is a little bit more robust – A progress web app (PWA) digital signage. Read on!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

TABLE OF CONTENTS

Download & Notes JS Digital Signage Useful Bits & Links
The End

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

  • Download and unzip into your HTTP folder.
  • This example will still run with file:// as a simple webpage.
  • But a proper installable PWA requires https:// (http://localhost works too).
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

EXAMPLE CODE DOWNLOAD

Click here to download all the example source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

 

JAVASCRIPT DIGITAL SIGNAGE

All right, let us now get into the digital signage example with HTML and Javascript. There are all kinds of signage from slideshows to videos to full-on POS hybrids. In this example, we will just stick with a simple slideshow.

 

PART 1) THE HTML

1-signage.html
<!-- (A) SLIDES -->
<div id="slides"></div>
 
<!-- (B) MENU ITEMS -->
<div id="menu">
  <h1>ONLY PIES</h1>
  <ul>
    <li>Apple Pie $1.10</li>
    <li>Banana Pie $2.20</li>
    <li>Cheese Pie $3.30</li>
    <li>Derby Pie $4.40</li>
    <li>Egg Pie $5.50</li>
    <li>Fried Pie $6.60</li>
  </ul>
 
  <div>Quote "uvuvwevwevwe onyetenyevwe ugwemubwem ossas" to get 10% off!</div>
</div>

To keep things simple, this page only has a “left and right side”.

  • <div id="slides"> Picture slides on the left.
  • <div id="menu"> Menu items are on the right.

 

 

PART 2) THE CSS

2-signage.css
/* (A) WHOLE PAGE */
* {
  font-family: "Brush Script MT", cursive;
  box-sizing: border-box;
}
body {
  display: flex;
  padding: 0; margin: 0;
  min-height: 100vh;
  background: #2e120f;
}
#slides { width: 60%; }
#menu { width: 40%; }
 
/* (B) SLIDES */
#slides { position: relative; }
#slides img {
  position: absolute;
  top: 0; left: 0;
  display: block;
  object-fit: cover;
  width: 100%; height: 100%;
  opacity: 0; visibility: collapse;
  transition: opacity 1s;
}
#slides img.show {
  opacity: 1; visibility: visible;
}
 
/* (C) MENU */
#menu {
  padding: 20px;
  color: #fff;
}
#menu ul {
  padding: 0;
  list-style: none;
}
#menu h1 { font-size: 36px; }
#menu ul li { font-size: 20px; }

Well, just some CSS cosmetics. Nothing “special” here.

 

 

PART 3) THE JAVASCRIPT

3-signage.js
var sign = {
  // (A) PROPERTIES
  swrap : null, // slides html wrapper
  now : 0, // current slide
  all : 2, // total number of slides
  slides : [], // html slide images
  delay : 4000, // delay between each slide
 
  // (B) INIT
  init : () => {
    // (B1) SLIDESHOW
    sign.swrap = document.getElementById("slides");
    for (let i=1; i<=sign.all; i++) {
      let slide = document.createElement("img");
      slide.src = `images/pie-${i}.jpg`;
      sign.swrap.appendChild(slide);
      sign.slides.push(slide);
    }
    sign.slides[0].className = "show";
 
    // (B2) ROTATE SLIDES
    setInterval(() => {
      sign.slides[sign.now].classList.remove("show");
      sign.now++;
      if (sign.now >= sign.all) { sign.now = 0; }
      sign.slides[sign.now].classList.add("show");
    }, sign.delay);
 
    // (B3) IF WORKER SUPPORTED
    if ("serviceWorker" in navigator) {
      navigator.serviceWorker.register("4-worker.js");
    }
  }
};
window.onload = sign.init;

A tad bit of Javascript to rotate the slides.

  • (B1) On window load, init() will run, create and insert <img src="images/pie-N.jpg"> into <div id="slides">.
  • (B2) Javascript interval timer to rotate between the slide images.
  • (B3) Register a service worker if it is available. More of this in part 4 below.

 

 

PART 4) SERVICE WORKER

4-worker.js
// (A) FILES TO CACHE
const cName = "js-sign",
cFiles = [
  // (A1) STATIC FILES
  "1-signage.html",
  "2-signage.css",
  "3-signage.js",
 
  // (A2) IMAGES
  "images/pie-1.jpg",
  "images/pie-2.jpg",
];
 
// (B) CREATE/INSTALL CACHE
self.addEventListener("install", (evt) => {
  evt.waitUntil(
    caches.open(cName)
    .then((cache) => { return cache.addAll(cFiles); })
    .catch((err) => { console.error(err) })
  );
});
 
// (C) LOAD FROM CACHE FIRST, FALLBACK TO NETWORK IF NOT FOUND
self.addEventListener("fetch", (evt) => {
  evt.respondWith(
    caches.match(evt.request)
    .then((res) => { return res || fetch(evt.request); })
  );
});

Just what does a “service-worker” do? For the uninitiated, a service worker is simply a script that is “installed” to run in the background. Yes, it can even run when the user is not even on the webpage itself. For this simple worker:

  • (A) A list of files and images to cache.
  • (B) Create a storage cache and save all the defined files and images.
  • (C) Serve files from the cache if it exists, fallback to the network if not found. That is, effectively creating an offline version of the page.

 

PART 5) INSTALLABLE PWA

5A) MANIFEST FILE

manifest.json
{
  "short_name": "JS Sign",
  "name": "JS Sign",
  "icons": [{
    "src": "images/favicon.png",
    "sizes": "64x64",
    "type": "image/png"
  }, {
    "src": "images/icon-512.png",
    "sizes": "512x512",
    "type": "image/png"
  }],
  "start_url": "1-signage.html",
  "scope": "/",
  "background_color": "white",
  "theme_color": "white",
  "display": "fullscreen"
}

 

5B) HTML HEADER

1-signage.html
<!-- MANIFEST -->
<link rel="manifest" href="manifest.json">

Finally, this manifest file should be pretty self-explanatory. It defines the name of the web app, the icons, preferred settings, etc… With that, we now have an installable PWA. Just tap on the icon to launch the page in fullscreen mode.

 

 

USEFUL BITS & LINKS

That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.

 

WHAT’S SO GREAT ABOUT PWA?

Before the trolls start to spew “so stupid”, “just copy HTML files into TV device”, or “just access a simple intranet website” – Here are a few plus points to developing a PWA.

  • Easy mass deployments and updates. Don’t have to go down to each device physically, just update the server and it will automatically push.
  • Offline capable, all the static files are cached in the device. It will still work if the Internet or intranet connection goes down.
  • Can deploy anywhere in the world. Think about it, just access a website and hit install.
  • Being a PWA opens up a world of possibilities. Maybe showing live streams, radio podcasts, flash offers, etc…

 

COMPATIBILITY CHECKS

Works on all modern “Grade A” browsers.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

Leave a Comment

Your email address will not be published.