DEV Community

Simon László
Simon László

Posted on

Customizing Vizzu Charts - Mouse-wheel zooming

Adding mouse-wheel zooming to a Vizzu chart in JavaScript can be useful for users who want to zoom in and out of a dense chart. In this how-to, we will create a Zoomer class that will handle the zooming functionality and then add event listeners to the Vizzu chart to connect the events to our Zoomer instance. And then, we will improve its performance by adding throttle to the zoom event calls.

Here are the steps to add mouse-wheel zooming over a Vizzu chart in JavaScript:

Step 1: Import Vizzu and data

First, we need to import the Vizzu library and an example data set as well, which we will visualize:

import Vizzu from 'https://cdn.jsdelivr.net/npm/vizzu@latest/dist/vizzu.min.js';
import { data } from 'https://lib.vizzuhq.com/0.7/assets/data/chart_types_eu.js'  
Enter fullscreen mode Exit fullscreen mode

Step 2: Create the chart

We can create the chart using the following code:

let chart = await (new Vizzu('vizzu-container', { data })).initializing;
Enter fullscreen mode Exit fullscreen mode

This creates a new Vizzu chart instance with the provided data.

Step 3: Initialize the Chart with Zoom Range

Next, we create a line chart with an initial x-axis range.

chart.animate({
  config: {
    x: {
      set: 'Year',
      range: {
        min: 0.5,
        max: 20.5
      }
    },
    y: 'Value 5 (+/-)',
    geometry: 'line'
  }
}, 0);
Enter fullscreen mode Exit fullscreen mode

Now that we have a static chart, we can add the zoom functionality.

Step 4: Create the Zoomer class and instance

The Zoomer class will be used to track the zoom level of the chart:

class Zoomer {
  constructor(min, max) {
    this.min = min;
    this.max = max;
    this.finalMin = min;
    this.finalMax = max;
    this.pos = null;
  }

  trackPos(pos) {
    this.pos = pos;
  }

  zoom(factor) {
    let ref = this.min + this.pos * (this.max - this.min);
    this.min = ref - (1 + factor) * (ref - this.min);
    this.max = ref + (1 + factor) * (this.max - ref);
    if (this.min < this.finalMin) this.min = this.finalMin;
    if (this.max > this.finalMax) this.max = this.finalMax;
  }
};
Enter fullscreen mode Exit fullscreen mode

The constructor takes the initial minimum and maximum value of the x-axis range. The trackPos method is used to track the mouse position, and the zoom method is used to zoom in or out based on the mouse wheel delta.

Now, we can create a new Zoomer instance with an initial zoom range of 0.5 to 20.5:

let zoomer = new Zoomer(0.5, 20.5);
Enter fullscreen mode Exit fullscreen mode

Step 5: Add event listeners to the chart

We need to add event listeners to the chart to detect mouse-wheel and mouse-move events and prevent the default scroll event on the container element:

let container = document.getElementById('vizzu-container');

container.addEventListener('wheel', event => {
  event.preventDefault();
})

chart.on('wheel', event => {
  // Zoom event handling
});

chart.on('mousemove', event => {
  // Mouse move event handling
});
Enter fullscreen mode Exit fullscreen mode

Step 6: Handle the Zoom Event

When a zoom event is triggered, we update the zoom level using the Zoomer object and trigger an animation to update the chart with the new zoom range.

chart.on('wheel', event => {
  zoomer.zoom(- event.data.delta / 200);
  chart.animate(
    { x: { range: {
      min: zoomer.min,
      max: zoomer.max
    } } },
    { duration: '50ms', easing: 'linear' });
});
Enter fullscreen mode Exit fullscreen mode

Step 7: Handle the Mouse Move Event

When a mouse move event is triggered, we update the position of the Zoomer object to reflect the current mouse position.

chart.on('mousemove', event => {
  zoomer.trackPos(event.data.coords.x);
});
Enter fullscreen mode Exit fullscreen mode

With these steps in place, your Vizzu chart should now be able to handle mouse-wheel zooming events. However, you will notice that zooming events can be called before the chart animation can finish, delaying the zoom effect. To prevent this behavior, we will need to throttle the zoom call.

Step 8: Create the Throttle class

The Throttle class will be used to limit the number of zoom events that are processed at any given time.

class Throttle {
  constructor() {
    this.finished = true;
    this.next = null;
  }
  call(func) {
    if (!this.finished) {
      this.next = func;
      return;
    }
    else {
      this.finished = false;
      func().then(() => {
        this.finished = true;
        if (this.next !== null) {
          let f = this.next;
          this.next = null;
          this.call(f);
        }
      })
    }
  }
}

let throttle = new Throttle();
Enter fullscreen mode Exit fullscreen mode

The call method takes a promise-returning function as an argument and calls it if the promise returned by the previous function has resolved. Otherwise, it stores the function and waits for the current function's promise to finish.

Step 9: Adding the throttle to the Zoom Event

We can now modify the zoom event to call the zoom method via our new throttle instance:

chart.on('wheel', event => {
  zoomer.zoom(- event.data.delta / 200);
  throttle.call(() =>
    chart.animate(
      { x: { range: {
        min: zoomer.min,
        max: zoomer.max
      } } },
      { duration: '50ms', easing: 'linear' })
  );
});
Enter fullscreen mode Exit fullscreen mode

With these additional steps, your Vizzu chart can handle mouse-wheel zooming events flawlessly.

Working example:

Top comments (0)