Extension API

The Extension API provides the ability to ‘extend’ the capability of the platform by creating your own custom annotation.

Steps to use Extension API

  1. Located in the project editor view, click on the alt text icon to open the widget library menu. alt text

  2. From here, click the HTML tab. This block of code contains all of the necessary scripts to get started. Editing the raw HTMLboiler-plate code gives you the freedom to build a custom extension or annotation tailored to your needs.
    alt text

This example represents a good starting point:

  <!doctype html>
<html>
  <head>
      <title></title>
      <meta charset="utf-8"/>
      <style type="text/css">
          html, body { margin: 0; padding: 0 }
      </style>
  </head>
  <body>
      <!-- HTML code goes here -->

      <script type="text/javascript" src="//d2qrdklrsxowl2.cloudfront.net/js/hapyak-iframe.js"></script>
      <script type="text/javascript" src="//d2qrdklrsxowl2.cloudfront.net/js/hapyak.api.js"></script>
      <script type="text/javascript">
          (function () {
              /*
              Write your script code here
              */

              hapyak.context.addEventListener('data', function (variables) {
                  /*
                  Access Environment variables here
                  */
              });
          }());
      </script>
  </body>
</html>

Player

Object: hapyak.context.player

METHOD: play()

hapyak.context.player.play()

  • Plays the video

METHOD: pause()

hapyak.context.player.pause()

  • Pauses the video

METHOD: mute()

hapyak.context.player.mute()

  • Mutes the video

METHOD: unmute()

hapyak.context.player.pause()

  • unmutes the video

METHOD: volume()

hapyak.context.player.volume()

  • Passing no arguments to this function returns a number between 0 to 1 representing the current volume.

hapyak.context.player.volume(0.5)

  • Passing a number between 0-1 will set the volume of the player to that value.

METHOD: addClass, removeClass

addClass(classNames, selector) and removeClass(classNames, selector)

Set or remove CSS classes on the IFRAME annotation where:

  • classNames (string or array)
    classNames can be a single class e.g myAwesomeClass or an array of classes ['class1', 'class2']
  • selector (optional)
    is used to target an existing class, id, or DOM element on the player element and add the class(es) to that element. If a selector is not passed in, the class will be added to the parent div within the iframe.

selector (optional) is used to target an existing class, id, or DOM element on the player element and add the class(es) to that element.

examples:

  • hapyak.context.player.addClass('myClass', 'div#wrapper > h1)
  • hapyak.context.player.removeClass('myClass', 'div#wrapper > .exampleElement')


PROPERTY: paused

READ ONLY

var playerPaused = hapyak.context.player.paused

  • Get whether video is paused or not

PROPERTY: duration

READ ONLY

var videoLength = hapyak.context.player.paused //duration in seconds

  • returns video duration (unit: seconds)

PROPERTY: currentTime

READ / WRITE

var currentTime = hapyak.context.player.currentTime //returns time in seconds

  • can be used to Get current video time (unit: seconds)

hapyak.context.player.currentTime = 20 //will jump to 20 seconds

  • can also be used to set the current time of the video (jump to time)

PROPERTY: isEditMode

READ ONLY

hapyak.context.player.isEditMode

  • Returns true if the IFRAME is being displayed inside a HapYak editor

PROPERTY: isEditing

READ ONLY

hapyak.context.player.isEditing

  • Returns true if the IFRAME is currently being edited


Object: Annotation

IMPORTANT NOTE

In order to set properties, the iFrame must be visible. The following example is one recommended way to ensure that the iframe is shown prior to attempting a resize.

hapyak.context.addEventListener('iframeshow', function () {
  hapyak.context.width = document.body.querySelector('.hapyak-iframe-container').offsetWidth;
});

METHOD: releaseGate()

hapyak.context.releaseGate()

A gate restricts the progress of a viewer in the video, requiring that they interact with an annotation prior to continuing on. In the extension api, you must explicitly state when a gate is to be relased. To set a gate, toggle the respective option in the edit tab on the annotation to y as seen in this screenshot:

alt text

  • If the IFRAME is set to be gated, calling this method will release that gate.

PROPERTY: annotationData


READ ONLY

hapyak.context.annotationData

  • Returns list of current annotation's properties. From here we can gain access to group and project configuration elements, including group and project level css. It is good practice to maintain styling by adding your group and project level CSS to the extension. In order to return this object, you must wait for the annotation to load:
hapyak.context.addEventListener('annotationload', function(){
        console.log("annotation Data", hapyak.context.annotationData)
});

PROPERTY: width

READ / WRITE

hapyak.context.width = pixels

  • Sets or gets the width of the IFRAME element.

PROPERTY: height

READ / WRITE

hapyak.context.height = pixels

  • Sets or gets the IFRAME element.

Events

Events are accessed through event listeners on the hapyak.context object:

hapyak.context.addEventListener("event", function () {
  //do something here
});


annotationload

hapyak.context.addEventListener("annotationload", function (data) {
  console.log(data)
});
  • Emitted when the current annotation loads.

  • The object emitted by this event contains data related to the annotation, as well as group, and project configuration data.

{
top: "19.999999999999993%",
left: "20%",
width: "60%",
height: "60%",
duration: 3,
durationFormat: "seconds"
durationValue: 3
end: 6.2256
groupConfig: {gates: true, minWidth: "0", iframeTimeout: 30000}
height: "60%"
id: "iframe1560519550307"
left: "20%"
projectConfig: {css: "", title: "Extension API example"},
projectId: 284539
projectTrackId: 575497
start: 3.2256
startTimeFormat: "seconds"
startTimeValue: 3.2256
}


loadedmetadata

hapyak.context.addEventListener("loadedmetadata", function (data) {
  console.log(data)
});
  • Emitted when the HapYak metadata has finished loading.


data

hapyak.context.addEventListener("data", function (data) {
  console.log(data);
});
  • The 'data' event will fire anytime there is a change in the environment variables. This happens often. Below is an example of the object that is returned.
{
annotationIds: {1457229: true, 1457445: true, 1457474: true, 1457475: true}
annotationsLoaded: true
configuration: {gates: true, minWidth: "0", iframeTimeout: 30000,}
projectAnnotations: {1457229: {}, 1457445: {}, 1457474: {}, 1457475: {}}
projectConfig: {css: "", title: "Extension API example"}
projectId: 284539
projectName: "Extension API example"
}


iframeshow

hapyak.context.addEventListener("iframeshow", function () {
  console.log('Iframe has appeared');
});
  • Emitted when the IFRAME annotation enters its start time & is shown

timeupdate

hapyak.context.addEventListener("timeupdate", function () {
  // prints current time of video to the console
  console.log(hapyak.context.player.currentTime);
});
  • Emitted when the current video time changes, and at a regular interval while the video is playing

resized

hapyak.context.addEventListener("resized", function () {
  console.log('Player is becoming smaller');
});
  • Emitted when the player is resized relative to the window

play

hapyak.context.addEventListener("play", function () {
  console.log("Video is currently playing");
});
  • Emitted when the video begins playing

pause

hapyak.context.addEventListener("pause", function () {
  console.log('Player has been paused');
});
  • Emitted when the video becomes paused

iframehide

hapyak.context.addEventListener("iframehide", function () {
  console.log('Iframe annotation is no longer visible');
});
  • Emitted when the IFRAME annotation passes its end time & is hidden

editModeChange

hapyak.context.addEventListener("editModeChange", function () {
  console.log('Video is currently being edited');
});
  • Emitted when the edit mode is changed within the HapYak editor.

playerHover

hapyak.context.addEventListener("playerHover", function () {
  console.log('Mouse is being hovered within the player');
});
  • Emitted when a hover event occurs over the player. This event as a returned value of true or false for hovering or not hovering respectively.

Object: Tracking

hapyak.context.tracking.widgetAction(action, properties)

Allows partners to track custom analytics.

trackButton.addEventListener( "click", function () {
  hapyak.context.tracking.widgetAction('Follow', {'username': 'foobar123'});
});
  • Action: The name of the action being tracked. This can be any string.
  • Properties: Object of properties you wish to attach to this tracked action. The properties you wish to track is entirely up to you, but must be in true JSON format.
  • using the VideoJS4 Embed type provided in the share modal, you can add options to the viewer object that will allow you to see, and track your own analytics as seen below:
    <video id="hapyak-player-157199-8825"  class="video-js vjs-default-skin" width="720" height="405" playsinline="playsinline">
      <source src="https://sample.hapyak-hosted.com/group_uploads/23/16673/videos/862f7e32a9b94974b98f004ae49fa9ef/Sample-Video-with-sound.mp4" type="video/mp4"/>
  </video>
  <link rel="stylesheet" href="//vjs.zencdn.net/4.8/video-js.css">
  <script type="text/javascript" src="//vjs.zencdn.net/4.8/video.js"></script>

  <script type="text/javascript" src="//d2qrdklrsxowl2.cloudfront.net/js/hapyak.js"></script>
  <script type="text/javascript">
      (function () {
          var vjs = videojs('hapyak-player-157199-8825');

          hapyak.viewer({
              apiKey: "12345678910111213",
              projectId: 286041,
              resetVariables: true,
              player: vjs,
              videoType: "html5",
              playerType: "videojs4",
              autoplay: false,
              oncustomtrackingevent: function(data) {
                console.log("custom Data", data)
              }
          });
      })();
  </script>
  • for more information on the viewer object check out these docs

Session Variables

These variables only exists during the session… Setting variables via the Extension API is functionally equivalent to passing in a "variables" object on the Viewer.

OBJECT: hapyak.context.env

METHOD: set(name, value, temp, scope)

hapyak.context.env.set('obj', {name: "Andrew", anotherName: "Homer J Simpson"}, false, 'track');

Sets the value of the variable by name.

  • temp if true, the value will not be captured to the browser local storage. (default: false)
  • scope should be set to track to make the data available to other annotations. (default: annotation scope)
  • Variables where scope is annotation scope, there is no limitation to the data types that can be used.

Based on the example above, if we wanted to access the data from the the variable obj we could do so in a text annotation like this:

alt text

The variable would resolve after the function is called: alt text

METHOD: get(name)

  hapyak.context.env.get('name')
  • Returns the value of the variable by name.

  • set sets data asynchronously, so if you call get immediately after set and before the data event fires, the values may be different.

To return annotation data in current project:

hapyak.context.addEventListener("data", function() { //wait for data event to fire
hapyak.context.env.get('projectAnnotations')
})

METHOD: clear(name)

  hapyak.context.env.clear('name')
  • Clears the value of a single variable by name.

NOTES:

Any variables set with env.set are changed asynchronously because they need time to be communicated to the parent window. The new value will not be returned by env.get until the next "data" event fires, which should occur within a few milliseconds.

console.log(hapyak.context.env.get('myData')); //foo
hapyak.context.env.set('myData', 'bar');
console.log(hapyak.context.env.get('myData')); //foo
hapyak.context.addEventListener('data', function () {
  console.log(hapyak.context.env.get('myData')); //bar
});