Create interactive content with jSignage

From SpinetiX Support Wiki

Jump to: navigation, search

This page is related to Interactivity page.

Introduction

The JSignage API provides both high-level interactive layers (multi-page, carousel, pop-up etc. ) and low-level interactive event functions (click, keydown, textInput, etc.) to make it easy to build interactive applications in SVG.

Interactivity is typically achieved by installing handlers (callbacks) for typical input events (such as mouse or key events) or Shared Variable updates (cause by events from serial port devices, USB I/O devices and the network) - these callbacks could then perform one or more of these actions:

  • Show or hide a layer.
    This is done simply by calling the .show(), .hide() or .setVisible() functions common to all layers. In or out animation effects are triggered automatically, and all animations inside the layer are restarted as well.
  • Switch to a 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. 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.
  • Push new data to a slideshow, playlist, crawler, textTicker or textBar layer.
    This is done using the .pushData( ) function, and it 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.
  • Move to the next or previous slide of a carousel.
  • Pause or resume media content.
    Simply call the .pause() or .resume() functions common to all layers.
  • Make an AJAX request to a web server with some user input.
    The response handler will then call methods to modify the content accordingly.
  • Send requests to an attached device via the serial port or USB I/O API.
  • Modify a Shared Variable for synchronized actions on multiple devices.
    When the interactive application is running on a wall of monitors, it is necessary to add intermediary steps through Shared Variables to synchronize all the displays. This is done with using SV.set() function.

Interactive layers

The following types of layers are included into jSignage for building interactive content:

More layers' types can be added by extending the jSignage library with new constructors.

Interactive events

jSignageLayer.<eventHandler>( callback );

Returns: jSignage Object

Description

jSignage API offer support for all the SVG Tiny 1.2 events, such as:

  • .click(), .mousedown(), .mouseup(), .mouseover(), .mousemove(), .mouseout(), .mouseenter(), .mouseleave(), .mousewheel(), .hover() for all layer types
  • .keydown(), .keyup(), and .textInput() for focus sensitive layers, or on the top-level $('svg')
  • .DOMFocusIn(), .DOMFocusOut(), and .DOMActivate() for focus sensitive layers
Note Notes:

Parameters

  • callback
    Type: Callback.
    The callback function is invoked when the event occurs with one parameter, an object holding the event details.

Tutorials

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;
    }					
  });
});

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.

Control 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;
        }   
    });
});
Note 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.

Start / stop a timer on mouse events

This example shows how easy is to start / stop a timer based on mouse events.

$(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);
    });
});

See JSignage timer methods page for more details on the timers methods.

Change color on mouse over

Create a rectangle, add it to the svg element and change its color on mouse movements:

$(function(){ 
    $.rect( { width: 200, height: 100, top:'20%', left: '20%', fill:'blue' })
            .addTo('svg')
            .mouseover( function() { $(this).attr('fill','red'); })
            .mouseout( function() { $(this).attr('fill','green'); }) ;
});

Draw 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 );
  });
});
Note 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

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).
    }                                         
  });
});

Media menu

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 Notes:
  • 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 the cur media before its end.

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(); 
});
This page was last modified on 4 March 2021, at 21:13.