如何制作具有多个系列 enaber/disabler 的人力车传奇?

How can I make a Rickshaw legend with multiple series enaber/disabler?

我需要制作一个人力车传奇,我可以在其中制作时间序列组。

例如我在图表中显示了 20 个时间序列,我希望将它们分为 4 组,分别命名为系列 1、系列 2、系列 3、系列 4。 Series1 将包含图表中的前 5 个时间序列,series2 将包含第 6 个到第 10 个,依此类推。

在我尝试在我的 .js 中添加自定义对象来解决我的问题之前,有人知道是否有我找不到的内置功能吗?

我没有找到任何有用的东西,所以我创建了一个与传统图例一起工作的多重图例的个性化版本。 不幸的是,要在修改标准图例时更新多个图例,我必须创建一个 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 = '&#10004;';
        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() };

};