Class: Compass::Magick::Types::Gradients::Linear

Inherits:
Compass::Magick::Type show all
Includes:
Utils
Defined in:
lib/magick/types/gradients.rb

Overview

A type that generates a Canvas from a region filled using point-to-point linear gradient at an angle.

Examples:


Linear.new(
  Sass::Script::Number.new(45), [
    ColorStop.new(Sass::Script::Number.new(0),   Sass::Script::Color.new([255,   0,   0])),
    ColorStop.new(Sass::Script::Number.new(50),  Sass::Script::Color.new([  0, 255,   0])),
    ColorStop.new(Sass::Script::Number.new(100), Sass::Script::Color.new([  0,   0, 255]))
  ]
)

Instance Attribute Summary collapse

Attributes included from Scriptable

#context, #options

Instance Method Summary collapse

Methods included from Utils

#assert_one_of, #assert_type, #to_chunky_color, #value_of

Constructor Details

#initialize(angle, stops) ⇒ Linear

Initializes a new Linear instance.



55
56
57
58
59
60
61
# File 'lib/magick/types/gradients.rb', line 55

def initialize(angle, stops)
  assert_type 'angle', angle, Sass::Script::Number
  assert_type 'stops', stops, Array
  stops.each_with_index { |stop, index| assert_type "stop[#{index}]", stop, ColorStop }
  @angle = angle
  @stops = cache_stops(stops)
end

Instance Attribute Details

#angleSass::Script::Number (readonly)



65
66
67
# File 'lib/magick/types/gradients.rb', line 65

def angle
  @angle
end

#stopsArray<ColorStop> (readonly)



69
70
71
# File 'lib/magick/types/gradients.rb', line 69

def stops
  @stops
end

Instance Method Details

#to_canvas(width, height) ⇒ Object



71
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
# File 'lib/magick/types/gradients.rb', line 71

def to_canvas(width, height)
  assert_type 'width',  width,  Sass::Script::Number
  assert_type 'height', height, Sass::Script::Number
  canvas = Canvas.new(width, height)
  point_center    = Point.new(canvas.width  / 2,  canvas.height  / 2)
  length_diagonal = Math.sqrt(canvas.width ** 2 + canvas.height ** 2);
  segments_rectangle = [
    [Point.new(0, 0),                                Point.new(canvas.width - 1, 0)],
    [Point.new(canvas.width - 1, 0),                 Point.new(canvas.width - 1, canvas.height - 1)],
    [Point.new(canvas.width - 1, canvas.height - 1), Point.new(0, canvas.height - 1)],
    [Point.new(0, canvas.height - 1),                Point.new(0, 0)]
  ]
  point_start  = nil
  point_finish = nil
  [-1, 1].each do |direction|
    segment = [
      Point.new(point_center.x, point_center.y),
      Point.new(point_center.x + direction * length_diagonal * Math.cos(@angle.value * Math::PI / 180), point_center.y + direction * length_diagonal * Math.sin(@angle.value * Math::PI / 180))
    ];
    segments_rectangle.each do |edge|
      point = intersect(segment, edge)
      if point
        point_start  ||= point if direction == -1
        point_finish ||= point if direction ==  1
      end
    end
  end
  # Michael Madsen & dash-tom-bang
  # http://stackoverflow.com/questions/2869785/point-to-point-linear-gradient#answer-2870275
  vector_gradient   = [point_finish.x - point_start.x, point_finish.y - point_start.y]
  length_gradient   = Math.sqrt(vector_gradient[0] * vector_gradient[0] + vector_gradient[1] * vector_gradient[1])
  vector_normalized = [vector_gradient[0] * (1 / length_gradient), vector_gradient[1] * (1 / length_gradient)]
  (0...canvas.height).each do |y|
    (0...canvas.width).each do |x|
      result_normalized = (vector_normalized[0] * (x - point_start.x) + vector_normalized[1] * (y - point_start.y)) / length_gradient
      canvas.set_pixel(x, y, interpolate(100 * (result_normalized < 0 ? 0 : result_normalized > 1 ? 1 : result_normalized)))
    end
  end
  canvas
end