render_on (PDF::Charts::StdDev)

         # File lib/pdf/charts/stddev.rb, line 220
    220:   def render_on(pdf)
    221:     raise TypeError, PDF::Writer::Lang[:charts_stddev_data_empty] if @data.empty?
    222:     data = @data.dup
    223:     leftover_data = nil
    224:
    225:     loop do
    226:       # Set up the scale information.
    227:       scale = []
    228:
    229:       (@scale.first + @scale.step).step(@scale.last, @scale.step) do |ii|
    230:         scale << "%01.#{@scale.label.decimal_precision}f" % ii
    231:       end
    232:
    233:       scales = PDF::Writer::OHash.new
    234:       scale.each_with_index do |gg, ii|
    235:         scales[ii] = OpenStruct.new
    236:         scales[ii].value = gg
    237:       end
    238:
    239:       # Add information about the scales' locations to the scales
    240:       # hash. Note that the count is one smaller than it should be, so we're
    241:       # increasing it. The first scale is the bottom of the chart.
    242:       scale_count = scale.size + 1
    243:
    244:       label_height_adjuster = 0
    245:       label_height_adjuster = @label.height if @show_labels
    246:
    247:       chart_area_height = @height - label_height_adjuster
    248:       scale_height   = chart_area_height / scale_count.to_f
    249:
    250:       scales.each_key do |index|
    251:         this_height = scale_height * (index + 1) + @label.height
    252:         scales[index].line_height = this_height
    253:         if @scale.show_labels
    254:           scales[index].label_height = this_height -
    255:           (@scale.label.text_size / 3.0)
    256:         end
    257:       end
    258:
    259:       # How many sections do we need in this chart, and how wide will it
    260:       # need to be?
    261:       chunk_width = @datapoint_width
    262:       num_chunks  = data.size
    263:       widest_scale_label = 0
    264:
    265:       if @scale.show_labels
    266:         scales.each_value do |scale|
    267:           this_width = pdf.text_width(scale.value, @scale.label.text_size)
    268:           widest_scale_label = this_width if this_width > widest_scale_label
    269:         end
    270:       end
    271:
    272:       chart_width = chunk_width * num_chunks
    273:       total_width = chart_width + widest_scale_label + @scale.label.pad
    274:
    275:         # What happens if the projected width of the chart is too big?
    276:         # Figure out how to break the chart in pieces.
    277:       if total_width > @maximum_width
    278:         max_column_count = 0
    279:         base_width = widest_scale_label + @scale.label.pad
    280:         (1..(num_chunks + 1)).each do |ii|
    281:           if (base_width + (ii * chunk_width)) > @maximum_width
    282:             break
    283:           else
    284:             max_column_count += 1
    285:           end
    286:         end
    287:
    288:         leftover_data = data.slice!(max_column_count, -1)
    289:
    290:         num_chunks  = data.size
    291:         chart_width = chunk_width * num_chunks
    292:         total_width = chart_width + widest_scale_label + @scale.label.pad
    293:       end
    294:
    295:       chart_y = pdf.y - @height + @leading_gap
    296:       chart_y += (@outer_borders.style.width * 2.0) if @outer_borders
    297:
    298:       if chart_y < pdf.bottom_margin
    299:         pdf.start_new_page
    300:         chart_y = pdf.y - @height
    301:         chart_y += (@outer_borders.style.width * 2.0) if @outer_borders
    302:       end
    303:
    304:       chart_x = pdf.absolute_x_middle - (total_width / 2.0) + widest_scale_label
    305:
    306:         # Add labels, if needed.
    307:       if @show_labels
    308:         pdf.save_state
    309:         pdf.fill_color! @label.background_color
    310:         # Draw a rectangle for each label
    311:         num_chunks.times do |ii|
    312:           this_x = chart_x + ii * chunk_width
    313:           pdf.rectangle(this_x, chart_y, chunk_width, @label.height).fill
    314:         end
    315:
    316:           # Add a border above the label rectangle.
    317:         if @outer_borders
    318:           pdf.stroke_style! @outer_borders.style
    319:           pdf.line(chart_x, chart_y + @label.height, chart_x + chart_width, chart_y + @label.height).stroke
    320:         end
    321:         pdf.fill_color! @label.text_color
    322:
    323:         data.each_with_index do |datum, ii|
    324:           label = datum.label.to_s
    325:           label_width = pdf.text_width(label, @label.text_size)
    326:           this_x = chart_x + (ii * chunk_width) + (chunk_width / 2.0) - (label_width / 2.0)
    327:           this_y = chart_y + (@label.height / 2.0) - (@label.text_size / 3.0)
    328:           pdf.add_text(this_x, this_y, label, @label.text_size)
    329:         end
    330:         pdf.restore_state
    331:       end
    332:
    333:       if @inner_borders
    334:         pdf.save_state
    335:         pdf.stroke_color! @inner_borders.color
    336:         pdf.stroke_style! @inner_borders.style
    337:         (num_chunks - 1).times do |ii|
    338:           this_x = chart_x + (ii * chunk_width) + chunk_width
    339:           pdf.line(this_x, chart_y, this_x, chart_y + @height).stroke
    340:         end
    341:         pdf.restore_state
    342:       end
    343:
    344:       pdf.save_state
    345:       if @outer_borders
    346:         pdf.stroke_color! @outer_borders.color
    347:         pdf.stroke_style! @outer_borders.style
    348:         pdf.rectangle(chart_x, chart_y, chart_width, @height).stroke
    349:       end
    350:
    351:       if @scale.style
    352:         pdf.save_state
    353:         pdf.stroke_style! @scale.style
    354:         scales.each_value do |scale|
    355:           this_y = chart_y + scale.line_height
    356:           pdf.line(chart_x, this_y, chart_x + chart_width, this_y).stroke
    357:         end
    358:         pdf.restore_state
    359:       end
    360:
    361:       if @scale.show_labels
    362:         pdf.save_state
    363:         scales.each_value do |scale|
    364:           this_y = chart_y + scale.label_height
    365:           label_width = pdf.text_width(scale.value, @scale.label.text_size)
    366:           this_x = chart_x - label_width - @scale.label.pad
    367:           pdf.fill_color! @scale.label.text_color
    368:           pdf.add_text(this_x, this_y, scale.value, @scale.label.text_size)
    369:         end
    370:         pdf.restore_state
    371:       end
    372:
    373:       data.each_with_index do |datum, ii|
    374:         avg_height    = datum.average * scale_height
    375:         stddev_height = datum.stddev * scale_height
    376:         this_y        = chart_y + label_height_adjuster + avg_height
    377:         this_x        = chart_x + (ii * chunk_width) + (chunk_width / 2.0)
    378:         line_top_y    = this_y + (stddev_height / 2.0)
    379:         line_bot_y    = this_y - (stddev_height / 2.0)
    380:
    381:           # Plot the dot
    382:         if @dot
    383:           pdf.stroke_color! @dot.color
    384:           pdf.stroke_style! @dot.style
    385:           pdf.circle_at(this_x, this_y, (@dot.style.width / 2.0)).fill
    386:         end
    387:
    388:           # Plot the bar
    389:         if @bar
    390:           pdf.stroke_color! @bar.color
    391:           pdf.stroke_style! @bar.style
    392:           pdf.line(this_x, line_top_y, this_x, line_bot_y).stroke
    393:         end
    394:
    395:           # Plot the crossbars
    396:         if @upper_crossbar
    397:           if @dot
    398:             cb_width = @dot.style.width
    399:           else
    400:             cb_width = @upper_crossbar.style.width
    401:           end
    402:           pdf.stroke_color! @upper_crossbar.color
    403:           pdf.stroke_style! @upper_crossbar.style
    404:           pdf.line(this_x - cb_width, line_top_y, this_x + cb_width, line_top_y).stroke
    405:         end
    406:         if @lower_crossbar
    407:           if @dot
    408:             cb_width = @dot.style.width
    409:           else
    410:             cb_width = @lower_crossbar.style.width
    411:           end
    412:           pdf.stroke_color! @lower_crossbar.color
    413:           pdf.stroke_style! @lower_crossbar.style
    414:
    415:           pdf.line(this_x - cb_width, line_bot_y, this_x + cb_width, line_bot_y).stroke
    416:         end
    417:       end
    418:
    419:       pdf.restore_state
    420:
    421:       pdf.y = chart_y
    422:
    423:       break if leftover_data.nil?
    424:
    425:       data = leftover_data
    426:       leftover_data = nil
    427:     end
    428:
    429:     pdf.y
    430:   end