twb 0.0.33 → 0.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/twb.rb CHANGED
@@ -8,10 +8,11 @@ require_relative 'twb/localfield'
8
8
  require_relative 'twb/metadatafield'
9
9
  require_relative 'twb/docdashboard'
10
10
  require_relative 'twb/util/htmllistcollapsible'
11
+ require_relative 'twb/util/xraydashboards'
11
12
 
12
13
  # Represents Tableau Workbooks and their contents.
13
14
  #
14
15
  module Twb
15
- VERSION = '0.0.33'
16
+ VERSION = '0.0.34'
16
17
  end
17
18
 
@@ -25,37 +25,6 @@ module Twb
25
25
 
26
26
  attr_reader :title, :dashnode, :winnode, :type #, :panels, :autosize, :size
27
27
 
28
- @@oneColWebPageDash = Nokogiri::XML::Document.parse <<-ONECOlWEBDASH
29
- <dashdoc>
30
- <dashboard name='Single Column Web Page Automatic'>
31
- <style></style>
32
- <zones>
33
- <zone h='100000' id='3' param='vert' type='layout-flow' w='100000' x='0' y='0'>
34
- <zone h='6221' id='1' type='title' w='100000' x='0' y='0'></zone>
35
- <zone h='93157' id='4' param='horz' type='layout-flow' w='100000' x='0' y='6221'>
36
- <zone forceUpdate='' h='93157' id='6' param='URL' type='web' w='99655' x='0' y='6221'></zone>
37
- </zone>
38
- </zone>
39
- </zones>
40
- </dashboard>
41
- <window auto-hidden='0' class='dashboard' maximized='1' name='Single Column Web Page Automatic'>
42
- <zones>
43
- <zone h='6221' id='1' name='' type='title' w='100000' x='0' y='0' />
44
- <zone forceUpdate='' h='93157' id='5' name='' param='Web Page' type='web' w='50000' x='50000' y='6221' />
45
- </zones>
46
- </window>
47
- </dashdoc>
48
- ONECOlWEBDASH
49
- # notes:
50
- # - adding a size element to the <dashboard element will change it from automatic, e.g.
51
- #
52
- # <dashboard name='One Column Web Page Laptop (800w 600h)'>
53
- # <style>
54
- # </style>
55
- # <size maxheight='600' maxwidth='800' minheight='600' minwidth='800' />
56
- #
57
- # - the 'name' sttributes for the window and dashboard must match
58
-
59
28
  def title=(title)
60
29
  @title = title
61
30
  @dashnode['name'] = title
@@ -78,7 +47,7 @@ module Twb
78
47
  end
79
48
 
80
49
  def to_s
81
- return title + ' :: ' + type
50
+ return @title + ' :: ' + @type
82
51
  end
83
52
 
84
53
  end
@@ -88,9 +57,39 @@ module Twb
88
57
  attr_reader :url
89
58
 
90
59
  def initialize
60
+ @oneColWebPageDash = Nokogiri::XML::Document.parse <<-ONECOlWEBDASH
61
+ <dashdoc>
62
+ <dashboard name='Single Column Web Page Automatic'>
63
+ <style></style>
64
+ <zones>
65
+ <zone h='100000' id='3' param='vert' type='layout-flow' w='100000' x='0' y='0'>
66
+ <zone h='6221' id='1' type='title' w='100000' x='0' y='0'></zone>
67
+ <zone h='93157' id='4' param='horz' type='layout-flow' w='100000' x='0' y='6221'>
68
+ <zone forceUpdate='' h='93157' id='6' param='URL' type='web' w='99655' x='0' y='6221'></zone>
69
+ </zone>
70
+ </zone>
71
+ </zones>
72
+ </dashboard>
73
+ <window auto-hidden='0' class='dashboard' maximized='1' name='Single Column Web Page Automatic'>
74
+ <zones>
75
+ <zone h='6221' id='1' name='' type='title' w='100000' x='0' y='0' />
76
+ <zone forceUpdate='' h='93157' id='5' name='' param='Web Page' type='web' w='50000' x='50000' y='6221' />
77
+ </zones>
78
+ </window>
79
+ </dashdoc>
80
+ ONECOlWEBDASH
81
+ # notes:
82
+ # - adding a size element to the <dashboard element will change it from automatic, e.g.
83
+ #
84
+ # <dashboard name='One Column Web Page Laptop (800w 600h)'>
85
+ # <style>
86
+ # </style>
87
+ # <size maxheight='600' maxwidth='800' minheight='600' minwidth='800' />
88
+ #
89
+ # - the 'name' sttributes for the window and dashboard must match
91
90
  @type = 'columnar Web Page'
92
- @dashnode = @@oneColWebPageDash.at_xpath('//dashboard')
93
- @winnode = @@oneColWebPageDash.at_xpath('//window')
91
+ @dashnode = @oneColWebPageDash.at_xpath('//dashboard')
92
+ @winnode = @oneColWebPageDash.at_xpath('//window')
94
93
  end
95
94
 
96
95
  def title=(title)
@@ -109,7 +108,7 @@ module Twb
109
108
  def url
110
109
  dashurl = @dashnode.at_xpath('.//zone[@type="web"]').attribute('param').value
111
110
  winurl = @winnode.at_xpath( './/zone[@type="web"]').attribute('param').value
112
- url = if dashurl == winurl then dashurl end
111
+ @url = if dashurl == winurl then dashurl end
113
112
  end
114
113
 
115
114
  end
@@ -22,7 +22,7 @@ class HashToHTMLList
22
22
  def li(collection)
23
23
  @level += 1
24
24
  collection.each do |key,value|
25
- open_tag('li',key) { ul(value) if value.is_a?(Hash) || value.is_a?(Array) }
25
+ open_tag('li',key) { ul(value) if (value.is_a?(Hash) || value.is_a?(Array)) && !value.empty? }
26
26
  end
27
27
  @level -= 1
28
28
  end
@@ -174,19 +174,7 @@ COLLAPSIBLELIST
174
174
  end
175
175
 
176
176
  def installNavImageFile
177
- puts "looking for nav controls image"
178
- # puts " __FILE__ #{__FILE__}" #File.expand_path(File.dirname(_FILE_))
179
- puts " Dir.pwd #{Dir.pwd}"
180
- puts " File.dirname(__FILE__) #{File.dirname(__FILE__)}"
181
- puts " __FILE__ #{__FILE__}"
182
177
  navimage = File.dirname(__FILE__) + "/UpLeftArrowsNav.png"
183
- puts " filemask: #{navimage}"
184
- cnt = 0
185
- Dir.glob(navimage) do |twb|
186
- puts twb
187
- cnt += 1
188
- end
189
- puts " found #{cnt} files"
190
178
  FileUtils.cp(navimage, Dir.pwd)
191
179
  end
192
180
 
@@ -0,0 +1,553 @@
1
+ # Copyright (C) 2014, 2015 Chris Gerrard
2
+ #
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require 'nokogiri'
17
+
18
+ module Twb
19
+
20
+
21
+ class DashboardXRayer
22
+
23
+ @@typeLabels = {
24
+ 'bitmap' => 'Image',
25
+ 'color' => 'Color Legend',
26
+ 'currpage' => 'Pages Control',
27
+ 'draw' => 'Draw',
28
+ 'empty' => 'Blank',
29
+ 'filter' => 'Filter',
30
+ 'layout-basic' => 'Layout - Basic',
31
+ 'layout-flow' => 'Layout - Flow',
32
+ 'map' => 'Map Legend',
33
+ 'mru-entry' => 'Mru Entry',
34
+ 'paramctrl' => 'Parameter',
35
+ 'shape' => 'Shape Legend',
36
+ 'size' => 'Size Legend',
37
+ 'text' => 'Text',
38
+ 'text-block' => 'Text Block',
39
+ 'title' => 'Title',
40
+ 'web' => 'Web Page'
41
+ }
42
+
43
+ @@zoneNamePadText = '&ndash;'
44
+
45
+ @@shapeRadius = 1000
46
+ @@shapeDiam = 2*@@shapeRadius
47
+
48
+ @@htmlTableLead = '<p style="font: normal 12px Verdana, Calibri, Geneva, sans-serif; color: #000000;">The Dashboard\'s panels, one per row.<br />Mouse over the table to highlight in the diagram.</p>'
49
+ @@htmlTableFNote = '<p><span style="font: normal 12px Verdana, Calibri, Geneva, sans-serif; color: #000000;">Note: the Dashboard\'s \'x\', \'y\', \'w\', and \'h\' values are shown as coded in the<br />Tableau Workbook. It appears that the maximum value &ndash;100,000&ndash; indicates<br />that the Dashboard size is set to Automatic.</span></p>'
50
+
51
+ @maxSVGDim = 600.0 # need the decimal for dashboard scaling with svgScale in fn termDashSVG
52
+ @maxDashWidth = 1.0
53
+ @strokeWidth = 300
54
+ @@fontSize = 2000
55
+
56
+ @htmlHead = ''
57
+
58
+ @@htmlTableHead = "<table>\n<tr><th align='left'>Zone Name</th><th align='left'>Type</th><th>x</th><th>y</th><th>w</th><th>h</th><th>ID</th></tr>"
59
+ @htmlTable = ''
60
+ @svgHead = ''
61
+ @svg = ''
62
+ @@svgTail = "</g>\n</svg>"
63
+
64
+
65
+ @@typeFillColors = {
66
+ 'bitmap' => 'white',
67
+ 'chart' => 'white',
68
+ 'Color Legend' => '#CD853F',
69
+ 'currpage' => 'white',
70
+ 'draw' => 'white',
71
+ 'empty' => 'white',
72
+ 'Blank' => 'white',
73
+ 'Filter' => '#228B22',
74
+ 'layout-basic' => '#B0C4DE',
75
+ 'Layout - Basic' => '#B0C4DE',
76
+ 'layout-flow' => '#B0C4DE',
77
+ 'Layout - Flow' => '#B0C4DE',
78
+ 'Layout - Vertical' => '#B0C4DE',
79
+ 'Layout - Horizontal' => '#B0C4DE',
80
+ 'Image' => 'lightgreen',
81
+ 'map' => '#CD853F',
82
+ 'map legend' => '#CD853F',
83
+ 'mru-entry' => 'white',
84
+ 'paramctrl' => '#228B22',
85
+ 'Parameter' => '#228B22',
86
+ 'shape' => '#CD853F',
87
+ 'Shape Legend' => '#CD853F',
88
+ 'size' => '#CD853F',
89
+ 'Size Legend' => '#CD853F',
90
+ 'Text' => '#5F9EA0',
91
+ 'text-block' => '#5F9EA0',
92
+ 'Title' => '#5F9EA0',
93
+ 'web' => 'lightgreen'
94
+ }
95
+ def init
96
+ # --
97
+ @jsVars = <<-JSVARS
98
+ var oldFill = ''
99
+ var oldOpac = ''
100
+ var oldStroW = ''
101
+ var origLColWidth = "%s"
102
+ var origSvgWidth = "%s"
103
+ var origSvgHeight = "%s"
104
+ var origSvgScale = "%s"
105
+ JSVARS
106
+
107
+ # --
108
+ @fnScaleDash = <<-FNSD
109
+ function scaleDash(){
110
+ var svg = document.getElementById("svg");
111
+ var lCol = document.getElementById("LeftColumn");
112
+
113
+ var sf = document.getElementById("scaleFactor").value;
114
+ var scale = 1;
115
+ var spct = sf;
116
+ if (isNaN(sf))
117
+ { scale = 1;
118
+ spct = 100
119
+ }
120
+ else if (sf < 10)
121
+ { scale = .1 ;
122
+ spct = 10
123
+ }
124
+ else if (sf > 100)
125
+ { scale = 1 ;
126
+ spct = 100
127
+ }
128
+ else
129
+ { scale = sf / 100 ;
130
+ spct = sf
131
+ }
132
+
133
+ var newLColWidth = (origLColWidth * scale) + 5
134
+ var newSvgWidth = origSvgWidth * scale
135
+ var newSvgHeight = origSvgHeight * scale
136
+ var newSvgScale = origSvgScale * scale
137
+ var newSvgTransf = "translate(10,10) scale(" + newSvgScale + ")"
138
+
139
+ document.getElementById("LeftColumn").setAttribute("width",newLColWidth);
140
+ svg.setAttribute("width", newSvgWidth)
141
+ svg.setAttribute("height",newSvgHeight)
142
+ svg.getElementById("svgTransform").setAttribute("transform",newSvgTransf)
143
+
144
+ var newDivWidthPx = newLColWidth + "px"
145
+ var newDivWidthStr = "display:block;width:" + newDivWidthPx
146
+ document.getElementById('LeftColumn').setAttribute("style",newDivWidthStr);
147
+ document.getElementById('LeftColumn').style.width=newDivWidthPx;
148
+
149
+ var r = document.getElementById("result");
150
+ r.innerHTML = "scale: " + spct + "%" // + document.getElementById("LeftColumn").getAttribute("width")
151
+ }
152
+ FNSD
153
+ # --
154
+
155
+ end
156
+
157
+
158
+ # Create instance of the Dashboard X-Ray machine.
159
+ # The parameter 'twb' can be either a Twb::Workbook
160
+ # or a String naming the TWB to be X-Rayed.
161
+ def initialize twb
162
+ @workbook = if twb.instance_of?(Twb::Workbook)
163
+ then twb
164
+ else Twb::Workbook.new(twb)
165
+ end
166
+ @dashboards = @workbook.dashboards
167
+ @maxSVGDim = 600.0
168
+ @svgPadding = 10
169
+ init
170
+ end
171
+
172
+ # Performs an analysis of the Workbook's Sashboards akin to an X-Ray imaging.
173
+ # Each of the Dashboards' component parts, "<zone"s in the TWB's xml, is captured.
174
+ # Generates an HTML file that contains a schematic of the zones along with a
175
+ # table that identifes the zones and, when moused over, highlights the zone in
176
+ # the schematic.
177
+ # The active elements in the HTML file are in SVG.
178
+ def xray
179
+ dashCnt = 0
180
+ @dashboardHTMLDocs = {}
181
+ @dashboards.each do |dash|
182
+ @htmldoc = ''
183
+ @dashNodeDepth = dash.node.ancestors.size # depth 3 as of Tableau v7
184
+ $maxWidth, $maxHeight = 0, 0
185
+ @svg = ''
186
+ initDashSVG(dash.name)
187
+ setScale(dash)
188
+ dZones = dash.node.xpath('.//zone')
189
+ dzcnt = 0
190
+ @htmlTable = ''
191
+ dZones.each do |zone|
192
+ recordZone(dash.name, zone, dzcnt+=1)
193
+ end
194
+ termDashSVG
195
+ initDashHTML(dash.name, dashCnt += 1, @dashboards.length)
196
+ @dashboardHTMLDocs[dash.name] = termDashHTML
197
+ end
198
+ return @dashboardHTMLDocs
199
+ end
200
+
201
+ def getFillColor type
202
+ fillColor = if type.nil?
203
+ then 'white'
204
+ else @@typeFillColors[type.to_s]
205
+ end
206
+ return fillColor
207
+ end
208
+
209
+ def getZoneName zone
210
+ name = zone.attribute('name')
211
+ if name.nil?
212
+ then name = ''
213
+ end
214
+ zoneDepth = zone.ancestors.size
215
+ zoneRelDepth = zoneDepth - @dashNodeDepth - 2
216
+ # example TWB structure
217
+ # <dashboards>
218
+ # <dashboard
219
+ # <zones>
220
+ # <zone
221
+ zoneHead = @@zoneNamePadText * zoneRelDepth
222
+ name = zoneHead + '|' + name
223
+ return name
224
+ end
225
+
226
+ def getZoneType(zone)
227
+ type = zone.attribute('type')
228
+ param = zone.attribute('param').to_s
229
+ layoutHorz = zone.attribute('layout-horz').to_s
230
+ if type.nil?
231
+ then typeLabel = 'chart'
232
+ else typeLabel = @@typeLabels[type.to_s]
233
+ end
234
+ if typeLabel == 'Layout - Flow' then
235
+ typeLabel = case param
236
+ when 'vert' then 'Layout - Vertical'
237
+ when 'horz' then 'Layout - Horizontal'
238
+ else case layoutHorz
239
+ when 'true' then 'Layout - Horizontal'
240
+ when 'false' then 'Layout - Vertical'
241
+ else 'Layout - Flow'
242
+ end
243
+ end
244
+ end
245
+ return typeLabel
246
+ end
247
+
248
+ def initDashSVG(dashName)
249
+ dashFName = dashName.gsub(/[<>:'"\/\|?*]/,'')
250
+ $Fsvg = File.open("#{@workbook.name}.#{dashFName}.svg",'w')
251
+ $Fsvg.puts('<?xml version="1.0" standalone="no"?>')
252
+ $Fsvg.puts('<!DOCTYPE svg PUBLIC "-//W3C//Dth SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/Dth/svg11.dth">')
253
+ $Fsvg.puts(' ')
254
+ end
255
+
256
+
257
+
258
+ def termDashSVG
259
+ svgScale = @maxSVGDim / @maxDashWidth
260
+ @svgHead = "<svg id='svg' width='#{@maxDashWidth*svgScale + 2*@svgPadding}'\n"
261
+ @svgHead << " height='#{@maxDashHeight*svgScale + 2*@svgPadding}'\n"
262
+ @svgHead << " version='1.1'\n"
263
+ @svgHead << " xmlns='http://www.w3.org/2000/svg'>\n"
264
+ @svgHead << " <g id=\"svgTransform\" transform=\"translate(10,10) scale(#{svgScale})\">"
265
+ $Fsvg.puts @svgHead
266
+ $Fsvg.puts @svg
267
+ $Fsvg.puts @@svgTail
268
+ $Fsvg.close unless $Fsvg.nil?
269
+ end
270
+
271
+ def initDashHTML(dashName, dashNum, dashCount)
272
+ @htmlHead = '<!DOCTYPE HTML PUBLIC "-//W3C//Dth HTML 3.2 Final//EN">'
273
+ @htmlHead << "\n<HTML>"
274
+ @htmlHead << "\n<HEAD>"
275
+
276
+ @htmlHead << "<TITLE>#{dashName}Dashboard Schematic</TITLE>"
277
+ @htmlHead << "\n<META NAME=\"Generator\" CONTENT=\"xraydashboards.rb\">"
278
+ @htmlHead << "\n<META NAME=\"Author\" CONTENT=\"Chris Gerrard\">"
279
+ @htmlHead << "\n<META NAME=\"Copyright\" CONTENT=\"2012, 2015 Chris Gerrard all rights reserved.\">"
280
+ @htmlHead << "\n<META NAME=\"Keywords\" CONTENT=\"xraydashboards.rb TWB Tools\">"
281
+ @htmlHead << "\n<META NAME=\"Description\" CONTENT=\"Creates an interactive diagram of Tableau dashboard components with associated table of values.\">"
282
+
283
+ @htmlHead << "\n<style>"
284
+
285
+ @htmlHead << "\n#LeftTitle {font: Verdana, Calibri, Geneva, sans-serif; font-size:1em; float:left; margin: 0 5px 0 0; vertical-align:top; text-align:left;}"
286
+ @htmlHead << "\n#RightTitle {font: Verdana, Calibri, Geneva, sans-serif; font-size:1em; float:left; margin: 0 0 0 10px; vertical-align:top;}"
287
+ @htmlHead << "\n#LeftColumn {font: Verdana, Calibri, Geneva, sans-serif; font-size:1em; float:left; margin: 0 5px 0 0; vertical-align:top; text-align:left;}"
288
+ @htmlHead << "\n#RightColumn {font: Verdana, Calibri, Geneva, sans-serif; font-size:1em; float:left; margin: 0 0 0 10px; vertical-align:top;}"
289
+
290
+ @htmlHead << "\ntable { font-family: Verdana, Calibri, Geneva, sans-serif; font-size:.9em; border-collapse:collapse;padding:5 15 5 10; text-align:right;}"
291
+ @htmlHead << "\ntable td, table th { font-family: Verdana, Calibri, Geneva, sans-serif; font-size:.9em; border:3px solid #B0C4DE; padding:0 0 0 0; }"
292
+ @htmlHead << "\ntable th { font-family: Verdana, Calibri, Geneva, sans-serif; font-size:.9em; font-size:.8em; background-color:lightgrey; color:black; }"
293
+ @htmlHead << "\ntable tr.alt td { font-family: Verdana, Calibri, Geneva, sans-serif; font-size:.9em; border:1px solid #B0C4DE; color:#000; background-color:#EAF2D3; }"
294
+
295
+ @htmlHead << "\n</style>"
296
+ @htmlHead << "\n<script>\n"
297
+ @htmlHead << @jsVars % [@maxSVGDim, @maxDashWidth, @maxDashHeight, @maxSVGDim/@maxDashWidth]
298
+ @htmlHead << "\nfunction highlightDashComponent(id)"
299
+ @htmlHead << "\n{"
300
+ @htmlHead << "\n element = document.getElementById(id)"
301
+ @htmlHead << "\n oldFill = element.getAttribute('fill')"
302
+ @htmlHead << "\n oldOpac = element.getAttribute('opacity')"
303
+ @htmlHead << "\n oldStroW = element.getAttribute('stroke-width')"
304
+ @htmlHead << "\n element.setAttribute('fill','darkgrey')"
305
+ @htmlHead << "\n element.setAttribute('opacity','1')"
306
+ @htmlHead << "\n element.setAttribute('stroke-width','800')"
307
+ @htmlHead << "\n // alert(id + ' HIGH fill: ' + oldFill)"
308
+ @htmlHead << "\n}"
309
+ @htmlHead << "\nfunction resetDashComponent(id)"
310
+ @htmlHead << "\n{"
311
+ @htmlHead << "\n element = document.getElementById(id)"
312
+ @htmlHead << "\n element.setAttribute('fill',oldFill)"
313
+ @htmlHead << "\n element.setAttribute('opacity',oldOpac)"
314
+ @htmlHead << "\n element.setAttribute('stroke-width',oldStroW)"
315
+ @htmlHead << "\n}\n"
316
+ @htmlHead << @fnScaleDash
317
+ @htmlHead << "\n</script>"
318
+
319
+ @htmlHead << "\n</HEAD>"
320
+
321
+ @htmlHead << "\n<BODY BGCOLOR=\"#FFFFFF\">\n"
322
+ @htmlHead << <<-PAGELEAD
323
+ <div id='LeftTitle' width='45%'>
324
+ <p><span style='font: normal 16px Verdana, Calibri, Geneva, sans-serif; color: #000000;padding: 0px 10px 0px 15px;'>#{@workbook.name}</span><br />
325
+ <span style='font: normal 12px Verdana, Calibri, Geneva, sans-serif; color: #000000;padding: 10px 10px 0px 15px;'>Dashboard: \"#{dashName}\" \##{dashNum} of #{dashCount} </span></p>
326
+ </div>
327
+ <div id='RightTitle' width='45%'>
328
+ <p><span style='font: normal 12px Verdana, Calibri, Geneva, sans-serif; color: #351c75;padding: 10px 10px 0px 15px;'>
329
+ Resize the Dashboard, from 10-100% :
330
+ </span>
331
+ <input id='scaleFactor' type='range' min='10' max='100' value='100' step='5' onChange='scaleDash();'> <span id='result' style='font: normal 12px Verdana, Calibri, Geneva, sans-serif; color: #351c75;padding: 10px 10px 0px 15px;'>scale: 100%</span>
332
+ </p>
333
+ </div>
334
+ <div style='clear:both;'></div>
335
+ PAGELEAD
336
+ end
337
+
338
+ def termDashHTML
339
+ dhtml = ''
340
+ dhtml << @htmlHead
341
+ dhtml << '<div id="LeftColumn" width="620">'
342
+ dhtml << @svgHead
343
+ dhtml << @svg
344
+ dhtml << @@svgTail
345
+ dhtml << '</div>'
346
+ dhtml << '<div id="RightColumn">'
347
+ dhtml << @@htmlTableLead
348
+ dhtml << @@htmlTableHead
349
+ dhtml << @htmlTable
350
+ dhtml << ('</table>')
351
+ dhtml << @@htmlTableFNote
352
+ dhtml << '</div>'
353
+ dhtml << ('</BODY>')
354
+ dhtml << ('</HTML>')
355
+ end
356
+
357
+ def setScale dashboard
358
+ dashSize = dashboard.node.xpath('./size')
359
+ @maxDashWidth = 0
360
+ @maxDashHeight = 0
361
+ if dashSize.nil?
362
+ then
363
+ $maxWidth = 0
364
+ $maxHeight = 0
365
+ else
366
+ sizeNode = dashSize.first
367
+ if sizeNode.nil?
368
+ then
369
+ $maxWidth = 0
370
+ $maxHeight = 0
371
+ else
372
+ $maxWidth = if sizeNode.attribute('maxwidth').nil? then 1000.0 else sizeNode.attribute('maxwidth').text.to_f end
373
+ $maxHeight = if sizeNode.attribute('maxheight').nil? then 1000.0 else sizeNode.attribute('maxheight').text.to_f end
374
+ end
375
+ end
376
+ end
377
+
378
+ def recordZone(dashName, zone, thcnt)
379
+ id = "#{zone.attribute('id')}-:-#{thcnt}"
380
+ zoneName = getZoneName zone
381
+ type = getZoneType(zone)
382
+ fillColor = getFillColor(type)
383
+ fill = "fill=\"#{fillColor}\";"
384
+ @svg += "\n<g>"
385
+ rxy = ' rx="3000" ry="3000"'
386
+ drawLine = ''
387
+ if type.start_with?('Layout') then
388
+ @strokeWidth = 500
389
+ strokeStyle = 'stroke:black;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1200, 1200;stroke-dashoffset:0;'
390
+ x = zone.attribute('x').text.to_i + @strokeWidth
391
+ y = zone.attribute('y').text.to_i + @strokeWidth
392
+ w = zone.attribute('w').text.to_i
393
+ h = zone.attribute('h').text.to_i
394
+ rxy = ''
395
+ drawLine = if /.*ertical.*/ =~ type then 'vert' else 'horz' end
396
+ # ecx = x+w/2
397
+ # erx = w/2
398
+ # ecy = y+h/2
399
+ # ery = h/2
400
+ # @svg += "\n<ellipse cx=\"#{ecx}\" cy=\"#{ecy}\" rx=\"#{erx}\" ry=\"#{ery}\" style=\"stroke:darkblue;fill:blue;\"/>"
401
+ else
402
+ drawLine = ''
403
+ rxy = ' rx="3000" ry="3000"'
404
+ # @strokeWidth = 200
405
+ strokeStyle = 'stroke:blue;'
406
+ x = zone.attribute('x').text.to_i + @strokeWidth
407
+ y = zone.attribute('y').text.to_i + @strokeWidth
408
+ w = zone.attribute('w').text.to_i
409
+ h = zone.attribute('h').text.to_i
410
+ end
411
+ cw = x+w
412
+ ch = y+h
413
+ @maxDashWidth = [@maxDashWidth, cw].max
414
+ @maxDashHeight = [@maxDashHeight, ch].max
415
+ @svg += "\n<rect"
416
+ @svg += " id=\"#{id}-:-#{thcnt}\""
417
+ @svg += " width=\"#{w}\""
418
+ @svg += " height=\"#{h}\""
419
+ @svg += " x=\"#{x}\""
420
+ @svg += " y=\"#{y}\""
421
+ @svg += rxy
422
+ @svg += " fill=\"#{fillColor}\""
423
+ @svg += " opacity=\"0.2\""
424
+ @svg += " stroke-width=\"#{@strokeWidth}\""
425
+ @svg += " style=\"color:#000000;#{strokeStyle}stroke-opacity:1;\" />"
426
+ @svg += "\n"
427
+ case drawLine
428
+ when 'vert' then @svg += "\n<line x1=\"#{x}\" y1=\"#{y}\" x2=\"#{x+w}\" y2=\"#{y+h}\" style=\"stroke:grey;stroke-width:100\"/>"
429
+ when 'horz' then @svg += "\n<line x1=\"#{x}\" y1=\"#{y+h}\" x2=\"#{x+w}\" y2=\"#{y}\" style=\"stroke:grey;stroke-width:100\"/>"
430
+ end
431
+ case type.downcase
432
+ when 'color legend' then addColorLegend(x,y,w,h)
433
+ when 'filter' then addFilterLegend(x,y,w,h)
434
+ when 'chart' then addChartLegend(x,y,w,h)
435
+ when 'image' then addImageLegend(x,y,w,h)
436
+ when 'empty',
437
+ 'blank' then addLabel(x,y,w,h,'[ ]')
438
+ when 'paramctrl',
439
+ 'parameter' then addLabel(x,y,w,h,'>...<')
440
+ when 'size',
441
+ 'size legend' then addSizeLegend(x,y,w,h)
442
+ when 'shape',
443
+ 'shape legend' then addShapeLegend(x,y,w,h)
444
+ when 'text' then addLabel(x,y,w,h,'loren ipsum')
445
+ # else addLabel(x,y,w,h, "#{type} id: #{id}")
446
+ end
447
+ @svg += "\n</g>\n"
448
+ @htmlTable += "\n<tr style=\"cursor: pointer;\" onMouseOver=\"highlightDashComponent('#{id}-:-#{thcnt}')\" onMouseOut=\"resetDashComponent('#{id}-:-#{thcnt}')\">"
449
+ @htmlTable += " <td style='text-align: left;'>#{zoneName}</td>"
450
+ @htmlTable += " <td style='text-align: left;'>#{type}</td>"
451
+ @htmlTable += " <td>#{x.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse}</td>"
452
+ @htmlTable += " <td>#{y.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse}</td>"
453
+ @htmlTable += " <td>#{w.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse}</td>"
454
+ @htmlTable += " <td>#{h.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse}</td>"
455
+ @htmlTable += " <td>#{id.gsub('-:-','.')}.#{thcnt}</td>"
456
+ @htmlTable += "</tr>"
457
+ return @htmlTable
458
+ end # def recordZone
459
+
460
+ def addLabel(x,y,w,h,type)
461
+ tw = type.length * @@fontSize
462
+ centerX = x + w/2
463
+ centerY = y + h/2
464
+ transform = if tw > w*1.2 then " transform=\"rotate(-90 #{centerX} #{centerY})\"" else '' end
465
+ twh = tw/4
466
+ tx = x + w/2 - twh
467
+ ty = y + (h/2) + 500
468
+ @svg += "<text x=\"#{tx}\" y=\"#{ty}\" font-size=\"#{@@fontSize}\" font-family=\"Verdana,Arial\"#{transform}>#{type}</text>"
469
+ end
470
+
471
+ def addFilterLegend(x,y,w,h)
472
+ lx = x + w/2 - @@fontSize
473
+ ly = y + h/2 + @@fontSize/2
474
+ @svg += "<text x=\"#{lx}\" y=\"#{ly}\""
475
+ @svg += ' id="FilterYes"'
476
+ @svg += " font-size=\"#{@@fontSize}\""
477
+ @svg += ' font-family="Verdana,Arial">'
478
+ @svg += "&#x2713; X</text>"
479
+ end
480
+
481
+ def addChartLegend(x,y,w,h)
482
+ barHeight = h/4
483
+ barWidth = [w/20, barHeight/5].min
484
+ bx = x + (w/2) - barWidth
485
+ by = y + (h/2) - (barHeight/2)
486
+ @svg += "\n<rect x=\"#{bx}\" y=\"#{by}\" width=\"#{barWidth}\" height=\"#{barHeight}\" fill=\"blue\" stroke-width=\"200\" stroke=\"black\"/>"
487
+ @svg += "\n<rect x=\"#{bx + 1.5*barWidth}\" y=\"#{by+barHeight/2}\" width=\"#{barWidth}\" height=\"#{barHeight/2}\" fill=\"orange\" stroke-width=\"100\" stroke=\"black\"/>"
488
+ @svg += "\n"
489
+ end
490
+
491
+ def addImageLegend(x,y,w,h)
492
+ cameraW = @@shapeRadius * 5
493
+ cameraH = @@shapeRadius * 3
494
+ cx = x + w/2 - cameraW/2
495
+ cy = y + h/2
496
+ lx = cx + @@shapeDiam
497
+ ly = cy + cameraH/2
498
+ vw = cameraW / 5
499
+ vh = cameraH / 5
500
+ vx = cx + cameraW - vw*1.5
501
+ vy = cy + vh
502
+ @svg += "\n<rect x=\"#{cx}\" y=\"#{cy}\" width=\"#{cameraW}\" height=\"#{cameraH}\" fill=\"lightgrey\" stroke-width=\"200\" stroke=\"black\" opacity=\"1\"/>"
503
+ @svg += "\n<rect x=\"#{vx}\" y=\"#{vy}\" width=\"#{vw}\" height=\"#{vh}\" fill=\"lightgrey\" stroke-width=\"200\" stroke=\"black\" opacity=\"1\"/>"
504
+ @svg += "\n<circle cx=\"#{lx}\" cy=\"#{ly}\" r=\"#{@@shapeRadius*0.8}\" fill=\"lightgrey\" stroke-width=\"200\" stroke=\"black\" opacity=\"1\"/>"
505
+ @svg += "\n"
506
+ end
507
+
508
+ def addColorLegend(x,y,w,h)
509
+ d = @@shapeDiam
510
+ cx = x + w/2
511
+ cy = y + h/2
512
+ sx = cx - (2 * d)
513
+ sy = cy - (d / 2)
514
+ @svg += "\n<rect x=\"#{sx}\" y=\"#{sy}\" width=\"#{d}\" height=\"#{d}\" fill=\"blue\" stroke-width=\"none\" stroke=\"none\" opacity=\"1\"/>"
515
+ @svg += "\n<rect x=\"#{sx + 1.5*d}\" y=\"#{sy}\" width=\"#{d}\" height=\"#{d}\" fill=\"red\" stroke-width=\"none\" stroke=\"none\" opacity=\"1\"/>"
516
+ @svg += "\n<rect x=\"#{sx + 3*d}\" y=\"#{sy}\" width=\"#{d}\" height=\"#{d}\" fill=\"green\" stroke-width=\"none\" stroke=\"none\" opacity=\"1\"/>"
517
+ @svg += "\n"
518
+ end
519
+
520
+ def addShapeLegend(x,y,w,h)
521
+ centerX = x + w/2
522
+ centerY = y + h/2
523
+ cx = centerX - 3*@@shapeRadius
524
+ cy = centerY + @@shapeRadius/2
525
+ rx = centerX - @@shapeRadius
526
+ ry = centerY - @@shapeRadius/2
527
+ tx = centerX + @@shapeDiam
528
+ ty = centerY - @@shapeRadius/2
529
+ @svg += "\n<circle cx=\"#{cx}\" cy=\"#{cy}\" r=\"#{@@shapeRadius}\" fill=\"#008080\" stroke-width=\"200\" stroke=\"black\" opacity=\"0.8\"/>"
530
+ @svg += "\n<rect x=\"#{rx}\" y=\"#{ry}\" width=\"#{@@shapeDiam}\" height=\"#{@@shapeDiam}\" fill=\"#008080\" stroke-width=\"200\" stroke=\"black\" opacity=\"0.8\"/>"
531
+ @svg += "\n<polyline points=\"#{tx} ,#{ty+@@shapeDiam}
532
+ #{tx+@@shapeDiam} ,#{ty+@@shapeDiam}
533
+ #{tx+@@shapeRadius},#{ty}
534
+ #{tx} ,#{ty+@@shapeDiam}\" fill=\"#008080\" stroke-width=\"200\" stroke=\"black\" opacity=\"0.8\"/>"
535
+ end
536
+
537
+ def addSizeLegend(x,y,w,h)
538
+ centerX = x + w/2
539
+ centerY = y + h/2
540
+ smallRadius = @@shapeRadius/2
541
+ medRadius = @@shapeRadius
542
+ largeRadius = smallRadius + medRadius
543
+ sx = centerX - medRadius*3
544
+ mx = centerX - medRadius
545
+ lx = centerX + medRadius*2
546
+ @svg += "\n<circle cx=\"#{sx}\" cy=\"#{centerY}\" r=\"#{smallRadius}\" fill=\"#008080\" stroke-width=\"200\" stroke=\"black\" opacity=\"0.8\"/>"
547
+ @svg += "\n<circle cx=\"#{mx}\" cy=\"#{centerY}\" r=\"#{medRadius}\" fill=\"#008080\" stroke-width=\"200\" stroke=\"black\" opacity=\"0.8\"/>"
548
+ @svg += "\n<circle cx=\"#{lx}\" cy=\"#{centerY}\" r=\"#{largeRadius}\" fill=\"#008080\" stroke-width=\"200\" stroke=\"black\" opacity=\"0.8\"/>"
549
+ end
550
+
551
+ end
552
+
553
+ end