Search code examples
csshighchartsopacityoverlapbubble-chart

highcharts opacity when "bubbles" are stacked


I have a problem regarding opacity(transparency) with highcharts in my case bubble chart and i think i can explain it best with an example

Example: i have a series with 100 bubbles that cover each other in the chart and the opacity is set to 1% (0.01). My problem here is shouldn't all the bubbles that are over each other have an opacity of 100% (1) or is my knowlage of how opacity works wrong?

$(function () {
    $('#container').highcharts({
        chart:{
            type:'bubble'
        },        
        series: [{
            name: '1',
            data: [{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},
                   {x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},
                   {x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},
                   {x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},
                   {x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},
                   {x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},
                   {x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},
                   {x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},
                   {x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},
                   {x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1}                 
                  ],
            marker:{
                fillOpacity:0.01,
                lineWidth:0,
                fillColor:'#000000'
            }
        }]
    });
});

fidle: http://jsfiddle.net/kte3omhg/1/

And if there is a work around this problem i would appreciate it if someone posts it

Edit: Okey i found out that opacity doesn't work as i thought it would

Total Opacity = First Opacity + (100 - First Opacity) * Second Opacity
              = 0.7 + (1 - 0.7) * 0.7
              = 0.7 + (0.3) * 0.7
              = 0.7 + 0.21
              = 0.91

http://en.wikipedia.org/wiki/Mathematical_descriptions_of_opacity

But i would still like to know if there is a solution to getting my result


Solution

  • There are a few approaches you could use:

    1. Using the opacity the way it is

      1.1. Keep fillOpacity, but vary the # of elements:

      • Keeping the fillOpacity: 0.01:

      • How many elements it is necessary to get a resultant 0.99 opacity?

      function calculateTimes(opacity, overlappingOpacity) {
          var times = 1;
          var currentOpacity = opacity;
          while (currentOpacity < overlappingOpacity) {
              currentOpacity += (1 - currentOpacity) * opacity;
              times++;
          }
          return times;
      }
      calculateTimes(0.01, 0.99); //Gives you 459 elements
      

      Fiddle for 459 elements

      1.2. Keep the # of elements, but vary fillOpacity

      • Keeping the 100 elements:

      • How much should fillOpacity be set to get a resultant 0.99 opacity?

      function calculateOverlappedOpacity(opacity, times) {
          return times == 1 ? opacity : opacity + (1 - opacity) * calculateOverlappedOpacity(opacity, times - 1);
      }
      
      function calculateOpacityFor(resultantOpacity, times) {
          for (var i = 0.0001; i <= 1; i += 0.0001) {
              if (calculateOverlappedOpacity(i, times) >= resultantOpacity) {
                  return i;
              }
          }
          return 1;
      }
      calculateOpacityFor(0.99, 100) //Gives you a fillOpacity of 0.0451
      

      Fiddle for fillOpacity: 0.0451

    2. Using the opacity the way you thought it worked

      • Use 1 element set with a desired fillOpacity based on the element quantity:

      • How much should the resultant opacity be (based on the quantity of elements)?

      0.01 * chartData.length
      

      Fiddle for a simulation of the expected opacity algorithm