javascripthighchartsdiagram

How to customize Highcharts Euler diagram?


I would like to create a Euler diagram with Highcharts library :

My goal example:

I found this solution, which involves forcing the x attribute of the points.

I would like to do something similar to the example, but I need the dataLabels and I want them to be correctly positioned on each circle.

Please see what I tried

Highcharts.chart('container', {
  chart: {
    events: {
      load: function() {
        var points = this.series[0].points,
          point1R = points[0].shapeArgs.r;

        points[1].graphic.attr({
          y: points[1].graphic.getBBox().y - (point1R - points[1].shapeArgs.r)
        });

        points[2].graphic.attr({
          y: points[2].graphic.getBBox().y - (point1R - points[2].shapeArgs.r)
        });
      }
    }
  },
  series: [{
    type: 'venn',
    dataLabels: {
            inside: true,
            enabled: true,
            verticalAlign: 'top'
        },
    data: [{
      sets: ['A'],
      value: 10
    }, {
      sets: ['B'],
      value: 3
    }, {
      sets: ['C'],
      value: 1,
    }, {
      sets: ['A', 'C'],
      value: 1
    }, {
      sets: ['A', 'B'],
      value: 3
    }, {
      sets: ['B', 'C'],
      value: 1
    }]
  }]
});

Could someone help me to design it ? Thank you in advance !


Solution

  • hello actually you can apply what you did for y chart offset (on your first jsfiddle , not the one inside the comment) to the x and y offset of the labels

    except for put your code inside a loop i've just applied the same concept to the labels:

    Highcharts.chart('container', {
      chart: {
        events: {
          load: function() {
            var points = this.series[0].points;
            var point1R = points[0].shapeArgs.r;
            
            points.forEach((p)=>{
              if((p.shapeArgs ?? false)!=false){
                //this is the same of your code but inside the loop
                //it just move the y circles offsset
                p.graphic.attr({
                  y: p.graphic.getBBox().y - (point1R - p.shapeArgs.r)
                });
    
                //and you can do the same with labels in this way
                p.dataLabel.translate(
                  p.shapeArgs.x-(p.dataLabel.bBox.width), 
                  (p.shapeArgs.r * 2)-(p.dataLabel.bBox.height*2)
                );
              }
            });
            
          
          }
        }
      },
      series: [{
        type: 'venn',
        dataLabels: {
                inside: true,
                enabled: true,
                verticalAlign: 'left'
            },
        data: [{
          sets: ['A'],
          value: 10
        }, {
          sets: ['B'],
          value: 3
        }, {
          sets: ['C'],
          value: 1,
        }, {
          sets: ['A', 'C'],
          value: 1
        }, {
          sets: ['A', 'B'],
          value: 3
        }, {
          sets: ['B', 'C'],
          value: 1
        }]
      }]
    });
    #container {
        height: 400px; 
    }
    <script src="https://code.highcharts.com/highcharts.js"></script>
    <script src="https://code.highcharts.com/modules/venn.js"></script>
    
    <div id="container"></div>

    if you want to invert the chart like in the pics you need some math

    you should search something about coordinate translation , this is a good starting point:

    https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Transformations#translating

    and apply it to both shapes and labels

    Highcharts.chart('container', {
      chart: {
        events: {
          load: function() {
            var points = this.series[0].points;
            var point1R = points[0].shapeArgs.r;
            var maxR = 0;
            points.forEach((p)=>{if(p?.shapeArgs?.r>maxR){maxR=p?.shapeArgs?.r;}})
            
            points.forEach((p)=>{
              if((p.shapeArgs ?? false)!=false){
                //this is the same of your code but inside the loop
                //it just move the y circles offsset
                p._newY=maxR+(maxR-p.shapeArgs.r);
                p.graphic.attr({
                  //do some math here
                  y: maxR+(maxR-p.shapeArgs.r)
                });
    
                //and you can do the same with labels in this way
            
                p.dataLabel.translate(
                  p.shapeArgs.x-(p.dataLabel.bBox.width), 
                  //do some math here
                  p._newY-p.shapeArgs.r
                );
                
              }
            });
            
          
          }
        }
      },
      series: [{
        type: 'venn',
        dataLabels: {
                inside: true,
                enabled: true,
                verticalAlign: 'left'
            },
        data: [{
          sets: ['A'],
          value: 10
        }, {
          sets: ['B'],
          value: 3
        }, {
          sets: ['C'],
          value: 1,
        }, {
          sets: ['A', 'C'],
          value: 1
        }, {
          sets: ['A', 'B'],
          value: 3
        }, {
          sets: ['B', 'C'],
          value: 1
        }]
      }]
    });
    #container {
        height: 400px; 
    }
    <script src="https://code.highcharts.com/highcharts.js"></script>
    <script src="https://code.highcharts.com/modules/venn.js"></script>
    
    <div id="container"></div>