lib/prawn/graphics.rb in prawn-0.12.0 vs lib/prawn/graphics.rb in prawn-0.13.0

- old
+ new

@@ -10,11 +10,11 @@ require "prawn/graphics/dash" require "prawn/graphics/cap_style" require "prawn/graphics/join_style" require "prawn/graphics/transparency" require "prawn/graphics/transformation" -require "prawn/graphics/gradient" +require "prawn/graphics/patterns" module Prawn # Implements the drawing facilities for Prawn::Document. # Use this to draw the most beautiful imaginable things. @@ -28,11 +28,11 @@ include Dash include CapStyle include JoinStyle include Transparency include Transformation - include Gradient + include Patterns ####################################################################### # Low level drawing operations must map the point to absolute coords! # ####################################################################### @@ -80,23 +80,23 @@ # def rectangle(point,width,height) x,y = map_to_absolute(point) add_content("%.3f %.3f %.3f %.3f re" % [ x, y - height, width, height ]) end - + # Draws a rounded rectangle given <tt>point</tt>, <tt>width</tt> and - # <tt>height</tt> and <tt>radius</tt> for the rounded corner. The rectangle + # <tt>height</tt> and <tt>radius</tt> for the rounded corner. The rectangle # is bounded by its upper-left corner. # # pdf.rounded_rectangle [300,300], 100, 200, 10 # def rounded_rectangle(point,width,height,radius) x, y = point rounded_polygon(radius, point, [x + width, y], [x + width, y - height], [x, y - height]) end - + ########################################################### # Higher level functions: May use relative coords # ########################################################### # Sets line thickness to the <tt>width</tt> specified. @@ -136,19 +136,19 @@ # Draws a horizontal line from <tt>x1</tt> to <tt>x2</tt> at the # current <tt>y</tt> position, or the position specified by the :at option. # # # draw a line from [25, 75] to [100, 75] - # horizontal_line 25, 100, :at => 75 + # horizontal_line 25, 100, :at => 75 # def horizontal_line(x1,x2,options={}) if options[:at] y1 = options[:at] else y1 = y - bounds.absolute_bottom end - + line(x1,y1,x2,y1) end # Draws a horizontal line from the left border to the right border of the # bounding box at the current <tt>y</tt> position. @@ -220,23 +220,23 @@ move_to(x + r1, y) # Upper right hand corner curve_to [x, y + r2], - :bounds => [[x + r1, y + l1], [x + l2, y + r2]] + :bounds => [[x + r1, y + l2], [x + l1, y + r2]] # Upper left hand corner curve_to [x - r1, y], - :bounds => [[x - l2, y + r2], [x - r1, y + l1]] + :bounds => [[x - l1, y + r2], [x - r1, y + l2]] # Lower left hand corner curve_to [x, y - r2], - :bounds => [[x - r1, y - l1], [x - l2, y - r2]] + :bounds => [[x - r1, y - l2], [x - l1, y - r2]] # Lower right hand corner curve_to [x + r1, y], - :bounds => [[x + l2, y - r2], [x + r1, y - l1]] + :bounds => [[x + l1, y - r2], [x + r1, y - l2]] move_to(x, y) end # Draws a polygon from the specified points. @@ -250,11 +250,11 @@ line_to(*point) end # close the path add_content "h" end - + # Draws a rounded polygon from specified points using the radius to define bezier curves # # # draws a rounded filled in polygon # pdf.fill_and_stroke_rounded_polygon(10, [100, 250], [200, 300], [300, 250], # [300, 150], [200, 100], [100, 150]) @@ -266,24 +266,23 @@ rounded_vertex(radius, points[i], points[i + 1], points[i + 2]) end # close the path add_content "h" end - - + + # Creates a rounded vertex for a line segment used for building a rounded polygon # requires a radius to define bezier curve and three points. The first two points define # the line segment and the third point helps define the curve for the vertex. def rounded_vertex(radius, *points) - x0,y0,x1,y1,x2,y2 = points.flatten radial_point_1 = point_on_line(radius, points[0], points[1]) bezier_point_1 = point_on_line((radius - radius*KAPPA), points[0], points[1] ) radial_point_2 = point_on_line(radius, points[2], points[1]) bezier_point_2 = point_on_line((radius - radius*KAPPA), points[2], points[1]) line_to(radial_point_1) curve_to(radial_point_2, :bounds => [bezier_point_1, bezier_point_2]) - end + end # Strokes the current path. If a block is provided, yields to the block # before closing the path. See Graphics::Color for color details. # def stroke @@ -296,68 +295,335 @@ # def close_and_stroke yield if block_given? add_content "s" end - + # Draws and strokes a rectangle represented by the current bounding box # def stroke_bounds stroke_rectangle bounds.top_left, bounds.width, bounds.height end + # Draws and strokes X and Y axes rulers beginning at the current bounding + # box origin (or at a custom location). + # + # == Options + # + # +:at+:: + # Origin of the X and Y axes (default: [0, 0] = origin of the bounding + # box) + # + # +:width+:: + # Length of the X axis (default: width of the bounding box) + # + # +:height+:: + # Length of the Y axis (default: height of the bounding box) + # + # +:step_length+:: + # Length of the step between markers (default: 100) + # + # +:negative_axes_length+:: + # Length of the negative parts of the axes (default: 20) + # + # +:color+: + # The color of the axes and the text. + # + def stroke_axis(options = {}) + options = { + :at => [0,0], + :height => bounds.height.to_i - (options[:at] || [0,0])[1], + :width => bounds.width.to_i - (options[:at] || [0,0])[0], + :step_length => 100, + :negative_axes_length => 20, + :color => "000000", + }.merge(options) + + Prawn.verify_options([:at, :width, :height, :step_length, + :negative_axes_length, :color], options) + + save_graphics_state do + fill_color(options[:color]) + stroke_color(options[:color]) + + dash(1, :space => 4) + stroke_horizontal_line(options[:at][0] - options[:negative_axes_length], + options[:at][0] + options[:width], :at => options[:at][1]) + stroke_vertical_line(options[:at][1] - options[:negative_axes_length], + options[:at][1] + options[:height], :at => options[:at][0]) + undash + + fill_circle(options[:at], 1) + + (options[:step_length]..options[:width]).step(options[:step_length]) do |point| + fill_circle([options[:at][0] + point, options[:at][1]], 1) + draw_text(point, :at => [options[:at][0] + point - 5, options[:at][1] - 10], :size => 7) + end + + (options[:step_length]..options[:height]).step(options[:step_length]) do |point| + fill_circle([options[:at][0], options[:at][1] + point], 1) + draw_text(point, :at => [options[:at][0] - 17, options[:at][1] + point - 2], :size => 7) + end + end + end + # Closes and fills the current path. See Graphics::Color for color details. # - def fill + # If the option :fill_rule => :even_odd is specified, Prawn will use the + # even-odd rule to fill the path. Otherwise, the nonzero winding number rule + # will be used. See the PDF reference, "Graphics -> Path Construction and + # Painting -> Clipping Path Operators" for details on the difference. + # + def fill(options={}) yield if block_given? - add_content "f" + add_content(options[:fill_rule] == :even_odd ? "f*" : "f") end # Closes, fills, and strokes the current path. If a block is provided, # yields to the block before closing the path. See Graphics::Color for # color details. # - def fill_and_stroke + # If the option :fill_rule => :even_odd is specified, Prawn will use the + # even-odd rule to fill the path. Otherwise, the nonzero winding number rule + # will be used. See the PDF reference, "Graphics -> Path Construction and + # Painting -> Clipping Path Operators" for details on the difference. + # + def fill_and_stroke(options={}) yield if block_given? - add_content "b" + add_content(options[:fill_rule] == :even_odd ? "b*" : "b") end # Closes the current path. # def close_path add_content "h" end - # Provides the following shortcuts: + ## + # :method: stroke_rectangle # - # stroke_some_method(*args) #=> some_method(*args); stroke - # fill_some_method(*args) #=> some_method(*args); fill - # fill_and_stroke_some_method(*args) #=> some_method(*args); fill_and_stroke + # Draws and strokes a rectangle given +point+, +width+ and +height+. The + # rectangle is bounded by its upper-left corner. # - def method_missing(id,*args,&block) - case(id.to_s) - when /^fill_and_stroke_(.*)/ - send($1,*args,&block); fill_and_stroke - when /^stroke_(.*)/ - send($1,*args,&block); stroke - when /^fill_(.*)/ - send($1,*args,&block); fill - else - super - end + # :call-seq: + # stroke_rectangle(point,width,height) + + ## + # :method: fill_rectangle + # + # Draws and fills ills a rectangle given +point+, +width+ and +height+. The + # rectangle is bounded by its upper-left corner. + # + # :call-seq: + # fill_rectangle(point,width,height) + + ## + # :method: fill_and_stroke_rectangle + # + # Draws, fills, and strokes a rectangle given +point+, +width+ and +height+. + # The rectangle is bounded by its upper-left corner. + # + # :call-seq: + # fill_and_stroke_rectangle(point,width,height) + + ## + # :method: stroke_rounded_rectangle + # + # Draws and strokes a rounded rectangle given +point+, +width+ and +height+ + # and +radius+ for the rounded corner. The rectangle is bounded by its + # upper-left corner. + # + # :call-seq: + # stroke_rounded_rectangle(point,width,height,radius) + + ## + # :method: fill_rounded_rectangle + # + # Draws and fills a rounded rectangle given +point+, +width+ and +height+ + # and +radius+ for the rounded corner. The rectangle is bounded by its + # upper-left corner. + # + # :call-seq: + # fill_rounded_rectangle(point,width,height,radius) + + ## + # :method: stroke_and_fill_rounded_rectangle + # + # Draws, fills, and strokes a rounded rectangle given +point+, +width+ and + # +height+ and +radius+ for the rounded corner. The rectangle is bounded by + # its upper-left corner. + # + # :call-seq: + # stroke_and_fill_rounded_rectangle(point,width,height,radius) + + ## + # :method: stroke_line + # + # Strokes a line from one point to another. Points may be specified as + # tuples or flattened argument list. + # + # :call-seq: + # stroke_line(*points) + + ## + # :method: stroke_horizontal_line + # + # Strokes a horizontal line from +x1+ to +x2+ at the current y position, or + # the position specified by the :at option. + # + # :call-seq: + # stroke_horizontal_line(x1,x2,options={}) + + ## + # :method: stroke_horizontal_rule + # + # Strokes a horizontal line from the left border to the right border of the + # bounding box at the current y position. + # + # :call-seq: + # stroke_horizontal_rule + + ## + # :method: stroke_vertical_line + # + # Strokes a vertical line at the x coordinate given by :at from y1 to y2. + # + # :call-seq: + # stroke_vertical_line(y1,y2,params) + + ## + # :method: stroke_curve + # + # Strokes a Bezier curve between two points, bounded by two additional + # points. + # + # :call-seq: + # stroke_curve(origin,dest,options={}) + + ## + # :method: stroke_circle + # + # Draws and strokes a circle of radius +radius+ with the centre-point at + # +point+. + # + # :call-seq: + # stroke_circle(center,radius) + + ## + # :method: fill_circle + # + # Draws and fills a circle of radius +radius+ with the centre-point at + # +point+. + # + # :call-seq: + # fill_circle(center,radius) + + ## + # :method: fill_and_stroke_circle + # + # Draws, strokes, and fills a circle of radius +radius+ with the + # centre-point at +point+. + # + # :call-seq: + # fill_and_stroke_circle(center,radius) + + ## + # :method: stroke_ellipse + # + # Draws and strokes an ellipse of x radius +r1+ and y radius +r2+ with the + # centre-point at +point+. + # + # :call-seq: + # stroke_ellipse(point, r1, r2 = r1) + + ## + # :method: fill_ellipse + # + # Draws and fills an ellipse of x radius +r1+ and y radius +r2+ with the + # centre-point at +point+. + # + # :call-seq: + # fill_ellipse(point, r1, r2 = r1) + + ## + # :method: fill_and_stroke_ellipse + # + # Draws, strokes, and fills an ellipse of x radius +r1+ and y radius +r2+ + # with the centre-point at +point+. + # + # :call-seq: + # fill_and_stroke_ellipse(point, r1, r2 = r1) + + ## + # :method: stroke_polygon + # + # Draws and strokes a polygon from the specified points. + # + # :call-seq: + # stroke_polygon(*points) + + ## + # :method: fill_polygon + # + # Draws and fills a polygon from the specified points. + # + # :call-seq: + # fill_polygon(*points) + + ## + # :method: fill_and_stroke_polygon + # + # Draws, strokes, and fills a polygon from the specified points. + # + # :call-seq: + # fill_and_stroke_polygon(*points) + + ## + # :method: stroke_rounded_polygon + # + # Draws and strokes a rounded polygon from specified points, using +radius+ + # to define Bezier curves. + # + # :call-seq: + # stroke_rounded_polygon(radius, *points) + + ## + # :method: fill_rounded_polygon + # + # Draws and fills a rounded polygon from specified points, using +radius+ to + # define Bezier curves. + # + # :call-seq: + # fill_rounded_polygon(radius, *points) + + ## + # :method: fill_and_stroke_rounded_polygon + # + # Draws, strokes, and fills a rounded polygon from specified points, using + # +radius+ to define Bezier curves. + # + # :call-seq: + # fill_and_stroke_rounded_polygon(radius, *points) + + ops = %w{fill stroke fill_and_stroke} + shapes = %w{line_to curve_to rectangle rounded_rectangle line horizontal_line horizontal_rule vertical_line + curve circle_at circle ellipse_at ellipse polygon rounded_polygon rounded_vertex} + + ops.product(shapes).each do |operation,shape| + class_eval "def #{operation}_#{shape}(*args); #{shape}(*args); #{operation}; end" end private - + def current_line_width graphic_state.line_width end - + def current_line_width=(width) graphic_state.line_width = width end - + def write_line_width add_content("#{current_line_width} w") end def map_to_absolute(*point) @@ -370,19 +636,19 @@ end def degree_to_rad(angle) angle * Math::PI / 180 end - + # Returns the coordinates for a point on a line that is a given distance away from the second # point defining the line segement def point_on_line(distance_from_end, *points) x0,y0,x1,y1 = points.flatten length = Math.sqrt((x1 - x0)**2 + (y1 - y0)**2) p = (length - distance_from_end) / length xr = x0 + p*(x1 - x0) yr = y0 + p*(y1 - y0) [xr, yr] end - + end end