Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

build out a first pass at posting and viewing Grades

Includes adding Highcharts for Grade analysis
  • Loading branch information...
commit 38bbc10c83d20e89a153dddf1be5689d11b1fc08 1 parent 5b6cf9d
@agrobbin authored
Showing with 511 additions and 21 deletions.
  1. +1 −0  Gemfile
  2. +3 −0  Gemfile.lock
  3. +2 −0  app/assets/javascripts/application.js
  4. +40 −0 app/assets/javascripts/grades.js.coffee
  5. +3 −0  app/assets/stylesheets/base.css.scss
  6. +14 −0 app/assets/stylesheets/events.css.scss
  7. +142 −0 app/assets/stylesheets/grades.css.scss
  8. +0 −5 app/controllers/events_controller.rb
  9. +49 −0 app/controllers/grades_controller.rb
  10. +4 −0 app/controllers/institutions_controller.rb
  11. +17 −5 app/models/event.rb
  12. +60 −1 app/models/grade.rb
  13. +4 −0 app/models/section.rb
  14. +10 −0 app/views/events/_form.html.haml
  15. +3 −0  app/views/events/destroy.js.erb
  16. +3 −0  app/views/events/success.js.erb
  17. +23 −0 app/views/grades/_assignment.html.haml
  18. +26 −0 app/views/grades/_form.html.haml
  19. +13 −0 app/views/grades/analysis.html.haml
  20. +5 −0 app/views/grades/edit.html.haml
  21. +30 −1 app/views/grades/index.html.haml
  22. +1 −0  app/views/grades/update_failure.js.erb
  23. +2 −0  app/views/grades/update_success.js.erb
  24. +4 −1 config/routes.rb
  25. +2 −1  db/migrate/20110301010754_create_base.rb
  26. +7 −7 db/schema.rb
  27. +43 −0 vendor/assets/javascripts/highcharts-theme.js
View
1  Gemfile
@@ -5,6 +5,7 @@ gem 'delayed_job_active_record', '~> 0.3.3'
gem 'exception_notification', '~> 3.0.0'
gem 'google-api', '~> 0.3.0'
gem 'haml-rails', '~> 0.3.5'
+gem 'highcharts-js-rails', '~> 0.1.10'
gem 'jquery-rails', '2.1.4'
gem 'jquery-ui-rails', '2.0.2'
gem 'kaminari', '~> 0.14.1'
View
3  Gemfile.lock
@@ -75,6 +75,8 @@ GEM
haml (~> 3.1)
railties (>= 3.1, < 4.1)
hashie (1.2.0)
+ highcharts-js-rails (0.1.10)
+ railties (~> 3.1)
highline (1.6.15)
hike (1.2.1)
http_parser.rb (0.5.3)
@@ -238,6 +240,7 @@ DEPENDENCIES
font-awesome-rails (~> 0.4.1)
google-api (~> 0.3.0)
haml-rails (~> 0.3.5)
+ highcharts-js-rails (~> 0.1.10)
jquery-rails (= 2.1.4)
jquery-ui-rails (= 2.0.2)
kaminari (~> 0.14.1)
View
2  app/assets/javascripts/application.js
@@ -18,4 +18,6 @@
//= require jquery-fileupload
//= require jquery-livequery
//= require jquery-timeago
+//= require highcharts
+//= require highcharts-theme
//= require_tree .
View
40 app/assets/javascripts/grades.js.coffee
@@ -0,0 +1,40 @@
+class Grade
+
+ @update_assignment: (id, data) ->
+ assignment_list = $('#assignment-list tbody')
+
+ if $("#assignment-list #assignment_#{id}").length > 0
+ $("#assignment-list #assignment_#{id}").replaceWith data
+ else
+ $('#assignment-list .none').remove()
+ assignment_list.append data
+ $("#assignment-list #assignment_#{id}_analysis").remove()
+ assignment_list.html assignment_list.find('tr.assignment').sort (a, b) ->
+ $(a).data('sort') > $(b).data('sort')
+
+ @remove_assignment: (id) ->
+ $("#assignment_#{id}").remove()
+ $("#assignment_#{id}_analysis").remove()
+ if $('td.assignment').length is 0
+ colspan = $('#assignment-list tr.heading th').length
+ $('#assignment-list tbody').append "<tr class='none'><td colspan='#{colspan}'>There are currently no assignments available for grading for this course.</td></tr>"
+
+# Open up the Grade class to the global namespace
+(exports ? @).Grade = Grade
+
+$(document).on "click", "a.grade-analysis", (e) ->
+ e.preventDefault()
+ $(@).toggleClass('active')
+ assignment = $(@).parents('tr').attr('id')
+ analysis = $("tr##{assignment}_analysis")
+ if analysis.length > 0
+ analysis.find('div.analysis').slideToggle()
+ else
+ $.ajax @href,
+ dataType: 'html'
+ success: (data) ->
+ $("tr##{assignment}").after data
+
+$(document).on "click", ".grades .grade .score", (e) ->
+ $(@).hide()
+ $(@).parent().find('input[type=text]').show().focus().select()
View
3  app/assets/stylesheets/base.css.scss
@@ -369,6 +369,9 @@ a.section {
font-size: 20px;
color: #ccc;
padding: 20px 0;
+ td {
+ padding: 20px 0;
+ }
}
.loading {
View
14 app/assets/stylesheets/events.css.scss
@@ -107,6 +107,20 @@ table#calendar {
}
}
+.assignment-grade-info {
+ padding-bottom: 20px;
+ border-bottom: 2px dashed #ccc;
+ p {
+ float: left;
+ padding-right: 15px;
+ margin: 0;
+ }
+ input.text {
+ width: 40px;
+ min-width: 40px;
+ }
+}
+
span.prepended_to_input {
color: #aaa;
font-size: 14px;
View
142 app/assets/stylesheets/grades.css.scss
@@ -0,0 +1,142 @@
+@import "mixins";
+
+table#assignment-list {
+ width: 100%;
+ background-color: #fefefe;
+ tr.heading {
+ @include calendar-header;
+ @include css3-attribute(box-shadow, 0 2px 5px #777);
+ th {
+ padding: 7px 10px;
+ text-align: center;
+ border-left: 1px solid #fff;
+ &:first-child {
+ border-left: 0;
+ text-align: left;
+ }
+ &:nth-child(2) {
+ width: 13%;
+ min-width: 155px;
+ }
+ &:nth-child(n+3) {
+ width: 10%;
+ min-width: 115px;
+ }
+ }
+ }
+ tr.none td {
+ border: {
+ width: 0 1px 1px;
+ style: solid;
+ color: #ccc;
+ }
+ }
+ tr.assignment {
+ &.invisible {
+ opacity: 0.5;
+ &:hover {
+ opacity: 1;
+ }
+ }
+ td {
+ padding: 7px 10px;
+ text-align: center;
+ border: {
+ width: 0 0 1px 1px;
+ style: solid;
+ color: #ccc;
+ }
+ &:first-child {
+ text-align: left;
+ .actions {
+ margin-left: 10px;
+ float: right;
+ a {
+ @include css3-attribute(transition, 0.3s);
+ color: #aaa;
+ text-decoration: none;
+ font-size: 14px;
+ margin-left: 7px;
+ &:hover, &.active {
+ color: #000;
+ }
+ }
+ }
+ }
+ &:last-child {
+ border-right-width: 1px;
+ }
+ }
+ }
+ tr.analysis td {
+ padding: 0;
+ border-bottom-width: 0;
+ .analysis {
+ border-bottom: 1px solid #ccc;
+ padding: 15px;
+ h3 {
+ font-size: 16px;
+ &:before {
+ padding-right: 7px;
+ }
+ }
+ .graph {
+ float: left;
+ margin-top: 15px;
+ height: 225px;
+ &.one-third {
+ width: 33%;
+ }
+ &.two-thirds {
+ width: 65%;
+ }
+ &.third-sep {
+ width: 2%;
+ }
+ }
+ }
+ }
+}
+
+form.edit_event {
+ b {
+ font-size: 18px;
+ }
+ .grades {
+ max-height: 425px;
+ overflow: auto;
+ .grade {
+ position: relative;
+ padding: 7px 0;
+ border-top: 1px solid #ccc;
+ label {
+ padding: 8px 0;
+ display: inline-block;
+ clear: both;
+ }
+ input {
+ float: right;
+ width: 28px;
+ min-width: 28px;
+ text-align: center;
+ &[type="checkbox"] {
+ margin-top: 8px;
+ }
+ }
+ .score {
+ float: right;
+ margin-right: 5px;
+ padding: 6px 8px;
+ width: 25px;
+ text-align: center;
+ font-size: 15px;
+ &:hover {
+ @include css3-attribute(border-radius, 4px);
+ border: 1px solid #ccc;
+ padding: 5px 7px;
+ cursor: pointer;
+ }
+ }
+ }
+ }
+}
View
5 app/controllers/events_controller.rb
@@ -68,9 +68,4 @@ def destroy
@event.destroy
end
- private
- def get_event
- @event = (current_user.is_a?(Professor) ? @section.events : @section.events.visible).find(params[:id])
- end
-
end
View
49 app/controllers/grades_controller.rb
@@ -1,5 +1,54 @@
class GradesController < InstitutionsController
before_filter :get_course_and_section, if: Proc.new {|p| p.params[:section_id]}
+ before_filter :get_event, :require_professor, except: :index
+ before_filter :get_grade_fields, only: [:edit, :update]
+
+ ajax :analysis, :edit
+
+ def index
+ @title = "Gradebook#{within_section? ? " for #{@section.title}" : nil}"
+ @assignments = (current_user.is_a?(Professor) ? @section.events : @section.events.visible).assignments
+ @grades = Grade.scores_for(@assignments)
+ @student_grades = Grade.student_scores_for(current_user, @assignments) if current_user.is_a?(Student)
+ end
+
+ def analysis
+ grades = Grade.letter_scores(@event).values
+
+ @chart_1 = Highcharts.new
+ @chart_1.chart(renderTo: "assignment_#{@event.id}_analysis_chart_1", type: 'scatter')
+ @chart_1.title(text: nil)
+ @chart_1.legend(enabled: false)
+ @chart_1.xAxis([{title: 'Grades', categories: ['A', 'B', 'C', 'D', 'F']}])
+ @chart_1.yAxis([{title: '# of Students', min: 0, allowDecimals: false}])
+ @chart_1.series([{name: 'Grades', type: 'column', data: grades}])
+
+ grades = @event.grades.select('score, COUNT(*) AS count').order(:score).group(:score)
+ grades = grades.collect(&:attributes).collect(&:values)
+
+ @chart_2 = Highcharts.new
+ @chart_2.chart(renderTo: "assignment_#{@event.id}_analysis_chart_2")
+ @chart_2.title(text: nil)
+ @chart_2.legend(enabled: false)
+ @chart_2.xAxis([{title: 'Grades', categories: (0..100).to_a}])
+ @chart_2.yAxis([{title: '# of Students', min: 0, allowDecimals: false}])
+ @chart_2.series([{name: 'Grades', type: 'line', data: grades}])
+ end
+
+ def update
+ respond_to do |format|
+ format.js { render action: "update_#{@event.update_attributes(params[:event]) ? 'success' : 'failure'}" }
+ end
+ end
+
+ protected
+ def get_grade_fields
+ @students = @section.students.order(:last_name, :first_name)
+ grades = @event.grades
+ @event_grades = @students.collect do |student|
+ grades.find {|grade| grade.student_id == student.id} || Grade.new(student_id: student.id)
+ end
+ end
end
View
4 app/controllers/institutions_controller.rb
@@ -58,6 +58,10 @@ def get_course_and_section
redirect_to root_path and return
end
+ def get_event
+ @event = (current_user.is_a?(Professor) ? @section.events : @section.events.visible).find(params[:event_id] || params[:id])
+ end
+
def within_section?
@course && @section
end
View
22 app/models/event.rb
@@ -11,17 +11,29 @@ class Event < ActiveRecord::Base
modal: true
scope :visible, where(visible: true)
+ scope :assignments, where(assignment: true).order(:ends_at)
scope :for, lambda {|date_range| where(starts_at: date_range).order(:starts_at)}
belongs_to :section
+ has_many :grades, dependent: :destroy
has_many :documents, as: :resource
- validates_presence_of :title, :starts_at, :ends_at
- validate :check_starts_at,
- on: :create
- validate :check_ends_at
+ validates_presence_of :title, :starts_at, :ends_at
+ validate :check_starts_at,
+ on: :create
+ validate :check_ends_at
+ # Assignment-specific validations
+ validates_numericality_of :points_possible,
+ if: Proc.new {|event| event.assignment}
+ validates_numericality_of :weight,
+ less_than_or_equal_to: Proc.new {|event| 100 - event.section.weight_total + (event.weight_was || 0)},
+ if: Proc.new {|event| event.assignment}
- attr_accessible :visible, :assignment, :title, :description, :starts_at, :ends_at
+ attr_accessible :visible, :assignment, :title, :description, :starts_at, :ends_at, :points_possible, :weight, :grades_attributes
+
+ accepts_nested_attributes_for :grades,
+ allow_destroy: true,
+ reject_if: Proc.new {|attributes| !attributes['id'] && attributes['score'].blank?}
def full_title
"#{assignment ? 'DUE: ' : nil}#{title}"
View
61 app/models/grade.rb
@@ -3,6 +3,65 @@ class Grade < ActiveRecord::Base
belongs_to :event
belongs_to :student
- attr_accessible :score, :points_possible, :weight
+ validates_numericality_of :score,
+ less_than_or_equal_to: Proc.new {|grade| grade.event.points_possible}
+
+ attr_accessible :student_id, :score
+
+ # This pulls out the score calculation logic for Professors in order to avoid a potentially horrendous N+1 problem.
+ # Pass an array of Events and expect the following response:
+ #
+ # {1: {average: "75 / 100", range: "50-100 / 100"}, 2: {average: "75 / 100", range: "50-100 / 100"}}
+ #
+ # Where the `key` is the ID of the Event.
+ def self.scores_for(*events)
+ events.flatten!
+ grades = Grade.select("event_id, AVG(score) AS average, MIN(score) AS min, MAX(score) AS max").where(event_id: events.collect(&:id)).group(:event_id)
+ grades.inject({}) do |scores, grade|
+ event = events.find {|e| grade.event_id == e.id}
+ scores[event.id] = {
+ average: "#{grade.average.to_f} / #{event.points_possible}",
+ range: "#{grade.min}-#{grade.max} / #{event.points_possible}"
+ }
+ scores
+ end
+ end
+
+ # Pull out all of the scores for a particular Student and a particular set of Events.
+ # Pass a student and then an array of Events and expect the following response:
+ #
+ # {1: 95, 2: 100, 3: 77, 4: 82, 5: 86}
+ #
+ # Where the `key is the ID of the Event.
+ def self.student_scores_for(student, *events)
+ events.flatten!
+ grades = Grade.select("event_id, score").where(event_id: events.collect(&:id), student_id: student.id)
+ grades.inject({}) do |scores, grade|
+ event = events.find {|e| grade.event_id == e.id}
+ scores[event.id] = "#{grade.score} / #{event.points_possible}"
+ scores
+ end
+ end
+
+ # This take the grades for an Event and maps them to the appropriate letter grade. The final result is a Hash
+ # of letter: count key/value pairs:
+ #
+ # {'A' => 1, 'B' => 2, 'C' => 3, 'D' => 2, 'F' => 1}
+ def self.letter_scores(event)
+ letter_map = {
+ 'A' => 90,
+ 'B' => 80,
+ 'C' => 70,
+ 'D' => 65,
+ 'F' => 0
+ }
+
+ grades = event.grades.pluck(:score)
+ grades = grades.group_by {|g| letter_map.find {|l, min| g >= min }.first }
+ letter_map.inject({}) do |scores, (letter, min)|
+ scores[letter] = grades[letter].try(:length) || 0
+ scores
+ end
+ end
end
View
4 app/models/section.rb
@@ -34,4 +34,8 @@ def time
time += ends_at.strftime(" to %-l:%M%P")
end
+ def weight_total
+ events.assignments.sum(:weight)
+ end
+
end
View
10 app/views/events/_form.html.haml
@@ -3,6 +3,16 @@
= f.label :assignment do
= f.check_box :assignment
Is this an assignment?
+ .assignment-grade-info.assignment_labels{style: @event.assignment ? nil : 'display: none;'}
+ %p
+ = f.label :points_possible
+ = f.text_field :points_possible, class: 'text'
+ - if @section.grading_system == 'weight'
+ %p
+ = f.label :weight
+ = f.text_field :weight, class: 'text'
+ = "/ 100% (#{100 - @section.weight_total}% remaining)"
+ .clear
%p
= f.label :starts_at, 'Starts', class: 'event_labels', style: @event.assignment ? 'display: none;' : nil
= f.label :starts_at, 'Starting Due Date', class: 'assignment_labels', style: @event.assignment ? nil : 'display: none;'
View
3  app/views/events/destroy.js.erb
@@ -1,2 +1,5 @@
$('#event_<%= params[:id] %>').remove();
+<% if @event.assignment -%>
+Grade.remove_assignment(<%= params[:id] %>);
+<% end -%>
Modal.clear();
View
3  app/views/events/success.js.erb
@@ -1,2 +1,5 @@
Event.update(<%= @event.id %>, '<%= @event.starts_at.to_date.to_s(:db) %>', '<%=j render @event %>');
+<% if @event.assignment -%>
+Grade.update_assignment(<%= @event.id %>, '<%=j render partial: 'grades/assignment', object: @event %>');
+<% end -%>
Modal.clear();
View
23 app/views/grades/_assignment.html.haml
@@ -0,0 +1,23 @@
+- grade = (@grades || Grade.scores_for(assignment))[assignment.id]
+- student_grade = @student_grades[assignment.id] if current_user.is_a?(Student)
+%tr.assignment{id: "assignment_#{assignment.id}", class: current_user.is_a?(Professor) && !assignment.visible ? 'invisible' : nil, data: {sort: assignment.ends_at}}
+ %td
+ - if current_user.is_a?(Professor)
+ .actions
+ = link_to '', edit_section_event_grades_path(@section, assignment), class: 'icon-check modal', data: {tooltip: 'Post Grades'}
+ - if grade
+ = link_to '', analysis_section_event_grades_path(@section, assignment), class: 'icon-bar-chart grade-analysis', data: {tooltip: 'Analysis'}
+ = link_to '', edit_section_event_path(@section, assignment), class: 'icon-pencil modal', data: {tooltip: 'Edit'}
+ = link_to '', section_event_path(@section, assignment), class: 'icon-remove', method: :delete, confirm: 'Are you sure?', remote: true, data: {tooltip: 'Delete'}
+ = link_to assignment.title, section_event_path(@section, assignment), class: 'modal'
+ %td= assignment.ends_at.strftime("%b. %d, %Y by %I:%M%P")
+ - if current_user.is_a?(Student)
+ %td= student_grade || 'N/A'
+ - if @section.grading_system == 'weight'
+ %td= "#{assignment.weight}%"
+ - if grade
+ %td= grade[:average]
+ %td= grade[:range]
+ - else
+ %td N/A
+ %td N/A
View
26 app/views/grades/_form.html.haml
@@ -0,0 +1,26 @@
+= form_for [@section, @event], url: section_event_grades_path(@section, @event), remote: true do |f|
+ %p
+ This assignment has a maximum points possible of
+ %b= @event.points_possible
+ and is weighted
+ %b= "#{@event.weight}%."
+ .grades
+ = f.fields_for :grades, @event_grades do |g|
+ .grade
+ - if g.object.persisted?
+ = g.check_box :_destroy, data: {tooltip: 'Delete'}
+ - unless g.object.score_changed?
+ .score{data: {tooltip: 'Edit'}}= g.object.score
+ - else
+ = g.hidden_field :student_id
+ = g.text_field :score, class: 'text small', maxlength: 3, autocomplete: 'off', style: g.object.new_record? || g.object.score_changed? ? nil : 'display: none;'
+ = g.label :score, @students.find {|s| s.id == g.object.student_id}.name
+ .clear
+ %p.center
+ %i
+ Any updates to these grades will be
+ - if @event.visible
+ immediately visible to students.
+ - else
+ not be visible to students until you make the assignment visible.
+ = f.submit 'Post Grades'
View
13 app/views/grades/analysis.html.haml
@@ -0,0 +1,13 @@
+%tr.assignment.analysis{id: "assignment_#{@event.id}_analysis"}
+ %td{colspan: @section.grading_system == 'weight' ? 5 : 4}
+ .analysis
+ %h3.icon-bar-chart Assignment Grade Analysis
+ = @chart_1
+ .graph.one-third{id: "assignment_#{@event.id}_analysis_chart_1"}
+ .graph.third-sep
+ = @chart_2
+ .graph.two-thirds{id: "assignment_#{@event.id}_analysis_chart_2"}
+ .clear
+
+:javascript
+ $('tr#assignment_#{@event.id}_analysis td div.analysis').hide().slideToggle();
View
5 app/views/grades/edit.html.haml
@@ -0,0 +1,5 @@
+#modal-heading
+ %h2= "Post Grades for #{@event.title}"
+#modal-inner
+ = render 'error_messages', object: @event, as: :object
+ = render 'form'
View
31 app/views/grades/index.html.haml
@@ -1,3 +1,32 @@
- if within_section?
= render 'sections/subnavigation'
- #course= render 'sections/heading'
+
+#course
+ - if within_section?
+ = render 'sections/heading'
+ %br
+ %h2
+ - if current_user.is_a?(Professor)
+ = link_to 'Create an Assignment', new_section_event_path(@section, assignment: true), class: 'icon-check modal right button'
+ Course Gradebook
+ %p All assignments available for grading for this course are available below. Learn more about each grade by clicking on them.
+ %table#assignment-list{cellspacing: 0, cellpadding: 0}
+ %thead
+ %tr.heading
+ %th Assignment
+ %th Due
+ - if current_user.is_a?(Student)
+ %th Grade
+ - if @section.grading_system == 'weight'
+ %th Weight
+ %th Average
+ %th Range
+ %tbody
+ = render partial: 'assignment', collection: @assignments
+ - if @assignments.length.zero?
+ %tr.none
+ %td{colspan: @section.grading_system == 'weight' ? 5 : 4} There are currently no assignments available for grading for this course.
+ .clear
+ - if current_user.is_a?(Professor)
+ %p.center
+ %em NOTE: Assignments that are partially faded out are invisible to students.
View
1  app/views/grades/update_failure.js.erb
@@ -0,0 +1 @@
+$('#modal-body').html('<%=j render template: 'grades/edit' %>');
View
2  app/views/grades/update_success.js.erb
@@ -0,0 +1,2 @@
+Grade.update_assignment(<%= @event.id %>, '<%=j render partial: 'grades/assignment', object: @event %>');
+Modal.clear();
View
5 config/routes.rb
@@ -33,9 +33,12 @@
resources :events do
get ':year(/:month)', action: 'index', as: 'calendar', on: :collection, constraints: {year: /20[0-9]{2}/, month: /(?:0?[1-9]|1[0-2])/}
post 'upload', on: :member
+ resource :grades, only: [:edit, :update] do
+ get 'analysis', on: :collection
+ end
end
- resources :grades
get 'roster', on: :member
+ get 'grades', to: 'grades#index'
end
get '/events(/:year(/:month))', to: 'events#index', as: 'events', constraints: {year: /20[0-9]{2}/, month: /(?:0?[1-9]|1[0-2])/}
get '/grades', to: 'grades#index', as: 'grades'
View
3  db/migrate/20110301010754_create_base.rb
@@ -35,12 +35,13 @@ def change
t.string :title
t.text :description
t.datetime :starts_at, :ends_at
+ t.integer :points_possible, :weight
t.timestamps
end
create_table :grades do |t|
t.belongs_to :event, :student
- t.integer :score, :points_possible, :weight
+ t.integer :score
t.timestamps
end
View
14 db/schema.rb
@@ -58,24 +58,24 @@
create_table "events", :force => true do |t|
t.integer "section_id"
- t.boolean "visible", :default => true
+ t.boolean "visible", :default => true
t.boolean "assignment"
t.string "title"
t.text "description"
t.datetime "starts_at"
t.datetime "ends_at"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
+ t.integer "points_possible"
+ t.integer "weight"
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
end
create_table "grades", :force => true do |t|
t.integer "event_id"
t.integer "student_id"
t.integer "score"
- t.integer "points_possible"
- t.integer "weight"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
end
create_table "institutions", :force => true do |t|
View
43 vendor/assets/javascripts/highcharts-theme.js
@@ -0,0 +1,43 @@
+Highcharts.theme = {
+ colors: ["#29869d", "#f5e7be", "#e1a72f", "#f0a9b6", "#991B32"],
+ chart: {
+ backgroundColor: '#fff',
+ shadow: {
+ color: '#ddd',
+ offsetX: 0,
+ offsetY: 0,
+ opacity: 0.4,
+ width: 7
+ },
+ borderColor: '#ccc',
+ borderWidth: 1,
+ spacingTop: 25,
+ spacingRight: 25,
+ spacingBottom: 20,
+ spacingLeft: 20
+ },
+ credits: {
+ enabled: false
+ },
+ tooltip: {
+ pointFormat: '{series.name}: <b>{point.y}</b><br/>'
+ },
+ xAxis: {
+ title: {
+ style: {
+ color: '#333'
+ }
+ }
+ },
+ yAxis: {
+ title: {
+ style: {
+ color: '#333'
+ }
+ }
+ }
+
+};
+
+// Apply the theme
+var highchartsOptions = Highcharts.setOptions(Highcharts.theme);
Please sign in to comment.
Something went wrong with that request. Please try again.