Custom Modules

Overview

There are two different types of modules in ZingChart: chart type modules and plugin modules. Chart type modules are initialized by the value of the type attribute in the graph object. Plugin modules are initialized through the use of the modules option in the zingchart.render() method.

With each of these custom module types, the idea is similar: modify the original JSON, add event listeners, and define options for your custom module.

Define a module using the defineModule() method:

zingchart.defineModule(String name, String type, Function callback);

Parameters

Parameter Type Values Details
name String N/A Required. User defined string to use as the name for the module.
type String "chart"|"plugin" Required. Determines the type of the module. A module of type "chart" will be used when the value of a chart object's type attribute matches that of the module name. A module of type "plugin" will be used when there is an object within the chart JSON that matches the plugin name.
callback Function N/A Required. User defined function that is used to manipulate the original chart JSON, define options, and add event listeners. This function receives the original chart JSON of the chart using the custom module. This function must return the modified version of the original chart object, or an entirely new object altogether.

Note: Module definitions can be placed within your HTML page, or in a separate zingchart-[MODULE NAME].min.js file.

Defining a Chart Type Module

To define a module that will serve as a standalone chart type, set the defineModule type parameter to chart. Be sure to pass a single argument to your function. This argument will allow you to gain access to the chart configuration object that makes use of your custom module.

Example

/** 
 * Perform JSON manipulation on the originalJson object, define options, 
 * and add event listeners here.
 */
zingchart.defineModule('hello-world', "chart", function (originalJson) {
  return originalJson; // Modified version of originalJson
});

When defined in this way, any chart object that uses the module name as the value for the type attribute will apply this module's logic.

zingchart.render({
  id: 'myChart',
  height: 400,
  width: 600,
  data: {
    type: 'hello-world'
  }
});

View all of the options on the Defining Chart Type Module Options page.

Defining a Plugin Module

To define a module that will serve as a plugin, set the defineModule type parameter to plugin. Be sure to pass a single argument to your function. This argument will allow you to gain access to the chart configuration object that makes use of your custom module.

Example

/** 
 * Perform JSON manipulation on the originalJson object, define options, 
 * and add event listeners here.
 */
zingchart.defineModule('hello-world', "plugin", function (originalJson){
  return originalJson; // Modified version of originalJson
});

Plugin modules must be explicitly loaded using the modules option in the render method. When defined in this way, any chart that contains an object of the plugin name will apply this module's logic.

zingchart.render({
  id: 'myChart',
  height: 400,
  width: 600,
  modules: 'hello-world', // Load the module
  data: {
    type: 'bar',
    'hello-world': {}
  }
});

JSON Manipulation

For both chart type modules and plugin modules, JSON manipulation is handled the same way. In the example below, originalJson is the chart object containing a chart with the matching type attribute (since this is a chart type module). If this were a plugin module, originalJson would be the chart object containing the hello-world object in the top level of the chart JSON. Perform your JSON manipulation on the originalJson object, taking the steps necessary to prevent data obliteration!

Chart Type Example

zingchart.defineModule('hello-world', "chart", function (originalJson) {
  /* Create our hello world label */
  var helloWorldLabel = {
    text: "Hello, world!",
    id: "label1",
    height: "60%",
    width: "80%",
    x: "10%",
    y: "20%"
  };
  /* 
   * The ?: ternary operation is used here to check for existing labels in the originalJson object. 
   * If a labels array exists, the label is pushed into it,
   * otherwise, it is placed into a new array.
   */
  originalJson[ "labels" ] ?
    originalJson[ "labels" ].push(helloWorldLabel) :
    originalJson[ "labels" ] = [helloWorldLabel];

  return originalJson;
});

If you are using a graphset array with multiple chart objects, the defineModule method will automatically loop over each object in the array, applying your module's logic to only the chart objects that use the custom module.

Defining Chart Type Module Options

While you can define options in a number of ways, we recommend placing options for a chart type module in an options object at the graph level. For example,

{
  type: 'hello-world',
  options: {
    universe: true
  }
}

Now to define our boolean universe attribute in our chart type module definition:

zingchart.defineModule('hello-world', "chart", function (originalJson) {
  /* Previously shown code omitted for brevity */

  /* Check for the existence of the options object */
  if (originalJson[ "options" ]) {

    /* It exists! Instantiate oOptions as the object containing our custom options. */
    var optionsObj = originalJson[ "options" ];

    /* Check for universe: true, find our label and modify it if true */
    if (optionsObj[ "universe" ]) {
      for (var n = 0; n < originalJson[ "labels" ].length; n++) {
        if (originalJson[ "labels" ][n][ "id" ] == "label1") {
          originalJson[ "labels" ][n] = "Hello, UNIVERSE!";
        }
      }
    }
  }
  return originalJson;
});

Defining Plugin Module Options

For a plugin module, check the plugin object for options, instead of checking for an options object:

zingchart.defineModule('hello-world', "plugin", function (originalJson) {
  /* Previously shown code omitted for brevity */

  /* Instantiate oOptions as the plugin object */
  var optionsObj = originalJson[ 'hello-world' ];

  /* Check for universe: true, find our label and modify it if true */
  if (optionsObj[ "universe" ]) {
    for (var n = 0; n < originalJson[ "labels" ].length; n++) {
      if (originalJson[ "labels" ][n][ "id" ] == "label1") {
        originalJson[ "labels" ][n] = "Hello, UNIVERSE!";
      }
    }
  }
  return originalJson;
});

Adding Event Listeners

If you want to make your module interactive, event listeners are a must. For example, if you added shape objects for some kind of toolbar during the JSON manipulation phase, you'll need to set up event listeners to allow the user to interact with your toolbar. Here, we add a label_click event listener to our module:

zingchart.defineModule('hello-world', "chart", function (originalJson) {
  /* Previously shown code omitted for brevity */

  zingchart.bind(null, 'label_click', function (chartObj) {
    if (chartObj.graphid == "helloworld0") {
      console.log('What? What do you want?');
    }
  });
  return originalJson;
});

Notice that comparison between chartObj's graphid value and helloworld0? The defineModule() method generates an ID for a chart type module, using the name of the module itself (with hyphens removed) and the index of the chart object in the graphset. So, if you have a module called my-first-module at index 0 in your graphset (or it's just a lone chart object not in a graphset), defineModule() will generate and apply an ID called myfirstmodule0. You can use this to increase event specificity in your charts, as we have done above.

Minifying Your Script

We recommend using UglifyJS for the minification of the library.

To use as a command line app, install using NPM:

npm install uglify-js -g

Then define the UglifyJS options in the command line as follows:

uglifyjs [input file] [options]

If the defineModule code is placed in a standalone file instead of directly in the HTML document, you may output the minified source to a separate file (UglifyJS defaults to STDOUT):

uglifyjs zingchart-hello-world.js --compress --output zingchart-hello-world.min.js

View further details of UglifyJS on GitHub.

Examples

The following two demos may look identical on the surface, but if you dive into the code used to create each one of these custom modules, you'll soon discover the difference between the two.

Custom Chart Type Module

Custom Plugin Module

https://app.zingsoft.com/demos/embed/FJB8TBKD
https://app.zingsoft.com/demos/embed/FJB8TBKD

Custom Zoom Module

https://app.zingsoft.com/demos/embed/5J2NFY6W
https://app.zingsoft.com/demos/embed/5J2NFY6W

GitHub Examples

We also have a full example of a Distributed Weighted Average module for you to use as a reference guide for writing custom modules. You can see the code and a usage guide on our GitHub.

https://app.zingsoft.com/demos/create/4DIK5BAJ
https://app.zingsoft.com/demos/create/4DIK5BAJ

Summary

Custom modules allow you to create and reuse your own ZingChart chart types and features. See our list of ZingChart modules before building your own - we might already have it!