Monday, February 27, 2017

Chartjs V2 Add Custom Legend and Show/Hide Chart Data through Click

To add interactive feature for Chartjs version such as select/unselect group of data, you can use chart.metadata.hidden attribute. For doghnut chart, the hidden attribute can work with datasets and data both. However, for line and bar chart, only datasets.hidden is effective. To work with line and bar chart, you need to manually change data.

Following method can be used to add the interactive feature with Custom Legend for bar/line/doghnut charts:

//add custom legends
var addCustomLegends = function (canvas, data) {
    var legendLabel = canvas.replace('canvas', 'legendLabel');
    var legendNameBase = canvas.replace('canvas', 'legend');
    $('#' + canvas).before('<div id="' + legendLabel + '" style="width:100%;text-align:center;padding-left:25px;padding-right:25px;"></div>');
    var divWidth = 75 / data.labels.length;
    var innerHTMLStr = '';
    for (var i = 0; i < data.labels.length; i++) {
        var clickEvents = '';
        clickEvents += 'hideChartLabels(event,\'' + i + ',' + data.labels.length
            + ', \'#datalist\');'; //don't put space after comma inside the string presenting as array
    }
    innerHTMLStr += '<div style="display:inline-block; height:12px; text-align:center; vertical-align:middle; margin-right:5px; background:' + gbService.getColor('lightgray') + '; border:1px solid rgba(0, 0, 0, .2); width: '
        + '12px;"></div><div id="' + legendNameBase + i + '" style="display:inline-block; text-align:center; vertical-align:top; padding-right:10px; width=' + divWidth + '"% '
        + ' onclick ="' + clickEvents + '">'
        + data.labels[i] + '</div>';
    }
    document.getElementById(legendLabel).innerHTML = innerHTMLStr;
    if (legendStatus != null && legendStatus.length == data.labels.length) {
        for (var i = 0; i < data.labels.length; i++) {
            if (legendStatus[i] !== 'none') { //hidden the data
                $('#' + legendNameBase + i).click();
            }
        }
    }
}

var hideChartLabels = function (e, idName, index, length) {
    var idNameBase = idName;
    if (index < 10) {
        idNameBase = idNameBase.substring(0, idNameBase.length - 1);
    }
    else {
        idNameBase = idNameBase.substring(0, idNameBase.length - 2);
    }

    if (chart == null || chart == undefined) return;
    var data = chart.data;

    //draw the line-through to show the data is hidding
    if ($('#' + idNameBase + index).css("text-decoration") == "none") {
        $('#' + idNameBase + index).css({ "text-decoration": "line-through" });
    }
    else {
        $('#' + idNameBase + index).css({ "text-decoration": "none" });
    }

    //set hidden attribute for meta data
    for (var i = 0; i < data.datasets.length; i++) {
        updateChartDatasetItem(window[chart], i, index);
    }

    chart.update();
};

var updateChartDatasetItem = function (ci, index, elementIndex) {
    var meta = ci.getDatasetMeta(index);
    if (meta.dataset) {
        meta.hidden = !meta.hidden; //hidden whole dataset
    }
    else {
        meta.data[elementIndex].hidden = !meta.data[elementIndex].hidden;
    }
}

Reference:
https://github.com/chartjs/Chart.js/issues/2565