Close More (Vert) Close

I use Google Analytics daily. One amazing feature I wanted to emulate for myself was the ability to add annotations to charts. This tutorial will cover how to add basic annotations to ZingChart using JavaScript.

We have been covering using ZingChart's API in the past few blog posts. Check them out below to get caught up:

  1. Changing Data Sets With Drop-Downs

  2. Setting Crosshairs With JavaScript Range Sliders

HTML

This demo was created with the ZingChart selection tool module. The selection tool allows you to exhibit an active state to each node clicked on (aka changes the node color when clicked on). To include the module, add this script to your header:

<script src="cdn.zingchart.com/modules/zingchart-selection-tool.min.js"></script>  

To start this demo out, we're going to need a normal <div> with an ID so we can reference this later in our CSS & JavaScript.

We will also need a <form> element with two <input> elements. One will take the type of "text" for a text field & the other will take the type of "submit" for a submit field. This will be where we submit our annotations.

<div id="myChart">
  
  <form id="addNote">
    <input type="text">
    <input type="submit">
  </form>
  
</div>

CSS

There are three significant sections to our CSS:

First, we need to define a height & width to our chart container <div>. Our chart will not render otherwise.

#myChart {
  height: 500px;
  width: 600px;
}

Second, our form <form id="addNote"> will need to be hidden by default (we will make it visible later upon node click). We can use opacity to do so:

#addNote {
  opacity: 0;
}

We also want our form <form id="addNote"> to have a class of 'open' in our CSS. We can dynamically add this class with JavaScript later (will occur when a user clicks a node). This 'open' class will have an opacity value of 1 to make our form <form id="addNote"> visible.

#addNote.open {
  opacity: 1;
}

JavaScript

Our JavaScript will start inside of our chart configuration. We mentioned the selection tool module earlier. To use this, we will need to add two attributes into our plot attribute:

plot: {
    selectionMode: 'multiple',
    selectedState: {
      backgroundColor: 'black'
    }
  }

selectionMode: 'multiple' defines the ability to select multiple nodes. Within selectedState we are able to define a backgroundColor of our selected nodes.

The next step will be to store our chart render method in a variable. This will allow us to "bind" ZingChart events to our chart in a legible fashion.

var chart = zingchart.render({
  id: "myChart",
  data: myConfig
});

There are two very important parts of this demo. One happens on a chart node click & the other happens when we submit text to our form element for an annotation.

Chart Node Click Function

In this node click function, we will store chart x and y coordinates from our chart node (we will use this to position our annotation later) into variables & add a class of "open" to our form element to make it visible.

We are going to start by grabbing our form element from the DOM.

// Grabs the <form> element from the DOM
var form = document.querySelector('#addNote');

Next, we will define two variables xValue & yValue to store our node x and y coordinates in.

/ Creates variables that will hold node_click x & y coordinates
var xValue = 0;
var yValue = 0;

Finally, we will add our function. We can use the "chart" variable we created from our render method earlier.

We will bind this variable to a ZingChart API event. There is a built-in 'node_click' event built into ZingChart we can use. This ZingChart API event will take a callback function, which will take in an event (e) as a parameter. This is structured almost identically to adding event listeners. The node_click event (e) will give us information about our nodes including x and y coordinate values (if specified).

This function will create two variables: nodeValueX & nodeValueY. These two values will take in the x and y coordinate values of our node_click event.

We will then re-assign these values to our original xValue & yValue variables so that we can use them for our annotation position later. Finally, this function will also use classList.add to add a class of "open" to our <form> element.

chart.bind('node_click', function(e) {
  // These variables store node_click event (e) x and y coordinates
  var nodeXValue = e.x;
  var nodeYValue = e.y;
  // Re-assigns variables to original xValue and yValue variables
  xValue = nodeXValue;
  yValue = nodeYValue;
  // Adds open class to our <form> element
  form.classList.add('open');  
}); 

Form Submit Function

We grabbed the <form> element from the DOM earlier. We will now be attaching an event listener to fire a function on the "submit" event. Four major things will happen when a user submits the <form> element:

  1. Preventing a <form> submit without a value using e.preventDefault().

  2. Grabbing the <input> text value from the DOM & assigning it to a variable.

  3. Creating an annotation with the zingchart.exec() API method. Using the built-in 'addobject' method, we can add and style a ZingChart label object as our annotation. This label will take in the x & y coordinate variables we created upon node_click earlier. This ensures our label is added to the node clicked.

  4. Removing the "open" class from our <form> element using classList.remove()

// This event listener function fires when our <form> element is submitted
form.addEventListener('submit', function(e) {
  // Prevents a <form> element submit without a value
  e.preventDefault();
  // Grabs the <input> text value from the DOM and assigns to a variable
  var note = form.querySelector('input[type="text"]').value;
  // Creates a ZingChart label object from the <input> text value submitted 
  zingchart.exec('myChart', 'addobject', {
    type: 'label',
    data: {
      text: note,
      x: xValue,
      y: yValue,
      backgroundColor: '#eee',
      padding: [10, 25],
      borderRadius: 4,
    }
  });
  // Removes open class form <form> element
  form.classList.remove('open');
})

Final Result

comments powered by Disqus