Я не нашел ничего полезного, поэтому создал персональную версию множественной легенды, которая работает вместе с традиционной легендой. К сожалению, для обновления множественной легенды при изменении стандартной легенды мне пришлось создать объект myLegend вместо стандартного.
Вы можете использовать эту версию таким образом:
//you must have a traditional Rickshaw seriesData
var graph = new Rickshaw.Graph({
element: document.getElementById("chart"),
width: 960,
height: 500,
renderer: 'line',
series: seriesData
});
graph.render();
var legend = new Rickshaw.Graph.Legend({
graph: graph,
element: document.getElementById('legend')
});
var mLegend = new multiLegend({
graph: graph,
element: document.getElementById('multi_legend'),
multiDivision: [
{
name: "Africa",
indexes: [ 0, 1, 2, 3, 4, 5, 6, 7 ]
}
{
name: "Asia",
indexes: [ 8, 9, 10, 11, 12 ]
},
{
name: "Europe",
indexes: [ 13, 14, 15, 16, 17]
},
{
name: "North America",
indexes: [ 18, 19, 20 ]
}
]
});
new myToggle({
graph: graph,
legend: legend,
multiLegend: mLegend
});
new multiToggle({
graph: graph,
multiLegend: mLegend,
legend: legend
});
Вот код:
multiLegend = Rickshaw.Class.create({
className: 'rickshaw_legend',
initialize: function(args) {
this.element = args.element;
this.graph = args.graph;
this.naturalOrder = args.naturalOrder;
this.seriesGroups = args.multiDivision;
this.element.classList.add(this.className);
this.list = document.createElement('ul');
this.element.appendChild(this.list);
this.render();
// we could bind this.render.bind(this) here
// but triggering the re-render would lose the added
// behavior of the series toggle
this.graph.onUpdate(function() {});
},
render: function() {
var self = this;
while (this.list.firstChild) {
this.list.removeChild(this.list.firstChild);
}
this.lines = [];
var allSeries = this.graph.series;
self.seriesGroups.forEach(function(s) {
var series = allSeries.filter(function(value, index) {
return (s.indexes.indexOf(index)!=-1) ? true : false;
});
series = series.reverse();
self.addLine(s.name, series);
});
},
addLine: function (name, series) {
var line = document.createElement('li');
line.className = 'line';
if (series.disabled) {
line.className += ' disabled';
}
if (series.className) {
d3.select(line).classed(series.className, true);
}
var swatch = document.createElement('div');
swatch.className = 'swatch';
swatch.style.backgroundColor = "#0000FF";
line.appendChild(swatch);
var label = document.createElement('span');
label.className = 'label';
label.innerHTML = name;
line.appendChild(label);
this.list.appendChild(line);
line.series = series;
var _line = { element: line, series: series, disabled: false};
if (this.shelving) {
this.shelving.addAnchor(_line);
this.shelving.updateBehaviour();
}
if (this.highlighter) {
this.highlighter.addHighlightEvents(_line);
}
this.lines.push(_line);
return line;
}
});
multiToggle = function(args) {
this.graph = args.graph;
this.multiLegend = args.multiLegend;
this.legend = args.legend;
var self = this;
this.addAnchor = function(line) {
var anchor = document.createElement('a');
anchor.innerHTML = '✔';
anchor.classList.add('action');
line.element.insertBefore(anchor, line.element.firstChild);
anchor.onclick = function(e) {
if (line.disabled) {
line.series.forEach(function(serie) {
serie.enable();
});
line.element.classList.remove('disabled');
line.disabled = false;
self.legend.lines
.filter(function(value) {
return (line.series.indexOf(value.series)!=-1) ? true : false;
})
.forEach(function(l) {
l.element.classList.remove('disabled');
l.disabled = false;
});
} else {
if (this.graph.series.filter(function(s) { return !s.disabled }).length <= 1) return;
line.series.forEach(function(serie) {
serie.disable();
});
line.element.classList.add('disabled');
line.disabled = true;
self.legend.lines
.filter(function(value) {
return (line.series.indexOf(value.series)!=-1) ? true : false;
})
.forEach(function(l) {
l.element.classList.add('disabled');
l.disabled = true;
});
}
self.graph.update();
}.bind(this);
var label = line.element.getElementsByTagName('span')[0];
label.onclick = function(e){
var disableAllOtherLines = line.disabled;
if (! disableAllOtherLines) {
for (var i = 0; i < self.multiLegend.lines.length; i++) {
var l = self.multiLegend.lines[i];
if (line.series === l.series) {
// noop
} else if (l.series.disabled) {
// noop
} else {
disableAllOtherLines = true;
break;
}
}
}
// show all or none
if (disableAllOtherLines) {
// these must happen first or else we try (and probably fail) to make a no line graph
line.series.forEach(function(serie) {
serie.enable();
});
line.element.classList.remove('disabled');
line.disabled = false;
self.legend.lines
.filter(function(value) {
return (line.series.indexOf(value.series)!=-1) ? true : false;
})
.forEach(function(l) {
l.element.classList.remove('disabled');
l.disabled = false;
});
self.multiLegend.lines.forEach(function(l){
if (line.series === l.series) {
// noop
} else {
l.series.forEach(function(serie) {
serie.disable();
});
l.element.classList.add('disabled');
l.disabled = true;
self.legend.lines
.filter(function(value) {
return (l.series.indexOf(value.series)!=-1) ? true : false;
})
.forEach(function(l2) {
l2.element.classList.add('disabled');
l2.disabled = true;
});
}
});
} else {
self.multiLegend.lines.forEach(function(l){
l.series.forEach(function(serie) {
serie.enable();
});
l.element.classList.remove('disabled');
l.disabled = false;
self.legend.lines
.filter(function(value) {
return (l.series.indexOf(value.series)!=-1) ? true : false;
})
.forEach(function(l2) {
l2.element.classList.remove('disabled');
l2.disabled = false;
});
});
}
self.graph.update();
};
};
if (this.multiLegend) {
var $ = jQuery;
if (typeof $ != 'undefined' && $(this.multiLegend.list).sortable) {
$(this.multiLegend.list).sortable({
start: function(event, ui) {
ui.item.bind('no.onclick',
function(event) {
event.preventDefault();
}
);
},
stop: function(event, ui) {
setTimeout(function(){
ui.item.unbind('no.onclick');
}, 250);
}
});
}
this.multiLegend.lines.forEach(function(l) {
self.addAnchor(l);
});
}
this._addBehavior = function() {
this.graph.series.forEach(function(s) {
s.disable = function() {
if (self.graph.series.length <= 1) {
throw('only one series left');
}
s.disabled = true;
};
s.enable = function() {
s.disabled = false;
};
});
};
this._addBehavior();
this.updateBehaviour = function() { this._addBehavior() };
};
myToggle = function(args) {
this.graph = args.graph;
this.legend = args.legend;
this.multiLegend = args.multiLegend;
var self = this;
this.addAnchor = function(line) {
var anchor = document.createElement('a');
anchor.innerHTML = '✔';
anchor.classList.add('action');
line.element.insertBefore(anchor, line.element.firstChild);
anchor.onclick = function(e) {
if (line.series.disabled) {
line.series.enable();
line.element.classList.remove('disabled');
} else {
if (this.graph.series.filter(function(s) { return !s.disabled }).length <= 1) return;
line.series.disable();
line.element.classList.add('disabled');
self.multiLegend.lines.forEach(function(l) {
if(l.series.indexOf(line.series)!=-1) {
l.element.classList.add('disabled');
l.disabled = true;
}
});
}
self.graph.update();
}.bind(this);
var label = line.element.getElementsByTagName('span')[0];
label.onclick = function(e){
var disableAllOtherLines = line.series.disabled;
if (! disableAllOtherLines) {
for (var i = 0; i < self.legend.lines.length; i++) {
var l = self.legend.lines[i];
if (line.series === l.series) {
// noop
} else if (l.series.disabled) {
// noop
} else {
disableAllOtherLines = true;
break;
}
}
}
// show all or none
if (disableAllOtherLines) {
// these must happen first or else we try (and probably fail) to make a no line graph
line.series.enable();
line.element.classList.remove('disabled');
self.legend.lines.forEach(function(l){
if (line.series === l.series) {
// noop
} else {
l.series.disable();
l.element.classList.add('disabled');
}
});
self.multiLegend.lines.forEach(function(l) {
l.element.classList.add('disabled');
l.disabled = true;
});
} else {
self.legend.lines.forEach(function(l){
l.series.enable();
l.element.classList.remove('disabled');
});
}
self.graph.update();
};
};
if (this.legend) {
var $ = jQuery;
if (typeof $ != 'undefined' && $(this.legend.list).sortable) {
$(this.legend.list).sortable({
start: function(event, ui) {
ui.item.bind('no.onclick',
function(event) {
event.preventDefault();
}
);
},
stop: function(event, ui) {
setTimeout(function(){
ui.item.unbind('no.onclick');
}, 250);
}
});
}
this.legend.lines.forEach(function(l) {
self.addAnchor(l);
});
}
this._addBehavior = function() {
this.graph.series.forEach(function(s) {
s.disable = function() {
if (self.graph.series.length <= 1) {
throw('only one series left');
}
s.disabled = true;
};
s.enable = function() {
s.disabled = false;
};
});
};
this._addBehavior();
this.updateBehaviour = function() { this._addBehavior() };
};