Skip to content
Simon Brent edited this page Mar 8, 2022 · 1 revision

Almost all functions in Genoverse, Genoverse.Track, Genoverse.Track.Controller, Genoverse.Track.Model, and Genoverse.Track.View are wrapped so that when they are called, what actually happens is that the wrapper is called instead.

This wrapper calls a before and after hook for each function call, so that if, for example, the function track.foo('a', 'b', 'c') is called, what actually happens is:

() => {
  track.beforeFoo('a', 'b', 'c');

  const returnValue = track.foo('a', 'b', 'c');

  track.afterFoo('a', 'b', 'c');

  return returnValue;
}

Note that returnValue is not passed to the after hook, and that returned anything from either the before or after hook has no effect.

An example of how to use these hooks could be:

const saveConfigToDB = () => { /* send a request to the server, outside the scope of Genoverse */ }

Genoverse.extend({
  afterSaveConfig: function () {
    saveConfigToDB(window[this.storageType].getItem(this.saveKey))
  },
  tracks: [
    Genoverse.Track.extend({
      beforeInsertFeature: function (feature) {
        feature.decorations = true; // Add properties which are not present in the server response for getting data
      },
      decorateFeature: () => { /* draw some decoration */ }
    })
  ]
});

Because Genoverse uses Base.js, the above code can also be written in the following way:

Genoverse.extend({
  saveConfig: function (...args) {
    const returnValue = this.base(...args);

    saveConfigToDB(window[this.storageType].getItem(this.saveKey))

    return returnValue;
  },
  tracks: [
    Genoverse.Track.extend({
      insertFeature: function (feature, ...args) {
        feature.decorations = true; // Add properties which are not present in the server response for getting data

        return this.base(feature, ...args);
      },
      decorateFeature: () => { /* draw some decoration */ }
    })
  ]
});

It is usually preferable, in fact, to overwrite functions and use this.base() instead of using before and after hooks, because of the limitations around accessing returnValue discussed above. However, in the case where the function does not return a value, or code to be executed after a function does not depend on that function's return value, hooks are a simpler way of expressing the additional code.

Hooks can also be added to Genoverse and its tracks after they have been created, using genoverse.on, for example:

const genoverse = new Genoverse({ ... });

genoverse.on('afterAddTracks', () => { /* some code */ });
genoverse.on('beforeSetScale', () => { /* some code */ }, 'tracks');