Class: GD::GIS::PointsLayer
- Inherits:
-
Object
- Object
- GD::GIS::PointsLayer
- Defined in:
- lib/gd/gis/layer_points.rb
Overview
Renders point data as icons (markers) with optional labels.
A PointsLayer draws markers for arbitrary data records. Longitude and latitude values are extracted using callables, allowing the layer to work with any data structure.
Optionally, text labels can be rendered next to each marker.
Instance Method Summary collapse
-
#build_default_marker(fill, stroke) ⇒ GD::Image
Builds a default circular marker icon.
-
#draw_symbol_circle!(img:, x:, y:, symbol:, bg_color:, font_color:, font:, font_size:, angle: 0.0) ⇒ Object
Draws a filled circle (bullet) with a centered numeric label.
-
#initialize(data, lon:, lat:, icon:, label: nil, font: nil, size: 12, color: [0, 0, 0], font_color: nil, symbol: 0) ⇒ PointsLayer
constructor
Creates a new points layer.
-
#radius_from_text(img, text, font:, size:, padding: 4) ⇒ Object
Calculates a circle radius that fully contains the rendered text.
-
#render!(img, projector) ⇒ void
Renders all points onto the image.
Constructor Details
#initialize(data, lon:, lat:, icon:, label: nil, font: nil, size: 12, color: [0, 0, 0], font_color: nil, symbol: 0) ⇒ PointsLayer
Creates a new points layer.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/gd/gis/layer_points.rb', line 33 def initialize( data, lon:, lat:, icon:, label: nil, font: nil, size: 12, color: [0, 0, 0], font_color: nil, symbol: 0 ) @data = data @lon = lon @lat = lat @color = color @font_color = font_color if icon.is_a?(Array) || icon.nil? fill, stroke = icon || [GD::GIS::ColorHelpers.random_rgb, GD::GIS::ColorHelpers.random_rgb] @icon = build_default_marker(fill, stroke) elsif %w[numeric alphabetic symbol].include?(icon) @icon = icon else @icon = GD::Image.open(icon) @icon.alpha_blending = true @icon.save_alpha = true end @label = label @font = font @size = size @r, @g, @b, @a = color @a = 0 if @a.nil? @symbol = symbol end |
Instance Method Details
#build_default_marker(fill, stroke) ⇒ GD::Image
Builds a default circular marker icon.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/gd/gis/layer_points.rb', line 77 def build_default_marker(fill, stroke) size = 32 img = GD::Image.new(size, size) img.antialias = true cx = size / 2 cy = size / 2 r = 5 # stroke img.arc(cx, cy, (r * 2) + 4, (r * 2) + 4, 0, 360, stroke) # fill img.filled_arc(cx, cy, r * 2, r * 2, 0, 360, fill) img end |
#draw_symbol_circle!(img:, x:, y:, symbol:, bg_color:, font_color:, font:, font_size:, angle: 0.0) ⇒ Object
Draws a filled circle (bullet) with a centered numeric label.
-
x, y: circle center in pixels
-
y for text() is BASELINE (not top). We compute baseline to center the text.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/gd/gis/layer_points.rb', line 162 def draw_symbol_circle!(img:, x:, y:, symbol:, bg_color:, font_color:, font:, font_size:, angle: 0.0) diameter = radius_from_text(img, symbol, font: font, size: font_size) * 2 # 1) Bullet background img.filled_ellipse(x, y, diameter, diameter, bg_color) # 2) Measure text in pixels (matches rendering) text = symbol.to_s w, h = img.text_bbox(text, font: font, size: font_size, angle: angle) # 3) Compute centered position: # text() uses baseline Y, so: # top_y = y - h/2 # baseline = top_y + h = y + h/2 text_x = (x - (w / 2.0)).round text_y = (y + (h / 2.0)).round # 4) Draw number img.text( text, x: text_x, y: text_y, font: font, size: font_size, color: font_color ) end |
#radius_from_text(img, text, font:, size:, padding: 4) ⇒ Object
Calculates a circle radius that fully contains the rendered text.
img : GD::Image text : String (number, letters, etc.) font : path to .ttf size : font size in points padding : extra pixels around text (visual breathing room)
198 199 200 201 202 203 204 205 206 207 |
# File 'lib/gd/gis/layer_points.rb', line 198 def radius_from_text(img, text, font:, size:, padding: 4) w, h = img.text_bbox( text.to_s, font: font, size: size ) # Use the larger dimension to ensure the text fits ([w, h].max / 2.0).ceil + padding end |
#render!(img, projector) ⇒ void
This method returns an undefined value.
Renders all points onto the image.
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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/gd/gis/layer_points.rb', line 103 def render!(img, projector) value = case @icon when "numeric", "symbol" @symbol when "alphabetic" (@symbol + 96).chr else @icon end if @icon.is_a?(GD::Image) w = @icon.width h = @icon.height else w = radius_from_text(img, value, font: @font, size: @size) * 2 end @data.each do |row| lon = @lon.call(row) lat = @lat.call(row) x, y = projector.call(lon, lat) next unless @label && @font text = @label.call(row) next if text.nil? || text.strip.empty? font_h = @size * 1.1 if @icon == "numeric" || @icon == "alphabetic" || @icon == "symbol" draw_symbol_circle!( img: img, x: x, y: y, symbol: value, bg_color: @color, font_color: @font_color, font: @font, font_size: @size ) else img.copy(@icon, x - (w / 2), y - (h / 2), 0, 0, w, h) end img.text(text, x: x + (w / 2) + 4, y: y + (font_h / 2), size: @size, color: @font_color, font: @font) end end |