diff --git a/README.md b/README.md index b2c393e..e894493 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ new Chartist.Bar('.ct-chart', data, { | --- | --- | --- | --- | | `className` | Adds a class to the `ul` element. | `string` | `''` | | `clickable` | Sets the legends clickable state; setting this value to `false` disables toggling graphs on legend click. | `bool` | `true` | -| `legendNames` | Sets custom legend names. By default the `name` property of the series will be used if none are given. | `mixed` | `false` | +| `legendNames` | Sets custom legend names. By default the `name` property of the series will be used if none are given. Multiple series can be associated with a legend item using this property as well. See examples for more details. | `mixed` | `false` | | `onClick` | Accepts a function that gets invoked if `clickable` is true. The function has the `chart`, and the click event (`e`), as arguments. | `mixed` | `false` | | `classNames` | Accepts a array of strings as long as the chart's series, those will be added as classes to the `li` elements. | `mixed` | `false` | | `removeAll` | Allow all series to be removed at once. | `bool` | `false` | diff --git a/chartist-plugin-legend.js b/chartist-plugin-legend.js index 30286b7..930248a 100644 --- a/chartist-plugin-legend.js +++ b/chartist-plugin-legend.js @@ -33,10 +33,6 @@ Chartist.plugins.legend = function (options) { - function compareNumbers(a, b) { - return a - b; - } - // Catch invalid options if (options && options.position) { if (!(options.position === 'top' || options.position === 'bottom' || options.position instanceof HTMLElement)) { @@ -57,6 +53,25 @@ } return function legend(chart) { + function updateChart() { + var newSeries = []; + var newLabels = []; + + for (var i = 0; i < seriesMetadata.length; i++) { + if(seriesMetadata[i].legend != -1 && legends[seriesMetadata[i].legend].active) { + newSeries.push(seriesMetadata[i].data); + newLabels.push(seriesMetadata[i].label); + } + } + + chart.data.series = newSeries; + if (useLabels) { + chart.data.labels = newLabels; + } + + chart.update(); + } + var existingLegendElement = chart.container.querySelector('.ct-legend'); if (existingLegendElement) { // Clear legend if already existing. @@ -93,9 +108,6 @@ legendElement.style.cssText = 'width: ' + chart.options.width + 'px;margin: 0 auto;'; } - var removedSeries = [], - originalSeries = chart.data.series.slice(0); - // Get the right array to use for generating the legend. var legendNames = chart.data.series, useLabels = isPieChart && chart.data.labels; @@ -104,12 +116,29 @@ legendNames = chart.data.labels; } legendNames = options.legendNames || legendNames; + + var legends = []; + var seriesMetadata = new Array(chart.data.series.length); + var activeLegendCount = 0; + + // Initialize the array that associates series with legends. + // -1 indicates that there is no legend associated with it. + for (var i = 0; i < chart.data.series.length; i++) { + seriesMetadata[i] = { + data: chart.data.series[i], + label: useLabels ? chart.data.labels[i] : null, + legend: -1 + }; + } // Check if given class names are viable to append to legends var classNamesViable = (Array.isArray(options.classNames) && (options.classNames.length === legendNames.length)); // Loop through all legends to set each name in a list item. legendNames.forEach(function (legend, i) { + var legendText = legend.name || legend; + var legendSeries = legend.series || [i]; + var li = document.createElement('li'); li.className = 'ct-series-' + i; // Append specific class to a legend element, if viable classes are given @@ -117,8 +146,20 @@ li.className += ' ' + options.classNames[i]; } li.setAttribute('data-legend', i); - li.textContent = legend.name || legend; + li.textContent = legendText; legendElement.appendChild(li); + + legendSeries.forEach(function(seriesIndex) { + seriesMetadata[seriesIndex].legend = i; + }); + + legends.push({ + text: legendText, + series: legendSeries, + active: true + }); + + activeLegendCount++; }); chart.on('created', function (data) { @@ -148,66 +189,36 @@ return; e.preventDefault(); - var seriesIndex = parseInt(li.getAttribute('data-legend')), - removedSeriesIndex = removedSeries.indexOf(seriesIndex); + var legendIndex = parseInt(li.getAttribute('data-legend')); + var legend = legends[legendIndex]; - if (removedSeriesIndex > -1) { - // Add to series again. - removedSeries.splice(removedSeriesIndex, 1); + if (!legends[legendIndex].active) { + legend.active = true; + activeLegendCount++; li.classList.remove('inactive'); } else { - if (!options.removeAll) { - // Remove from series, only if a minimum of one series is still visible. - if ( chart.data.series.length > 1) { - removedSeries.push(seriesIndex); - li.classList.add('inactive'); - } - // Set all series as active. - else { - removedSeries = []; - var seriesItems = Array.prototype.slice.call(legendElement.childNodes); - seriesItems.forEach(function (item) { - item.classList.remove('inactive'); - }); - } - } - else { - // Remove series unaffected if it is the last or not - removedSeries.push(seriesIndex); - li.classList.add('inactive'); + legend.active = false; + activeLegendCount--; + li.classList.add('inactive'); + + if (!options.removeAll && activeLegendCount == 0) { + //If we can't disable all series at the same time, let's + //reenable all of them: + for (var i = 0; i < legends.length; i++) { + legends[i].active = true; + activeLegendCount++; + legendElement.childNodes[i].classList.remove('inactive'); + } } } - - // Reset the series to original and remove each series that - // is still removed again, to remain index order. - var seriesCopy = originalSeries.slice(0); - if (useLabels) { - var labelsCopy = originalLabels.slice(0); - } - - // Reverse sort the removedSeries to prevent removing the wrong index. - removedSeries.sort(compareNumbers).reverse(); - - removedSeries.forEach(function (series) { - seriesCopy.splice(series, 1); - if (useLabels) { - labelsCopy.splice(series, 1); - } - }); - + + updateChart(); + if (options.onClick) { options.onClick(chart, e); } - - chart.data.series = seriesCopy; - if (useLabels) { - chart.data.labels = labelsCopy; - } - - chart.update(); }); } - }; }; diff --git a/index.html b/index.html index 25278b8..6255785 100644 --- a/index.html +++ b/index.html @@ -70,6 +70,20 @@ background-color: #453d3f; border-color: #453d3f; } + + .ct-chart-line-multipleseries .ct-legend .ct-series-0:before { + background-color: #d70206; + border-color: #d70206; + } + + .ct-chart-line-multipleseries .ct-legend .ct-series-1:before { + background-color: #f4c63d; + border-color: #f4c63d; + } + + .ct-chart-line-multipleseries .ct-legend li.inactive:before { + background: transparent; + } .crazyPink li.ct-series-0:before { background-color: #C2185B; @@ -341,6 +355,28 @@
legendNames
property can be used to associate multiple series with a legend item.
+
+
+new Chartist.Line('.ct-chart-line-multipleseries', {
+ labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
+ series: [
+ [12, 9, 7, 8, 5],
+ [2, 1, 3.5, 7, 3],
+ [1, 3, 4, 5, 6]
+ ]
+}, {
+ fullWidth: true,
+ chartPadding: {
+ right: 40
+ },
+ plugins: [
+ Chartist.plugins.legend({
+ legendNames: [{name: 'Red-ish', series: [0,1]}, {name: 'Yellow', series: [2]}],
+ })
+ ]
});
clickable
is true. The function has the chart
, and the click event (e
), as arguments.
@@ -564,6 +600,25 @@