4

I'm creating a bubble chart using chartjs. I am able to create tooltips that describe each of the bubbles, but users of my chart may not be able to hover over it to see the tooltip. The BubbleData object format doesn't include a label element (I put one in anyway - no luck), I've tried the "labels" element for the Chart Data object (even though the docs say this is for Category labels - you never know!), and everything I can think of to put label on the bubble.

Is there a tooltip configuration that makes all the tooltips visible at all times? This would work for me as well.

Thanks;

Glenn

Glenn Wolf
  • 41
  • 1
  • 4

5 Answers5

3

I was looking for the same thing and figured out how to do it.

  1. add in the datasets the title:"dataTitle3" you want to show.

  2. use the data labeling plugin.

  3. simple code manipulation achieves what you want using dataset.title

I have made a sample but I think you could find out how and represent the data you want if you play with: external link

new Chart(document.getElementById("bubble-chart"), {
  type: 'bubble',
  data: {
    labels: "Africa",
    datasets: [{
      label: ["China"],
      backgroundColor: "rgba(255,221,50,0.2)",
      borderColor: "rgba(255,221,50,1)",
      title: "dataTitle1", //adding the title you want to show
      data: [{
        x: 21269017,
        y: 5.245,
        r: 15
      }]
    }, {
      label: ["Denmark"],
      backgroundColor: "rgba(60,186,159,0.2)",
      borderColor: "rgba(60,186,159,1)",
      title: "dataTitle2",
      data: [{
        x: 258702,
        y: 7.526,
        r: 10
      }]
    }, {
      label: ["Germany"],
      backgroundColor: "rgba(0,0,0,0.2)",
      borderColor: "#000",
      title: "dataTitle3", //adding the title you want to show
      data: [{
        x: 3979083,
        y: 6.994,
        r: 15
      }]
    }, {
      label: ["Japan"],
      backgroundColor: "rgba(193,46,12,0.2)",
      borderColor: "rgba(193,46,12,1)",
      title: "dataTitle4", //adding the title you want to show
      data: [{
        x: 4931877,
        y: 5.921,
        r: 15
      }]
    }]
  },
  options: {
    title: {
      display: true,
      text: 'Predicted world population (millions) in 2050'
    },
    scales: {
      yAxes: [{
        scaleLabel: {
          display: true,
          labelString: "Happiness"
        }
      }],
      xAxes: [{
        scaleLabel: {
          display: true,
          labelString: "GDP (PPP)"
        }
      }]
    }
  }
});

Chart.plugins.register({
  afterDatasetsDraw: function(chart, easing) {
    var ctx = chart.ctx;

    chart.data.datasets.forEach(function(dataset, i) {
      var meta = chart.getDatasetMeta(i);
      if (meta.type == "bubble") { //exclude scatter
        meta.data.forEach(function(element, index) {
          // Draw the text in black, with the specified font
          ctx.fillStyle = 'rgb(0, 0, 0)';
          var fontSize = 13;
          var fontStyle = 'normal';
          var fontFamily = 'Helvetica Neue';
          ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);

          // Just naively convert to string for now
          var dataString = dataset.data[index].toString();
          // Make sure alignment settings are correct
          ctx.textAlign = 'center';
          ctx.textBaseline = 'middle';

          var padding = 15;
          var position = element.tooltipPosition();
          ctx.fillText(dataset.title, position.x, position.y - (fontSize / 2) - padding);
        });
      } //if
    });
  }
});
<canvas id="bubble-chart" width="800" height="800"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js" integrity="sha512-ElRFoEQdI5Ht6kZvyzXhYG9NqjtkmlkfYk0wr6wHxU9JEHakS7UJZNeml5ALk+8IKlU6jDgMabC3vkumRokgJA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Teocci
  • 7,189
  • 1
  • 50
  • 48
1

ChartJs has a plugin now for this.

https://github.com/chartjs/chartjs-plugin-datalabels

Just install it using nuget or bower and add the reference of it. It wil automatically set z as label

Nouman Bhatti
  • 1,341
  • 6
  • 28
  • 54
0

The sytax has changed with chart.js V3 in a few places so I thought I'd share my variation on the chosen answer.

Chart.register({
   id: 'permanentLabel',
   afterDatasetsDraw: function (chart, args, options) {
     var ctx = chart.ctx

     chart.data.datasets.forEach(function (dataset, i) {
       var meta = chart.getDatasetMeta(i)
       if (meta.type == 'bubble') {
         meta.data.forEach(function (element, index) {
           ctx.textAlign = 'center'
           ctx.textBaseline = 'middle'
           var position = element.tooltipPosition()
           ctx.fillText(dataset.data[index].label.toString(), position.x, position.y - dataset.data[index].r - Chart.defaults.font.size)
         })
       }
     })
   },
 })

example image of labels

rmaspero
  • 573
  • 2
  • 11
  • 23
0

enter image description hereI have an some extra code, to avoid overlapping of labels.

var labelPlugin = {

        myTimeout: null,
        getNewYPostion:function(item, alreadyUsed, fontSize){
            for(let i of alreadyUsed){
                
                if((item.y_from >= i.y_from && item.y_from <= i.y_to) || (item.y_to>= i.y_from && item.y_to <= i.y_to)){
                    if((item.x_from >= i.x_from && item.x_from <= i.x_to) || (item.x_to>= i.x_from && item.x_to <= i.x_to)){
                        item.y_from=i.y_to+(fontSize*0.1);
                        item.y_to=item.y_from+fontSize;
                        return this.getNewYPostion(item, alreadyUsed, fontSize);
                    }
                }
            }
            return item;
        },
        afterDatasetsDraw: function (chart, args, options) {
            var ctx = chart.ctx;
            var that=this;

            clearTimeout(this.myTimeout);

            this.myTimeout = setTimeout(function () {

                var alreadyUsed = [];

                chart.data.datasets.forEach(function (dataset, i) {

                    var txt = dataset.label;
                    var txtSize = ctx.measureText(txt).width;

                    var meta = chart.getDatasetMeta(i);
                    if (meta.type === "bubble") { //exclude scatter

                        var fontSize = 10;
                        var fontStyle = 'normal';
                        var fontFamily = 'Helvetica Neue';
                        ctx.font = Chart.helpers.fontString(fontSize, fontStyle, fontFamily);
                        ctx.fillStyle = 'rgb(0, 0, 0)';
                        ctx.textAlign = 'left';
                        ctx.textBaseline = 'middle';
                        var padding, position, x_from, x_to, y, y_from, y_to;

                        meta.data.forEach(function (element, index) {

                            padding = element.options.radius;
                            position = element.tooltipPosition();
                            x_from = position.x + padding + 5; // left
                            x_to = x_from + txtSize; // left
                            y = position.y; // top
                            y_from = y - (fontSize * 0.5);
                            y_to = y + (fontSize * 0.5);

                            var item={
                                'y_from': y_from,
                                'y_to': y_to,
                                'x_from': x_from,
                                'x_to': x_to,
                            };

                            item=that.getNewYPostion(item, alreadyUsed, fontSize);
                            alreadyUsed.push(item);
                            ctx.fillText(txt, item.x_from, item.y_from+(0.5*fontSize));
                        });
                    } 
                });
            }, 500);
        }
    };
0

In 2022 the current version is 3.9.1 here is a working snippet:

const $canvas = document.getElementById('chart')

const popData = {
  datasets: [{
    label: ['Deer Population'],
    data: [{
      x: 100,
      y: 0,
      r: 25,
      label: 'Russia',
    }, {
      x: 60,
      y: 30,
      r: 20,
      label: 'China',
    }, {
      x: 40,
      y: 60,
      r: 25,
      label: 'Canada',
    }, {
      x: 80,
      y: 80,
      r: 40,
      label: 'US',
    }, {
      x: 20,
      y: 30,
      r: 25,
      label: 'Africa',
    }, {
      x: 0,
      y: 100,
      r: 5,
      label: 'Europe',
    }],
    backgroundColor: "#FF9966"
  }]
};

const bubbleChart = new Chart($canvas, {
  type: 'bubble',
  data: popData
});

const fontSize = Chart.defaults.font.size
Chart.register({
  id: 'permanentLabel',
  afterDatasetsDraw: (chart, args, options) => {
    const ctx = chart.ctx
    ctx.textAlign = 'center'
    ctx.textBaseline = 'middle'

    chart.data.datasets.forEach((dataset, i) => {
      const meta = chart.getDatasetMeta(i)
      if (meta.type !== 'bubble') return

      meta.data.forEach((element, index) => {
        const item = dataset.data[index]
        const position = element.tooltipPosition()
        ctx.fillText(item.label.toString(), position.x, position.y - item.r - fontSize)
      })
    })
  },
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<canvas id="chart" width="600" height="180"></canvas>
Teocci
  • 7,189
  • 1
  • 50
  • 48