Tạo đồ thị và bảng xếp hạng thật dễ dàng trong Rails với Chartkick (Phần 2)

Trong phần trước chúng ta đã thảo luận về Chartkick- một gem tốt để biểu diễn các biểu đồ đơn giản. Ở phần này, chúng ta sẽ tìm hiểu các loại biểu đồ khác nhau mà Chartkick có nhé!

Các kiểu biểu đồ

Biểu đồ cột (Column Chart)

Để thể hiện việc sử dụng biểu đồ cột, hãy xem có bao nhiêu vận động viên của mỗi nước tham gia. Đầu tiên, hãy tạo ra một helper mới tương tự như cái đã tạo ở trước:

statistics_helper.rb

[...]
def sporters_by_country
  column_chart sporters_by_country_charts_path, library: {
      title: {text: 'Sporters by country', x: -20},
      yAxis: {
          title: {
              text: 'Sporters count'
          }
      },
      xAxis: {
          title: {
              text: 'Country'
          }
      }
  }
end
[...]

Sau đó thêm vào view:

views/statistics/index.html.erb

[...]
<%= sporters_by_country %>
[...]

Thêm route:

config/routes.rb

[...]
resources :charts, only: [] do
  collection do
    get 'sporters_by_age'
    get 'sporters_by_country'
  end
end
[...]

Trong controller sẽ bị phức tạp hơn chút:

charts_controller.rb

[...]
def sporters_by_country
  result = {}
  Country.all.map do |c|
    result[c.name] = c.sporters.count
  end
  render json: [{name: 'Count', data: result}]
end
[...]

Chú ý: kết quả được xây dựng theo key ở đây là tên nước và giá trị là tổng số các vận động viên.

Tải lại page và quan sát kết quả!

Biều đồ xếp chồng cột (Stacked Column Chart)

Lần này chúng ta sẽ thể hiện xem có bao nhiêu lần mỗi nước có một vị trí (từ 1 đến 6). Định nghĩa một helper mới:

statistics_helper.rb

[...]
def results_by_country
  column_chart results_by_country_charts_path, stacked: true, height: '500px', library: {
      title: {text: 'Results by country', x: -20},
      yAxis: {
          title: {
              text: 'Count'
          }
      },
      xAxis: {
          title: {
              text: 'Countries and places'
          }
      }
  }
end
[...]

Chú ý option stacked: true cung cấp kết quả như sau:

Sau đó thêm vào view:

views/statistics/index.html.erb

[...]
<%= results_by_country %>
[...]

Thêm route:

config/routes.rb

resources :charts, only: [] do
  collection do
    get 'sporters_by_age'
    get 'sporters_by_country'
    get 'results_by_country'
  end
end

Trong controller:

charts_controller.rb

[...]
def results_by_country
  result = Country.all.map do |c|
    places = {}
    (1..6).each do |place|
      places[place] = c.sporters.joins(:competition_results).
          where("competition_results.place = #{place}").count
    end
    {
        name: c.name,
        data: places
    }
  end
  render json: result
end
[...]

Chúng ta lấy tất cả các nước và sử sụng map để xây dựng một mảng dữ liệu. Bên trong, tìm toàn bộ các vận động viên đến từ một nước.  joins được sử dụng để tham gia vào bảng competition_results bởi vì nó chứa thông tin về nơi chốn. Sau đó đơn giản sử dụng where và count để nhận được giá trị cần tìm. Sau đó, như chúng ta đã biết, gán tên :name  cho nước đó và chia nhỏ places cho :data . Xem kết quả, một mảng các hash sẽ được tạo ra.

Biểu đồ Line và Groupdate (Line Chart and Groupdate)

Kiểu biểu đồ cuối này chúng ta sẽ làm hôm nay là biều đồ line. Để biểu diễn nó, hãy xem có bao nhiêu cuộc thi đã được tổ chức mỗi năm.

Lần nữa, hãy tạo một helper:

statistics_helper.rb

[...]
def competitions_by_year
  line_chart competitions_by_year_charts_path, library: {
      title: {text: 'Competitions by year', x: -20},
      yAxis: {
          crosshair: true,
          title: {
              text: 'Competitions count'
          }
      },
      xAxis: {
          crosshair: true,
          title: {
              text: 'Year'
          }
      }
  }
end
[...]

option :crosshair  được sử dụng để thể hiện như sau:

Sau đó thêm vào view:

views/statistics/index.html.erb

[...]
<%= competitions_by_year %>
[...]

Thêm route:

config/routes.rb

resources :charts, only: [] do
  collection do
    get 'sporters_by_age'
    get 'sporters_by_country'
    get 'results_by_country'
    get 'competitions_by_year'
  end
end

Giờ chúng ta cần tạo ra một hành động controller mới, nhưng bằng cách nào để chúng ta nhóm các cuộc thi theo năm và đếm chúng? Tất nhiên, chúng ta có thể query chúng, nhưng tổ chức của Chartkick đã lo việc đó với Groupdate gem. Như cái tên gợi ý, nó cho phép bạn nhóm theo năm, tháng, ngày và hơn thế. Nó hỗ trợ timezones, phạm vi của ngày, format, order và công cụ ưa thích khác, nên nó là giải pháp tốt để sử dụng với Chartkick.

Thêm Groupdate vào Gemfile:

[...]
gem 'groupdate'
[...]

Có vấn đề duy nhất với Groupdate là nó không hỗ trợ SQLite3, nên bạn sẽ phải sử dụng vài DMBS khác. Với minh hoạ này tôi sẽ sử dụng PostgreSQL. Chú ý rằng nếu bạn quyết định sử dụng MySQL, timezone support phải được cài đặt.

Tinh chỉnh Gemfile của bạn một lần nữa bằng cách thay sqlite3 bởi pg gem

[...]
gem 'pg'
[...]

Sau đó cài đặt gems:

bundle install

và modify database.yml:

_config/database.yml

development:
  adapter: postgresql
  encoding: unicode
  database: your_database
  pool: 5
  username: your_user
  password: your_password
  host: localhost
  port: 5432

Giờ chạy các migration lần nữa và đặt vào trong các bản với dữ liệu mẫu.

$ rake db:migrate
$ rake db:seed

Đừng quên tạo một database (rake db:create).

Giờ chúng ta có thể code controller:

charts_controller.rb

[...]
def competitions_by_year
  result = CompetitionResult.group_by_year(:created_at, format: "%Y").count
  render json: [{name: 'Count', data: result}]
end
[...]

Tuỳ chọn :format cho phép bạn cung cấp định dạng cho các key. Cũng như chúng ta chỉ muốn thể hiện các năm, tôi sử dụng %Y.

Tải lại page của bạn lần nữa và quan sát kết quả cuối cùng. Nếu bạn không thoả mãn với cách tạo ra các biểu đồ như thế, hãy sử dụng các thiết lập trong Highcharts documentation.

Tổng kết:

Trong bài này chúng ta đã thảo luận về Chartkick- một gem tốt để biểu diễn các biểu đồ đơn giản. Chúng ta đã thử các kiểu biểu đồ khác nhau, làm chúng tải lên không đồng bộ, cũng như tìm hiểu thêm các gems bổ sung . Tất nhiên, khi dùng nhiều các gems này, nên hãy kiểm duyệt các tài liệu đó và trải nghiệm thêm với code.

Thank you!!

Tài liệu dịch: https://www.sitepoint.com/make-easy-graphs-and-charts-on-rails-with-chartkick/