Enhance Your Highcharts Funnel Presentation with Customized Labels

I am working on creating a guest return funnel that will display the number of guests and the percentage of prior visits for three categories of consumers: 1 Visit, 2 Visits, and 3+ Visits.

$(function () {
    var dataEx = [
                ['1 Visit', 352000],
                ['2 Visits',       88000],
                ['3+ Visits',       42000]
            ],
        len = dataEx.length,
        sum = 0,
        minHeight = 0.05,
        data = [];
    
    for(var i = 0; i < len; i++){
        sum += dataEx[i][1];
    }
    
    for(var i = 0; i < len; i++){
        var t = dataEx[i],
            r = t[1] / sum;
        data[i] = {
            name: t[0],
            y: ( r > minHeight ? t[1]  : sum * minHeight ),
            label: t[1]
        }
    }
    $('#container').highcharts({
        chart: {
            type: 'funnel',
            marginRight: 100,
       
          events: {
        load: function() {
          var chart = this;
          Highcharts.each(chart.series[0].data, function(p, i) {
            p.dataLabel.attr({
              x: (chart.plotWidth - chart.plotLeft) / 2,
              'text-anchor': 'middle'
            })
          })
        },
        redraw: function() {
          var chart = this;
          Highcharts.each(chart.series[0].data, function(p, i) {
            p.dataLabel.attr({
              x: (chart.plotWidth - chart.plotLeft) / 2,
              'text-anchor': 'middle'
            })
          })
        }
      },
        
       },  
      
        title: {
            text: 'Guest Return Funnel',
            x: -50
        },
        tooltip: {
            formatter: function() {
                return '<b>'+ this.key  +
                    '</b> = <b>'+ Highcharts.numberFormat(this.point.label, 0) +'</b>';
            }
        },
        plotOptions: {
            series: {
            
            allowPointSelect: true,
            borderWidth: 12,
            
            animation: {
                duration: 400
            },
            
                dataLabels: {
                    enabled: true,
                    
                    connectorWidth:0,
                    distance: 0,
                    
                    formatter: function(){
                      var point = this.point;  
                        console.log(point);
                      return '<b>' + point.name + '</b> (' + Highcharts.numberFormat(point.label, 0) + ')'; 
                    },                
                    minSize: '10%',
                    color: 'black',
                    softConnector: true
                },
                
                neckWidth: '30%',
                neckHeight: '0%',
                width: '50%',
                height: '110%'
                
            }
        },
        legend: {
            enabled: false
        },
        series: [{
            name: 'Unique users',
            data: data
        }]
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/funnel.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>

<div id="container" style="width: 600px; height: 400px; margin: 0 auto"></div>

Currently, my funnel displays the number of guests for each category with center alignment. A preprocessing algorithm is used to visualize small values effectively in the final result.

I want to include the percentage of prior visit values in the funnel but I am unsure how to incorporate this into the existing data format for the series I am using, and I have concerns about compatibility with the data preprocessing algorithm.

I also aim to modify the tooltip to show specific information when hovered over (ignore the red color).

Your assistance would be greatly appreciated.

Answer №1

If I followed correctly, it is indeed possible to utilize your current data processing algorithm to achieve the desired outcome. This can be accomplished by rounding the calculated percentage value and assigning it to a new parameter in the point object within your code:

for (var i = 0; i < len; i++) {
  var t = dataEx[i],
  r = t[1] / sum;
  data[i] = {
    name: t[0],
    y: (r > minHeight ? t[1] : sum * minHeight),
    percent: Math.round(r * 100),
    label: t[1]
  }
}

Subsequently, you can access this rounded percentage value in both your tooltip and data labels formatter functions:

Tooltip formatter:

tooltip: {
   formatter: function() {
     return '<b>' + this.key +
       '</b><br/>Percent of Prior Visit: '+ this.point.percent + '%<br/>Guests: ' + Highcharts.numberFormat(this.point.label, 0);
   }
},

Data labels formatter:

formatter: function() {
   var point = this.point;
   console.log(point);
   return '<b>' + point.name + '</b> (' + Highcharts.numberFormat(point.label, 0) + ')<br/>' + point.percent + '%';
}

To ensure proper alignment of the dataLabels in the vertical position and center them, the following adjustment needs to be implemented:

chart: {
 type: 'funnel',
 marginRight: 100,
 events: {
   load: function() {
     var chart = this;
     Highcharts.each(chart.series[0].data, function(p, i) {
       var bBox = p.dataLabel.getBBox()
       p.dataLabel.attr({
         x: (chart.plotWidth - chart.plotLeft) / 2,
         'text-anchor': 'middle',
         y: p.labelPos.y - (bBox.height / 2)
       })
     })
   },
   redraw: function() {
     var chart = this;
     Highcharts.each(chart.series[0].data, function(p, i) {
        p.dataLabel.attr({
          x: (chart.plotWidth - chart.plotLeft) / 2,
          'text-anchor': 'middle',
          y: p.labelPos.y - (bBox.height / 2)
        })
      })
    }
  },
}

For a live demonstration, please visit: http://jsfiddle.net/yzx46p38/

Sincerely!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Modify the button input value within a PHP script

I am currently working on a piece of code that involves following different users and inserting values from a MySQL table. <td align="center"> <input type="button" name="<?php echo $id; ?>" id="<?php ech ...

What sets local Node package installation apart from global installation?

My curiosity sparked when I began the process of installing nodemon through npm. Initially, I followed the recommended command and noticed the instant results displayed on the right side of my screen: npm i nodemon This differed from the installation ins ...

Conceal the div by clicking outside of it

Is there a way to conceal the hidden div with the "hidden" class? I'd like for it to slide out when the user clicks outside of the hidden div. HTML <!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.c ...

Retrieve information from the table and display it in a reverse order

Below is a link to view the table in my database: click here I want to retrieve and display the names of users whose user_group is "member". I plan to put their ratings in an array and then print their names in descending order based on their rating. For ...

What is the best way to send an array of objects to a Jade template?

I'm looking to retrieve an array of objects from MongoDB and pass it to the client... Here is an example object: var objeto_img= { name:'name of the file', ...

Are there any JavaScript libraries available that can mimic SQLite using localStorage?

My current application makes use of SQLite for storage, but I am looking to switch it up to make it compatible with Firefox and other browsers. I've been considering localStorage as an option. However, I've noticed that localStorage lacks some o ...

The wells are surpassing the line

I'm attempting to arrange 3 Wells horizontally in one row, as shown below <div class="row" style="margin-top: 10px"> <div class="span4 well"> <h3 class="centralizado"><img src="/assets/temple.png" /> & ...

How can React and Redux ensure that response data is accessible to every component?

When using react and redux, how can data written in the useDispatch function be made available in other components? Additionally, how can the customerId be accessed in all components? I have created a code that calls an API and returns data in response. I ...

Laravel's routing system may cause complications when trying to send data via jQuery AJAX post requests

My current challenge involves passing an ID to a PHP script through AJAX. Previously, everything was working perfectly with the code snippet below: var baseURL = '/W4W/public/'; function voteUp(){ var snippetID = document.getElementById(&ap ...

Searching for an identification using jQuery within a th:each loop

Hey everyone, I'm facing a challenge with my HTML code that uses th:each (spring) to create a list of divs. I need to be able to select a specific button within these divs that opens a bootstrap modal. The modal should display the values of the select ...

Modify the text in a paragraph by clicking on a link using JQuery and HTML

I'm attempting to implement a straightforward action, but I'm facing some challenges. My navigation bar consists of a few links followed by a text section. What I aim for is that when I click on a link, the paragraph of text should change to refl ...

Guide on using a pipe feature with varying arguments when the main function is called

I am delving into functional programming for the first time and have a query regarding using pipes. Imagine I have this particular function: const updateArray = R.curry((index, value, array) => Object.assign([], array, {[index]: v ...

The animation unexpectedly resets to 0 just before it begins

Currently, I am developing a coverflow image slider with jQuery animate. However, there are two issues that I am facing. Firstly, when the animation runs for the first time, it starts at `0` instead of `-500`. Secondly, after reaching the end and looping b ...

Using Selenium to handle asynchronous JavaScript requests

Having recently started working with Selenium and JavaScript callback functions, I've encountered a problem that I can't seem to solve on my own. My issue revolves around needing to retrieve a specific variable using JavaScript. When I manually i ...

I'm working on a CSS project and my goal is to ensure that all the items are perfectly aligned in a

I have been working on a ReactJS code and I'm struggling to achieve the desired result. Specifically, I am using Material UI tabs and I want them to be aligned in line with an icon. The goal is to have the tabs and the ArrowBackIcon in perfect alignme ...

Converting yard values to meter values using AngularJS: A comprehensive guide

My task is to convert meter values to yard using two dropdowns. The first dropdown contains various values, while the second dropdown has "meter" and "yard" options. If "meter" is selected in the second dropdown, the values in the first dropdown remain unc ...

Issue: NextRouter is not mounted when the client is used

After implementing use client, I encountered the following error: Error: NextRouter was not mounted error. However, upon removing use client, a different error surfaced: Error when use client is removed: ReactServerComponentsError: A component requirin ...

What is the best way to perform a redirect in Node.js and Express.js following a user's successful login

As I work on developing an online community application with nodejs/expressjs, one persistent issue is arising when it comes to redirecting users to the correct page after they have successfully signed in. Despite reading several related articles and attem ...

What is the method to implement timeago.js?

I've recently embarked on my journey to learn JavaScript, and it has only been two weeks since I started. As a beginner, I'm encountering some difficulties with implementing timeago from . The specific line of instruction that's giving me tr ...

How to use Angular 2 to communicate with JavaScript API whenever the router switches to

I am currently working on an Angular2 component that has a template which relies on JavaScript calls to load various components such as Facebook, Google Maps, and custom scripts. The necessary scripts are already loaded in the index.html file, so all I ne ...