@imaginary-maths/hilbert-gallery-viewer v1.0.0-alpha.2
Hilbert Gallery Viewer
This is a viewer component intended to serve as a client for
hilbert-gallery. However, the
viewer can also be used on its own. It is supposed to be remote-controlled from
a separate server which is not part of this package.
Features:
- display images and videos
- preload of the media content to be prepared when it needs to be displayed
- fit the media content to the viewer if the aspect ratios don't match up
- transition between consecutive media
- animate the current media
- transitions and animations are based on CSS animation to support low-power devices
- volume control for videos
- single interface for all actions
- validation of action arguments via JSON Schema
- supports semi-legacy web browsers: tested with Chrome 56
Usage
Install the package via npm:
npm install @imaginary-maths/hilbert-gallery-viewerInitialization
There are two ways to initialize the viewer: HilbertGalleryViewer class or
<hilbert-gallery-viewer> custom HTML element.
Via the class
Import the class and instantiate it with an already present HTML element:
import HilbertGalleryViewer from '@imaginary-maths/hilbert-gallery-viewer';
const container = document.querySelector('#my-container'); // use your own id here
const viewer = new HilbertGalleryViewer(container);Via the custom HTML element
The custom HTML element needs to be registered before it is first used and the module should do this automatically upon import:
import '@imaginary-maths/hilbert-gallery-viewer';The registration of the custom HTML element relies on side effects of the module, which some bundlers do not include in the final bundle. In this case, register the custom HTML element manually:
import HilbertGalleryViewer from '@imaginary-maths/hilbert-gallery-viewer';
HilbertGalleryViewer.defineCustomElement();Then, add the <hilbert-gallery-viewer> to your static HTML file or add it
dynamically through JS:
const viewer = document.createElement('hilbert-gallery-viewer');
document.body.appendChild(viewer);Actions
The viewer exposes only one method:
viewer.execute(type, args);type is the name of the action (show, clear, preload, mute, unmute,
set-volume or reload) and args are the arguments to the action (differs
from action to action).
The show action
This is the principal action supported by the viewer for displaying media files:
viewer.execute('show', showArgs);with showArgs being of type
interface ShowActionOptions {
mimetype: string;
url: string;
fit?: FitType;
color?: string;
startDelay?: number;
volume?: number;
muted?: boolean;
transition?: { type: string; options?: Record<string, unknown> };
animation?: { type: string; options?: Record<string, unknown> };
}mimetype: MIME type of the media to show. Must start with eitherimage/orvideo/.url: The URL of the media to show.fit(default:cover): Fit the media to the viewer if their aspect ratios don't match up.containscales the media such that it is completely visible. Some parts of the background may be visible.coverwill scale the media such that it covers to full area of the viewer.color(default:black): The background color of the media as a CSS color string. Will only be visible whenfitis set tocontain, if the media file contains (semi-)transparent parts or if the media's position is changed by an animation.startDelay: (default: depends on the transition): If the media file is a video: Start playback after the given number of seconds. Useful for delaying the playback to the point where the media is visible during a transition.volume(default1): If the media file is a video: Use this audio volume. The value must be in[0, 1].muted(defaultfalse): If the media file is a video: Whentrue, mute the video initially. See theunmuteaction.transition(default{ type: 'none' }): Define how to visually transition from the currently displayed media to the one defined by this action. See the section about transitions.animation(default{ type: 'none' }): Define how to animate the media defined by this action. See the section about animations.
Note that the media will be added to the DOM tree as soon as the action is issued. Therefore, other actions like changing the audio volume also apply to the media file, even though its actual display may be delayed due to the transition.
Transitions
By default, media files are displayed immediately during the show action.
However, in most cases a smooth transition just looks better. Delaying media
display is also supported.
Similar to actions, transitions are defined by their type and have certain options:
interface Transition {
type: string;
options?: Record<string, unknown>;
}Currently, all transitions support at least the following options:
interface TransitionOptions {
delay?: number;
duration?: number;
}delay(default:0): Delay the transition to the new media file by this number of seconds. The corresponding HTML element will already be part of the DOM tree beforehand, but will be hidden.duration(default: depends on the transition): Duration of the transition in seconds.
The previous media will be removed after it has been transitioned out, i.e. the transition determines when the actual removal happens.
The none transition
Display the media abruptly after delay seconds.
When this transition is used by the show action, the startDelay option
defaults to delay.
The cross-fade transition
Cross-fade between the previous media and the current one, i.e. the current
media is displayed with opacity 0 after delay seconds and gradually
increases opacity to 1 within duration seconds.
When this transition is used by the show action, the startDelay option
defaults to delay.
The fade transition
After delay seconds, fade-out the previous media to color for duration / 2
(seconds), then, fade-in the current media for duration / 2 (seconds).
interface FadeTransitionOptions extends TransitionOptions {
color?: string;
}color(default:black): The CSS color to fade-out to and fade-in from.
When this transition is used by the show action, the startDelay option
defaults to delay + duration / 2.
Animations
Animation can be used to bring some movement into otherwise static images while they are on display. Animation can also be applied to videos. However, they should not be overused. Good candidates for video animations are videos with only slow moving content.
Currently, all animations support at least the following options:
interface AnimationOptions {
delay?: number;
duration?: number;
}delay(default:0): Delay the beginning of the animation by this number of seconds. Note that the initial state of the animation will be set immediately, regardless of the delay.duration(default: depends on the animation): Duration of the animation in seconds.
Animations will currently only run once, then stop and stay in their final position.
The none animation
This animation does nothing. It is used internally as a placeholder whenever animations are optional.
The pan-zoom animation
This animates the position and zoom level of the media file on a linear path over time.
interface PanZoomAnimationOptions extends AnimationOptions {
from?: Partial<View>;
to?: Partial<View>;
}from(default:{ x: 0.5, y: 0.5, scale: 1 }): The initial view after applying the animation.to(default:{ x: 0.5, y: 0.5, scale: 1 }): The final view at the end of the animation.
interface View {
x: number;
y: number;
scale: number;
}x: The horizontal coordinate to center.y: The vertical coordinate of center.scale: The scale factor to apply after re-centering.
The view options should be chosen with care. { x: 0, y: 0 } is a valid view,
but will center the upper left corner of the media such that the background will
become visible. Note that negative number are supported as well, even though
their usefulness is questionable.
For media files that are displayed by the show action with the fit option
set to cover, the minimum value of scale can be determined as follows:
// assumption: ( 0 <= x && x <= 1 ) && ( 0 <= y && y <= 1 )
const borderDistance = Math.min(x, 1 - x, y, 1 - y);
const minScale = 1 / borderDistance;The clear action
Removes all media from the viewer and clears the background to a certain color, optionally using a transition:
viewer.execute('clear', clearArgs);with clearArgs being of type
interface ClearActionOptions {
color?: string;
transition?: { type: string; options?: Record<string, unknown> };
}color(default:black): The background color to clear to.transition(default{ type: 'none' }): Define how to visually transition from the currently displayed media to the solid color. See the section about transitions.
The preload action
Preload media files before showing them. Preloading should happen early enough
such that the following is true when the corresponding show action is issued:
- Images: Completely downloaded (equivalent to the image's
loadevent having fired). - Video: Buffered such that playback can start immediately and can continue to
the end if download continues at the current download rate (equivalent to the
video's
canplaythroughhaving fired).
The syntax is
viewer.execute('preload', preloadArgs);with preloadArgs being an array of items of type
type PreloadItem = {
mimetype: string;
url: string;
};where mimetype and url are defined as in the arguments to the
show action.
The action will return an array containing a Promise for each item which
resolves once the items has been sufficiently preloaded.
The viewer will create an <img> or <video> tag for each preload item and, if
necessary, apply the right settings to start buffering. The tags will be
inserted into a hidden area in the viewer's DOM tree. When the media file is
supposed to be displayed through a show action, the corresponding HTML element
from the preloading area will be just be moved into the visible area of the
viewer's DOM tree, keeping a cloned element in the preload area for later use.
This makes it possible to display media files directly after show action
without having any visual interruption or flickering.
The mute and unmute actions
Mute or unmute the audio of videos:
viewer.execute('mute');
viewer.execute('unmute');The action will apply to all currently active media elements, i.e. it also applies to media currently transitioning in or out of view.
The set-volume action
Set the audio volume of videos:
viewer.execute('set-volume', setVolumeArgs);with setVolumeArgs being of type
interface SetVolumeActionOptions {
volume: number;
mode?: 'absolute' | 'relative';
}volume: The volume to apply. Needs to be in[0, 1]forabsolutemode and in[0,∞)forrelativemode.mode(default:absolute): Inabsolutemode, the volume will be applied as is to all videos. Inrelativemode, the given volume will be multiplied with the current volume of each video, e.g. a value of0.5reduces the audio volume of all video elements to half of their current volume.
The action will apply to all currently media elements, i.e. it also applies to media currently transitioning in or out of view.
Note that the volume can also be set for muted elements, i.e. the change in volume has no immediate effect and will only apply after the element is unmuted.
The reload action
Since the viewer is intended to be controlled from a remote server, the reload
action offers a convenient way to reload the client, possibly fetching a new
client version from the server.
viewer.execute('reload');Note that the whole page will be reloaded, not just the current viewer instance.
Build
Install the dependencies:
npm installBuild the redistributable files to the dist folder using
npm run buildor start a development server using
npm run serveBefore sending any pull requests, your changes should be properly formatted using
npm run formatand the linter should not have any complaints:
npm run lintCheck out package.json for additional run scripts.
This project is using Parcel as a build system. The viewer is written in HTML, SCSS and Typescript.
Credits
Developed by Christian Stussak for IMAGINARY gGmbH.
License
Copyright 2022 IMAGINARY gGmbH
Licensed under the MIT license (see the LICENSE file).
3 years ago
3 years ago