【问题标题】:Flot charts- producing custom trend with unique x-axis values浮动图表 - 生成具有唯一 x 轴值的自定义趋势
【发布时间】:2014-09-20 23:07:18
【问题描述】:

我有一个数据库关系,其中包含我希望显示的信息。 每条记录都包含一个数值和一个类似于“20140325_064532”的“名称”。

创建记录的顺序无关紧要,所以我希望在y轴和x轴上呈现数值:

  1. 在刻度之间具有恒定边距
  2. 根据'name' order(字典顺序)呈现数据。
  3. x 轴标签不应显示所有值,而是“选定的值”,这样不应显示重叠。
  4. 以防止将两个点放置在相同的 x 值中,即使它们具有相同的“名称”(内部顺序没有意义)。

我应该如何定义我的 Flot 图表才能实现这一点?

编辑:到目前为止我的实现想法:

  1. 我将从数据库中(明确地)获取“名称”字段以及 row_number 值(从 1 开始)。
  2. 在此基础上,我将创建一个哈希,使用名称作为行号的键。让我们说:name => row#
  3. 我将生成具有以下结构的系列:rawdata = [ [row#1, numericValue1], [row#2, numericValue2], ....];

    请注意,row# 将是一个从 1 开始的数值。

  4. 我将定义刻度以表示实际名称。 (这将是一个带点的折线图,而不是条形图)。

现在,所有这些都会起作用(我认为),但看起来真的很乱。 而且,最重要的是,刻度几乎肯定会重叠,而且它是硬编码的,任何放大和缩小都不会呈现带有重叠想法的刻度。

更新 #2:

我使用两个数据属性将数据传递给 js。 “结果”有一个表示系列的数组,并包含 4 个字段,这样 data-results="[[[0,371144,"20140206_000030-std",375],[1,373141,"20140328_230027",343],[2,374196,"20140401_230051",436],[3,374734,"20140401_230051_2",460],[4,374394,"20140401_230051_3",484],[5,376029,"20140401_230051_4",508]],... ,[another_series]]]

第三个字段是'name',最后一个是'id'

“系列”代表我对每个系列的名称(以及它在图例中的显示方式),看起来像:

data-series="["PLATFORM_A__CONFIG_B","PLATFORM_B__CONFIG_NONE"]"

我尝试编辑工具提示的content,试图整合每个点最后部分的信息,以便显示如下内容: 跑: ID: value: $y(第二个数组字段,代表y轴值)

我搜索了网络,但找不到任何可以使用工具提示(看起来更好处理)的东西。 在文档中提到:

如果您需要对工具提示的生成方式进行更多控制,您可以 可以传递一个回调函数(label,xval,yval,flotItem),它必须 返回具有所述格式的字符串。

我尝试通过调用 Chart.getTooltip 来实现这一点,但我在控制台中得到的只是

Uncaught TypeError: undefined is not a function jquery.flot.tooltip.min.js?body=1:2h jquery.flot.tooltip.min.js?body=1:2(anonymous function) jquery.flot.tooltip.min.js?body=1:2jQuery.event.dispatch jquery.js?body=1:4642elemData.handle jquery.js?body=1:4310jQuery.event.trigger jquery.js?body=1:4551(anonymous function) jquery.js?body=1:5261jQuery.extend.each jquery.js?body=1:384jQuery.fn.jQuery.each jquery.js?body=1:137jQuery.fn.extend.trigger jquery.js?body=1:5260Y jquery.flot.cust.min.js?body=1:2V jquery.flot.cust.min.js?body=1:2jQuery.event.dispatch jquery.js?body=1:4642elemData.handle jquery.js?body=1:4310

更新 #3 感谢@Ryley 的精彩提示和指导,我能够使用传递给 Flot 的唯一值正确显示我的图表。 我更新了我的代码,为了避免刻度值重叠,我使用flot-tickrotor js 来旋转外观。 我遇到了一个问题,我的最低值被截断了。 我还注意到这是reported issue,但我找不到任何解决方案或解决方法。 这个问题有解决办法吗?

接下来,我想让查看器通过单击来显示/隐藏该系列。 我找到了一堆解决方案,包括官方的和其他的,但没有一个对我有用。 我来解释一下:

  1. Official turning series on/off:这可行,但看起来很乱,因为传说最终被复制了两次(一旦系列关闭,官方传说就会消失)。
  2. Hiddengraphs.js:这是一个插件,可以在插件存储库中找到,但它不能工作并且与 Chrome 交互不好(尝试了不止一台机器,它就是不工作)。
  3. This solution 实际上非常好(我不介意没有要检查的复选框),但是当我将它集成到我的代码中时,我得到的只是“跳转”到页面顶部,没有任何反应。
  4. Lastly, I found this solution,虽然使用另一个名为 flot.togglelegend.js 的 js 库,但它也可以工作。 在这个实现中,我发现了与flot.cust.js 的一些重大冲突,并且无法让它们一起工作。

最后,我尝试实现选择缩放和双击缩放重置,使用flot.selection.js 我确实能够使该功能正常工作,但是重新渲染过程会在我的第二个和第三个图表中生成第一个图表的数据。

值得一提的是,我在这个页面中渲染了 3 个图表,都以相同的方式渲染。

这是我更新的代码:

这是我当前的js(用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

getTooltip: (label, xval, yval, flotItem) ->
    return 'Build: <span>'+ flotItem.series.data[flotItem.dataIndex][2]+'</span>' +" | Run ID: <strong> #{flotItem.series.data[flotItem.dataIndex][3].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=\"#\" onClick=\"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 # 仅在 chart-id 存在时渲染

    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

非常感谢!

【问题讨论】:

  • 嗨@Ryley。我还没有实现这个,但我已经更新了我目前对此的想法。希望现在更清楚了。
  • 您的具体问题/问题是什么?显示代码并解释您遇到的问题。
  • 在这个网站上,我们希望您在提问之前尽可能多地了解。听起来你在正确的轨道上。更进一步 - 制作一个示例数据集,将其与您认为可行的选项一起放入 flot,然后使用您的示例数据发布代码。否则,您是在要求我们读懂您的想法:)
  • @Ryley,谢谢。我今天取得了一些进展,并相应地更新了我的问题。

标签: javascript jquery flot


【解决方案1】:

嗯,你已经完成了大部分的工作,我刚刚为你完成了......

基本问题:

  • 数据格式为[[x1,y1],[x2,y2],...

     data: [[all_series_data[i][0],all_series_data[i][1]]]
    
  • 正确指定刻度(这只是抓取每个奇数)

    tick_labels = []
    for series, i in all_series
        if i % 2
            tick_labels.push [i,series]
        else
            tick_labels.push [i,'']  
    

然后在你的情节选项中:

       xaxis:
            ticks: tick_labels  
  • 包含工具提示库并以默认方式使用它。我使用了来自a CDN 的副本。
  • 修复一个基本的coffeescript语法错误(可能只是从这里复制过来的)。在您的 GenerateChartOptions 中,您打开一个 ( 并且永远不要在最后关闭它。

这是一个工作示例:http://jsfiddle.net/ryleyb/0tn1uzs9/2/

基于 cmets,我将其添加到示例中:

    #in the flot options
        tooltipOpts:
            content: Chart.getToolTip

#to the Chart object
getToolTip: (label, xval, yval, flotItem) ->
    return 'Run: '+raw_data[xval][3]+': value: '+Chart.commify(yval)
commify: (x) ->
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");

【讨论】:

  • 非常感谢您的意见。我的浮动图表实际上可以使用我提供的配置呈现(我在外部生成数据、系列和刻度数组并将它们传递给 Coffeescript)。错误来自尝试在悬停框工具提示中实现自定义消息,使用更多数据(这就是为什么我在数组中插入了两个以上的项目,如this thread, second answer 所示,并且还操纵了 y 轴数据。即 -我想要而不是 1234567 值 -> 1,234,567
  • 当然,好吧...我现在也添加了。
  • 谢谢!这工作得很好!!事实证明我没有使用他最近的 tooltip.js 之一,所以这就是为什么我得到这个 undefined is not a function 错误。我真的快要完成我的实施了。我在主要问题中发布了一个更新#3,其中包含我当前的问题。
  • 执行此操作的通常方法不是在解决问题时更新您的问题,更常见的是提出一个新问题来询问您的新问题。这个想法是这个问题应该保持原样,以便其他有同样问题的人可以来看看它并看到答案。通过编辑您的问题,它会混淆答案的用途。
  • 感谢您的提示!我已经编辑了这篇文章和created a new one to the most troubling issue I have。如果需要,我将为其余问题创建一个新帖子。
猜你喜欢
  • 1970-01-01
  • 2017-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-16
  • 1970-01-01
相关资源
最近更新 更多