render_on (PDF::Charts::StdDev)

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