How to write your own custom legends for google line chart/ Google line chart legend manipulation
Asked Answered
S

2

12

I am using Google Visualisation to create line charts for my application. I have following requirements in that :

  1. Manipulating events on legends (like doubleClick, which I have solved somehow)
  2. Wrapping the legends in two rows avoiding pagination (Most imp and required)

I have gone through the following questions to get solution for my answers: 1) Issue with legend pagination (Google Interactive chart API) Issue : I would avoid playing with font-size because the number of legends may increase over time

2)How the legends on Google charts can be wrapped Issue: I do not want legends to be anywhere else than at the position:bottom. And maxLines solution does not work on position : bottom

3) Is there any way I can avoid pagination in legends of a google visualisation chart and show all the lines in two lines in a single page? Issue: This is another link, which mentions my problem, but no useful answers found on it.

4) Google Documentation : Heading : Chart Legend Text and Style chdl, chdlp, chdls [All charts] https://developers.google.com/chart/image/docs/chart_params#axis-label-styles-chxs Heading : Setting Chart Margines https://developers.google.com/chart/image/docs/chart_params#chart-margins-chma-all----charts Heading : Tooltips https://developers.google.com/chart/interactive/docs/customizing_tooltip_content#tooltips-an-introduction Comment : These are few google documentation links where few legend manipulating properties are mentioned, but still they does not solve my problem.

5)https://github.com/google/google-visualization-issues/issues/1286 Comment : This is the link where I can see that, google has not provided many properties to manipulate legends, and no much useful information to solve my issue

6) Google charts legend manipulation Comment : This is the only link, where I got a hint about how to solve my issue i.e. writing own legends. But there is no more links provided for documentation, no jsFiddle or no ref links apart from one link which is not useful for me.

While gone through all these, I can see only solution to solve my problem is to write my own custom legends. But I have no idea about how to write a complete element adding to google API.

Please guide me to go through this, any suggestions/links/refs/hints are welcome.

Thank you.

Selfassertion answered 14/3, 2016 at 12:1 Comment(3)
you wouldn't add the custom legend to the Google API. just build your own HTML in an element below the chart, using chart events to sync activity. for instance, wait for the chart's 'ready' event before displaying the legend.Fauch
@Fauch Thanks for the reply. I understand that we have to write it on 'ready' event. But i have no prev experience of writing any plugin. So need guidance in that direction. I could provide anything in this way, then that would be more helpfulSelfassertion
Have you figured it out for the solution code?Lasalle
F
13

Example: Build custom legend, which syncs with data and chart...

google.charts.load('44', {
  callback: drawChart,
  packages: ['controls', 'corechart']
});

function drawChart() {
  // adapted from a previous example
  var colorPallette = ['#273746','#707B7C','#dc7633','#f1c40f','#1e8449','#2874a6','#6c3483','#922b21'];

  var data = new google.visualization.DataTable();
  data.addColumn('date', 'X');
  data.addColumn('number', 'Y1');
  data.addColumn('number', 'Y2');

  data.addRow([new Date(2016,  0, 1),   1, 123]);
  data.addRow([new Date(2016,  1, 1),   6,  42]);
  data.addRow([new Date(2016,  2, 1),   4,  49]);
  data.addRow([new Date(2016,  3, 1),  23, 486]);
  data.addRow([new Date(2016,  4, 1),  89, 476]);
  data.addRow([new Date(2016,  5, 1),  46, 444]);
  data.addRow([new Date(2016,  6, 1), 178, 442]);
  data.addRow([new Date(2016,  7, 1),  12, 274]);
  data.addRow([new Date(2016,  8, 1), 123, 934]);
  data.addRow([new Date(2016,  9, 1), 144, 145]);
  data.addRow([new Date(2016, 10, 1), 135, 946]);
  data.addRow([new Date(2016, 11, 1), 178, 747]);

  // use view to add various columns for example purposes
  var view = new google.visualization.DataView(data);
  view.setColumns([0, 1, 2,
    {
      calc: function (data, row) {
        return data.getValue(row, 1) + data.getValue(row, 2);
      },
      type: 'number',
      label: 'Y3'
    },
    {
      calc: function (data, row) {
        return data.getValue(row, 2) - data.getValue(row, 1);
      },
      type: 'number',
      label: 'Y4'
    },
    {
      calc: function (data, row) {
        return data.getValue(row, 1) * 2;
      },
      type: 'number',
      label: 'Y5'
    },
    {
      calc: function (data, row) {
        return data.getValue(row, 2) * 3;
      },
      type: 'number',
      label: 'Y6'
    },
    {
      calc: function (data, row) {
        return data.getValue(row, 1) * 1.5;
      },
      type: 'number',
      label: 'Y7'
    },
    {
      calc: function (data, row) {
        return data.getValue(row, 1) * 1.5;
      },
      type: 'number',
      label: 'Y8'
    }
  ]);

  var control = new google.visualization.ControlWrapper({
    controlType: 'DateRangeFilter',
    containerId: 'control_div',
    options: {
      filterColumnIndex: 0
    }
  });

  var chart = new google.visualization.ChartWrapper({
    chartType: 'LineChart',
    containerId: 'chart_div',
    options: {
      chartArea: {
        width: '80%'
      },
      // add colors for legend mapping
      colors: colorPallette,
      hAxis: {
        format: 'MMM',
        slantedText: false,
        maxAlternation: 1
      },
      legend: 'none',
      width: 320
    }
  });

  // add legend marker
  function addLegendMarker(markerProps) {
    var legendMarker = document.getElementById('template-legend-marker').innerHTML;
    for (var handle in markerProps) {
      if (markerProps.hasOwnProperty(handle)) {
        legendMarker = legendMarker.replace('{{' + handle + '}}', markerProps[handle]);
      }
    }
    document.getElementById('legend_div').insertAdjacentHTML('beforeEnd', legendMarker);
  }

  // chart ready event
  google.visualization.events.addListener(chart, 'ready', function () {
    var legend = document.getElementById('legend_div');

    // colors from chart
    var colorPallette = chart.getOption('colors');

    // clear previous legend
    legend.innerHTML = '';

    // add legend marker for each Y axis column - skip X axis --> i = 1
    for (var i = 1; i < chart.getDataTable().getNumberOfColumns(); i++) {
      var markerProps = {};
      markerProps.index = i;
      markerProps.color = colorPallette[i - 1];
      markerProps.label = chart.getDataTable().getColumnLabel(i);
      addLegendMarker(markerProps);
    }

    // add click event to each legend marker
    var markers = legend.getElementsByTagName('DIV');
    Array.prototype.forEach.call(markers, function(marker) {
      marker.addEventListener('click', function (e) {
        var marker = e.target || e.srcElement;
        if (marker.tagName.toUpperCase() !== 'DIV') {
          marker = marker.parentNode;
        }
        var columnIndex = parseInt(marker.getAttribute('data-columnIndex'));
        document.getElementById('message_div').innerHTML = 'legend marker clicked = ' + chart.getDataTable().getColumnLabel(columnIndex);
      }, false);
    });
  });

  var dash = new google.visualization.Dashboard(document.getElementById('dashboard'));
  dash.bind([control], [chart]);
  dash.draw(view);
}
#legend_div {
  text-align: center;
  width: 320px;
}

.legend-marker {
  display: inline-block;
  padding: 16px 4px 8px 4px;
}

.legend-marker-color {
  display: inline-block;
  height: 12px;
  width: 12px;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard">
  <div id="chart_div"></div>
  <div id="legend_div"></div>
  <br/>
  <div id="control_div"></div>
  <br/>
  <div id="message_div"></div>
</div>

<!-- template for building marker -->
<script id="template-legend-marker" type="text/html">
  <div class="legend-marker" data-columnIndex="{{index}}">
    <div class="legend-marker-color" style="background-color: {{color}}"></div>
    <span>{{label}}</span>
  </div>
</script>
Fauch answered 17/3, 2016 at 15:21 Comment(3)
thanks for the code snippet... it explained well.... Now I started developing my own and as soon as I will complete, i will update my question with answer... ur answer would help me to direct to the solution.Selfassertion
The above example is very helpful, thanks. Just a word of caution - if using this code with Python Jinja templates, the code snippet will not work because of {{ }} used here. The jinja template will replace the markers within template-legend-marker with empty strings or values it may hold for these markers.Hellkite
see this answer for building a legend when the colors are provided using a style column role...Fauch
L
-1
 if ($("#source svg text[text-anchor='end']").length > 0){
        var n = $("#source svg text[text-anchor='end']").length;
        $("#source svg text[text-anchor='end']")[n-5].innerHTML = "";
        $("#source svg text[text-anchor='end']")[n-4].innerHTML = "Create your own legend";
        $("#source svg text[text-anchor='end']")[n-3].innerHTML = "Create your own legend";
        $("#source svg text[text-anchor='end']")[n-2].innerHTML = "Create your own legend";
        $("#source svg text[text-anchor='end']")[n-1].innerHTML = "";
    }
Leery answered 22/3, 2018 at 14:33 Comment(1)
Code-only answers are low value on StackOverflow because they do a poor job of educating the OP and thousands of future researchers. Please take the time to edit your answer and explain how your approach works and why it is recommended. Working solutions are a good start to any answer, but always post answers with the intent to educate.Sipe

© 2022 - 2024 — McMap. All rights reserved.