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.

Parameters:

  • angle (Sass::Script::Number)

    The angle of the linear gradient. The two points that form the point-to-point linear fill are determined based on this value.

  • stops (Array<ColorStop>)

    A list of color stops to interpolate between.



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)

Returns angle The angle of the linear gradient.

Returns:

  • (Sass::Script::Number)

    angle The angle of the linear gradient.



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

def angle
  @angle
end

#stopsArray<ColorStop> (readonly)

Returns A list of color stops to interpolate between.

Returns:

  • (Array<ColorStop>)

    A list of color stops to interpolate between.



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