Class: DynamicImageSources::GradientSource
- Inherits:
-
SourceFactory
- Object
- SourceFactory
- DynamicImageSources::GradientSource
- Defined in:
- lib/sources/gradient_source.rb
Overview
Source providing gradient source to drawing.
Class Method Summary collapse
-
.parse(source) ⇒ Object
Returns source object or nil if it can’t parse it.
Instance Method Summary collapse
-
#initialize(type, ext, *args) ⇒ GradientSource
constructor
Creates gradient source object from type and extend type.
-
#set_source(context, x, y, w, h) ⇒ Object
Sets color as source to given context.
Constructor Details
#initialize(type, ext, *args) ⇒ GradientSource
Creates gradient source object from type and extend type.
Valid values for type are :linear and :radial. Default is :linear.
Valid values for extend type are :pad, :repeat and :reflect. Default is :pad.
13 14 15 16 17 18 |
# File 'lib/sources/gradient_source.rb', line 13 def initialize(type, ext, *args) @type = type || :linear @ext = ext || :pad @args = args @stops = [] end |
Class Method Details
.parse(source) ⇒ Object
Returns source object or nil if it can’t parse it.
Supported syntax
All values can be given as Array
or String
separated by space chars.
Values has to be in this order: [:gradient_name, *gradient_arguments, stop_value1, stop_value2, ..., stop_valueN]
. All values has to be in one-dimensional array.
Gradient name
Valid gradient names are:
-
Linear:
-
:gradient
for linear gradient -
:gradient_repeat
for linear gradient with repeating -
:gradient_reflect
for linear gradient with reflection
-
-
Radial:
-
:gradient_radial
for radial gradient -
:gradient_radial_repeat
for radial gradient with repeating -
:gradient_radial_reflect
for radial gradient with reflection
-
Gradient arguments
Gradient arguments are different for linear and radial gradients. Adding gradient options is optional.
Linear
Valid values are [x0, y0, x1, y1]
or [angle, size]
where size is optional.
At first place x0, y0 locates first and x1, y1 second points of gradient vector in pixels.
At second place angle defines direction of gradient from top left corner. Valid values are 0deg - 360deg (“deg” must be included). Default is 0deg meaning East. Angle is counted in clockwise direction.
Size is a length of gradinet vector. You can use percentage. F.e.: "50%"
.
Radial
Valid values are [x0, y0, r0, x1, y1, r1]
or [size, angle0, dif0, angle1, dif1]
where size and pair angle1, dif1 are optional.
At first place x0, y0 locates first and x1, y1 second centers of circles and r0, r1 theirs radius. All in pixels.
At second place size is a length of gradinet vector. You can use percentage. F.e.: "50%"
.
Angle and dif defines direction and value of circle movement. Valid values for angle are 0deg - 360deg (“deg” must be included). Default is 0deg meaning East. Angle is counted in clockwise direction. You can use percentage for dif. F.e.: "50%"
.
Stop values
Stop is described as offset value at first position followed by color. The offset specifies the location in % along the gradient’s control vector. For color see ColorSource.parse.
Example
-
[:gradient, "0%", :red, "100%", :blue]
will create linear gradient red at left side and blue at right side -
[:gradient, "0%", 1, 0, 0, "100%", 0, 0, 1]
same as above -
[:gradient_reflect, "50%", "0%", 1, 0, 0, "100%", 0, 0, 1]
will create gradient red at left side, blue in middle and red at right side -
[:gradient, "90deg", "0%", :red, "100%", :blue]
will create linear gradient red at top and blue at bottom -
[:gradient_radial, "0%", :red, "100%", :blue]
will create radial gradient red in center and blue at sides -
[:gradient_radial, 100, "0%", :red, "100%", :blue]
will create radial gradient red in center and blue 100px from center -
[:gradient_radial, "225deg", "50%", "0%", :red, "100%", :blue]
will create radial gradient red in left top quadrant and blue at sides
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/sources/gradient_source.rb', line 72 def self.parse(source) if source[0].to_s.downcase =~ /\Agradient_?(radial)?_?(reflect|repeat)?\Z/ ext = $2 source.shift unless $1 #linear if source[0..3].join(' ') =~ /\A(\d+) (\d+) (\d+) (\d+)\Z/ # x0, y0, x1, y1 args = [$1, $2, $3, $4].map(&:to_i) source.shift 4 else # angle deg, [size (%)] args = [0, 1.0] if source.first.to_s =~ /\A\d+deg\Z/ #angle args[0] = source.first.to_i source.shift end if source.first.to_s =~ /\A\d+\Z/ #size args[1] = source.first.to_i source.shift end if source[1].to_s =~ /\A\d+%\Z/ && source.first.to_s =~ /\A(\d+)%\Z/ # size args[1] = $1.to_f/100.0 source.shift end end object = new :linear, ext, *args else #radial # Args => [size (%),] [angle1 deg, dif1 (%), [angle2 deg, dif2 (%)]] if source[0..5].join(' ') =~ /\A(\d+) (\d+) (\d+) (\d+) (\d+) (\d+)\Z/ # x0, y0, d0, x1, y1, d1 args = [$1, $2, $3, $4, $5, $6].map(&:to_i) source.shift 6 else args = [1.0, 0, 0, 0, 0] if source.first.to_s =~ /\A\d+\Z/ #size args[0] = source.first.to_i source.shift end if source[1].to_s =~ /\A\d+(%|deg)\Z/ && source.first.to_s =~ /\A(\d+)%\Z/ # size args[0] = $1.to_f/100.0 source.shift end if source[0..1].join(' ') =~ /\A(\d+)deg (\d+)(%)?\Z/ # angle1 deg, dif1 (%) args[1] = $1.to_i args[2] = $3 ? $2.to_f/100.0 : $2.to_i source.shift 2 end if source[0..1].join(' ') =~ /\A(\d+)deg (\d+)(%)?\Z/ # angle2 deg, dif2 (%) args[3] = $1.to_i args[4] = $3 ? $2.to_f/100.0 : $2.to_i source.shift 2 end end object = new :radial, ext, *args end stops = [] source.each do |i| if i.to_s =~ /(\d+)%/ stops << [$1.to_f/100.0] else stops.last << i if stops.last end end stops.each do |stop| color = ColorSource.parse(stop[1..-1]) return nil unless color object.send :add_stop, stop.first, color end object end end |
Instance Method Details
#set_source(context, x, y, w, h) ⇒ Object
Sets color as source to given context
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/sources/gradient_source.rb', line 142 def set_source(context, x, y, w, h) case @type.to_sym when :linear if @args.size == 4 pattern = Cairo::LinearPattern.new @args[0]+x, @args[1]+y, @args[2]+x, @args[3]+y else if @args[1].class == Float deg = (@args[0]%180+180)%180 deg = 180 - deg if deg > 90 deg *= Math::PI / 180 deg -= Math.atan(h.to_f/w.to_f) dist = Math.sqrt(w**2 + h**2) * Math.cos(deg) dist = dist * @args[1] else dist = @args[1] end pattern = Cairo::LinearPattern.new *[x, y, degree_dist(@args[0], dist, x, y)].flatten end when :radial if @args.size == 6 pattern = Cairo::RadialPattern.new @args[0]+x, @args[1]+y, @args[2], @args[3]+x, @args[4]+y, @args[5] else x, y = [x+w/2, y+h/2] radius = @args[0].class == Float ? Math.sqrt(w**2 + h**2)/2 * @args[0] : @args[0] dist1 = @args[2].class == Float ? radius * @args[2] : @args[2] dist2 = @args[4].class == Float ? radius * @args[4] : @args[4] pattern = Cairo::RadialPattern.new *[degree_dist(@args[1], dist1, x, y), 0, degree_dist(@args[3], dist2, x, y), radius].flatten end end pattern.set_extend({ :pad => Cairo::EXTEND_NONE, :repeat => Cairo::EXTEND_REPEAT, :reflect => Cairo::EXTEND_REFLECT }[@ext.to_sym]) unless @type.to_sym == :radial && @ext.to_sym == :pad @stops.each do |stop| pattern.add_color_stop_rgba *stop end context.set_source pattern context.fill_preserve end |