libisi 0.3.0
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/LICENSE +677 -0
- data/Manifest +89 -0
- data/Rakefile +34 -0
- data/lib/inifile.rb +119 -0
- data/lib/libisi.rb +948 -0
- data/lib/libisi/attribute.rb +32 -0
- data/lib/libisi/attribute/activerecord.rb +34 -0
- data/lib/libisi/attribute/base.rb +33 -0
- data/lib/libisi/base.rb +109 -0
- data/lib/libisi/bridge.rb +21 -0
- data/lib/libisi/bridge/base.rb +23 -0
- data/lib/libisi/bridge/java.rb +71 -0
- data/lib/libisi/bridge/python.rb +37 -0
- data/lib/libisi/cache.rb +21 -0
- data/lib/libisi/cache/base.rb +67 -0
- data/lib/libisi/cache/file_cache.rb +24 -0
- data/lib/libisi/chart.rb +21 -0
- data/lib/libisi/chart/base.rb +320 -0
- data/lib/libisi/chart/jfreechart.rb +682 -0
- data/lib/libisi/chart/jfreechart_generator.rb +206 -0
- data/lib/libisi/color.rb +21 -0
- data/lib/libisi/color/base.rb +66 -0
- data/lib/libisi/color/colortools.rb +92 -0
- data/lib/libisi/color/java.rb +44 -0
- data/lib/libisi/concept.rb +33 -0
- data/lib/libisi/concept/activerecord.rb +39 -0
- data/lib/libisi/concept/base.rb +58 -0
- data/lib/libisi/doc.rb +35 -0
- data/lib/libisi/doc/base.rb +414 -0
- data/lib/libisi/doc/html.rb +85 -0
- data/lib/libisi/doc/text.rb +98 -0
- data/lib/libisi/doc/wiki.rb +55 -0
- data/lib/libisi/environment.rb +21 -0
- data/lib/libisi/environment/base.rb +36 -0
- data/lib/libisi/environment/http.rb +105 -0
- data/lib/libisi/environment/rails.rb +27 -0
- data/lib/libisi/environment/root.rb +23 -0
- data/lib/libisi/fake_logger/logger.rb +61 -0
- data/lib/libisi/function/base.rb +30 -0
- data/lib/libisi/hal.rb +558 -0
- data/lib/libisi/instance.rb +27 -0
- data/lib/libisi/instance/activerecord.rb +21 -0
- data/lib/libisi/instance/base.rb +42 -0
- data/lib/libisi/log.rb +237 -0
- data/lib/libisi/mail/base.rb +32 -0
- data/lib/libisi/mail/tmail.rb +120 -0
- data/lib/libisi/parameter/base.rb +41 -0
- data/lib/libisi/property.rb +27 -0
- data/lib/libisi/property/base.rb +28 -0
- data/lib/libisi/reciever/base.rb +31 -0
- data/lib/libisi/reciever/socket.rb +31 -0
- data/lib/libisi/relation.rb +23 -0
- data/lib/libisi/request.rb +22 -0
- data/lib/libisi/request/base.rb +29 -0
- data/lib/libisi/request/http.rb +129 -0
- data/lib/libisi/response/base.rb +27 -0
- data/lib/libisi/task/base.rb +27 -0
- data/lib/libisi/task/http.rb +90 -0
- data/lib/libisi/tee.rb +296 -0
- data/lib/libisi/ui/base.rb +116 -0
- data/lib/libisi/ui/console.rb +238 -0
- data/lib/libisi/ui/kde.rb +94 -0
- data/lib/libisi/ui/nobody.rb +29 -0
- data/lib/libisi/ui/rails.rb +150 -0
- data/lib/libisi/ui/x11.rb +55 -0
- data/lib/libisi/uri.rb +42 -0
- data/lib/libisi/uri/activerecord.rb +152 -0
- data/lib/libisi/uri/base.rb +115 -0
- data/lib/libisi/uri/file.rb +43 -0
- data/lib/libisi/uri/ldap.rb +72 -0
- data/lib/libisi/uri/mysql.rb +98 -0
- data/lib/libisi/value.rb +31 -0
- data/lib/libisi/value/attribute_value.rb +19 -0
- data/lib/libisi/value/base.rb +55 -0
- data/lib/libisi/value/property_value.rb +19 -0
- data/lib/libisi/value/relation_value.rb +19 -0
- data/lib/ordered_hash.rb +228 -0
- data/libisi.gemspec +31 -0
- data/test/bridge_test.rb +77 -0
- data/test/cache_test.rb +65 -0
- data/test/chart_test.rb +179 -0
- data/test/color_test.rb +64 -0
- data/test/concept_test.rb +56 -0
- data/test/doc_test.rb +172 -0
- data/test/fixtures/test.db +0 -0
- data/test/ordered_hash_test.rb +39 -0
- data/test/profile_test.rb +36 -0
- data/test/request_test.rb +121 -0
- data/test/test +0 -0
- data/test/ui_test.rb +62 -0
- metadata +244 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Copyright (C) 2007-2010 Logintas AG Switzerland
|
|
2
|
+
#
|
|
3
|
+
# This file is part of Libisi.
|
|
4
|
+
#
|
|
5
|
+
# Libisi is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# Libisi is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU General Public License
|
|
16
|
+
# along with Libisi. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
class FileCache < BaseCache
|
|
19
|
+
|
|
20
|
+
def initialize(file, options = {})
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
data/lib/libisi/chart.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Copyright (C) 2007-2010 Logintas AG Switzerland
|
|
2
|
+
#
|
|
3
|
+
# This file is part of Libisi.
|
|
4
|
+
#
|
|
5
|
+
# Libisi is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# Libisi is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU General Public License
|
|
16
|
+
# along with Libisi. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
require "libisi/base.rb"
|
|
19
|
+
class Chart < Base
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# Copyright (C) 2007-2010 Logintas AG Switzerland
|
|
2
|
+
#
|
|
3
|
+
# This file is part of Libisi.
|
|
4
|
+
#
|
|
5
|
+
# Libisi is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# Libisi is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU General Public License
|
|
16
|
+
# along with Libisi. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
class BaseChart
|
|
19
|
+
|
|
20
|
+
BAR_TYPES = [:bar, :pie, :gantt, :xy]
|
|
21
|
+
|
|
22
|
+
attr_accessor :title, :height, :width, :stacked, :type, :legend_rotation, :legend_chart_ratio
|
|
23
|
+
|
|
24
|
+
DEFAULT_HEIGHT = 480
|
|
25
|
+
DEFAULT_WIDTH = 640
|
|
26
|
+
DEFAULT_STACKED = false
|
|
27
|
+
DEFAULT_CHART_TYPE = :bar
|
|
28
|
+
DEFAULT_LEGEND_ROTATION = 0.0 #Math::PI / 6.0
|
|
29
|
+
DEFAULT_LEGEND_CHART_RATIO = 0.4
|
|
30
|
+
|
|
31
|
+
def initialize(options = {})
|
|
32
|
+
@height = DEFAULT_HEIGHT
|
|
33
|
+
@width = DEFAULT_WIDTH
|
|
34
|
+
@stacked = DEFAULT_STACKED
|
|
35
|
+
@legend_chart_ratio = DEFAULT_LEGEND_CHART_RATIO
|
|
36
|
+
@options = options
|
|
37
|
+
@options ||= {}
|
|
38
|
+
@axes = []
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def display_legend; data_dimension > 1; end
|
|
42
|
+
def enable_urls; false; end
|
|
43
|
+
def enable_tooltips; true; end
|
|
44
|
+
def orientation
|
|
45
|
+
return @orientation if @orientation
|
|
46
|
+
if @type == :gantt
|
|
47
|
+
:horizontal
|
|
48
|
+
else
|
|
49
|
+
:vertical
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
def legend_rotation; @legend_rotation or DEFAULT_LEGEND_ROTATION; end
|
|
53
|
+
|
|
54
|
+
# data
|
|
55
|
+
def save(filename, options = {})
|
|
56
|
+
create_chart unless @chart
|
|
57
|
+
case filename
|
|
58
|
+
when /.html$/
|
|
59
|
+
Pathname.new(filename).open("w") {|f|
|
|
60
|
+
f.write(data("text/html",options))
|
|
61
|
+
}
|
|
62
|
+
when /.png$/
|
|
63
|
+
Pathname.new(filename).open("w") {|f| f.write(data("image/png",options))}
|
|
64
|
+
else
|
|
65
|
+
raise "Dont know how to save to file #{filename}"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def ranges
|
|
70
|
+
@ranges
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# axes
|
|
74
|
+
def xaxis; @axes[0]; end
|
|
75
|
+
def xaxis=(val); @axes[0] = val; end
|
|
76
|
+
def yaxis; @axes[1]; end
|
|
77
|
+
def yaxis=(val); @axes[1] = val; end
|
|
78
|
+
def zaxis; @axes[2]; end
|
|
79
|
+
def zaxis=(val); @axes[2] = val; end
|
|
80
|
+
|
|
81
|
+
# markers
|
|
82
|
+
def mark(name, from = nil, to = nil, options = {})
|
|
83
|
+
raise "Marker value may not be nil" if
|
|
84
|
+
from.nil? and !block_given?
|
|
85
|
+
if to.class == Hash
|
|
86
|
+
options = to
|
|
87
|
+
to = nil
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if name.class == Hash
|
|
91
|
+
options = name
|
|
92
|
+
name = nil
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
options ||= {}
|
|
96
|
+
options = options.dup
|
|
97
|
+
|
|
98
|
+
if from.nil?
|
|
99
|
+
options[:type] = :category
|
|
100
|
+
options[:key] = name
|
|
101
|
+
else
|
|
102
|
+
if to.nil?
|
|
103
|
+
options[:type] = :value
|
|
104
|
+
options[:value] = from
|
|
105
|
+
else
|
|
106
|
+
options[:type] = :interval
|
|
107
|
+
options[:start] = from
|
|
108
|
+
options[:end] = to
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
options[:name] = name
|
|
112
|
+
|
|
113
|
+
if block_given?
|
|
114
|
+
# this is a domain marker
|
|
115
|
+
# add all values that has been added
|
|
116
|
+
# yield
|
|
117
|
+
options[:axis] = :domain
|
|
118
|
+
previous_keys = @current_serie.keys.dup
|
|
119
|
+
yield
|
|
120
|
+
current_keys = @current_serie.keys.dup
|
|
121
|
+
new_keys = current_keys.reject {|k| previous_keys.include?(k)}
|
|
122
|
+
|
|
123
|
+
@current_range_options[:markers] ||= []
|
|
124
|
+
new_keys.each {|k|
|
|
125
|
+
o = options.dup
|
|
126
|
+
o[:key] = k
|
|
127
|
+
@current_range_options[:markers] << o
|
|
128
|
+
}
|
|
129
|
+
else
|
|
130
|
+
options[:axis] = :range
|
|
131
|
+
add_to = @options
|
|
132
|
+
add_to = @current_range_options if @current_range_options
|
|
133
|
+
|
|
134
|
+
add_to[:markers] ||= []
|
|
135
|
+
add_to[:markers] << options
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
alias :marker :mark
|
|
139
|
+
|
|
140
|
+
# Adding values
|
|
141
|
+
def range(name = nil, options = {})
|
|
142
|
+
@range_options ||= {}
|
|
143
|
+
@ranges ||= OrderedHash.new
|
|
144
|
+
|
|
145
|
+
raise "Range #{name.inspect} already exist" unless
|
|
146
|
+
@ranges[name].nil?
|
|
147
|
+
|
|
148
|
+
@range_options[name] = options
|
|
149
|
+
@current_range_options = @range_options[name]
|
|
150
|
+
|
|
151
|
+
@current_range = OrderedHash.new
|
|
152
|
+
@ranges[name] = @current_range
|
|
153
|
+
yield
|
|
154
|
+
@current_range = nil
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def serie(name = nil, options = {})
|
|
158
|
+
unless @current_range
|
|
159
|
+
range {
|
|
160
|
+
return serie(name) {
|
|
161
|
+
yield
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
@series_options ||= {}
|
|
167
|
+
@series_options[name] = {}
|
|
168
|
+
|
|
169
|
+
@current_serie = OrderedHash.new
|
|
170
|
+
@current_range[name] = @current_serie
|
|
171
|
+
yield
|
|
172
|
+
@current_serie = nil
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def value(name, value)
|
|
176
|
+
@current_serie[name] = value
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def time_span(name, start_time, end_time, options = {})
|
|
180
|
+
raise "No current serie." unless @current_serie
|
|
181
|
+
@type ||= :gantt
|
|
182
|
+
raise "No time_spans allowed for chart type #{@type}" unless
|
|
183
|
+
@type == :gantt
|
|
184
|
+
|
|
185
|
+
new_span = {:start => start_time, :end => end_time}
|
|
186
|
+
new_span[:percentage] = options[:percentage] if options[:percentage]
|
|
187
|
+
|
|
188
|
+
old_span = @current_timespan
|
|
189
|
+
if @current_timespan
|
|
190
|
+
# ok, we are already in a timespan block
|
|
191
|
+
# add children
|
|
192
|
+
@current_timespan[:children] ||= OrderedHash.new
|
|
193
|
+
raise "There is already a timespan called #{name.inspect}" if
|
|
194
|
+
@current_timespan[:children][name]
|
|
195
|
+
@current_timespan[:children][name] = new_span
|
|
196
|
+
else
|
|
197
|
+
@current_timespan = new_span
|
|
198
|
+
raise "There is already a timespan called #{name.inspect}" if
|
|
199
|
+
@current_serie[name]
|
|
200
|
+
@current_serie[name] = @current_timespan
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
yield if block_given?
|
|
204
|
+
@current_timespan = old_span
|
|
205
|
+
new_span
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def data_dimension
|
|
209
|
+
# RANGE x SERIE x CATEGORY x ARRAY
|
|
210
|
+
return 0 unless @ranges
|
|
211
|
+
return 4 if @ranges.keys.length > 1
|
|
212
|
+
return 3 if @ranges[0].nil? or @ranges[0].keys > 1
|
|
213
|
+
return 2 if @ranges[0][0].nil? or @ranges[0][0].keys > 1
|
|
214
|
+
return 1
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# old fashioned loading from alois
|
|
218
|
+
def load(input)
|
|
219
|
+
input = input.split("\n").reverse
|
|
220
|
+
# System.out.println("Chart title?");
|
|
221
|
+
@title = input.pop
|
|
222
|
+
|
|
223
|
+
# System.out.println("Width?");
|
|
224
|
+
@options[:width] = input.pop.to_i
|
|
225
|
+
|
|
226
|
+
# System.out.println("Height?");
|
|
227
|
+
@options[:height] = input.pop.to_i
|
|
228
|
+
|
|
229
|
+
# System.out.println("X-Axis?");
|
|
230
|
+
@axes = []
|
|
231
|
+
@axes[0] = input.pop
|
|
232
|
+
|
|
233
|
+
# System.out.println("Y-Axis?");
|
|
234
|
+
@axes[1] = input.pop
|
|
235
|
+
|
|
236
|
+
# System.out.println("Series count?");
|
|
237
|
+
serie_count = input.pop.to_i
|
|
238
|
+
|
|
239
|
+
# System.out.println("Range count?");
|
|
240
|
+
range_count = input.pop.to_i
|
|
241
|
+
|
|
242
|
+
@ranges = OrderedHash.new
|
|
243
|
+
range_count.times {|range|
|
|
244
|
+
range_name = input.pop
|
|
245
|
+
range_name = nil if range_name == "<<NULL>>"
|
|
246
|
+
|
|
247
|
+
current_range = OrderedHash.new
|
|
248
|
+
@ranges[range_name] = current_range
|
|
249
|
+
|
|
250
|
+
serie_count.times {|serie|
|
|
251
|
+
serie_name = input.pop
|
|
252
|
+
serie_name = nil if serie_name == "<<NULL>>"
|
|
253
|
+
$log.debug("Serie name: #{category_name}")
|
|
254
|
+
|
|
255
|
+
current_serie = OrderedHash.new(serie_name)
|
|
256
|
+
current_range[serie_name] = current_serie
|
|
257
|
+
|
|
258
|
+
rowCount = input.pop.to_i
|
|
259
|
+
columnCount = input.pop.to_i
|
|
260
|
+
|
|
261
|
+
rowCount.times {|row|
|
|
262
|
+
category_name = input.pop
|
|
263
|
+
category_name = nil if category_name == "<<NULL>>"
|
|
264
|
+
$log.debug("Category name: #{category_name}")
|
|
265
|
+
|
|
266
|
+
current_category = []
|
|
267
|
+
current_serie[category_name] = current_category
|
|
268
|
+
|
|
269
|
+
columnCount.times {|col|
|
|
270
|
+
current_category << input.pop
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def create_chart(type = nil, options = {})
|
|
280
|
+
t = (type or @type or DEFAULT_CHART_TYPE)
|
|
281
|
+
|
|
282
|
+
case options[:combined_axis]
|
|
283
|
+
when nil, :x, "x",:xaxis, "xaxis", :domain, "domain"
|
|
284
|
+
options[:combined_axis] = :domain
|
|
285
|
+
when nil, :y, "y",:yaxis, "yaxis", :range, "range"
|
|
286
|
+
options[:combined_axis] = :range
|
|
287
|
+
else
|
|
288
|
+
raise "Unexpected combined axis option: #{options[:combined_axis].inspect}"
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
case t
|
|
292
|
+
when :bar, :line, :gantt, :pie
|
|
293
|
+
plot = nil
|
|
294
|
+
case data_dimension
|
|
295
|
+
when 4
|
|
296
|
+
plot = create_combined_plot(@ranges, options[:combined_axis])
|
|
297
|
+
when 3
|
|
298
|
+
plot = create_plot(nil,@ranges.values[0])
|
|
299
|
+
else
|
|
300
|
+
raise "Unexpected data dimension #{data_dimension}"
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
create_chart_implementation(plot)
|
|
304
|
+
return @chart
|
|
305
|
+
when :xy
|
|
306
|
+
raise "Not implemented yet chart type #{t}"
|
|
307
|
+
else
|
|
308
|
+
raise "Unknown chart type #{t}"
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def create_combined_plot(data, combination_axis = :category)
|
|
313
|
+
create_combined_plot_implementation(data,combination_axis)
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def create_plot(name, data)
|
|
317
|
+
create_plot_implementation(name,data)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
end
|
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
# Copyright (C) 2007-2010 Logintas AG Switzerland
|
|
2
|
+
#
|
|
3
|
+
# This file is part of Libisi.
|
|
4
|
+
#
|
|
5
|
+
# Libisi is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# Libisi is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU General Public License
|
|
16
|
+
# along with Libisi. If not, see <http://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
require "libisi/bridge/java.rb"
|
|
19
|
+
require "libisi/chart/base.rb"
|
|
20
|
+
require "libisi/chart/jfreechart_generator.rb"
|
|
21
|
+
require "libisi/color.rb"
|
|
22
|
+
require "stringio"
|
|
23
|
+
|
|
24
|
+
JavaBridge.load("/usr/share/java/jfreechart.jar")
|
|
25
|
+
|
|
26
|
+
[
|
|
27
|
+
"org.jfree.ui.RectangleAnchor",
|
|
28
|
+
"org.jfree.ui.TextAnchor",
|
|
29
|
+
"org.jfree.ui.Layer",
|
|
30
|
+
"org.jfree.chart.plot.CategoryMarker",
|
|
31
|
+
"org.jfree.chart.plot.IntervalMarker",
|
|
32
|
+
"org.jfree.chart.plot.ValueMarker",
|
|
33
|
+
"org.jfree.chart.LegendItemCollection",
|
|
34
|
+
"org.jfree.chart.axis.CategoryLabelPositions",
|
|
35
|
+
"org.jfree.chart.axis.CategoryLabelPosition",
|
|
36
|
+
"org.jfree.chart.axis.CategoryLabelWidthType",
|
|
37
|
+
"org.jfree.chart.ChartColor",
|
|
38
|
+
"java.awt.image.BufferedImage",
|
|
39
|
+
"java.awt.Rectangle",
|
|
40
|
+
"java.awt.TexturePaint",
|
|
41
|
+
"java.awt.Font",
|
|
42
|
+
"org.jfree.text.TextBlockAnchor",
|
|
43
|
+
"org.jfree.util.TableOrder",
|
|
44
|
+
"org.jfree.chart.JFreeChart",
|
|
45
|
+
"org.jfree.chart.ChartFactory",
|
|
46
|
+
"org.jfree.chart.axis.CategoryAxis",
|
|
47
|
+
"org.jfree.chart.axis.ExtendedCategoryAxis",
|
|
48
|
+
"org.jfree.chart.axis.NumberAxis",
|
|
49
|
+
"org.jfree.chart.plot.XYPlot",
|
|
50
|
+
"org.jfree.chart.entity.StandardEntityCollection",
|
|
51
|
+
"org.jfree.chart.ChartUtilities",
|
|
52
|
+
"org.jfree.chart.plot.CombinedRangeCategoryPlot",
|
|
53
|
+
"org.jfree.chart.plot.CombinedDomainCategoryPlot",
|
|
54
|
+
"org.jfree.chart.plot.CombinedRangeXYPlot",
|
|
55
|
+
"org.jfree.chart.plot.CombinedDomainXYPlot",
|
|
56
|
+
"org.jfree.chart.axis.DateAxis",
|
|
57
|
+
# produces already initialized constant DEFAULT_TOOL_TIP_FORMAT_STRING at javabridge.import
|
|
58
|
+
# but this class is not needed
|
|
59
|
+
# "org.jfree.chart.labels.IntervalCategoryToolTipGenerator",
|
|
60
|
+
"org.jfree.chart.axis.QuarterDateFormat",
|
|
61
|
+
"java.text.DateFormat",
|
|
62
|
+
"org.jfree.chart.plot.CategoryPlot",
|
|
63
|
+
"org.jfree.chart.plot.PlotOrientation",
|
|
64
|
+
|
|
65
|
+
# rendering
|
|
66
|
+
"org.jfree.chart.renderer.category.IntervalBarRenderer",
|
|
67
|
+
"org.jfree.chart.renderer.category.GanttRenderer",
|
|
68
|
+
"org.jfree.chart.renderer.xy.StackedXYAreaRenderer2",
|
|
69
|
+
"org.jfree.chart.renderer.category.StackedBarRenderer",
|
|
70
|
+
"org.jfree.chart.ChartRenderingInfo",
|
|
71
|
+
"org.jfree.chart.renderer.category.BarRenderer",
|
|
72
|
+
"org.jfree.chart.plot.MultiplePiePlot",
|
|
73
|
+
"org.jfree.chart.renderer.xy.XYBarRenderer",
|
|
74
|
+
|
|
75
|
+
# datasets
|
|
76
|
+
"org.jfree.data.category.DefaultCategoryDataset",
|
|
77
|
+
"org.jfree.data.xy.CategoryTableXYDataset",
|
|
78
|
+
|
|
79
|
+
"org.jfree.data.gantt.Task",
|
|
80
|
+
"org.jfree.data.gantt.TaskSeries",
|
|
81
|
+
"org.jfree.data.gantt.TaskSeriesCollection",
|
|
82
|
+
|
|
83
|
+
"org.jfree.data.time.SimpleTimePeriod",
|
|
84
|
+
"java.util.Calendar"
|
|
85
|
+
].each {|klass|
|
|
86
|
+
if klass == "org.jfree.chart.labels.IntervalCategoryToolTipGenerator"
|
|
87
|
+
p "kde" if defined?(DEFAULT_TOOL_TIP_FORMAT_STRING)
|
|
88
|
+
p "here"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
eval("#{klass.split(".")[-1]} = JavaBridge.import(klass)")
|
|
92
|
+
if klass == "org.jfree.chart.labels.IntervalCategoryToolTipGenerator"
|
|
93
|
+
p "end"
|
|
94
|
+
end
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
# same space
|
|
98
|
+
[
|
|
99
|
+
"java.util.Date",
|
|
100
|
+
"java.io.File",
|
|
101
|
+
].each {|klass|
|
|
102
|
+
eval("J#{klass.split(".")[-1]} = JavaBridge.import(klass, :prefix => 'J')")
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class JfreechartChart < BaseChart
|
|
107
|
+
|
|
108
|
+
def data(mime_type, options = {})
|
|
109
|
+
raise "No chart defined" unless @chart
|
|
110
|
+
|
|
111
|
+
temp_file {|temp_image_file|
|
|
112
|
+
info = ChartRenderingInfo.new(StandardEntityCollection.new)
|
|
113
|
+
ChartUtilities.saveChartAsPNG(JFile.new(temp_image_file.to_s),
|
|
114
|
+
@chart, width.to_i, height.to_i, info);
|
|
115
|
+
|
|
116
|
+
case mime_type
|
|
117
|
+
when "image/png"
|
|
118
|
+
temp_image_file.open("r").read
|
|
119
|
+
when "text/html"
|
|
120
|
+
image_file = nil
|
|
121
|
+
image_file = Pathname.new(options[:image_file]) if
|
|
122
|
+
image_file.nil? and options[:image_file]
|
|
123
|
+
image_file = Pathname.new(image_path) + "jfreechart.png" if
|
|
124
|
+
image_file.nil? and options[:image_path]
|
|
125
|
+
|
|
126
|
+
image_map_file = nil
|
|
127
|
+
image_map_file = Pathname.new(option[:image_map_file]) if
|
|
128
|
+
image_map_file.nil? and options[:image_map_file]
|
|
129
|
+
|
|
130
|
+
image_map_file.open("w") {|f|
|
|
131
|
+
f.write(ChartUtilities.getImageMap("chart", info))
|
|
132
|
+
} if image_map_file
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
html_file = StringIO.new
|
|
136
|
+
# write an HTML page incorporating the image with an image map
|
|
137
|
+
if options[:layout].nil? or !options[:layout]
|
|
138
|
+
html_file.write("<HEAD><TITLE>JFreeChart Image Map</TITLE></HEAD>\n")
|
|
139
|
+
html_file.write("<BODY>\n");
|
|
140
|
+
end
|
|
141
|
+
html_file.write(ChartUtilities.getImageMap("chart", info));
|
|
142
|
+
|
|
143
|
+
if image_file
|
|
144
|
+
FileUtils.mv(temp_image_file, image_file)
|
|
145
|
+
html_file.write("<IMG SRC=\"#{image_file.to_s}\" " +
|
|
146
|
+
"WIDTH=\"#{width}\" HEIGHT=\"#{height}\" BORDER=\"0\" USEMAP=\"#chart\">\n")
|
|
147
|
+
else
|
|
148
|
+
image_data = Base64.encode64(temp_image_file.open("r").read)
|
|
149
|
+
html_file.write("<IMG SRC=\"data:image/png;base64,#{image_data}\" " +
|
|
150
|
+
"WIDTH=\"#{width}\" HEIGHT=\"#{height}\" BORDER=\"0\" USEMAP=\"#chart\">\n")
|
|
151
|
+
end
|
|
152
|
+
if options[:layout].nil? or !options[:layout]
|
|
153
|
+
html_file.write("</BODY>\n");
|
|
154
|
+
html_file.write("</HTML>\n");
|
|
155
|
+
end
|
|
156
|
+
html_file.string
|
|
157
|
+
else
|
|
158
|
+
raise "Cannot render to #{mime_type.inspect}"
|
|
159
|
+
end
|
|
160
|
+
}
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private
|
|
164
|
+
def jf_orientation(flipped = false)
|
|
165
|
+
case orientation
|
|
166
|
+
when nil, :horizontal
|
|
167
|
+
if flipped
|
|
168
|
+
PlotOrientation.VERTICAL
|
|
169
|
+
else
|
|
170
|
+
PlotOrientation.HORIZONTAL
|
|
171
|
+
end
|
|
172
|
+
when :vertical
|
|
173
|
+
if flipped
|
|
174
|
+
PlotOrientation.HORIZONTAL
|
|
175
|
+
else
|
|
176
|
+
PlotOrientation.VERTICAL
|
|
177
|
+
end
|
|
178
|
+
else
|
|
179
|
+
raise "Unexpected orientation #{orientation.inspect}"
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def configure_renderer(renderer)
|
|
184
|
+
configure_colors(renderer)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def configure_colors(renderer)
|
|
188
|
+
paint_array = ChartColor.createDefaultPaintArray()
|
|
189
|
+
second_color = Color.create("java","white").java_object
|
|
190
|
+
i = 0
|
|
191
|
+
if (false)
|
|
192
|
+
paint_array.each {|item|
|
|
193
|
+
renderer.setSeriesPaint(i, GradientPaint.new(0.0, 0.0, item, 1000, 0.0, second_color))
|
|
194
|
+
i += 1;
|
|
195
|
+
}
|
|
196
|
+
else
|
|
197
|
+
paint_array.each {|item|
|
|
198
|
+
renderer.setSeriesPaint(i, item)
|
|
199
|
+
i += 1;
|
|
200
|
+
}
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
paint_array.each {|item|
|
|
204
|
+
bi = BufferedImage.new(2, 2, BufferedImage.TYPE_INT_RGB);
|
|
205
|
+
big = bi.createGraphics();
|
|
206
|
+
big.setColor(item);
|
|
207
|
+
big.fillRect(0, 0, 1, 1);
|
|
208
|
+
big.fillOval(1, 1, 2, 2);
|
|
209
|
+
big.setColor(second_color);
|
|
210
|
+
big.fillRect(1, 0, 2, 1);
|
|
211
|
+
big.fillOval(0, 1, 1, 2);
|
|
212
|
+
r = Rectangle.new(0, 0, 2, 2);
|
|
213
|
+
renderer.setSeriesPaint(i,TexturePaint.new(bi, r))
|
|
214
|
+
i += 1;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
paint_array.each {|item|
|
|
218
|
+
bi = BufferedImage.new(2, 2, BufferedImage.TYPE_INT_RGB);
|
|
219
|
+
big = bi.createGraphics();
|
|
220
|
+
big.setColor(item);
|
|
221
|
+
big.fillRect(0, 0, 1, 1);
|
|
222
|
+
big.fillOval(1, 0, 2, 1);
|
|
223
|
+
big.setColor(second_color);
|
|
224
|
+
big.fillRect(0, 1, 1, 2);
|
|
225
|
+
big.fillOval(1, 1, 2, 2);
|
|
226
|
+
r = Rectangle.new(0, 0, 2, 2);
|
|
227
|
+
renderer.setSeriesPaint(i, TexturePaint.new(bi, r))
|
|
228
|
+
i += 1;
|
|
229
|
+
}
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def jf_xaxis
|
|
233
|
+
name = [name, xaxis].compact.join(" ")
|
|
234
|
+
case type
|
|
235
|
+
when :line, :xy
|
|
236
|
+
axis_obj = NumberAxis.new(name)
|
|
237
|
+
axis_obj.setAutoRangeIncludesZero(false)
|
|
238
|
+
axis_obj.setAutoRangeStickyZero(false)
|
|
239
|
+
axis_obj.setAutoRange(true)
|
|
240
|
+
axis_obj
|
|
241
|
+
else
|
|
242
|
+
axis_obj = CategoryAxis.new(xaxis)
|
|
243
|
+
#axis_obj.setTickLabelFont(Font.new("SansSerif", Font.PLAIN, 8))
|
|
244
|
+
#axis_obj.setTickLabelPaint(Color.create("java","red").java_object)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
clp = CategoryLabelPositions.new(
|
|
249
|
+
# TOP
|
|
250
|
+
CategoryLabelPosition.new(
|
|
251
|
+
RectangleAnchor.BOTTOM,
|
|
252
|
+
TextBlockAnchor.BOTTOM_LEFT,
|
|
253
|
+
TextAnchor.BOTTOM_LEFT,
|
|
254
|
+
-legend_rotation,
|
|
255
|
+
CategoryLabelWidthType.RANGE,
|
|
256
|
+
0.40),
|
|
257
|
+
# BOTTOM
|
|
258
|
+
CategoryLabelPosition.new(
|
|
259
|
+
RectangleAnchor.TOP,
|
|
260
|
+
TextBlockAnchor.TOP_RIGHT,
|
|
261
|
+
TextAnchor.TOP_RIGHT,
|
|
262
|
+
-legend_rotation,
|
|
263
|
+
CategoryLabelWidthType.RANGE,
|
|
264
|
+
0.40),
|
|
265
|
+
# LEFT
|
|
266
|
+
CategoryLabelPosition.new(
|
|
267
|
+
RectangleAnchor.RIGHT,
|
|
268
|
+
TextBlockAnchor.BOTTOM_RIGHT,
|
|
269
|
+
TextAnchor.BOTTOM_RIGHT,
|
|
270
|
+
-legend_rotation,
|
|
271
|
+
CategoryLabelWidthType.RANGE,
|
|
272
|
+
0.40),
|
|
273
|
+
# RIGHT
|
|
274
|
+
CategoryLabelPosition.new(
|
|
275
|
+
RectangleAnchor.LEFT,
|
|
276
|
+
TextBlockAnchor.TOP_LEFT,
|
|
277
|
+
TextAnchor.TOP_LEFT,
|
|
278
|
+
-legend_rotation,
|
|
279
|
+
CategoryLabelWidthType.RANGE,
|
|
280
|
+
0.40)
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
# clp = CategoryLabelPositions.createUpRotationLabelPositions(legend_rotation)
|
|
285
|
+
|
|
286
|
+
axis_obj.setCategoryLabelPositions(clp)
|
|
287
|
+
axis_obj.getCategoryLabelPositions
|
|
288
|
+
#axis_obj.setCategoryLabelPositionOffset(10)
|
|
289
|
+
|
|
290
|
+
axis_obj
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
def jf_yaxis
|
|
294
|
+
name = [name, yaxis].compact.join(" ")
|
|
295
|
+
case type
|
|
296
|
+
when :gantt
|
|
297
|
+
DateAxis.new(name)
|
|
298
|
+
else
|
|
299
|
+
axis_obj = NumberAxis.new(name)
|
|
300
|
+
axis_obj.setAutoRangeIncludesZero(false)
|
|
301
|
+
axis_obj.setAutoRangeStickyZero(false)
|
|
302
|
+
axis_obj.setAutoRange(true)
|
|
303
|
+
axis_obj
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
def jf_zaxis(name = nil)
|
|
307
|
+
name = [name, zaxis].compact.join(" ")
|
|
308
|
+
CategoryAxis.new(name)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def jf_yvalue(value)
|
|
312
|
+
case type
|
|
313
|
+
when :gantt
|
|
314
|
+
case value
|
|
315
|
+
when DateTime,Date,Time
|
|
316
|
+
Time.parse(value.strftime("%F %T")).to_f * 1000.0
|
|
317
|
+
else
|
|
318
|
+
Time.parse(value.to_s).to_f * 1000.0
|
|
319
|
+
end
|
|
320
|
+
else
|
|
321
|
+
value.to_f
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# combined plot
|
|
326
|
+
def create_combined_plot_implementation(data, combination_axis = :domain)
|
|
327
|
+
cap_name = combination_axis.to_s.capitalize
|
|
328
|
+
other_name = if combination_axis == :domain then "Range" else "Domain" end
|
|
329
|
+
combined_axis_name = {:range => "yaxis", :domain => "xaxis"}[combination_axis]
|
|
330
|
+
|
|
331
|
+
axis_obj = eval("jf_#{combined_axis_name}")
|
|
332
|
+
|
|
333
|
+
case type
|
|
334
|
+
when :line,:xy
|
|
335
|
+
plot_class = eval("Combined#{cap_name}XYPlot")
|
|
336
|
+
else
|
|
337
|
+
plot_class = eval("Combined#{cap_name}CategoryPlot")
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
plot = plot_class.new(axis_obj)
|
|
341
|
+
|
|
342
|
+
num = 0
|
|
343
|
+
data.each {|range_name, data|
|
|
344
|
+
range_options = @range_options[range_name] or {}
|
|
345
|
+
subplot = create_plot(range_name,data)
|
|
346
|
+
#subplot.setRangeAxis(nil) if num > 0
|
|
347
|
+
|
|
348
|
+
begin
|
|
349
|
+
plot.add(subplot, data.values.map {|h| h.keys}.flatten.length)
|
|
350
|
+
rescue
|
|
351
|
+
$log.warn("Failed to determine weight #{$!}")
|
|
352
|
+
plot.add(subplot)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
eval("subplot.get#{other_name}Axis").setLabel(range_name)
|
|
356
|
+
|
|
357
|
+
subplot.setOrientation(jf_orientation(true)) rescue $log.warn("Orientation not set #{$!}")
|
|
358
|
+
}
|
|
359
|
+
plot.setOrientation(jf_orientation) rescue $log.warn("Orientation not set #{$!}")
|
|
360
|
+
|
|
361
|
+
lis = plot.getLegendItems
|
|
362
|
+
new_legend_collection = LegendItemCollection.new
|
|
363
|
+
legend_labels = []
|
|
364
|
+
lis.getItemCount.times {|i|
|
|
365
|
+
li = lis.get(i)
|
|
366
|
+
unless legend_labels.include?(li.getLabel)
|
|
367
|
+
new_legend_collection.add(li)
|
|
368
|
+
legend_labels << li.getLabel
|
|
369
|
+
end
|
|
370
|
+
}
|
|
371
|
+
plot.setFixedLegendItems(new_legend_collection)
|
|
372
|
+
plot
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def create_plot_implementation(range_name, data, options = {})
|
|
376
|
+
range_options = @range_options[range_name] or {}
|
|
377
|
+
range_options = @range_options.values[0] if range_name.nil?
|
|
378
|
+
|
|
379
|
+
case @type
|
|
380
|
+
when :bar
|
|
381
|
+
if stacked
|
|
382
|
+
my_renderer = StackedBarRenderer.new
|
|
383
|
+
else
|
|
384
|
+
my_renderer = BarRenderer.new
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
#ItemLabelPosition position1 = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BOTTOM_CENTER);
|
|
388
|
+
#ItemLabelPosition position2 = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE6, TextAnchor.TOP_CENTER);
|
|
389
|
+
#renderer.setPositiveItemLabelPosition(position1);
|
|
390
|
+
#renderer.setNegativeItemLabelPosition(position2);
|
|
391
|
+
#renderer.setDrawBarOutline(false);
|
|
392
|
+
configure_renderer(my_renderer)
|
|
393
|
+
|
|
394
|
+
#MyGenerator generator = new MyGenerator(this.URLPrefix, this.rangeNames[range], this);
|
|
395
|
+
#my_renderer.setBaseItemURLGenerator(generator);
|
|
396
|
+
#my_renderer.setBaseToolTipGenerator(generator);
|
|
397
|
+
|
|
398
|
+
plot = CategoryPlot.new(create_category_dataset(data),
|
|
399
|
+
jf_xaxis,
|
|
400
|
+
jf_yaxis,
|
|
401
|
+
my_renderer)
|
|
402
|
+
when :line
|
|
403
|
+
if @stacked
|
|
404
|
+
my_renderer = StackedXYAreaRenderer2.new;
|
|
405
|
+
else
|
|
406
|
+
raise "not impl"
|
|
407
|
+
my_renderer = StandardXYItemRenderer.new(StandardXYItemRenderer.SHAPES_AND_LINES);
|
|
408
|
+
end
|
|
409
|
+
configure_renderer(my_renderer)
|
|
410
|
+
#MyGenerator generator = new MyGenerator(@URLPrefix, @rangeNames[range], this);
|
|
411
|
+
# my_renderer.setURLGenerator(generator);
|
|
412
|
+
# my_renderer.setBaseToolTipGenerator(generator);
|
|
413
|
+
#
|
|
414
|
+
#
|
|
415
|
+
|
|
416
|
+
plot = XYPlot.new(create_xy_dataset(data),
|
|
417
|
+
jf_xaxis,
|
|
418
|
+
jf_yaxis,
|
|
419
|
+
my_renderer)
|
|
420
|
+
when :gantt
|
|
421
|
+
my_renderer = GanttRenderer.new
|
|
422
|
+
|
|
423
|
+
my_renderer.setBaseItemURLGenerator(StandardCategoryURLGenerator.new) if
|
|
424
|
+
enable_urls
|
|
425
|
+
|
|
426
|
+
configure_renderer(my_renderer)
|
|
427
|
+
|
|
428
|
+
plot = CategoryPlot.new(create_task_series_collection(data),
|
|
429
|
+
jf_xaxis, jf_yaxis, my_renderer)
|
|
430
|
+
when :pie
|
|
431
|
+
plot = MultiplePiePlot.new(create_category_dataset(data));
|
|
432
|
+
plot.setDataExtractOrder(TableOrder.BY_ROW);
|
|
433
|
+
plot.setOutlineStroke(nil);
|
|
434
|
+
|
|
435
|
+
# if (enable_tooltips)
|
|
436
|
+
# tooltipGenerator = StandardPieToolTipGenerator.new();
|
|
437
|
+
# pp = plot.getPieChart().getPlot();
|
|
438
|
+
# pp.setToolTipGenerator(tooltipGenerator);
|
|
439
|
+
# end
|
|
440
|
+
|
|
441
|
+
if (enable_urls)
|
|
442
|
+
urlGenerator = new StandardPieURLGenerator();
|
|
443
|
+
pp = plot.getPieChart().getPlot();
|
|
444
|
+
pp.setURLGenerator(urlGenerator);
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
# plot = @chart.getPlot();
|
|
448
|
+
# subchart = plot.getPieChart();
|
|
449
|
+
|
|
450
|
+
# p = subchart.getPlot();
|
|
451
|
+
# /* p.setLabelGenerator(new StandardPieItemLabelGenerator("{0}"));*/
|
|
452
|
+
# p.setLabelFont(Font.new("SansSerif", Font.PLAIN, 8));
|
|
453
|
+
# p.setInteriorGap(0.30);
|
|
454
|
+
#generator = MyGenerator.new(this.URLPrefix,this.category_datasets[0]);
|
|
455
|
+
#p.setURLGenerator(generator);
|
|
456
|
+
# // p.setToolTipGenerator(generator);
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
else
|
|
460
|
+
raise "Unexpected chart type #{@type}"
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
if enable_tooltips and my_renderer and my_renderer.getClass.toString =~ /category/
|
|
464
|
+
generator = JfreechartGenerator.new(self, range_name)
|
|
465
|
+
generator = Rjb::bind(generator, "org.jfree.chart.labels.CategoryToolTipGenerator")
|
|
466
|
+
my_renderer.setBaseToolTipGenerator(generator) rescue "Unable to set tooltip generator: #{$!}"
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
plot.setOrientation(jf_orientation) rescue $log.warn("Orientation not set #{$!}")
|
|
470
|
+
|
|
471
|
+
@options ||= {}
|
|
472
|
+
range_options ||= {}
|
|
473
|
+
((@options[:markers] or []) + (range_options[:markers] or [])).each {|marker|
|
|
474
|
+
new_maker = nil
|
|
475
|
+
|
|
476
|
+
case marker[:type]
|
|
477
|
+
when :value
|
|
478
|
+
# value marker
|
|
479
|
+
marker[:layer] ||= :front
|
|
480
|
+
new_marker = ValueMarker.new(jf_yvalue(marker[:value]))
|
|
481
|
+
new_marker.setLabelTextAnchor(TextAnchor.TOP_LEFT)
|
|
482
|
+
new_marker.setLabel(marker[:name])
|
|
483
|
+
when :interval
|
|
484
|
+
# range marker
|
|
485
|
+
marker[:layer] ||= :back
|
|
486
|
+
new_marker = IntervalMarker.new(jf_yvalue(marker[:start]),jf_yvalue(marker[:end]));
|
|
487
|
+
new_marker.setLabelTextAnchor(TextAnchor.CENTER_LEFT)
|
|
488
|
+
new_marker.setLabelAnchor(RectangleAnchor.LEFT)
|
|
489
|
+
new_marker.setLabel(marker[:name])
|
|
490
|
+
when :category
|
|
491
|
+
marker[:layer] ||= :back
|
|
492
|
+
new_marker = CategoryMarker.new_with_sig("Ljava.lang.Comparable;",marker[:key])
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
new_marker.setLabelFont(Font.new("SansSerif", Font.BOLD, 11))
|
|
496
|
+
new_marker.setPaint(Color.create("java",(marker[:color] or "red")).java_object)
|
|
497
|
+
new_marker.setAlpha(1.0)
|
|
498
|
+
|
|
499
|
+
case marker[:layer].to_s
|
|
500
|
+
when "foreground", "front",""
|
|
501
|
+
layer = Layer.FOREGROUND
|
|
502
|
+
when "back","background"
|
|
503
|
+
layer = Layer.BACKGROUND
|
|
504
|
+
else
|
|
505
|
+
raise "Unexpected layer value #{marker[:layer].inspect}"
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
case marker[:axis]
|
|
509
|
+
when :range
|
|
510
|
+
plot.addRangeMarker(new_marker,layer)
|
|
511
|
+
when :domain
|
|
512
|
+
plot.addDomainMarker(new_marker,layer)
|
|
513
|
+
else
|
|
514
|
+
raise "Unexpected marker axis"
|
|
515
|
+
end
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
if range_color = range_options[:color]
|
|
520
|
+
plot.setBackgroundPaint(Color.create("java",range_color).java_object)
|
|
521
|
+
else
|
|
522
|
+
plot.setBackgroundPaint(Color.create("java","LightGray").java_object)
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
plot.setDomainGridlinePaint(Color.create("java","white").java_object) rescue $log.warn("setDomainGridlinePaint failed: #{$!}")
|
|
526
|
+
plot.setRangeGridlinePaint(Color.create("java","white").java_object) rescue $log.warn("setRangeGridlinePaint failed: #{$!}")
|
|
527
|
+
#plot.clearDomainAxes();
|
|
528
|
+
|
|
529
|
+
plot
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
def create_chart_implementation(plot)
|
|
533
|
+
@chart = JFreeChart.new(@title, nil, plot, display_legend)
|
|
534
|
+
@chart.setBackgroundPaint(Color.create("java","white").java_object)
|
|
535
|
+
|
|
536
|
+
@chart
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
def to_date(obj)
|
|
540
|
+
c = Calendar.getInstance
|
|
541
|
+
case obj
|
|
542
|
+
when String
|
|
543
|
+
obj = DateTime.parse(obj) rescue raise("#{$!}: #{obj}")
|
|
544
|
+
when Date,DateTime
|
|
545
|
+
else
|
|
546
|
+
raise "Unexpected data class #{obj.class}"
|
|
547
|
+
end
|
|
548
|
+
# !month is 0 based in java!
|
|
549
|
+
c.set(obj.year, obj.month - 1, obj.day, obj.hour, obj.min, obj.sec)
|
|
550
|
+
c.getTime()
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
# Data Sets
|
|
555
|
+
def create_xy_dataset(data)
|
|
556
|
+
# STRING x VAL x VAL
|
|
557
|
+
# means STRING x STRING x VAL
|
|
558
|
+
# means SERIE x CATEGORY x ARRAY[0]
|
|
559
|
+
|
|
560
|
+
# add(Number x, Number y, String seriesName, boolean notify)
|
|
561
|
+
xy_dataset = CategoryTableXYDataset.new
|
|
562
|
+
data.each {|serie_name, category|
|
|
563
|
+
category.each {|category_name, val|
|
|
564
|
+
xy_dataset.add(category_name.to_f, val.to_f, serie_name)
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
xy_dataset
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
def create_category_dataset(data)
|
|
571
|
+
# STRING x STRING x VAL
|
|
572
|
+
# means SERIE x CATEGORY x ARRAY[0]
|
|
573
|
+
category_dataset = DefaultCategoryDataset.new
|
|
574
|
+
data.each {|serie_name, category|
|
|
575
|
+
category.each {|category_name, val|
|
|
576
|
+
# addValue(Number value, Comparable rowKey, Comparable columnKey)
|
|
577
|
+
category_dataset._invoke("addValue",
|
|
578
|
+
"Ljava.lang.Number;Ljava.lang.Comparable;Ljava.lang.Comparable;",
|
|
579
|
+
val.to_i,category_name,serie_name)
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
category_dataset
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
# Task Series
|
|
586
|
+
def create_task_series_collection(data)
|
|
587
|
+
# STRING x TASK
|
|
588
|
+
m_series = TaskSeriesCollection.new
|
|
589
|
+
data.each {|serie_name, values|
|
|
590
|
+
m_serie = TaskSeries.new((serie_name or ""))
|
|
591
|
+
|
|
592
|
+
values.each {|key, value|
|
|
593
|
+
task = create_task(key,value)
|
|
594
|
+
m_serie.add(task)
|
|
595
|
+
if value.class == Hash and value[:children]
|
|
596
|
+
value[:children].each {|key, value|
|
|
597
|
+
task.addSubtask(create_task(key,value))
|
|
598
|
+
}
|
|
599
|
+
end
|
|
600
|
+
}
|
|
601
|
+
m_series.add(m_serie)
|
|
602
|
+
}
|
|
603
|
+
m_series
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
# data: [start,end,percentage] or {:start => start, :end => end, :percentage}
|
|
607
|
+
def create_task(name, data)
|
|
608
|
+
data = [data[:start],data[:end], data[:percentage]] if data.class == Hash
|
|
609
|
+
|
|
610
|
+
$log.debug("Create Task #{name.inspect}: #{data[0].inspect} - #{data[1].inspect} (#{data[2].inspect})")
|
|
611
|
+
period = SimpleTimePeriod.new(to_date(data[0]),to_date(data[1]))
|
|
612
|
+
task = Task.new(name.to_s,period)
|
|
613
|
+
task.setPercentComplete(data[2].to_f) if data[2]
|
|
614
|
+
task
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
=begin
|
|
618
|
+
public GanttDemo1(final String title) {
|
|
619
|
+
|
|
620
|
+
super(title);
|
|
621
|
+
|
|
622
|
+
final IntervalCategoryDataset dataset = createDataset();
|
|
623
|
+
final JFreeChart chart = createChart(dataset);
|
|
624
|
+
|
|
625
|
+
# add the chart to a panel...
|
|
626
|
+
final ChartPanel chartPanel = new ChartPanel(chart);
|
|
627
|
+
chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
|
|
628
|
+
setContentPane(chartPanel);
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
final TaskSeriesCollection collection = new TaskSeriesCollection();
|
|
633
|
+
collection.add(s1);
|
|
634
|
+
collection.add(s2);
|
|
635
|
+
|
|
636
|
+
return collection;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Utility method for creating <code>Date</code> objects.
|
|
641
|
+
*
|
|
642
|
+
* @param day the date.
|
|
643
|
+
* @param month the month.
|
|
644
|
+
* @param year the year.
|
|
645
|
+
*
|
|
646
|
+
* @return a date.
|
|
647
|
+
*/
|
|
648
|
+
private static Date date(final int day, final int month, final int year) {
|
|
649
|
+
|
|
650
|
+
final Calendar calendar = Calendar.getInstance();
|
|
651
|
+
calendar.set(year, month, day);
|
|
652
|
+
final Date result = calendar.getTime();
|
|
653
|
+
return result;
|
|
654
|
+
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Creates a chart.
|
|
659
|
+
*
|
|
660
|
+
* @param dataset the dataset.
|
|
661
|
+
*
|
|
662
|
+
* @return The chart.
|
|
663
|
+
*/
|
|
664
|
+
private JFreeChart createChart(final IntervalCategoryDataset dataset) {
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Starting point for the demonstration application.
|
|
669
|
+
*
|
|
670
|
+
* @param args ignored.
|
|
671
|
+
*/
|
|
672
|
+
public static void main(final String[] args) {
|
|
673
|
+
|
|
674
|
+
final GanttDemo1 demo = new GanttDemo1("Gantt Chart Demo 1");
|
|
675
|
+
demo.pack();
|
|
676
|
+
RefineryUtilities.centerFrameOnScreen(demo);
|
|
677
|
+
demo.setVisible(true);
|
|
678
|
+
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
end
|
|
682
|
+
=end
|