Click here to Skip to main content
15,895,746 members
Articles / Web Development / HTML

Web Presentation, an Application in a Single File, now with Video

Rate me:
Please Sign up or sign in to vote.
4.97/5 (16 votes)
4 Sep 2023CC (ASA 3U)11 min read 38.2K   1.1K   33   17
A cross-platform replacement for all those office presentation applications in a single file
Who needs presentations created with boring bulky office presentation packages not always available for all systems? All you need is a Web browser and a set of vector/pixel images. With a solution in just one HTML/CSS/JavaScript file, you have all the features people use in presentations. Since v.2, in addition to graphics and animated graphics, video elements can be added and controlled from the presentation frames.

(This demo uses one AV1 video, which is compatible with almost all browsers, but not Microsoft Edge)

presentation.h

Contents

Introduction
Motivation
Usage
Presentation Data
Presentation Properties
Video Properties
Image File Types
Animation
Implementation Detail
Preserved Animation
Loading, Starting, Pausing, and Stopping Video
Touchscreen Support
RTL Support
Releases
License Note

Introduction

This article is the first article of the small series of articles on the Web presentation products:

Motivation

For the last presentation I delivered, I already had a collection of SVG images mostly representing some architectural solutions. When you develop architectural and design solutions, you always have some, as SVG is the most universal vector format. While photos can be easily shown in a presentation manner using a suitable image viewer, SVG typically takes some extra effort, and probably the worst option would be messing with those office presentation applications. Why not showing the images themselves? After all, they are scalable and compatible with all non-nonsense Web browsers.

So I quickly put together the images in a JavaScript file and added the simplest script used to move from one image to another. What a relief! Who would ever need anything else?

In the demo, I added some animated SVG, static WebP photographs, and a WebP video converted from an out-of-camera video in the form of WebP animation, and, in a later version, also a real WebM video sample. These files and the features have nothing to do with the presentation product itself, they just demonstrate that all we need is already available, can be created using open-source products only. At the same time, we can have all the features expected from those bloated office software applications, in a much easier way.

Usage

The basic usage is probably as simple as it can be. The live demo also provides an introduction to the presentation system and shows its features.

Basically, the presenter creates a set of files each representing a presentation frame, lists their paths in required order in a presentation data file, and loads “presentation.h” in a browser, passing the presentation data file in the URL query string. Presentation starts.

There is also some minimal set of advanced properties; each of them is optional.

Presentation Data

In addition to image files, the presentation needs to be described. First of all, it needs a list of relative paths to image file, to define both image data and the order of images in the presentation. All other properties can be omitted, then the default values are used. For example, let’s assume we put it in a file “demo/presentation.js”, path is relative to “presentation.html”:

JavaScript
const presentation = {
    images: [ // relative to presentation.html
        "demo/1.webp",
        "demo/1.svg",
        "demo/2.webp",
    ],
    title: "Presentation Demo",
    hideHelpOnStart: false,
    colors: {
        background: "white",
        text: {
            background: "azure",
            foreground: "black",
            border: "lightBlue",
        },
    },
    rtl: false,
};

The extended syntax since v. 2 allows for adding of the video elements in the list. Here is the example:

JavaScript
const presentation = {
    images: [ // relative to presentation.html
        "demo/1.webp",
        image("demo/1.svg"), // same as "demo/1.svg"
        video("demo/myClip.webm", {
            title: "My concert",
            poster: "demo/our-concert-hall.webp"
        }),
        video("demo/myTrip.webm", {
            title: "On the road",
            play: true, // auto-play
        }),
    ],
}

This way, the list of the presentation frames can be polymorphic, a sequential mixture of the image and video elements. See the video properties below.

This presentation can be loaded on a Web page by using the path to the presentation file in a query string of the URL. The easiest way to do it is to have a separate presentation-specific HTML file. Let’s assume this is the file “demo/index.html”, then its content could be:

HTML
<!doctype HTML>
<html>
    <head>
        <meta http-equiv="refresh" content="0; url=
        ../presentation.html?demo/presentation.js" />
    </head>
</html>

Presentation Properties

All paths are relative to the location of “presentation.html”.

presentation.images: an array of image file names, paths are relative to “presentation.html”. This property is the only mandatory one. If it is missing, or this is an empty list, the application will report an error.

Optional Properties:

title: presentation title

hideHelpOnStart: boolean (true/false), default: false, that is, by default help text is shown on started.

colors: colors for the presentation background and rendering of text data.

colors.background: presentation background. It is also applied as a background for all images supporting transparency or alpha channel.

colors.text: colors for the rendering of text data, an object with three self-explained properties.

rtl: the option for right-to-left cultures, explained in detail below, default: false.

Video Properties

Each video element is added in the form

JavaScript
video("path_to_video_source_file", // relative to presentation.html
    { /* video properties... */ } // optional
)

Properties:

title: String, the title of the <video> element.

poster: String, the path to the raster graphics file shown as the poster over the video element before the video starts.

play: true/false: auto play; if it is true, the video starts to play when its presentation frame becomes active.

Note that using both poster and play at the same time makes little sense because if the video is started to play automatically, the spectators won’t have enough time to see the poster.

Image File Types

For the presentation frames, all MIME types standardized for Web are acceptable. For vector graphics this is SVG, image/svg+xml. For raster graphics and acceptable types are: image/apng, image/avif, image/gif, image/jpeg, image/png and image/webp.

Image file types accepted by specific browser but not standardized for Web, such as .bmp, .ico, or .tif, should be best avoided.

For raster images, the most practical and recommended format is WebP. It provides much better compression than older image types, supports progressive rendering, separate presets optimized for Picture, Icon, Photo, Drawing, and Text, and animation. Other animation-supporting types for raster graphics are APNG, AVIF, and GIF.

However, for presentation purposes, the most important type of animation is vector animation, SVG, because people widely use various transition effects. Even though such effects more distract from the presentation than help to understand the material, they are considered as a must.

Animation

Even though the creation of the image files is the sole responsibility of the user, I just want to comment on the creation of animation, using only the image file types standardized for Web and only open-source products and standards. There are many tools for the creation of the animation.

For example, SVG can be created using Inkscape. There is a lot of documentation on SVG animation, first of all, SMIL, which is probably the most suitable approach for presentation purposes: each transition effect takes just one short line of XML code, and the effects can be combined on the same element. Also, some add-ons for animation are available.

For raster graphics, the best approach is probably WebP. I used two tools for the creation of animation. First of all, the animation can be composed of a set of separate frames in GIMP. To do so, one needs to put each frame in a separate layer, perform animation optimization ([Main menu] => Filters => Animation => Optimize (Difference)), and save the result in a WebP image. At the moment of saving, GIMP will offer an option to create an animation.

Also, FFMpeg can convert available video file to a WebP animation. The example of a command line:

ffmpeg -i input_file -vcodec libwebp -filter:v fps=fps=20 -lossless 0 -compression_level 6 -an -vsync 0 output_file.webp

See FFMpeg documentation for more detail.

All the software tools I mentioned are not only open-source but also available on most platforms.

Implementation Detail

The implementation is trivial enough to get into detail too much. The purpose of this article is to provide a comprehensive working tool for presentations, not so much to teach anything. If this work can teach something, it’s the taste for minimalism and sober practical look at all those commercial bloated products.

So, I’ll touch only a few not-so-obvious aspects.

Preserved Animation

Animation is preserved by not loading all images during the initialization phase. Instead, there is only one img element which is loaded from source by assignment to its src property only for the very first image of the presentation. All other images are loaded as the are shown:

JavaScript
const move = backward => {
    // ...
    // undefined: initialization, boolean: backward/forward:
    if (backward != undefined) {
        if (backward)
            if (current > 0) --current; else current = presentation.images.length - 1;
        else
            if (current < presentation.images.length - 1) ++current; else current = 0;
    image.src = presentation.images[current];
    // ...
    if (isVideo) {
        // ...
        videoSource.src = item.source;
        // ...
    } else {
        image.src = item;
        resize(image);
    }
    show(video, isVideo);
    show(image, !isVideo);
};

This way, each image.src property assignment starts the animation. Accordingly, the animation is started again every time the same image is shown. After the video capability feature has been added in v. 2, <img> and <video> elements are shown/hidden, depending on the type of the current element in the images list. In contrast to graphics animation, video is started either by explicit user command (key “P”, Play/Pause) or automatically, when the frame with the video becomes active — this is controlled by the video boolean property play, optionally found in the image list.

Loading, Starting, Pausing, and Stopping Video

There are several confusing parts of the video API, so I want to make some useful notes on it.

I have to start from the aspects required by the design. There could be a clash between the navigation inside of a video and the “outer” navigation of the presentation frames. I decided to resolve it in the following design: let’s consider the ← and → keys dedicated to the presentation frame navigation. Jumping between the location withing a video is rarely needed during the presentation, but even if it is needed, mouse/touchscreen/touchpad can be used. Additionally, I dedicate the key “P” for video Play/Pause. When the video has played to the end, it also works as the video restarts, because this is how the call to HTMLVideoElement.play() works.

Now, when an active frame needs to load a video, a previously shown video or graphics image should be unloaded. In contrast to the img element, assignment a string value to the property HTMLSourceElement.src is not enough; also HTMLVideoElement.load() should be called.

All of this is taken into consideration here:

JavaScript
const move = backward => {
    video.pause();
    document.exitFullscreen();
    videoSource.src = undefined;
    image.src = undefined;
    // ...
    if (isVideo) {
        if (item.source) {
            video.poster = item.poster;
            video.title = item.title;
            videoSource.src = item.source;
            video.onplay = event => event.target.requestFullscreen();
            video.onended = event => document.exitFullscreen();
            video.load();
            if (item.play)
                video.play();
        } else
            video.title = "Video file not specified";
    } else {
        image.src = item;
        resize(image);
    } //if
    // ...
}
JavaScript
document.body.onkeydown = event => {
    switch (event.code) {
        // ...
        case "KeyP":
            if (videoSource.src)
                if (video.paused) video.play(); else video.pause();
    }
};

I would say, most confusing part here is document.exitFullscreen(). I use the fullscreen API to show video in fullscreen when it is started, and naturally, we need the previous mode to be restored when the active presentation frame is changed. But what happens if the user also uses the browser’s fullscreen mode? Surprisingly, nothing wrong. Despite the function name, document.exitFullscreen() will render the same browser’s fullscreen or window mode as before playing of the video. Video fullscreen and browser window fullscreen are different things and do not clash.

Touchscreen Support

JavaScript
let touchStart = undefined;
addEventListener("touchstart", event => {
    touchStart = { x: event.changedTouches[0].clientX,
                   y: event.changedTouches[0].clientY };
}, false);
addEventListener("touchend", event => { touchStart = undefined; }, false);
addEventListener("touchmove", event => {
    if (touchStart == undefined) return;
    const vector = { x: event.changedTouches[0].clientX - touchStart.x,
                    y: event.changedTouches[0].clientY - touchStart.y };
    const horizontal = Math.abs(vector.x) > Math.abs(vector.y);
    let back = horizontal ? vector.x > 0 : vector.y > 0;
    if (horizontal && presentation.rtl) back = !back;
    move(back);
    touchStart = undefined;
}, false);

This behavior also depends on the presentation.rtl property explained below.

RTL Support

Written writing cultures based on the right-to-left system also slightly modify the views of people. This cultural element can affect the way some people look at the arrow of time: while in Western cultures people imagine time as something floating from left to right, other people may think otherwise. In this case, it can be more natural to view the flow of the presentation as something moving from right to left. For such people, the rtl property is provided. It only changes the use of left/right arrows and left/right swipe with a touchscreen: the direction changed to is opposite. It has nothing to do with CSS direction but is based on similar considerations.

Effectively, it only affects how people treat arrow keys “←” and “→” and the direction of the touchscreen swipe. In Western cultures it is implied that “←” means “previous” and “→” means “next”, a person performing these operations imagines a current frame as a window, showing a strip of frames, representing the timeline. For touch screen swipe, a person “moves” not a window, but a strip of frames itself, so “←” means “next” and “→” means “previous”. In RTL cultures, all four operations come in opposite directions. At the same time, the meaning of up and down directions doesn’t depend on the culture.

Therefore, as the function move accepts a boolean parameter with the meaning of “go to previous frame”, the handling of arrow keys depends on the presentation.rtl, but only for horizontal directions:

JavaScript
switch (event.code) {
    case "Space":
    case "ArrowDown": move(false); break;
    case "Backspace":
    case "ArrowUp": move(true); break;
    case "ArrowRight": move(presentation.rtl); break;
    case "ArrowLeft": move(!presentation.rtl); break;
    //...
}

Similarly, the direction in reverse is used for horizontal directions only in the implementation of the touchscreen swipe gestures.

Releases

1.1.0

November 22, 2020

First production release, supports only media compatible with the <img> element: vector/raster graphics, and animated vector/raster graphics.

2.1.0

November 24, 2020

Video-ready release. In addition to images, a video can be added. The syntax of the media list is extended to embrace a polymorphic list of a mixture of graphics and video elements, while original syntax is preserved.

3.0.0

December 6, 2020

Style improvements for video. In response to feature requests (CodeProject member gunamoi1), the video element is always centered or in the fullscreen mode.

4.0.0

December 21, 2020

Minor fixes. In this release, an alternative product has been added, under the nickname “the other way around”. It is described in a separate article.

4.2.0

January 12, 2021

The help element close box replaced with platform-independent SVG

4.3.0

January 17, 2021

Fixed close box size problem manifested with Gecko and Goanna engines.

4.4.0

September 4, 2023

Fixed typo in both Presentation products

Credits

Nelek found a typo in both Presentation products. Fixed in v. 4.4.0

License Note

All photo, video, and graphics materials used in the demo are created by the

License

This article, along with any associated source code and files, is licensed under The Creative Commons Attribution-Share Alike 3.0 Unported License


Written By
Architect
United States United States
Physics, physical and quantum optics, mathematics, computer science, control systems for manufacturing, diagnostics, testing, and research, theory of music, musical instruments… Contact me: https://www.SAKryukov.org

Comments and Discussions

 
QuestionVideo on the last page doesn't work in Edge, but works in Chrome. Pin
Member 92708315-Jan-21 0:28
Member 92708315-Jan-21 0:28 
AnswerVideo issue has nothing to do with the product Pin
Sergey Alexandrovich Kryukov13-Jan-21 6:07
mvaSergey Alexandrovich Kryukov13-Jan-21 6:07 
QuestionMessage Closed Pin
20-Dec-20 23:21
Member 1502655720-Dec-20 23:21 
QuestionCSS class names can be used instead of specifying in javascript Pin
Helena Munzarova8-Dec-20 4:43
Helena Munzarova8-Dec-20 4:43 
AnswerSomething to think about Pin
Sergey Alexandrovich Kryukov8-Dec-20 14:31
mvaSergey Alexandrovich Kryukov8-Dec-20 14:31 
AnswerSome conclusions... Pin
Sergey Alexandrovich Kryukov8-Dec-20 15:32
mvaSergey Alexandrovich Kryukov8-Dec-20 15:32 
AnswerMy advice: 1) signal-to-noise, 2) structural, 3) semantic, 4) data abstracted out Pin
Sergey Alexandrovich Kryukov8-Dec-20 20:41
mvaSergey Alexandrovich Kryukov8-Dec-20 20:41 
AnswerNow, the great merit of your approach I can see Pin
Sergey Alexandrovich Kryukov8-Dec-20 22:03
mvaSergey Alexandrovich Kryukov8-Dec-20 22:03 
GeneralRe: Now, the great merit of your approach I can see Pin
Helena Munzarova9-Dec-20 5:02
Helena Munzarova9-Dec-20 5:02 
Hi Sergey

I'm sorry I wrote that my solution is simpler. Your way of specifying the file list in the JavaScript file is really the simplest and fastest solution for showing only a set of images and videos. I admit that I didn't read your first article again before writing my answer. I just placed it to my mind as a valuable way of quickly preparing a web presentation almost equivalent to MS PowerPoint.

And yes, the presentation in my point of view would consist of one HTML file, images and video files, and your JavaScript file as an engine. It could also be saved as one MHT file.

In fact my solution does not simplify your solution, it rather extends your presentation from "images and videos only" to "any HTML you need", and it keeps the JavaScript engine library intact.

I used divs because for me they are the basic containers for grouping HTML elements.

I thought that the users would simply use their favorite graphical web page editor to edit the html file - type and format text and tables, insert pictures or videos into the page div. For adding a new page to the presentation they would just add a new div. They would need nothing more than editing an HTML file (just taking care not to remove the parts including your JavaScript library and calling the onload function).

I like your solution using only the pure structure instead of named classes. For the JavaScript function it does not matter whether you use div or li or whatever tag you choose, it's up to you. I usually simply choose what fits my needs and what should be supported by web browsers.

In fact it could be even more simple: every direct child of the body (or article or section) would be one presentation page, be it a div, paragraph, ul, section, ... But it might be confusing for the users because they would not see the individual pages.

I revoke my proposal of having an extra template page. The users can create their own class style with background and size and apply it to each presentation page. They can easily change the page size in the class style to fit the resolution of the destination device and keep elements properly aligned or centered. They could also check whether the page contents is not too large for the page size.

As you dislike the usage of classes (and you are right about the class name uniqueness), I had bad experience with JavaScript syntax errors when generating a complex structure of objects and arrays in PHP for using it in a JavaScript library for showing graphical charts. The library was really great but hunting the syntax errors was horrible, as you mention in one of your answers.

In my own project I use classes for onload tasks because
1. In my own project there is no risk of confusing class names (and the class names used by JavaScript always have prefixes like WPresent_ saying what they are used for).
2. The web pages around have quite complex structure and I cannot rely on the structure remaining unchanged.
3. I get all the elements at once with document.getElementsByClassName(sClassName) and then access their individual children by names.

The situation in the web presentation is really different. The class name uniqueness is important because of many users with possibly many various style names, so it is better to avoid class names.

The only thing remaining (except for real writing the functions) is automatic starting of a video placed somewhere inside the presentation page on activating the page (if the page is not only a video itself). If you have the page element, you can call vPresentationPage.getElementsByTagName('li') and then handle them by the type (which would have to be explicitly specified so that you wouldn't handle the user's regular li elements as images or videos).

I realized that I often have different approach to using the techniques than others. Many people would call it bad habits Smile | :) . And I tend to write long answers Smile | :) . But I like the work we do here. Thank you both for the idea and for the functionality you wrote.

Helena
AnswerAgree... Some more... Pin
Sergey Alexandrovich Kryukov9-Dec-20 10:40
mvaSergey Alexandrovich Kryukov9-Dec-20 10:40 
GeneralNew Web Presentation article published Pin
Sergey Alexandrovich Kryukov20-Dec-20 19:11
mvaSergey Alexandrovich Kryukov20-Dec-20 19:11 
GeneralMessage Closed Pin
7-Dec-20 7:55
Member 150146197-Dec-20 7:55 
QuestionGood idea. But maybe video option needs work? Pin
gunamoi11-Dec-20 19:42
gunamoi11-Dec-20 19:42 
AnswerUseful notes (video does work whenever is should work) Pin
Sergey Alexandrovich Kryukov2-Dec-20 7:25
mvaSergey Alexandrovich Kryukov2-Dec-20 7:25 
AnswerVersion 3.0.0 Pin
Sergey Alexandrovich Kryukov7-Dec-20 5:09
mvaSergey Alexandrovich Kryukov7-Dec-20 5:09 
QuestionYes I agree the video does not work. Pin
Mel Pama30-Nov-20 7:15
professionalMel Pama30-Nov-20 7:15 
AnswerVideo works perfectly where is should work; the problem not related to the product; this detail is incompatible browser, but it will work with older codecs Pin
Sergey Alexandrovich Kryukov30-Nov-20 16:13
mvaSergey Alexandrovich Kryukov30-Nov-20 16:13 
QuestionDemo Video did not play Pin
Craig P Williams Sr30-Nov-20 6:12
professionalCraig P Williams Sr30-Nov-20 6:12 
AnswerVideo works perfectly where is should work; it's not "video", this is the combination of Edge and AV1. The solution: either get another browser or use older codec. Shame on Micrsosoft. Pin
Sergey Alexandrovich Kryukov30-Nov-20 16:09
mvaSergey Alexandrovich Kryukov30-Nov-20 16:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.