Flot charts- toggling a series on/off

2019-02-20 12:23发布

问题:

I was successfully established my flot chart, based on this previous post

I want to enable to viewer to show/hide the series with a click. I found bunch of solutions, both official and others, but none of those worked for me. I'll explain:

  1. Official turning series on/off: this works, but looks very messy as the legend is eventually duplicated twice (disappears from official legend once the series turned off).
  2. Hiddengraphs.js: this is a plugin which can be found at the plugin repository, but it doesn't work and interact well with Chrome (tried more than one machine, it just don't work).
  3. This solution is actually really nice (I don't mind that there are no checkboxes to check), but when I integrated it into my code, all I got was "jumping" to the top of the page, and nothing happens.
  4. Lastly, I found this solution, which also works, altough using another js library, called flot.togglelegend.js. In this implementation I found some major conflicts with flot.cust.js, and couldn't get them both to work together.

Here's my current js (written in coffeescript)

    colorArray = []
    colorArray.push "rgba(180, 0, 75,    0.6)"
    colorArray.push "rgba(0, 150, 100,   0.6)"
    colorArray.push "rgba(0, 0, 255,     0.6)"
    colorArray.push "rgba(140, 0, 255,   0.6)"
    colorArray.push "rgba(90, 180, 20,   0.6)"
    colorArray.push "rgba(255, 236, 0,   0.6)"
    colorArray.push "rgba(234, 170, 21,  0.6)"
    colorArray.push "rgba(95, 180, 190,  0.6)"
    colorArray.push "rgba(214, 92, 63,   0.6)"
    colorArray.push "rgba(218, 106, 234, 0.6)"
    colorArray.push "rgba(213, 128, 155, 0.6)"

    # chart colors default 
    $chrt_border_color = "#efefef"
    $chrt_grid_color = "#DDD"
    $chrt_main = "#E24913"

    # red       
    $chrt_second = "#6595b4"
    # blue      
    $chrt_third = "#FF9F01"
    # orange    
    $chrt_fourth = "#7e9d3a"
    # green     
    $chrt_fifth = "#BD362F"
    # dark red  
    $chrt_mono = "#000"

    Chart = 

    generateDataObjects: (all_series, all_series_data) ->
        plotData = []

        for series, i in all_series
            obj =
                label: series.replace /__/g, "|"
                data: all_series_data[i]
                color: colorArray[i]

            plotData.push obj

        return plotData

    togglePlot: (seriesIdx) ->
        someData = plot.getData()
        someData[seriesIdx].lines.show = not someData[seriesIdx].lines.show
        plot.setData someData
        plot.draw()
        return  

    getTooltip: (label, xval, yval, flotItem) ->
            return 'Build: <span>'+ flotItem.series.data[flotItem.dataIndex][6]+'</span>' +" |     Run ID: <strong> #{flotItem.series.data[flotItem.dataIndex][7].toString()}</strong>" + '<br> Result: <span>'+Chart.commify(yval)+'</span>'

    commify: (x) ->
        return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");

    generateChartOptions: (legend_container, ticks) ->
        return (
            series:
                lines:
                    show: true

                points:
                    show: true

            crosshair:
                mode: "x"

            legend:
                container: $("##{legend_container}")
                labelFormatter: (label, series) ->
                    "<a href=\"javascript:void(0);\" onClick=\"Chart.togglePlot(" + series.idx + "); return false;\">" + label + "</a>"
                noColumns: 4
                # hideable: true

            grid:
              hoverable: true
              clickable: true
              tickColor: $chrt_border_color
              borderWidth: 0
              borderColor: $chrt_border_color

            tooltip: true
            tooltipOpts: 
              content : Chart.getTooltip
              #content : "Value <b>$x</b> Value <span>$y</span>",
              defaultTheme: false

            xaxis:
                ticks: ticks
                rotateTicks: 30

            selection:
                mode: "xy"
            )



     jQuery ->
        if $("#normalized_bw_chart").length         # render only if the chart-id is present

            raw_data = $("#normalized_bw_chart").data('results')
            ticks = $("#normalized_bw_chart").data('ticks')
            all_series = $("#normalized_bw_chart").data('series')

            plot = $.plot($("#normalized_bw_chart"), Chart.generateDataObjects(all_series, raw_data), Chart.generateChartOptions('normalized_bw_legend', ticks))    

        if $("#concurrent_flows_chart").length      # render only if the chart-id is present

            raw_data = $("#concurrent_flows_chart").data('results')
            ticks = $("#concurrent_flows_chart").data('ticks')
            all_series = $("#concurrent_flows_chart").data('series')

            plot = $.plot($("#concurrent_flows_chart"), Chart.generateDataObjects(all_series, raw_data), Chart.generateChartOptions('concurrent_flows_legend', ticks))

        if $("#bandwidth_chart").length         # render only if the chart-id is present

            raw_data = $("#bandwidth_chart").data('results')
            ticks = $("#bandwidth_chart").data('ticks')
            all_series = $("#bandwidth_chart").data('series')

            plot = $.plot($("#bandwidth_chart"), Chart.generateDataObjects(all_series, raw_data), Chart.generateChartOptions('bandwidth_legend', ticks))    

        $("[data-behavior~=chart-selection]").bind "plotselected", (event, ranges) ->
                selected_chart = $(this).attr('id')[0...-6] # slicing the name of the selected item
                console.log  ("zooming in to " + selected_chart)
                plot = $.plot($("##{selected_chart}_chart"), plot.getData(), $.extend(true, {}, Chart.generateChartOptions(selected_chart+'_legend', ticks),
                  xaxis:
                    min: ranges.xaxis.from
                    max: ranges.xaxis.to

                  yaxis:
                    min: ranges.yaxis.from
                    max: ranges.yaxis.to
                ))
             return

        $("[data-behavior~=chart-selection]").bind "dblclick", (event, pos, item) ->
                selected_chart = $(this).attr('id')[0...-6] # slicing the name of the selected item
                console.log  ("zooming out to " + selected_chart)
                plot = $.plot($("##{selected_chart}_chart"), plot.getData(), $.extend(true, {}, Chart.generateChartOptions(selected_chart+'_legend', ticks),
                  xaxis:
                    min: null
                    max: null
              yaxis:
                min: null
                max: null
            ))
         return

here's a fiddle: http://jsfiddle.net/danklein/0tn1uzs9/3/

thanks a lot!

回答1:

1) The onClick directly in the HTML is a bad idea when the scope of the Chart object is not global. I changed it to a jquery event handler:

$('body').on 'click', 'a.legendtoggle', (event) ->
    Chart.togglePlot($(this).data('index'))
    return false

2) The series object in the labelFormatter function has no idx property, so I used a variable inside the Chart object:

labelFormatter: (label, series) ->
    "<a href=\"#\" class=\"legendtoggle\" data-index=\"" + Chart.legendindex++ + "\">" + label + "</a>"

3) I also put your plot object inside Chart so that it can be accessed inside the togglePlot function. And I changed the lines to points since your data has only one datapoint per series:

togglePlot: (seriesIdx) ->
    someData = this.plot.getData()
    someData[seriesIdx].points.show = not someData[seriesIdx].points.show
    this.plot.setData someData
    this.plot.draw()
    return

That should be all I changed, but compare for yourself if I got everything.
Here is a working fiddle: http://jsfiddle.net/jhpgtxz1/2/

PS: Never again CoffeeScript for me :-(