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).

https://i.sstatic.net/jjAT0.png

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

Is it possible to convert checkbox values from a form into a JSON format?

HTML snippet : <form class="form-horizontal" id="addpersons" style="padding:20px;"> <fieldset class="scheduler-border"> <!-- Form Title --> <legend class="scheduler-border">Information</legend> <!-- First Name input-- ...

Curved Edges Ensure Non-Interactive Elements

element, there is a query about utilizing a color wheel from a repository on GitHub. The goal is to disable any actions when clicking outside of the canvas border radius in this color wheel. Various steps need to be taken to prevent unwanted outcomes: - S ...

Determine in AngularJS whether there is a checked checkbox in a table row

Here is my HTML code snippet: <tbody ng-repeat="notification in notifications"> <tr> <td rowspan="{{notification.specs.length+1}}">{{notification.notification_id}}</td> </tr> <tr ng-repeat="position in ...

Reordering an action button on the WooCommerce My Account Orders page

How can I ensure that a specific action button remains at the top of the list on the WooCommerce My Account Orders page? I have a plugin that adds a "track" button once an order is shipped, and I want this button to always appear first in the list, even t ...

Can a class be passed to the binding attribute in Angular framework?

We currently have a system in place that is dependent on a numeric value being set to either 1 or 2 in order to display specific icons. This method is functional. <span *ngIf="config.icon" [class.fas]="true" [class.fa-plus]="icon===1" ...

Attempting to retrieve and save data in a variable using React Native

click here for image referenceI am a beginner in react-native and I recently attempted to use fetch to access an API. While I successfully managed to print the result on the console, I encountered difficulty in displaying it on a mobile screen. Below is a ...

Send an object to query when using Router.push in Next.js

Just getting started with NextJs and I'm experimenting with passing an object to another page through a component. Let me show you the code and explain what I'm attempting to accomplish: The object I want to pass looks like this: objectEx = { ...

Executing a script that has been inserted into the page post-loading

I'm facing an issue where the script tag at the bottom of my project is not being executed after adding new pages later on. Main const fetch = (url, call) => { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if ...

Unusual behavior in a for loop with node.js

Trying out some new things with node.js and running into issues with a basic for loop... for (var i = 0; i < 5; i++); {( console.log(i)) } Can anyone explain why I'm seeing 5 in the console? I was anticipating 0,1,2,3,4... ...

Exploring the capabilities of CasperJS through double clicking

I'm currently working on creating a bot using CasperJS. The main goal is for the bot to send trade offers by offering an item, but I'm facing difficulties in figuring out how to click on the item. I attempted to use Resurrectio, however, it' ...

Is it possible to bind computed values in Ember using .properties(...) with ember-model?

I'm attempting to utilize the .property('key') syntax in order to update a computed value within my model. The structure of my model is as follows: App.Camera = Em.Model.extend({ id: attr(), uid: attr(), name: attr(), type: ...

What is the process for enabling the experimental-modules option when running an npm package's bin command?

Beginning with Node v8.5.0, the support for ES6 style modules has been introduced. import x from 'x' You can access this feature by running node using the --experimental-modules option, like so: node --experimental-modules test.mjs By utilizi ...

Is there a way to modify controller properties and values externally?

Just starting out with ember.js and encountering an issue. Once a form is submitted, jQuery sends a POST request (which is successful). However, I need the success function to update "val1" to "newVal". Any suggestions on how to achieve this? HTML: < ...

What is the most efficient way to cycle through HTML image elements and display a unique random image for each one?

I'm currently working on coding a simple game that involves guessing the Hearthstone card based on its flavor text. I plan to add a button later to progress in the game, but I haven't implemented that yet. To start, I created 4 image elements an ...

What is the best way to ensure an SVG maintains a fluid width while keeping its height constant?

My goal is to achieve the following: The SVG should dynamically scale its width to occupy 100% of the container's width. The SVG should either stretch or compress when the container's width changes, specifically affecting the wave drawn wit ...

Can someone provide a list of events for the .on function in Vanilla NodeJS?

Currently experimenting with NodeJS by testing basic backend functionalities like sending various HTTP requests from my index.html file to the server.js file. I plan to delve into Express soon. I've noticed a lack of documentation on NodeJS 'eve ...

The ultimate guide to personalizing group titles in Angular UI-Select

Is there a way in Angular ui-select to customize the group label? I want to make it larger than the selection items as shown in the image below. https://i.stack.imgur.com/ofcak.png The list is currently grouped by country, but how can I adjust the size o ...

Updating token (JWT) using interceptor in Angular 6

At first, I had a function that checked for the existence of a token and if it wasn't present, redirected the user to the login page. Now, I need to incorporate the logic of token refreshing when it expires using a refresh token. However, I'm enc ...

Using Jquery to open a dialog box and then utilizing ajax to trigger the opening of

Currently experiencing some difficulties with jQuery and AJAX in trying to open a second dialog box within another dialog box. Below is the jQuery code: $( "#dropdownuser" ).dialog({ autoOpen: false, show: "blind", height : 600, ...

using javascript to animate multiple div elements

In my current project, I am harnessing the power of Javascript to incorporate some eye-catching animation effects on a rectangle. Once the animation is complete, I have set the box to disappear from view. Check out the code snippet below for more details: ...