If you don't already know, enigma.js is an open source library for communicating with Qlik Sense backend services. The QIX Service of enigma.js provides an API to communicate with a QIX Engine, giving you the ability to build applications powered by Qlik.

 

Vega calls itself a visualization grammar. It is a declarative language for creating visualizations. You just describe the appearance and behavior of the visualization you want to create, and Vega does the rest. And it can render with canvas, avoiding costly dom manipulations.

 

I'm going to demonstrate using enigma.js and Vega to create a simple bar chart. I'll be reusing the qApp.js module and qSessionObject class I introduced in Getting started with enigma.js, so check that out first if you haven't already.

 

Getting Setup

You can review Getting started with enigma.js, and follow the "Setup", "Connecting to an app", and "Creating Session Objects" sections. You'll also want to load jQuery and Vega (https://cdnjs.cloudflare.com/ajax/libs/vega/3.0.0-beta.25/vega.min.js).

 

Alternatively, you can download the getting-started.zip file below. The getting-started.zip file includes package.json and webpack.config.js files, the qApp.js and qSessionObject.js files, as well as an index.html file, and a main.js file. There's also a .qext file, in case you want to use Qlik Sense as your server for your static files.

 

For this demonstration, I'm using fields from the Helpdesk Management app, so make sure your qApp.js file is connecting to a copy of the Helpdesk Management app.

 

The Project

Now that you're setup, we can start the project. We'll do everything in main.js for this demonstration. So open up main.js. We'll need to import qSessionObject.js and create our session object.

import qSessionObject from "./qSessionObject";

let chartCube = new qSessionObject({
  qInfo: {
    qType: "visualization"
  },
  qHyperCubeDef: {
    qDimensions: [{
      qDef: {
        qFieldDefs: ["[Case Owner Group]"]
      },
      qNullSuppression: true
    }],
    qMeasures: [{
      qDef: {
        qDef: "Avg([Case Duration Time])"
      }
    }],
    qInitialDataFetch: [{
      qWidth: 2,
      qHeight: 1000
    }]
  }
});






 

Now that our qSessionObject has been created, let's define the Vega spec for our bar chart. The spec is roughly based on the spec from Vega's tutorial Vega: Let's Make A Bar Chart Tutorial, so feel free to check that out if you like. I simplified it a bit, and removed the data values so that we can stream the values in using data returned from enigma.js. It looks like this:

let barchartSpec = {
  "$schema": "https://vega.github.io/schema/vega/v3.0.json",
  "width": 400,
  "height": 200,
  "padding": 5,
  "data": [
    {
      "name": "table"
    }
  ],
  "scales": [
    {
      "name": "xscale",
      "type": "band",
      "domain": {"data": "table", "field": "category"},
      "range": "width"
    },
    {
      "name": "yscale",
      "domain": {"data": "table", "field": "amount"},
      "nice": true,
      "range": "height"
    }
  ],
  "axes": [
    {
      "orient": "bottom",
      "scale": "xscale",
      "encode": {
        "labels": {
          "update": {
            "angle": {"value": -50},
            "align": {"value": "right"},
            "baseline": {"value": "middle"},
            "radius": {"value": -2}
          }
        }
      }
    },
    {
      "orient": "left",
      "scale": "yscale"
    }
  ],
  "marks": [
    {
      "type": "rect",
      "from": {"data":"table"},
      "encode": {
        "enter": {
          "x": {"scale": "xscale", "field": "category", "offset": 1},
          "width": {"scale": "xscale", "band": 1, "offset": -1},
          "y": {"scale": "yscale", "field": "amount"},
          "y2": {"scale": "yscale", "value": 0}
        },
        "update": {
          "fill": {"value": "steelblue"}
        },
        "hover": {
          "fill": {"value": "red"}
        }
      }
    }
  ]
}





 

With our qSessionObject and our bar chart spec created, we can create the bar chart. After the dom is ready, we'll initialize the Vega view (Vega: View API), open the qSessionObject, get the layout of the qSessionObject, reformat the matrix to work with Vega, insert the values into our Vega view, setup updating the Vega view when the qSessionObject changes, and add an event listener to the Vega view to enable selections. It all looks like this:

$(() => {

  //initialize vega view
  let view = new vega.View(vega.parse(barchartSpec))
    .renderer('canvas')
    .initialize('#view')
    .hover();

  //open cube
  chartCube.open().then(() => {

    //get object layout and insert data into vega view
    chartCube.object.getLayout().then((layout) => {
      let values = layout.qHyperCube.qDataPages[0].qMatrix.map((row) => {
        return {"category": row[0].qText, "qElemNumber": row[0].qElemNumber, "amount": row[1].qNum}
      });
      view.insert('table', values).run();
    });

    //when object data changes, update data in vega view
    chartCube.object.on("changed", function() {
      chartCube.object.getLayout().then((layout) => {
        let values = layout.qHyperCube.qDataPages[0].qMatrix.map((row) => {
          return {"category": row[0].qText, "qElemNumber": row[0].qElemNumber, "amount": row[1].qNum}
        });
        view.remove('table', (d) => { return true; }).run();
        view.insert('table', values).run();
      });
    });

    //add event listener to make selections on hypercube when a bar is clicked
    view.addEventListener('click', function(event, item) {
      if(item){
        chartCube.object.selectHyperCubeValues("/qHyperCubeDef", 0, [item.datum.qElemNumber], true);
      }
    });

  });
});




 

And that's it. Don't forget npm run webpack, and check out the results. Here's what it should look like - Vega bar chart.

I've attached the full project in case you'd prefer to just download that and play around too.