使用Ruby on Rails绘制过去30天的Highcharts数据

时间:2017-07-10 03:56:24

标签: javascript ruby-on-rails highcharts

我正在尝试找出将Rails后端需要的数据暴露到前端以绘制过去30天数据的最佳方法,无论是否每天记录一个条目过去30天与否。

我的控制器代码如下:

@symptoms = @current_member.symptoms

@symptoms_array ||= []

@symptoms.each do |symptom|
    array = [ Time.parse(symptom.date).getutc.iso8601, symptom.level.to_i ]
    @symptoms_array.push(array)
end

在我看来,我只是把这些数据放到一个元素的data属性上用JS读取(我知道,有更好的方法可以做到这一点......)。

<div id="graph" class="graph" data-symptoms="<%= @symptoms_array %>">

然后我的Highcharts JS实例化看起来像这样:

const data = $('#graph').data('symptoms');

Highcharts.chart('graph', {
    chart: {
        type: 'column',
        title: 'Pain levels'
    },
    xAxis: {
        categories: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
        title: {
            text: 'Date'
        }
    },
    yAxis: {
        title: {
            text: 'Pain level'
        },
        min: 0,
        max: 10,
        tickInterval: 1
    },
    tooltip: {
        headerFormat: '<b>{series.name}</b><br>',
        pointFormat: '{point.y}'
    },
    series: [{
        name: 'Pain level',
        data: data
    }]
});

我需要的是图表显示过去30天内每天的症状,无论当天是否有条目(它应该在没有条目的情况下显示0天)。并且X轴应该显示M ... F与星期几的相关性。现在,使用硬编码数组,它只显示M,T,W,T,F,S,S,7,8,9,10等。

2 个答案:

答案 0 :(得分:1)

我建议您将groupdate gem(https://github.com/ankane/groupdate)与chartkickhttps://github.com/ankane/chartkick)结合使用。 在您的情况下,您可以使用以下内容:

@symptoms = current_user.symptoms.group_by_day(:created_at).count

按天聚集所有症状。然后绘制它们,例如:

<%= column_chart @symptoms %>

查看gems文档以获取更多示例。

答案 1 :(得分:1)

要考虑两件事:数组需要包含所有日期,包括没有数据的日期,每个日期都需要采用适当的格式;所以我将做以下事情:

  1. 更新控制器以返回哈希(而不是数组)。
  2. 创建 helper 方法以创建data_series数组。
  3. 在图表中使用label代替categories
  4. 控制器

    创建一个哈希来存储值,其中每个键都是dateDate格式),其值为level

    def action
      @symptoms_hash = @current_member.symptoms.each do |symptom|
        date = Time.parse(symptom.date).getutc.iso8601.to_date
        symptoms_hash[date] = symptom.level.to_i
      end
    end
    

    请注意添加的.to_date,这样我们就可以更轻松地将日期转换为javascript格式。

    辅助

    def data_series(symptoms_hash)
      dates = (symptoms_hash.keys.min..symptoms_hash.keys.max).to_a
    
      dates.map do |date, value|
        js_date = "Date.UTC(#{date.year}, #{date.month - 1}, #{date.day})"
        "[#{js_date}, #{symptoms_hash[date].to_i}]"
      end
    end
    

    要理解的一些注意事项:

    • dates代表要绘制的时间范围,并从symptoms_hash中的最小和最长日期获取其第一个和最后一个日期。
    • Date.UTC用于创建有效的 javascript 日期,因此 highcharts 可以将其识别为 date ,这将让我们获得匹配的星期几
    • date.month - 1被使用是因为javascript中的月份以0开头,您需要将1减去日期的月份,否则您的日期会错误。
    • 返回值是一个字符串数组,但我们会在视图中将其转换为数组数组。

    视图

    使用刚刚创建的帮助器设置data并将categories替换为labels,这需要自定义formatter来显示名称中的第一个字母星期几的名字。

    <script type="text/javascript">
      const data = [<%= data_series(@symptoms_hash).join(",") %>];
    
      Highcharts.chart('graph', {
          chart: {
              type: 'column',
              title: 'Pain levels'
          },
          xAxis: {
              type: 'datetime',
              labels: {
                formatter: function() {
                  var dayOfWeek   = Highcharts.dateFormat('%A', this.value);
                  var firstLetter = dayOfWeek.substring(0, 1);
                  return firstLetter;
              }
              },
              title: {
                  text: 'Date'
              }
          },
          yAxis: {
              title: {
                  text: 'Pain level'
              },
              min: 0,
              max: 10,
              tickInterval: 1
          },
          tooltip: {
              headerFormat: '<b>{series.name}</b><br>',
              pointFormat: '{point.y}'
          },
          series: [{
              name: 'Pain level',
              data: data
          }]
      });
    </script>
    

    设置join时请注意data,它用于创建图表series工作所需的数组数组。