Author: eallen
Date: 2009-07-13 13:32:39 -0400 (Mon, 13 Jul 2009)
New Revision: 3488
Modified:
mgmt/trunk/cumin/python/cumin/stat.py
mgmt/trunk/cumin/resources/open-flash-chart.swf
Log:
Add a "control" chart to bottom of flash charts when in fullpage mode.
Modified: mgmt/trunk/cumin/python/cumin/stat.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/stat.py 2009-07-13 17:31:38 UTC (rev 3487)
+++ mgmt/trunk/cumin/python/cumin/stat.py 2009-07-13 17:32:39 UTC (rev 3488)
@@ -119,6 +119,7 @@
params.append("class=%s" % cls)
params.append("id=%i" % object.id)
+ params.append("chart_id=%s" % self.render_id(session, None))
for stat in self.stats:
params.append("stat=%s" % stat)
@@ -642,8 +643,50 @@
params = self.get_href_params(session, object)
params.append("width=%i" % self.render_width(session, object))
params.append("height=%i" % self.render_height(session, object))
+ params.append("high=1")
return escape_entity("%s?" % self.get_flash_name(session) +
";".join(params))
+class XAxis(object):
+ def get_x_labels(self, duration, intervals, step, end_secs):
+ x_step = float(duration) / float(intervals)
+ labels = list()
+ for i in range(0, intervals + 1):
+ label = dict()
+ if i % step == 0:
+ value = int(round(duration - i * x_step + end_secs))
+ text = fmt_duration_brief(value)
+
+ label["text"] = text
+ else:
+ label["text"] = ""
+ label["x"] = i * x_step
+
+ labels.append(label)
+ return labels
+
+ def get_x_axis(self, duration, end_secs, tick_height=0):
+ x_intervals = 8
+ x_steps = 2
+ if duration == 600:
+ x_intervals = 10
+
+ x_axis = Element()
+ x_axis.colour = "#CCCCCC"
+ x_axis.grid_colour = "#DDDDDD"
+ x_axis.stroke = 1
+ x_axis.tick_height = tick_height
+
+ xlbls = Element()
+ xlbls.size = 12
+ xlbls.colour = "#999999"
+ xlbls.align = "auto"
+ xlbls.rotate = 0.0001
+
+ lbls = self.get_x_labels(duration, x_intervals, x_steps, end_secs)
+ xlbls.labels = lbls
+ x_axis.labels = xlbls
+ return x_axis
+
class FlashChart(Widget):
colors = ('#FF0000', '#0000FF', '#00FF00', '#FF00FF',
'#FFFF00', '#00FFFF', '#000000')
one_day = 24 * 60 * 60
@@ -651,19 +694,89 @@
super(FlashChart, self).__init__(app, name)
self.page = page
+ def pos_to_seconds(self, pos):
+ """ convert the flash chart slider position into a number of
seconds ago """
+
+ return int(round((1.0 - float(pos)) * self.one_day))
+
+ def get_end_seconds(self, session):
+ """ how many seconds ago the chart time span ends
"""
+
+ cmax = self.page.control_max.get(session)
+ if cmax:
+ end_seconds_ago = self.pos_to_seconds(cmax)
+ else:
+ end_seconds_ago = 0
+ return end_seconds_ago
+
+ def get_time_span(self, session):
+ """ the number of seconds between the chart begin and end
"""
+
+ cmax = self.page.control_max.get(session)
+ if cmax:
+ cmin = self.page.control_min.get(session)
+ start_seconds_ago = self.pos_to_seconds(cmin)
+ end_seconds_ago = self.pos_to_seconds(cmax)
+ return start_seconds_ago - end_seconds_ago
+ else:
+ return self.page.duration.get(session)
+
+ def get_elapsed(self, session):
+ """ load the javascript milliseconds since last update into a dict
"""
+
+ elapsed = {'seconds': 0, 'milliseconds': 0.0, 'value':
0.0}
+ e = self.page.elapsed.get(session)
+ if e:
+ js_milliseconds = long(e)
+ seconds = int(js_milliseconds / 1000)
+ milliseconds = (js_milliseconds % 1000.0) / 1000.0
+ elapsed['seconds'] = seconds
+ elapsed['milliseconds'] = milliseconds
+ elapsed['value'] = seconds + milliseconds
+ return elapsed
+
+ def get_duration(self, session):
+ """ the number of seconds we want to get a sample for
"""
+
+ duration = self.page.duration.get(session)
+ e = self.page.elapsed.get(session)
+ if e:
+ elapsed = self.get_elapsed(session)
+ if elapsed['seconds'] <= self.one_day:
+ duration = elapsed['seconds'] + 1
+ else:
+ duration = self.get_time_span(session)
+ return duration
+
+ def get_delta(self, session):
+ """ if we get an elapsed parameter, we want
+ to send only the new values, that is
+ unless the elapsed value is too large
+ in which case we want to get the entire sample """
+
+ e = self.page.elapsed.get(session)
+ if e:
+ elapsed = self.get_elapsed(session)
+ if elapsed['seconds'] <= self.one_day:
+ return True
+ return False
+
def create(self, session, object, stats):
# get the page parameters
width = self.page.container_width.get(session)
height = self.page.container_height.get(session)
mode = self.page.mode.get(session)
+ method = self.page.method.get(session)
+
+ time_span = self.get_time_span(session)
duration = self.get_duration(session)
- time_period = self.page.duration.get(session)
+ end_seconds_ago = self.get_end_seconds(session)
delta = self.get_delta(session)
+
interval = self.page.get_interval(session, duration, width)
- method = self.page.method.get(session)
# get the most recent samples
- samples = self.fetch_samples(object, duration, interval, method, mode, delta,
stats)
+ samples = self.fetch_samples(object, duration, interval, method, mode, delta,
stats, end_seconds_ago=end_seconds_ago)
max_value, min_value = self.get_max_min(session, stats, samples)
append = False
@@ -675,66 +788,19 @@
max_of_axiis = max(max_value, axis_for_vals)
# the most recent value(s) changed the y-axis range
if axis_max != max_of_axiis:
- #print "change in axis: axis_max=%s vals_max=%s max_new_values=%s
vals_axis=%s desired_axis=%s" % (str(axis_max), str(vals_max), str(max_value),
str(axis_for_vals), str(max_of_axiis))
- duration = time_period
- samples = self.fetch_samples(object, duration, interval, method, mode,
False, stats)
+ samples = self.fetch_samples(object, time_span, interval, method, mode,
False, stats, end_seconds_ago=end_seconds_ago)
max_value, min_value = self.get_max_min(session, stats, samples)
else:
append = True
# create the chart dict
- chart = self.get_chart(session, stats, samples, duration, max_value, min_value,
append)
+ chart = self.get_chart(session, object, stats, samples, time_span, max_value,
min_value, append, end_seconds_ago)
+ print "**********\n"+chart.create()
return chart.create()
- def get_chart(self, session, stats, samples, duration, max_value, min_value,
append):
+ def get_chart(self, session, object, stats, samples, duration, max_value, min_value,
append, end_secs):
return Chart()
- def get_duration(self, session):
- duration = self.page.duration.get(session)
- elapsed = self.get_elapsed(session)
- if elapsed['seconds'] <= self.one_day:
- duration = elapsed['seconds'] + 1
- return duration
-
- def get_elapsed(self, session):
- elapsed = {'seconds': 0, 'milliseconds': 0.0, 'value':
0.0}
- e = self.page.elapsed.get(session)
- if e:
- js_milliseconds = long(e)
- seconds = int(js_milliseconds / 1000)
- milliseconds = (js_milliseconds % 1000.0) / 1000.0
- elapsed['seconds'] = seconds
- elapsed['milliseconds'] = milliseconds
- elapsed['value'] = seconds + milliseconds
- return elapsed
-
- def get_delta(self, session):
- """ if we get an elapsed parameter, we want
- to send only the new values, that is
- unless the elapsed value is too large
- in which case we want to get the entire sample """
- elapsed = self.get_elapsed(session)
- if elapsed['seconds'] <= self.one_day:
- return True
- return False
-
- def get_x_labels(self, duration, intervals, step):
- x_step = duration / intervals
- labels = list()
- for i in range(0, intervals + 1):
- label = dict()
- if i % step == 0:
- value = duration - i * x_step
- text = fmt_duration_brief(value)
-
- label["text"] = text
- else:
- label["text"] = ""
- label["x"] = i * x_step
-
- labels.append(label)
- return labels
-
def get_y_labels(self, absy, intervals, step):
y_step = absy / intervals
labels = list()
@@ -759,29 +825,6 @@
labels.append(label)
return labels
- def get_x_axis(self, duration):
- x_intervals = 8
- x_steps = 2
- if duration == 600:
- x_intervals = 10
- steps = int(duration / x_intervals)
-
- x_axis = Element()
- x_axis.colour = "#CCCCCC"
- x_axis.grid_colour = "#DDDDDD"
- x_axis.stroke = 1
- x_axis.steps = steps
- xlbls = Element()
- #xlbls.steps = steps
- xlbls.size = 12
- xlbls.colour = "#999999"
- xlbls.align = "auto"
- xlbls.rotate = 0.0001
- lbls = self.get_x_labels(duration, x_intervals, x_steps)
- xlbls.labels = lbls
- x_axis.labels = xlbls
- return x_axis
-
def get_y_axis(self, max_value, min_value):
y_intervals = 6
absy = max_value - min_value
@@ -790,12 +833,12 @@
if int(max_value) < 3:
y_steps = 3
- # .swf won't show grid lines with a y_axis on the left
+ # .swf won't show grid lines without a y_axis on the left
y_axis = {
"min": int(min_value),
"max": int(max_value),
"steps": y_steps,
- "stroke": 0,
+ "stroke": 1,
"tick-length": 0,
"colour": "#CCCCCC",
"grid-colour": "#DDDDDD",
@@ -816,14 +859,12 @@
self.alpha = 0.3
- def fetch_samples(self, object, dur, interval, method, mode, delta, stats):
+ def fetch_samples(self, object, dur, interval, method, mode, delta, stats,
end_seconds_ago=0):
samples = dict()
if mode == "rate":
method = None # don't do averaging
- if delta: # need more than 1 point for calculating rate
- dur *= 4;
for stat in stats:
- os = stat.samples(object, dur, interval, method)
+ os = stat.samples(object, dur, interval, method, secs2=end_seconds_ago)
ns = list()
prev = None
@@ -839,7 +880,7 @@
samples[stat] = ns
else:
for stat in stats:
- samples[stat] = stat.samples(object, dur, interval, method)
+ samples[stat] = stat.samples(object, dur, interval, method,
secs2=end_seconds_ago)
return samples
@@ -861,10 +902,9 @@
return max_value, min_value
- def get_vals(self, session, samples, stat, text):
+ def get_vals(self, session, samples, stat, text, duration, end_secs):
tnow = time()
- time_period = self.page.duration.get(session)
- vals = [{"x":int(time_period -(tnow - secs(dt))),
+ vals = [{"x":int(duration -(tnow - secs(dt)) + end_secs),
"y":value,
"uid": dt.strftime("%m%d%Y%H%M%S"),
"tip": "<br>%s: #val#<br>Time: %s" % (text,
dt.strftime("%m/%d/%Y %H:%M:%S"))}
@@ -872,24 +912,11 @@
if value is not None]
return vals
- def get_chart(self, session, stats, samples, duration, max_value, min_value,
append):
- mode = self.page.mode.get(session)
-
- width = self.page.container_width.get(session)
- dot_size = 1
- halo_size = 0
- line_width = 1
- if width > 400:
- dot_size = 3
- halo_size = 1
- line_width = 2
-
- chart = Chart()
- chart.bg_colour = "#FFFFFF"
+ def make_chart_lines(self, session, chart, line_type, stats, dot_size, halo_size,
line_width, samples, duration, end_secs, mode):
chart.elements = list()
for stat, color in reversed(zip(stats, self.colors)):
line = Element()
- line.type = "area"
+ line.type = line_type
line.fill = color
line.fill_alpha = self.alpha
line.on_show.type = "No"
@@ -901,9 +928,27 @@
line.width = line_width
line.text = mode == "rate" and "%s / sec" % stat.title or
stat.title
- line.values = self.get_vals(session, samples, stat, line.text)
+ vals = self.get_vals(session, samples, stat, line.text, duration, end_secs)
+ line.values = vals
chart.elements.append(line)
+ def get_chart(self, session, object, stats, samples, duration, max_value, min_value,
append, end_secs):
+ mode = self.page.mode.get(session)
+
+ width = self.page.container_width.get(session)
+ dot_size = 1
+ halo_size = 0
+ line_width = 1
+ if width > 400:
+ dot_size = 3
+ halo_size = 1
+ line_width = 2
+
+ chart = Chart()
+ chart.id = self.page.chart_id.get(session);
+ chart.bg_colour = "#FFFFFF"
+ self.make_chart_lines(session, chart, "area", stats, dot_size,
halo_size, line_width, samples, duration, end_secs, mode)
+
if append:
chart.append = self.get_elapsed(session)['value']
#print "append: duration=%i elapsed=%f" % (duration,
float(self.get_elapsed(session)['value']))
@@ -918,11 +963,26 @@
"body": "{font-size: 10px; color:
#000000;}"
}
- chart.x_axis = self.get_x_axis(duration)
+ chart.x_axis = XAxis().get_x_axis(duration, end_secs)
y_axis, y_axis_right = self.get_y_axis(max_value, min_value)
chart.y_axis = y_axis
chart.y_axis_right = y_axis_right
+ # if we are big enough, add a control slider to pan and zoom
+ if width > 400:
+ chart.control.bg_colour = "#DDDDDD"
+ chart.control.x_axis = XAxis().get_x_axis(self.one_day, 0, tick_height=10)
+ chart.control.x_axis.labels.colour = "#333333"
+ samples = self.fetch_samples(object, self.one_day, 60, "avg", mode,
False, stats, end_seconds_ago=0)
+ max_value, min_value = self.get_max_min(session, stats, samples)
+ self.make_chart_lines(session, chart.control, "line", stats, 1, 0,
1, samples, self.one_day, 0, mode)
+ chart.control.y_min = max(min_value, 0)
+ chart.control.y_max = max(max_value-2, 1)
+ chart.control.slider_low.value = float(self.page.control_min.get(session))
+ chart.control.slider_low.colour = "#666666"
+ chart.control.slider_high.value = float(self.page.control_max.get(session))
+ chart.control.slider_high.colour = "#666666"
+
#print "sending entire sample set with y_axis.max=%i" %
chart.y_axis["max"]
return chart
@@ -967,14 +1027,13 @@
return max_value, min_value
- def get_vals(self, session, samples, stat, text):
+ def get_vals(self, session, samples, stat, text, duration, end_secs):
tnow = time()
- time_period = self.page.duration.get(session)
points = self.points.get(session)
vals = list()
if points:
- vals = [{"x":int(time_period -(tnow - secs(dt))),
+ vals = [{"x":int(duration -(tnow - secs(dt)) + end_secs),
"y":stacked_value,
"uid": dt.strftime("%m%d%Y%H%M%S"),
"tip": "<br>%s: %s<br>Time: %s" % (text,
str(value), dt.strftime("%m/%d/%Y %H:%M:%S"))}
@@ -1010,6 +1069,18 @@
self.chart_type.default = "area"
self.add_parameter(self.chart_type)
+ self.chart_id = Parameter(app, "chart_id")
+ self.add_parameter(self.chart_id)
+
+ self.control_min = Parameter(app, "low")
+ ten_min_of_day = 10.0 / (24.0 * 60.0)
+ self.control_min.default = str(1.0 - ten_min_of_day)
+ self.add_parameter(self.control_min)
+
+ self.control_max = Parameter(app, "high")
+ self.control_max.default = None
+ self.add_parameter(self.control_max)
+
def get_content_type(self, session):
return "text/plain"
Modified: mgmt/trunk/cumin/resources/open-flash-chart.swf
===================================================================
(Binary files differ)