Click here to Skip to main content
15,885,365 members
Articles / Web Development / HTML5

Building A Slideshow App Using SignalR

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
24 May 2017CPOL10 min read 11.6K   308   4  
Use SignalR to create a Slideshow app which asynchronously updates all web clients so they see the same slide you are seeing.

Introduction

Over the years I have sat through a great many slideshow presentations where we have local and remote attendees.  The facilitators I've seen have always used Microsoft PowerPoint and I've noticed that the remote users always have to flip the slides for themselves.  

NOTE: This article will move more quickly than a beginning article.  If you would like step by step on beginning SignalR, please see my other article here at CP : Beginner's Guide to Using SignalR via ASP.NET[^]

The Impetus For the Idea

Why couldn't there be a way to have everyone go to a specific URL and then when the facilitator flips to the next slide alll the viewers see the new slide also?  I know you can do Goto Meeting or whatever, but many people don't have WebEx or GoTo Meeting and besides those are difficult to get set up at times.  

Maybe there is a way to do this in PowerPoint now, I'm not sure.  However, that is the motivation behind my idea.

Main Idea

Using SignalR we can create just such a site.  In this walk-thru explanation we will create an app that allows you to change the image that the remote user sees in real-time.  All the user has to do is go to your URL and then each time you provide an image URL and push the broadcast button she will see the new image in her browser.  

Quick Example

Here's an example via animated gif that shows three different browsers (Chrome, FireFox, Edge) all looking at the same URL.  The user simply provides a URL to an image and clicks the [Broadcast] button and all other browsers are updated.  Watch closely because it's fast.  (I've pasted URLs to images in the text box ahead of time to shorten the animated gif.)

slideshow overview

Background

Once I knew what I wanted to do, the first thing I wanted to know was how difficult it would be to update the src attribute of an <img> tag.  Using jQuery, it is very easy.

I wrote a quick example to test it out.

Get Code Sample v000

First of all, you can get the code and try it out.  Just download the v000 version of the code at the top of this article.  Unzip it and drop the folder somewhere on your local drive.  Double-click the index.htm file and your default browser will fire up.  This version barely does anything.  

What Does It Do?

Initially, you'll see a ugly test image (red scrawled x) on the page.  When you click that image, the second ugly test image (blue x) will load.  If you click the image again, it will revert back to the first image.

ugly red x ugly blue x

I warned you it was ugly.   However, it allowed me to determine that what I need to do (update the src attribute of an <img> tag is possible and easy).  We'll take look at the code, but first allow me to mention why the project is structured the way it is.

Visual Studio Project Structure

During the time I wrote my previous article (Beginner's Guide to Using SignalR via ASP.NET[^] ) I learned about the project structure that Visual Studio creates for an empty project so stole that from my previous article's project.  That allowed me to create an index.htm that is ready to be copied into my final ASP.NET project that supports SignalR.  My point here is that is why the jQuery files are found in the /Scripts directory.  The project structure looks like:

project structure

Not Terribly Interesting

I know this isn't terribly interesting, but knowing about these things can make your life easier.  I can now take my index.htm and drop it into my ASP.NET project (which I will do later in this article) and it will reference the jQuery scripts properly.  OK, enough of this, let's take a look at the index.htm and the simple jQuery that updates the image.

HTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Slideshow</title>
    <link rel="stylesheet" href="css/main.css" />
    <script src="Scripts/jquery-1.6.4.min.js"></script>
    <script src="Scripts/jquery.signalR-2.2.2.min.js"></script>
    <script src="signalR/hubs"></script>
</head>
<body>
    <img src="assets/1_local.png" id="slides" onclick="setImageSource()"/>

    <script src="js/slideshow.js"></script>
</body>
</html>

You can see that this is basically just a skeleton that references all the scripts.  There is just that one <img> tag and you can see that if the user clicks the <img> then we call a JavaScript method named setImageSource().

Here's the code from slideshow.js:

JavaScript
function setImageSource(sourcePath) {
    if (sourcePath === undefined) {
        if ($("#slides").attr("src") == "assets/1_local.png") {
            $("#slides").attr("src", "assets/2_local.png");
        }
        else {
            $("#slides").attr("src", "assets/1_local.png");
        }
    }
    else {
        $("#slides").attr("src", sourcePath);
    }
}

First thing the script does, is check to see if sourcePath is defined.  In our use, it is not, because our method does not pass anything in.  That means this outer if statement will always be evaluated to true in this app (our SignalR app will use this to pass in a URL to our image later).

The next thing we see is how we can obtain the value of the image src using jQuery.  It is very easy.  We use the jQuery selector for the id of our <img> tag which is "slides".  We use the jQuery method called attr() passing in the value of src.  In the if statement we are checking to see if the src value is already equal to the first image.  If it is we simply use the same attr() method to set the src value to our second image which is in our assets directory (2_local.png).

What Does It Mean?

That's it.  I've proven that we can update the src value and see an image change in real-time (when the user clicks the image). 

Since I know I can do this, I now know that I can also use SignalR to broadcast the sourcePath to other browsers. That means I will be able to set the image src value and when I do, all other people looking at my URL will see the new image in their browser too.  It's a slideshow of sorts that I can use to control what other people are seeing on my page asynchronously or in real-time.  

Let's convert this code to a SignalR app.  

Setting Up the SignalR Project

I'm going to let you download the completed project from the top of this article and then I'll explain the code, because it is so simple.  If you want to know how to walk through Visual Studio and set up this project, please see my first article which I mentioned a couple of times already.

I Haz Da Codz : Download v001

Get the v001 version of the code from the top of the article, build it in Visual Studio (mine is built on VStudio 2017) and run it.

When you do that, you will see a page like the following in our browser.

signalR app - initial view

Yes, it is still a bit ugly and shows that ugly original image.  However, notice that it now includes a <input> text box and a <button>

Now you can add any URL (to an image) to the text box and click the Broadcast button and anyone who is viewing the page will see it in her browser.  You can open up two browser windows to your localhost URL and try it.  Here's what it'll look like if you load the same Mario and Luigi image.  :)

mario and luigi

I'll show the code that makes it work in just a moment.  But for now, just understand that when you click the Broadcast button it sends the URL to all remote browsers.  That, in turn fires the setImageSource() method in the remote browsers and the image src is updated and the remote users see the image you are looking at.  I think that is almost magical but I'm a geek.  You get all this magic from SignalR.  There's an interesting side effect that occurred while I was testing this.

An Interesting Side Effect

Now, this is where it becomes additionally interesting.  If you look closely at the text in the text box in the previous image you may notice that it starts out like data:image/jpeg;base64.

If you have ever used the HTML5 Canvas element you may have noticed that if you right-click on the Canvas it can generate the image data from the Canvas and it uses this exact format.  It's basically the base64 encoding of the entire image.  It's quite large. 

Grabbing Images From Google

First Interesting Thing

The first thing that is interesting is that I got that from simply googling Mario and Luigi images and then right-clicking in Chrome and choosing "Copy image address".  Why does attempting to get the image address give me the base64 encoded data of the entire image?  I'm not sure if this is chrome or Google.  

copy image address

Second Interesting Thing

It works.  It is interesting that since you can embed your image data into your <img> tag by setting the src value to the base64 encoded data, that my solution still works.  You see, when add that data and then click the Broadcast button I am expecting it to be a URL to the image location.  However, in this case -- because of the browser or Google site -- the data that is broadcasted is the entire base64 encoded data of the image and it still works.  It is a bit slower, because it is a ton of data, but it does work.  More magic!

Of course, it works perfectly fine with a normal URL also.

Let's take a look at how the code works and wrap this thing up.  Again, if you want the gory details of how SignalR works, take a look at my first article. 

The Codz!

The main class (a SignalR Hub) that implements the Broadcast in this project is named SlideHub and it looks like the following:

C#
using System;
using Microsoft.AspNet.SignalR;

namespace Slideshow
{
    public class SlideHub : Hub
    {
        public void Send(String sourcePath) 
        {
            // Call the broadcastMessage method to update clients.
            Clients.Others.broadcastMessage(sourcePath);
        }
    }
}

That's the class that generates the JavaScript for us that the client will use to do the Broadcast.  When the Send() method is called then the SignalR API method broadcastMessage() is fired.  Once thing I'd like to point out here is that we call that method on the Others collection object.  That broadcasts the message to all other browsers, except the one where the button is clicked.  

We could've called broadcastMessage on the Clients.All collection object and then the message would be received by our local client also.  However, it is faster to do the local update of the src via JavaScript / jQuery and only broadcast to the Others so that is how I implemented that.  

Finally, here is the entire JavaScript implementation which is self-explanatory for the most part -- especially if you've read my first article.  :)

JavaScript
//slideshow.js
var slideR = null;

$(document).ready(function () {
    slideR = $.connection.slideHub;
    slideR.client.broadcastMessage = function (sourcePath) {
        setImageSource(sourcePath);
    };

    $.connection.hub.start().done(function () {
        console.log("Hub is started.");
    });
});

function setImageSource(sourcePath) {
    if (sourcePath === undefined) {
        if ($("#slides").attr("src") == "assets/1_local.png") {
            $("#slides").attr("src", "assets/2_local.png");
        }
        else {
            $("#slides").attr("src", "assets/1_local.png");
        }
    }
    else {
        $("#slides").attr("src", sourcePath);
    }
}

function broadcastMessage() {
    setImageSource($('#sourcePath').val());
    slideR.server.send($('#sourcePath').val());
}

$(document).ready() is simply the jQuery way to insure code is run after the entire index.htm is loaded.  That code simply initializes SignalR for us.  

You can see that we initialize the broadcastMessage to an anonymous function that calls setImageSource() with a sourcePath that is passed through.  That is the value that comes from the text box.

You can see that when the broadcastMessage() function runs -- when the user clicks the [Broadcast] button , it calls the setImagteSource() locally and then broadcasts the message by calling the send() method. 

That's really all there is too it. 

Points of Interest

I have never had an article with a point of interest, but now I do.  You can see that I am not putting this particular project out on the web as a live app to try.  Normally I like to do that.  However, that would mean that anyone who navigated to the URL and then added a picture (of anything -- horror!!!) would be able to broadcast it to everyone else who was looking at my production URL.  I'm not interested in that, at all.  :)  Frankly, it scares me.

History

First release of article and code : 05-24-2017

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) RADDev Publishing
United States United States
"Everything should be made as simple as possible, but not simpler."

Comments and Discussions

 
-- There are no messages in this forum --