Create interactive content with jSignage
From SpinetiX Support Wiki
Contents
Introduction
The jSignage library provides both high-level interactive layer functions and low-level layer functions that can be used for building interactive projects for HMP devices.
Interactivity is typically achieved by installing handlers (callbacks) for input events (such as mouse events, key events, shared variable update events) and performing one or more of these actions from the handler:
- Hiding or showing a layer.
- This is done simply by calling the
.show()
,.hide()
or.setVisible()
functions common to all layers. - Applicable in or out animation effects are triggered automatically, and all animations inside the layer are restarted as well.
- This is done simply by calling the
- Switching page inside a multi-page layer.
- This causes the current content to disappear and be replaced by a new page of content, applying a transition effect as required.
- Note that the trigger for the change can be any type of event, including a click on a button inside the page that is about to be switched out.
- Pushing new data to a slideshow, playlist, crawler, textTicker or textBar layer using the
.pushData( )
function.- This will turn on the layer, as if doing a
.show()
if it is not currently displaying anything. - If it is already displaying something, the new items will be put at the end of the current data set.
- This will turn on the layer, as if doing a
- Triggering a navigation action on a carousel layer.
- For instance, moving to the next or previous slide.
- Pausing or resuming media content.
- Call the
.pause()
or.resume()
functions common to all layers.
- Call the
- Doing an AJAX request to an HTTP server with the user input.
- The response handler will then call methods to modify the content accordingly.
- Sending requests to an attached device via the RS232 port or USB I/O.
- Modifying shared variables for synchronized actions on multiple devices.
- When the interactive application is running on a wall of monitors, it is necessary to add intermadiary steps through shared variables to synchronise all the displays.
- When the application uses only one screen, this is typically not required.
Interactive layers
The following types of layers are included into jSignage for building interactive content:
- Multi-page, constructed with
$.multiPage
- Carousel, constructed with
$.carousel
- Pop-up, constructed with
$.popup
- Push button, constructed with
$.pushButton
- Progress bar, constructed with
$.progressBar
- Progress wheel, constructed with
$.progressWheel
More types can be added by extending the jSignage library with new constructors.
Installing handlers
It is possible to install interactivity handler in a lot of different ways:
-
.click()
,.dblclick()
,.hover()
,.mouseenter()
,.mouseleave()
,.mousemove()
etc. applicable for all types of layers. See jQuery documentation on Mouse Events for more details.
-
.focusin()
,.focusout()
for focus sensitive layers.
-
.keydown()
and.keyup()
for focus sensitive layers, or on the top-level$('svg')
. See jQuery documentation on Keyboard Events for more details.- Note that the keyboards event from SVG tiny 1.2 are a subset of the full DOM level 3 event. See SVG#KeyboardEvent for more.
-
.textInput()
for focus sensitive layers, or on the top-level$('svg')
. See SVG Tiny 1.2 uDOM for more details on the.textInput()
- In contrary to
.keydown()
and.keyup()
that return the keyIdentifier (U+0041 for 'A') and some modified flags (shiftKey=true), the.textInput()
returns adata
that contains the resulting pressed key ('a' or 'A'). However keys such as 'Enter' or 'Escape' will not trigger any.textInput()
events.
- In contrary to
- Shared variables changes, cause by events from serial port devices, USB I/O devices and the network. See Shared variables for more details.
Tutorials
- Simple push button
- Advanced click handler
- Virtual museum navigation
- Image carousels
- Interactive slideshow
- Interactive text ticker
- Add a mouse cursor
Examples
See also interactive projects page.
Add/remove a video on click
This example shows how you can easily add & remove a video with a mouse click. The first click adds the video (which starts to play immediately full-screen) to the svg element and the next one removes it.
$(function(){
var myVideo = null;
$('svg').click( function(){
if ( myVideo == null ){
myVideo = $.video( { href: 'video.avi', repeatCount: 'indefinite', begin: 'indefinite' } );
myVideo.addTo('svg').begin();
} else {
myVideo.removeAfter().end();
myVideo = null;
}
});
});
Add/remove a video in a multi-screen project
The above example works very well on a normal project, but not in a synchronized content type of project (for instance, a video wall). For this case, the shared variables mechanism must be used to ensure that the video is added / removed in the same time on all the players to keep the synchronization.
In this example, one of the players is the shared variables server (must have the Network API server enabled) and all the other players will get updates from the "master" player whenever a click is received (the "master" must have the "Enable events" option enabled).
- If a "slave" player is restarting, it will automatically get the last value of the control shared variable from the "master" and thus continue to be in sync with the others.
- If the "master" restarts, it will send a reset update to all the "slaves". Make sure to remove the begin attribute from the index file, otherwise this update will be sent in the past and therefore ignored by the other players.
- The video is started with a small delay (1.5s) to compensate the rendering latency of the players.
When using this script, make sure to change:
-
MASTER_IP
with the IP address of your "master" player (e.g. 192.168.1.10), optionally followed by a TCP port if the port number on the server is different from the port number on any of the "slaves" players (e.g. 192.168.1.10:1234); -
screen-1-1
with the multiscreen ID of your "master" player.
var varName = 'click@MASTER_IP';
var showVideo = 0;
$(function() {
var myGroup = $.createElement('g', {id: 'myGroup'}).addTo('svg');
var v = createSharedVariable( varName );
if (MULTI_SCREEN_ID == 'screen-1-1'){
// This code gets executed only by the master and is useful in case of a master restart.
// Make sure to remove the begin attribute from the index file, otherwise this update
// will be sent in the past and therefore ignored by the other players.
v.set('0');
}
$('svg').mousedown( function(){
showVideo = ( showVideo ? 0 : 1 );
v.set(showVideo);
} );
v.addUpdateListener( function(v) {
showVideo = parseInt(v.value);
if ( showVideo ){
$.video( { id:'myVideo', href: 'media/video.mp4', repeatCount: 'indefinite', begin: 'indefinite' } )
.addTo(myGroup) // Add the video to the group.
.begin( 1.5 ); // Start the video with a small delay to compensate the rendering latency.
} else {
myGroup.text(""); // Remove the video(s).
}
});
});
Play/pause a media
Play and pause a video by clicking on it. The first click pauses the video and the next one restarts it.
$(function(){
var paused = false;
$.media( { href: 'media/video.mp4', repeatCount: 'indefinite' } )
.click( function() {
if ( paused )
$(this).resume();
else
$(this).pause();
paused = !paused;
} )
.addTo('svg');
});
Note:
- This example is using the
$.media()
to display a fullscreen video.
Controlling media using keystrokes
The following examples demonstrates how to play, pause, hide and show a video using keystrokes. The first example is using the keydown
handler and the second is using the textInput
handler.
$(function(){
var media = $.media( { href: 'video.mp4', repeatCount: 'indefinite' } ).addTo('svg');
// The list of keyIdentifier can be found at http://www.w3.org/TR/SVGTiny12/svgudom.html#KeyIdentifiersSet
$('svg').keydown(function(event) {
switch ( event.keyIdentifier ){
case "U+0048": //'H'
media.hide(); break;
case "U+0053": //'S'
media.show(); break;
case "U+0050": //'P'
media.pause(); break;
case "U+0052": //'R'
media.resume(); break;
}
});
});
Same example as above, but using the .textInput()
handler.
$(function(){
var media = $.media( { href: 'video.mp4', repeatCount: 'indefinite' } ).addTo('svg');
$('svg').textInput( function(event) {
switch ( event.data ){
case "h": media.hide(); break;
case "s": media.show(); break;
case "p": media.pause(); break;
case "r": media.resume(); break;
}
});
});
Notes:
- SVG Tiny 1.2 uses a reduced interface for keyboard event (see SVG 1.2 uDom for more).
- It is recommended to have the above code directly into the index.svg file. Otherwise, the layer including the svg file having this code must have a "focusable" attribute set to "true" (i.e.
"focusable": "true"
). In Elementi, this attribute can also be set from Advanced tab of Layer Properties dialog.
Show 2 media when push buttons are pressed. When a media is started, a menu button is shown on top allowing the user to go back to the main menu.
$(function(){
// Create 2 button inside a <g>, and make it visisble using the show() function
var menu = $.g( { begin: 'indefinite' }).add([
p1 = $.pushButton( { left: 100, top: 100, width: 200, height: 60 }, 'P1' ),
p2 = $.pushButton( { left: 100, top: 200, width: 200, height: 60 }, 'P2' ),
]).addTo('svg').show();
// Create a placeholder for the media to be displayed
var media = $.g( { id: 'media'} ).addTo('svg');
// Create a button to go back to the menu. The button is not shown by default ( begin: 'indefinite')
back= $.pushButton( { left: 100, bottom: 100, width: 200, height: 60, begin: 'indefinite' }, 'Menu' ).addTo('svg');
// Function to show a media. Hide the main menu, show the back button, and create a new media
function showMedia( href ) {
menu.hide();
back.show();
cur = $.media( { href: href, begin: 'indefinite' })
.endEvent( function() {
menu.show();
back.hide();
cur[0].parentNode.removeChild( cur[0] );
} )
.addTo(media)
.show();
}
// Configure the action when the button are click
p1.click( function() { showMedia( "media/Fusion.jpg" ); });
p2.click( function() { showMedia( "media/hmp200_sd.mp4" ); });
back.click( function() {
cur.end();
});
});
Note:
- In the function
showMedia()
the media are created with the following functions:-
cur[0].parentNode.removeChild( cur[0] )
: make sure that the media is removed from the SVG file after being played to avoid memory leak. -
endEvent()
: make sure that the main menu is visible again, and that the back button is hiden
-
- The
back.click()
ends thecur
media before its end.
Start / stop a timer on mouse events
This example shows how easy is to start / stop a timer based on mouse events. See JSignage:Timers page for more details on the timers methods.
$(function(){
var timeout = 5000; // 5s
var timer = null;
function callback(){
// some code
}
$('svg')
.mousedown(function(){
if (timer) { $.clearTimeout(timer); }
})
.mouseup(function(){
timer = $.setTimeout( calback, timeout);
});
});
Drawing using the mouse
This example shows how to draw on the screen using the mouse. Press the mouse left button to star a new drawing and move it around to create your master piece. Release the mouse to finish the path. Press any other button to clear the screen.
$(function(){
var svg = $('svg');
var refMatrix = svg[0].getScreenCTM().inverse();
var pt = document.documentElement.createSVGPoint();
var path = d = null;
function realPos( evt ){
pt.x = evt.clientX;
pt.y = evt.clientY;
return pt.matrixTransform( refMatrix );
}
svg.mousedown( function( evt ) {
if ( evt.button ) {
$('path').remove();
return;
}
pt = realPos( evt );
d = new $.pathData().moveTo( pt.x, pt.y );
path = $.path({ fill: 'none', stroke: 'red', strokeWidth: 3, d: d }).addTo( svg );
}).mouseup( function() {
path = false;
}).mousemove( function( evt ) {
if ( !path ) return;
pt = realPos( evt );
d.lineTo( pt.x, pt.y );
path.attr( 'd', d );
});
});
Notes:
- A path is used to draw the line for each mousemove event. The path data is kept in the variable
d
which is modified every time the user moves the mouse. - It is necessary to convert the mouse position for the user space (depending on the screen configuration) and the document coordinates using
realPos()
function. - The event button property (
evt.button
) returns 0 for the left button, 1 for the middle button and 2 for right button.
Advanced examples
Tic-tac-toe
See how to build the basic game of Tic-tac-toe.
Paint using SVG
Based on the previous example, a full 'paint' application can be designed using jSignage, which allows the user to :
- Select the color of the line to draw.
- Change its size.
- Clear the content of the drawing area.
JavaScript code:
$(function(){
/* variables */
var g;
var path = null;
var d = null;
var color = 'red';
var width = 4;
var refMatrix;
/* functions */
function clear() {
if (g) { g.end(); }
g = $.g( { left: 60, frame: { backColor: 'grey' } } )
.mousedown( function( evt ) {
pt = realPos( evt, refMatrix );
d = new $.pathData();
d.moveTo( pt.x, pt.y );
path = $.path({ fill: 'none', stroke: color, strokeWidth: width, d: d }).addTo( g );
})
.mouseup( function() {
path = false;
})
.mousemove( function( evt ) {
if ( !path ) return;
pt = realPos( evt );
d.lineTo( pt.x, pt.y );
path.attr( 'd', d );
})
.removeAfter()
.addTo('svg');
refMatrix = g[0].getScreenCTM().inverse();
}
function realPos( evt ){
var pt=document.documentElement.createSVGPoint();
pt.x=evt.clientX;
pt.y=evt.clientY;
return pt.matrixTransform( refMatrix );
}
/* main code */
// Draw the menu on the left
$.table( { data : ['red', 'green', 'blue', 'cyan', 'pink', 'yellow', 'purple', 'white', 'black' ],
rows: 9,
width: 60, height: 9*50,
cellPadding: 5,
frame: { backColor: 'white', frameColor: 'black', padding: 5 },
renderToSVG: function() {
return $.rect( { fill: this } )
.click( function() { color = $(this).attr('fill'); $('#sample').attr('stroke', color); } );
}
}).addTo( 'svg' );
$.table( { data : [ $.textArea({ fontSize: 'max' }).text("-")
.click( function() {
if (width > 2) { width/=2; }
$('#sample').attr('stroke-width', width);
} ),
$.textArea({ fontSize: 'max' }).text("+")
.click( function() {
if (width < 32) { width*=2; }
$('#sample').attr('stroke-width', width);
} ) ],
rows: 2,
top: 9*50+10, width: 60, height: 2*50,
cellPadding: 5,
frame: { backColor: 'white', frameColor: 'black', padding: 5 },
}).attr("pointer-events","boundingBox").addTo( 'svg' );
$.textArea( { top: 11*50+20, width: 60, height: 100, frame: { backColor: 'blaks'}, fill: 'grey' } )
.text("CLR")
.click( function() { clear(); } )
.addTo('svg');
// add the sample line
$.g( { top: 11*50+120, width: 60, height: 50 } )
.add( $.line( { x1:5, x2: 50, y1: 25, y2: 25,
id: 'sample',
stroke: color, strokeWidth: width
} ) )
.addTo('svg');
// clear the screen to start;
clear();
});