Merge pull request #755 from kepstin/poll-recording

Add poll result display to the 'presentation' recording format
This commit is contained in:
Richard Alam 2015-08-11 16:38:12 -04:00
commit cde602ac9b
2 changed files with 110 additions and 27 deletions

View File

@ -147,7 +147,14 @@ function runPopcorn() {
var array = $(shapeelements[0]).find("g").filter(function(){ //get all the lines from the svg file
return $(this).attr('class') == 'shape';
});
var images = shapeelements[0].getElementsByTagName("image");
// Newer recordings have slide images identified by class="slide"
// because they might include images in shapes
var images = shapeelements[0].getElementsByClassName("slide");
// To handle old recordings, fetch a list of all images instead
if (images.length == 0) {
images = shapeelements[0].getElementsByTagName("image");
}
//create a map from timestamp to id list

View File

@ -437,6 +437,84 @@ def storeTextShape
$originalOriginY = $originY
end
def storePollResultShape(xml, shape)
origin_x = $shapeDataPoints[0].to_f / 100 * $vbox_width
origin_y = $shapeDataPoints[1].to_f / 100 * $vbox_height
width = $shapeDataPoints[2].to_f / 100 * $vbox_width
height = $shapeDataPoints[3].to_f / 100 * $vbox_height
result = JSON.load(shape.at_xpath('result').text)
num_responders = shape.at_xpath('num_responders').text.to_i
presentation = shape.at_xpath('presentation').text
$global_shape_count += 1
$poll_result_count += 1
dat_file = "#{$process_dir}/poll_result#{$poll_result_count}.dat"
gpl_file = "#{$process_dir}/poll_result#{$poll_result_count}.gpl"
pdf_file = "#{$process_dir}/poll_result#{$poll_result_count}.pdf"
svg_file = "#{$process_dir}/presentation/#{presentation}/poll_result#{$poll_result_count}.svg"
# Use gnuplot to generate an SVG image for the graph
File.open(dat_file, 'w') do |d|
result.each do |r|
d.puts("#{r['id']} #{r['num_votes']}")
end
end
File.open(dat_file, 'r') do |d|
BigBlueButton.logger.debug("gnuplot data:")
BigBlueButton.logger.debug(d.readlines(nil)[0])
end
File.open(gpl_file, 'w') do |g|
g.puts('reset')
g.puts("set term pdfcairo size #{height / 72}, #{width / 72} font \"Arial,48\"")
g.puts('unset key')
g.puts('set style data boxes')
g.puts('set style fill solid border -1')
g.puts('set boxwidth 0.9 relative')
g.puts('set yrange [0:*]')
g.puts('unset border')
g.puts('unset ytics')
xtics = result.map{ |r| "\"#{r['key'].gsub('%', '%%')}\" #{r['id']}" }.join(', ')
g.puts("set xtics rotate by 90 scale 0 right (#{xtics})")
x2tics = result.map{ |r| "\"#{(r['num_votes'].to_f / num_responders * 100).to_i}%%\" #{r['id']}" }.join(', ')
g.puts("set x2tics rotate by 90 scale 0 left (#{x2tics})")
g.puts('set linetype 1 linewidth 1 linecolor rgb "black"')
result.each do |r|
if r['num_votes'].to_f / num_responders <= 0.5
g.puts("set label \"#{r['num_votes']}\" at #{r['id']},#{r['num_votes']} left rotate by 90 offset 0,character 0.5 front")
else
g.puts("set label \"#{r['num_votes']}\" at #{r['id']},#{r['num_votes']} right rotate by 90 offset 0,character -0.5 textcolor rgb \"white\" front")
end
end
g.puts("set output \"#{pdf_file}\"")
g.puts("plot \"#{dat_file}\"")
end
File.open(gpl_file, 'r') do |d|
BigBlueButton.logger.debug("gnuplot script:")
BigBlueButton.logger.debug(d.readlines(nil)[0])
end
ret = BigBlueButton.exec_ret('gnuplot', '-d', gpl_file)
raise "Failed to generate plot pdf" if ret != 0
ret = BigBlueButton.exec_ret('pdftocairo', '-svg', pdf_file, svg_file)
raise "Failed to convert poll to svg" if ret != 0
xml.g(class: 'shape', id: "draw#{$global_shape_count}",
shape: "poll_result#{$poll_result_count}", style: 'visibility:hidden',
timestamp: $shapeCreationTime, undo: $shapeUndoTime) do
# Outer box to act as poll result backdrop
xml.rect(x: origin_x + 2, y: origin_y + 2, width: width - 4, height: height - 4,
'fill' => 'white', 'stroke' => 'black', 'stroke-width' => 4)
# Poll image
xml.image('xlink:href' => "presentation/#{presentation}/poll_result#{$poll_result_count}.svg",
height: width, width: height, x: $vbox_width, y: origin_y,
transform: "rotate(90, #{$vbox_width}, #{origin_y})")
end
end
#
# Calculate the offsets based on the start and stop recording events, so it's easier
# to translate the timestamps later based on these offsets
@ -614,7 +692,7 @@ def processShapesAndClears
$xml.svg(:id => :svgfile, :style => 'position:absolute; height:600px; width:800px;', :xmlns => 'http://www.w3.org/2000/svg', 'xmlns:xlink' => 'http://www.w3.org/1999/xlink', :version => '1.1', :viewBox => :'0 0 800 600') do
# This is for the first image. It is a placeholder for an image that doesn't exist.
$xml.image(:id => :image0, :in => 0, :out => $first_slide_start, :src => "logo.png", :width => 800)
$xml.image(:id => :image0, :class => 'slide', :in => 0, :out => $first_slide_start, :src => "logo.png", :width => 800)
$xml.g(:class => :canvas, :id => :canvas0, :image => :image0, :display => :none)
$presentation_name = ""
@ -625,7 +703,7 @@ def processShapesAndClears
# Print out the gathered/detected images.
$slides_compiled.each do |key, val|
$val = val
$xml.image(:id => "image#{$val[2].to_i}", :in => $val[0].join(' '), :out => $val[1].join(' '), 'xlink:href' => key[0], :height => key[1], :width => key[2], :visibility => :hidden, :text => $val[3], :x => 0)
$xml.image(:id => "image#{$val[2].to_i}", :class => 'slide', :in => $val[0].join(' '), :out => $val[1].join(' '), 'xlink:href' => key[0], :height => key[1], :width => key[2], :visibility => :hidden, :text => $val[3], :x => 0)
$canvas_number+=1
$xml.g(:class => :canvas, :id => "canvas#{$val[2].to_i}", :image => "image#{$val[2].to_i}", :display => :none) do
@ -654,14 +732,17 @@ def processShapesAndClears
$pageNumber = shape.xpath(".//pageNumber")[0].text()
$shapeDataPoints = shape.xpath(".//dataPoints")[0].text().split(",")
if($shapeType == "text")
case $shapeType
when 'pencil', 'rectangle', 'ellipse', 'triangle', 'line'
$shapeThickness = shape.xpath(".//thickness")[0].text()
colour = shape.xpath(".//color")[0].text()
when 'text'
$textValue = shape.xpath(".//text")[0].text()
$textFontType = "Arial"
$textFontSize = shape.xpath(".//fontSize")[0].text()
colour = shape.xpath(".//fontColor")[0].text()
else
$shapeThickness = shape.xpath(".//thickness")[0].text()
colour = shape.xpath(".//color")[0].text()
when 'poll_result'
# Just hand the 'shape' xml object to the poll rendering code.
end
# figure out undo time
@ -713,16 +794,12 @@ def processShapesAndClears
end
end
# Process the pencil shapes.
if $shapeType.eql? "pencil"
case $shapeType
when 'pencil'
storePencilShape()
# Process the line shapes.
elsif $shapeType.eql? "line"
when 'line'
storeLineShape()
# Process the rectangle shapes
elsif $shapeType.eql? "rectangle"
when 'rectangle'
square = shape.xpath(".//square")
if square.length > 0
$is_square = square[0].text()
@ -730,13 +807,9 @@ def processShapesAndClears
$is_square = 'false'
end
storeRectShape()
# Process the triangle shapes
elsif $shapeType.eql? "triangle"
when 'triangle'
storeTriangleShape()
# Process the ellipse shapes
elsif $shapeType.eql? "ellipse"
when 'ellipse'
circle = shape.xpath(".//circle")
if circle.length > 0
$is_circle = circle[0].text()
@ -744,12 +817,13 @@ def processShapesAndClears
$is_circle = 'false'
end
storeEllipseShape()
elsif $shapeType.eql? "text"
when 'text'
$textBoxWidth = shape.xpath(".//textBoxWidth")[0].text()
$textBoxHeight = shape.xpath(".//textBoxHeight")[0].text()
storeTextShape()
end # end if pencil (and other shapes)
when 'poll_result'
storePollResultShape($xml, shape)
end
end # end if(in_this_image)
end # end shape_events.each do |shape|
end
@ -801,6 +875,7 @@ $pencil_count = 0
$line_count = 0
$ellipse_count = 0
$text_count = 0
$poll_result_count = 0
$global_shape_count = -1
$global_slide_count = 1
$global_page_count = 0
@ -882,9 +957,6 @@ if ($playback == "presentation")
BigBlueButton.logger.info("Copied audio.ogg file")
end
BigBlueButton.logger.info("Copying files to package dir")
FileUtils.cp_r("#{$process_dir}/presentation", package_dir)
BigBlueButton.logger.info("Copied files to package dir")
processing_time = File.read("#{$process_dir}/processing_time")
@ -975,6 +1047,10 @@ if ($playback == "presentation")
# Write panzooms.xml to file
File.open("#{package_dir}/#{$cursor_xml_filename}", 'w') { |f| f.puts $cursor_xml.to_xml }
BigBlueButton.logger.info("Copying files to package dir")
FileUtils.cp_r("#{$process_dir}/presentation", package_dir)
BigBlueButton.logger.info("Copied files to package dir")
BigBlueButton.logger.info("Publishing slides")
# Now publish this recording files by copying them into the publish folder.
if not FileTest.directory?(publish_dir)