Module: CssGraphs

Defined in:
lib/css_graphs.rb

Constant Summary collapse

VERSION =
'0.1.0'

Instance Method Summary collapse

Instance Method Details

#bar_graph(data = []) ⇒ Object

Makes a vertical bar graph.

bar_graph [["Stout", 10], ["IPA", 80], ["Pale Ale", 50], ["Milkshake", 30]]

NOTE: Updated to take an array instead of forcing you to use *array. NOTE: Normalizes data to fit in the viewable area instead of being fixed to 100.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/css_graphs.rb', line 12

def bar_graph(data=[])
  width = 378
  height = 150
  colors = %w(#ce494a #efba29 #efe708 #5a7dd6 #73a25a)
  floor_cutoff = 24 # Pixels beneath which values will not be drawn in graph
  data_max = data.inject(0) { |memo, array| array.last > memo ? array.last : memo }

  
  html = <<-"HTML"
  <style>
    #vertgraph {    				
        width: #{width}px; 
        height: #{height}px; 
        position: relative; 
        background-color: #eeeeee;
        border: 4px solid #999999;
        font-family: "Lucida Grande", Verdana, Arial;
    }
  
    #vertgraph dl dd {
      position: absolute;
      width: 28px;
      height: 103px;
      bottom: 34px;
      padding: 0 !important;
      margin: 0 !important;
      background-image: url('/images/css_graphs/colorbar.jpg') no-repeat !important;
      text-align: center;
      font-weight: bold;
      color: white;
      line-height: 1.5em;
    }

    #vertgraph dl dt {
      position: absolute;
      width: 48px;
      height: 25px;
      bottom: 0px;
      padding: 0 !important;
      margin: 0 !important;
      text-align: center;
      color: #444444;
      font-size: 0.8em;
    }
  HTML

  bar_offset = 24
  bar_increment = 75
  bar_image_offset = 28
  
  data.each_with_index do |d, index|
    bar_left = bar_offset + (bar_increment * index)
    label_left = bar_left - 10
    background_offset = bar_image_offset * index
    
    html += <<-HTML
      #vertgraph dl dd.#{d[0].to_s.downcase} { left: #{bar_left}px; background-color: #{colors[index]}; background-position: -#{background_offset}px bottom !important; }
      #vertgraph dl dt.#{d[0].to_s.downcase} { left: #{label_left}px; background-position: -#{background_offset}px bottom !important; }
    HTML
  end
  
  html += <<-"HTML"
    </style>
    <div id="vertgraph">
      <dl>
  HTML
  
  data.each_with_index do |d, index|
    scaled_value = scale_graph_value(d.last, data_max, 100)
    html += <<-"HTML"
      <dt class="#{d.first.to_s.downcase}">#{d[0].to_s.humanize}</dt>
      <dd class="#{d.first.to_s.downcase}" style="height: #{scaled_value}px;" title="#{d.last}">#{scaled_value < floor_cutoff ? '' : d.last}</dt>
    HTML
  end
      
  html += <<-"HTML"
      </dl>
    </div>
  HTML
  
  html
end

#complex_bar_graph(data) ⇒ Object

Makes a multi-colored bar graph with a bar down the middle, representing the value.

complex_bar_graph [["Stout", 10], ["IPA", 80], ["Pale Ale", 50], ["Milkshake", 30]]

NOTE: Updated to take an array instead of forcing you to use *array. NOTE: Does not normalize data yet…TODO



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/css_graphs.rb', line 295

def complex_bar_graph(data)
  html = <<-"HTML"
    <style>
    /* Complex Bar Graph */
    div#complex_bar_graph dl { 
    	margin: 0; 
    	padding: 0;   
    	font-family: "Lucida Grande", Verdana, Arial;	
    }
    div#complex_bar_graph dt { 
    	position: relative; /* IE is dumb */
    	clear: both;
    	display: block; 
    	float: left; 
    	width: 104px; 
    	height: 20px; 
    	line-height: 20px;
    	margin-right: 17px;              
    	font-size: .75em; 
    	text-align: right; 
    }
    div#complex_bar_graph dd { 
    	position: relative; /* IE is dumb */
    	display: block;   
    	float: left;	 
    	width: 197px; 
    	height: 20px; 
    	margin: 0 0 15px; 
    	background: url("/images/css_graphs/g_colorbar.jpg"); 
    }
    * html div#complex_bar_graph dd { float: none; } /* IE is dumb; Quick IE hack, apply favorite filter methods for wider browser compatibility */

    div#complex_bar_graph dd div { 
    	position: relative; 
    	background: url("/images/css_graphs/g_colorbar2.jpg"); 
    	height: 20px; 
    	width: 75%; 
    	text-align:right; 
    }
    div#complex_bar_graph dd div strong { 
    	position: absolute; 
    	right: -5px; 
    	top: -2px; 
    	display: block; 
    	background: url("/images/css_graphs/g_marker.gif"); 
    	height: 24px; 
    	width: 9px; 
    	text-align: left;
    	text-indent: -9999px; 
    	overflow: hidden;
    }
    </style>
    <div id="complex_bar_graph">  
    <dl>
  HTML

  data.each do |d|
    html += <<-"HTML"
      <dt class="#{d[0].to_s.downcase}">#{d[0].to_s.humanize}</dt>
      <dd class="#{d[0].to_s.downcase}" title="#{d[1]}">
      <div style="width: #{d[1]}%;"><strong>#{d[1]}%</strong></div>
    </dd>
  HTML
  end
  
  html += "</dl>\n</div>"
  return html    
end

#horizontal_bar_graph(data) ⇒ Object

Make a horizontal graph that only shows percentages.

The label will be set as the title of the bar element.

horizontal_bar_graph [["Stout", 10], ["IPA", 80], ["Pale Ale", 50], ["Milkshake", 30]]

NOTE: Updated to take an array instead of forcing you to use *array. NOTE: Does not normalize data yet…TODO



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/css_graphs.rb', line 254

def horizontal_bar_graph(data)
  html = <<-"HTML"
    <style>
    /* Basic Bar Graph */
    .graph { 
      position: relative; /* IE is dumb */
      width: 200px; 
      border: 1px solid #B1D632; 
      padding: 2px; 
      margin-bottom: .5em;					
    }
    .graph .bar { 
      display: block;	
      position: relative;
      background: #B1D632; 
      text-align: center; 
      color: #333; 
      height: 2em; 
      line-height: 2em;									
    }
    .graph .bar span { position: absolute; left: 1em; } /* This extra markup is necessary because IE does not want to follow the rules for overflow: visible */	 
    </style>
  HTML
  
  data.each do |d|
    html += <<-"HTML"
      <div class="graph">
        <strong class="bar" style="width: #{d[1]}%;" title="#{d[0].to_s.humanize}"><span>#{d[1]}%</span> </strong>
      </div>
    HTML
  end
  return html
end

#multi_bar_graph(alldata = [], options = {}, &url_creator) ⇒ Object

Makes a vertical bar graph with several sets of bars.

NOTE: Normalizes data to fit in the viewable area instead of being fixed to 100.

Example: <% @data_for_graph = [[[‘January’,10],,[‘March’,45]],[,[‘February’,29],]] %> <%= bar_graph (@data_for_graph,=> 640,:height => 480) do |index,variable|

  url_for( :action => 'report', :month => index) 
end

%>

alldata should be an array of variables, each one an array itself, of the form:

[['label1',value1],['label2',value2]]

options hash:

  • :display_value_on_bar if set to true, will display the value on top each bar, default behavior is not to show the value

  • :colors is an array of colors in hex format: ‘#EEC2D2’ if you don’t set them, default colors will be used

  • :color_by can be set to ‘dimension’ or ‘index’

  • :width and :height set the dimensions, wich default to 378x150

url_creator_block:

the url_creator_block receives two parameters, index and variable, that are used to build the bars links. 
index is the position for this bar's that in its variable array, while variable is the variable this bar represents


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
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/css_graphs.rb', line 121

def multi_bar_graph(alldata=[], options={}, &url_creator)
  graph_id = (rand*10000000000000000000).to_i.to_s #we need a unique id for each graph on the page so we can have distinct styles for each of them
  if !options.nil? && options[:width] && options[:height]
    width,height=options[:width].to_i,options[:height].to_i
  else
    width,height = 378,150
  end
  colors = (%w(#ce494a #efba29 #efe708 #5a7dd6 #73a25a))*10 unless colors=options[:colors]
  floor_cutoff = 24 # Pixels beneath which values will not be drawn in graph
  data_max = (alldata.map { |data| data.max{ |a,b| a.last <=> b.last }.last } ).max
  dimensions=alldata.size
  size =  alldata.map{ |data| data.size }.max
  bar_offset = 24 #originally set to 24
  bar_group_width=(width-bar_offset)/size #originally set to 48px
  bar_increment = bar_group_width #originally set to 75
  bar_width=(bar_group_width-bar_offset)/dimensions #originally set to 28px
  bar_image_offset = bar_offset+4 #originally set to 28
  bar_padding = 2

  #p "dimensions = #{dimensions}"
  #p "bar_group_width =#{bar_group_width}"
  #p "bar_width = #{bar_width}"
  #p "bar_increment = #{bar_increment}"

  html = <<-"HTML"
  <style>
    #vertgraph-#{graph_id} {    				
        width: #{width}px; 
        height: #{height}px; 
        position: relative; 
        background-color: #eeeeee;
        border: 4px solid #999999;
        font-family: "Lucida Grande", Verdana, Arial;
    }
  
    #vertgraph-#{graph_id} dl dd {
      position: absolute;
      width: #{bar_width}px;
      height: #{height-50}px;
      bottom: 34px;
      padding: 0 !important;
      margin: 0 !important;
      background-image: url('/images/css_graphs/colorbar.jpg') no-repeat !important;
      text-align: center;
      font-weight: bold;
      color: white;
      line-height: 1.5em;
    }

    #vertgraph-#{graph_id} dl dt {
      position: absolute;
      width: #{bar_group_width}px;
      height: 25px;
      bottom: 0px;
      padding: 0 !important;
      margin: 0 !important;
      text-align: center;
      color: #444444;
      font-size: 0.8em;
    }
  HTML

  alldata.each_with_index do |data,dimension|
#    p "\n drawing dimension #{dimension}"
    data.each_with_index do |d, index|
#        bar_left = bar_offset + (bar_increment * index) 
      bar_group_left = bar_offset + (bar_increment * index) 
      bar_left = bar_group_left + ((bar_width+bar_padding)*dimension)
      #        bar_left = bar_group_left + ( 2*bar_width* (dimension-1))     
#        p "\n bar_left #{bar_left}"
      label_left = bar_group_left - 10
      background_offset = ( bar_image_offset * index ) 
      if options[:color_by]=='index'
        color=colors[index]
      else
        color=colors[dimension]
      end
      html += <<-HTML
        #vertgraph-#{graph_id} dl dd.a#{index.to_s}#{dimension.to_s} { left: #{bar_left}px; background-color: #{color}; background-position: -#{background_offset}px bottom !important; }
        #vertgraph-#{graph_id} dl dt.a#{index.to_s}#{dimension.to_s} { left: #{label_left}px; background-position: -#{background_offset}px bottom !important; }
      HTML
    end
  end  

    html += <<-"HTML"
      </style>
      <div id="vertgraph-#{graph_id}">
        <dl>
    HTML
  alldata.each_with_index do |data,dimension|    
#      data_max = data.inject(0) { |memo, array| array.last > memo ? array.last : memo }
    data.each_with_index do |d, index|
      scaled_value = scale_graph_value(d.last, data_max, height-50)
     if (options[:display_value_on_bar])
       bar_text=(scaled_value < floor_cutoff ? '' : d.last).to_s  #text on top of the bar
     else
        bar_text=''
     end  

   if dimension==0
      html += <<-"HTML"
        <!-- algo -->
        <dt class="a#{index.to_s}#{dimension.to_s}" >#{d[0].to_s}</dt>
      HTML
   end
    @url = url_creator.call(index,dimension) if !url_creator.nil?
    html += <<-"HTML"
    <a href="#{@url}">
      <!-- Tooltip for bar group -->
      <dd class="a#{index.to_s}#{dimension.to_s}" style="height: #{height-50}px;background: none;" title="#{d.last}"></dd>
      <!-- Color bar -->
      <dd class="a#{index.to_s}#{dimension.to_s}" style="height: #{scaled_value}px;" title="#{d.last}">#{bar_text}</dd>
    </a>
   HTML
    end
  end        
  html += <<-"HTML"
      </dl>
    </div>
  HTML
  
  html
end

#scale_graph_value(data_value, data_max, max) ⇒ Object

Scale values within a max. The max will usually be the height of the graph.



367
368
369
# File 'lib/css_graphs.rb', line 367

def scale_graph_value(data_value, data_max, max)
  ((data_value.to_f / data_max.to_f) * max).round
end