From 87551e88f8606ba70edef83d2d3215198f02a287 Mon Sep 17 00:00:00 2001 From: differentreality Date: Tue, 17 Sep 2013 15:21:45 +0300 Subject: [PATCH] Create charts for registrations Conflicts: app/controllers/admin/stats_controller.rb app/views/admin/stats/index.html.haml --- app/controllers/admin/stats_controller.rb | 48 ++++++++-- app/views/admin/stats/_other_info.html | 70 ++++++++++++++ .../admin/stats/_preregistered_onsite.html | 85 ++++++++++++++++ .../admin/stats/_registered_attended.html | 19 ++-- app/views/admin/stats/_registered_time.html | 35 ++----- .../admin/stats/_registrations.html.haml | 32 ++++++- .../admin/stats/_registrations_attendees.html | 96 +++++++++++++++++++ app/views/admin/stats/_tickets.html.haml | 33 +------ app/views/admin/stats/_tickets_time.html | 86 +++++++++++++++++ 9 files changed, 432 insertions(+), 72 deletions(-) create mode 100644 app/views/admin/stats/_other_info.html create mode 100644 app/views/admin/stats/_preregistered_onsite.html create mode 100644 app/views/admin/stats/_registrations_attendees.html create mode 100644 app/views/admin/stats/_tickets_time.html diff --git a/app/controllers/admin/stats_controller.rb b/app/controllers/admin/stats_controller.rb index e6e27bfa..f83bb675 100644 --- a/app/controllers/admin/stats_controller.rb +++ b/app/controllers/admin/stats_controller.rb @@ -11,8 +11,10 @@ class Admin::StatsController < ApplicationController @registered_with_partner = @conference.registrations.where("attending_with_partner = ?", true).count @attended_with_partner = @conference.registrations.where("attending_with_partner = ? AND attended = ?", true, true).count - - @handicapped_access = @conference.registrations.where("handicapped_access_required = ?", true).count + + @handicapped_access = @conference.registrations.where(handicapped_access_required: true).count + @handicapped_access_attended = @conference.registrations.where(handicapped_access_required: true) + @handicapped_access_attended = @handicapped_access_attended.where(attended: true).count @suggested_hotel_stay = @conference.registrations.where("using_affiliated_lodging = ?", true).count @speakers = Person.joins(:events).where("events.conference_id = ? AND events.state LIKE ?", @conference.id, 'confirmed').uniq @@ -21,27 +23,53 @@ class Admin::StatsController < ApplicationController @supporter_levels = @conference.supporter_levels @tickets = @conference.registrations.joins(:supporter_registration => :supporter_level) - @tickets = @tickets.where("registrations.conference_id = ? AND supporter_levels.title NOT LIKE ? ", @conference, "%Free%").count + @tickets = @tickets.where("supporter_levels.title NOT LIKE ? ", "%Free%") + + @mydays = [] + @mytickets = [] + + (@conference.registration_start_date..@conference.end_date).each do |day| + day_reg_count = @registrations.where("created_at LIKE '%#{day}%' ").count + day_ticket_count = @tickets.where("supporter_registrations.created_at LIKE '%#{day}%' ").count + if day_reg_count != 0 + @mydays << {"status" => "#{day}", "value" => day_reg_count} + end + @conference.supporter_levels.each do |level| + day_ticket_count = @tickets.where("supporter_registrations.created_at LIKE ? AND supporter_levels.title LIKE ?", "%#{day}%", "%#{level.title}%").count + if day_ticket_count !=0 + @mytickets << {"status" => "#{day}", "ticket" => "#{level}", "value" => day_ticket_count} + end + end + end + + @other_info = [ + {"status" => "with partner (registered)", "value" => @registered_with_partner}, + {"status" => "with partner (attended)", "value" => @attended_with_partner}, + {"status" => "handicapped (registered)", "value" => @handicapped_access}, + {"status" => "handicapped (attended)", "value" => @handicapped_access_attended}, + {"status" => "stay at suggested hotel", "value" => @suggested_hotel_stay} + ] + end - + def speaker_reg(speaker) speaker.registrations.where("conference_id = ? AND person_id = ?", @conference.id, speaker.id).first end - + def speaker_diet(reg) @conference.dietary_choices.find(reg.dietary_choice_id) end - + def diet_count(diet) - @conference.registrations.where("dietary_choice_id = ?", diet).count + @conference.registrations.where("dietary_choice_id = ?", diet) end - + def social_event_count(event) @conference.registrations.joins(:social_events).where("registrations_social_events.social_event_id = ?", event).count end - + helper_method :speaker_reg helper_method :speaker_diet helper_method :diet_count helper_method :social_event_count -end +end \ No newline at end of file diff --git a/app/views/admin/stats/_other_info.html b/app/views/admin/stats/_other_info.html new file mode 100644 index 00000000..33dd56eb --- /dev/null +++ b/app/views/admin/stats/_other_info.html @@ -0,0 +1,70 @@ + \ No newline at end of file diff --git a/app/views/admin/stats/_preregistered_onsite.html b/app/views/admin/stats/_preregistered_onsite.html new file mode 100644 index 00000000..f8b9038e --- /dev/null +++ b/app/views/admin/stats/_preregistered_onsite.html @@ -0,0 +1,85 @@ + + + \ No newline at end of file diff --git a/app/views/admin/stats/_registered_attended.html b/app/views/admin/stats/_registered_attended.html index 2eb094ac..67c9006c 100644 --- a/app/views/admin/stats/_registered_attended.html +++ b/app/views/admin/stats/_registered_attended.html @@ -13,7 +13,7 @@ var width = 250, radius = Math.min(width, height) / 2; var color = d3.scale.ordinal() - .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]); + .range(["#9ECAE1", "#6baed6", "#DEEBF7"]); var arc = d3.svg.arc() .outerRadius(radius - 10) @@ -24,16 +24,18 @@ var pie = d3.layout.pie() .value(function(d) { return d.value; }); // Where to put the chart -var svg = d3.select("#charts").append("svg") +var svg = d3.select("#registered_attended").append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); var registered = '<%= h @pre_registered%>'; +var attended = '<%= h @pre_registered_attended %>'; +var not_attended = '<%= h @pre_registered - @pre_registered_attended %>'; var data = [ -{"status":"did not attend","value":'<%= h @pre_registered - @pre_registered_attended %>'}, -{"status":"attended","value":'<%= h @pre_registered_attended %>'} +{"status":"did not attend","value":not_attended, "percent": d3.round(not_attended / registered * 100)}, +{"status":"attended","value": attended, "percent": d3.round(attended / registered * 100)} ]; var g = svg.selectAll(".arc") @@ -50,7 +52,8 @@ g.append("text") .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; }) .attr("dy", ".35em") .style("text-anchor", "middle") - .text(function(d) { return d3.round(d.data.value / registered * 100) + "%"; }); + .text(function(d) { return d.data.percent +"%"; }); + // Title of chart svg.append("text") .attr("class", "title") @@ -59,10 +62,10 @@ svg.append("text") .text("% of pre-registered"); // Create & position legend -var legend = d3.select("#charts").append("svg") +var legend = d3.select("#registered_attended").append("svg") .attr("class", "legend") .attr("width", radius*2) - .attr("height", 230) + .attr("height", radius) .selectAll("g") .data(color.domain().slice().reverse()) .enter().append("g") @@ -77,6 +80,6 @@ legend.append("text") .attr("x", 24) .attr("y", 9) .attr("dy", ".15em") - .text(function(d) { return d; }); + .text(function(d) { return d + " (" + data.filter(function(v){return v.status === d;})[0].value + " or " + data.filter(function(v){return v.status === d;})[0].percent + "%)" ; }); \ No newline at end of file diff --git a/app/views/admin/stats/_registered_time.html b/app/views/admin/stats/_registered_time.html index 5b700ced..fe1ecc48 100644 --- a/app/views/admin/stats/_registered_time.html +++ b/app/views/admin/stats/_registered_time.html @@ -3,14 +3,15 @@ var registered = '<%= h @registrations.count%>'; var data = <%=raw @mydays.to_json %>; -var valueLabelWidth = 40; // space reserved for value labels (right) +var valueLabelWidth = 10; // space reserved for value labels (right) var barHeight = 24; // height of one bar var barLabelWidth = 100; // space reserved for bar labels var barLabelPadding = 8; // padding between bar and bar labels (left) var gridLabelHeight = 18; // space reserved for gridline labels var gridChartOffset = 3; // space between start of grid and first bar var maxBarWidth = 420; // width of the bar with the max value - +var color = d3.scale.category20(); + // accessor functions var barLabel = function(d) { return d['status']; }; var barValue = function(d) { return d['value'] / registered * 100; }; @@ -20,29 +21,13 @@ var barValues = function(d) { return d['value']; }; var yScale = d3.scale.ordinal().domain(d3.range(0, data.length)).rangeBands([0, data.length * barHeight]); var y = function(d, i) { return yScale(i); }; var yText = function(d, i) { return y(d, i) + yScale.rangeBand() / 2; }; -var x = d3.scale.linear().domain([0, 100]).range([0, maxBarWidth]); - +var yMax = d3.max(data, function(d){ return barValue(d) + 15; }); +var x = d3.scale.linear().domain([0, yMax]).range([0, maxBarWidth]); +var width = maxBarWidth + barLabelWidth + valueLabelWidth; // svg container element -var chart = d3.select('#c2').append("svg") +var chart = d3.select('#registered_time').append("svg") .attr('width', maxBarWidth + barLabelWidth + valueLabelWidth) .attr('height', gridLabelHeight + gridChartOffset + data.length * barHeight); -/* -// grid line labels -var gridContainer = chart.append('g') - .attr('transform', 'translate(' + barLabelWidth + ',' + gridLabelHeight + ')'); -gridContainer.selectAll("text").data(x.ticks(10)).enter().append("text") - .attr("x", x) - .attr("dy", -3) - .attr("text-anchor", "middle") - .text(String); - -// vertical grid lines -gridContainer.selectAll("line").data(x.ticks(10)).enter().append("line") - .attr("x1", x) - .attr("x2", x) - .attr("y1", 0) - .attr("y2", yScale.rangeExtent()[1] + gridChartOffset) - .style("stroke", "#ccc");*/ // bar labels var labelsContainer = chart.append('g') @@ -64,18 +49,18 @@ barsContainer.selectAll("rect").data(data).enter().append("rect") .attr('height', yScale.rangeBand()) .attr('width', function(d) { return x(barValue(d)); }) .attr('stroke', 'white') - .attr('fill', 'steelblue'); + .attr('fill', function(d) { return color(barValue(d)); }); // bar value labels barsContainer.selectAll("text").data(data).enter().append("text") - .attr("x", function(d) { return x(barValue(d)); }) + .attr("x", 5) .attr("y", yText) .attr("dx", 3) // padding-left .attr("dy", ".35em") // vertical-align: middle .attr("text-anchor", "start") // text-align: right .attr("fill", "black") .attr("stroke", "none") - .text(function(d) { return d3.round(barValues(d), 2) + " registrations (" + d3.round(barValue(d), 0) + "%)"; }); + .text(function(d) { return d3.round(barValues(d), 2) + " (" + d3.round(barValue(d), 0) + "%)"; }); // start line barsContainer.append("line") .attr("y1", -gridChartOffset) diff --git a/app/views/admin/stats/_registrations.html.haml b/app/views/admin/stats/_registrations.html.haml index 74d41e4b..53abef12 100644 --- a/app/views/admin/stats/_registrations.html.haml +++ b/app/views/admin/stats/_registrations.html.haml @@ -1,2 +1,32 @@ +.row-fluid + .span4 + %h4{:style => "text-indent: 25px"}= "Registrations - Attendees (#{(@attendees.to_f / @registered * 100).round}%)" + .row-fluid + .span12#registrations_attendees + + .span4 + %h4{:style => "text-indent: 10px"}= "Attendance of pre-registered" + .row-fluid + .span12#registered_attended + + .span4 + %h4{:style => "text-indent: 25px"}= "% of pre-registered" + .row-fluid + .span12#preregistered_onsite + +.row-fluid + .span6 + %h4= "Other Info" + .row-fluid + .span12#other_info + + .span6 + %h4{:style => "text-indent: 98px"}= "Registrations over time" + .row-fluid + .span12#registered_time + = render :partial => "registered_attended" -= render :partial => "registered_time" \ No newline at end of file += render :partial => "registered_time" += render :partial => "preregistered_onsite" += render :partial => "registrations_attendees" += render :partial => "other_info" \ No newline at end of file diff --git a/app/views/admin/stats/_registrations_attendees.html b/app/views/admin/stats/_registrations_attendees.html new file mode 100644 index 00000000..57f097e4 --- /dev/null +++ b/app/views/admin/stats/_registrations_attendees.html @@ -0,0 +1,96 @@ + \ No newline at end of file diff --git a/app/views/admin/stats/_tickets.html.haml b/app/views/admin/stats/_tickets.html.haml index f9d1f18a..03c2e99b 100644 --- a/app/views/admin/stats/_tickets.html.haml +++ b/app/views/admin/stats/_tickets.html.haml @@ -1,28 +1,5 @@ -.row-fluid - .span12 - %h3 - Non-free Tickets (#{@tickets}) -.row-fluid - .span5 - - if @supporter_levels.count > 0 - %table.table.table-bordered.table-striped - %thead - %th Support Level - %th # - %th % - - @supporter_levels.each do |level| - - reg_count = level.supporter_registrations.where(conference_id: @conference).count - - if reg_count > 0 - %tr - %td= level.title - %td - = reg_count - %td - - if @registered and @registered > 0 - = "#{reg_count * 100 / @registered}% of registered" - - if @attendees and @attendees > 0 - %br - = "#{reg_count * 100 / @attendees}% of attendees" - - else - %p - No tickets sold yet +- if @tickets + %h2 + = "Non-Free Tickets(#{@tickets.count})" +.span4#tickets_time += render :partial => "tickets_time" \ No newline at end of file diff --git a/app/views/admin/stats/_tickets_time.html b/app/views/admin/stats/_tickets_time.html new file mode 100644 index 00000000..a984443b --- /dev/null +++ b/app/views/admin/stats/_tickets_time.html @@ -0,0 +1,86 @@ + \ No newline at end of file