Author: eallen
Date: 2009-06-04 16:35:18 -0400 (Thu, 04 Jun 2009)
New Revision: 3421
Modified:
mgmt/trunk/cumin/python/cumin/stat.py
mgmt/trunk/cumin/python/cumin/stat.strings
mgmt/trunk/cumin/resources/app.css
mgmt/trunk/cumin/resources/app.js
Log:
Added mouseover on charts to highlight data points.
Modified: mgmt/trunk/cumin/python/cumin/stat.py
===================================================================
--- mgmt/trunk/cumin/python/cumin/stat.py 2009-06-04 20:32:05 UTC (rev 3420)
+++ mgmt/trunk/cumin/python/cumin/stat.py 2009-06-04 20:35:18 UTC (rev 3421)
@@ -200,14 +200,27 @@
return (None, None)
+ def get_current(self, name):
+ if name in self.__files:
+ file = self.__files[name]["file"]
+ file.seek(0)
+ print "found current %s" % name
+ return (file.read(), self.__files[name]["cookie"])
+ else:
+ print "MISSED %s" % name
+ return (None, None)
+
+
def create_cache_file(self, name, args):
if name not in self.__files:
#file = tempfile.TemporaryFile()
file = cStringIO.StringIO()
+ print "added %s" % name
else:
file = self.__files[name]["file"]
file.seek(0)
file.truncate()
+ print "re-used %s" % name
self.__files[name] = {"time": datetime.now(), "file": file,
"cookie": args}
return file
@@ -356,6 +369,9 @@
self.method.default = "avg"
self.add_parameter(self.method)
+ self.samples = BooleanParameter(app, "samples")
+ self.add_parameter(self.samples)
+
self.container_width = IntegerParameter(app, "width")
self.container_width.default = 360
self.add_parameter(self.container_width)
@@ -367,7 +383,7 @@
self.cache = ImageCache()
def get_content_type(self, session):
- return "image/png"
+ return self.samples.get(session) and "text/plain" or
"image/png"
def get_cache_control(self, session):
return "no-cache"
@@ -382,13 +398,23 @@
def get_cached(self, session, recent):
filename = self.gen_filename(session)
- chart, last_recent = self.cache.find_recent(filename, 3)
- if recent == last_recent:
- return chart
+ chart, args = self.cache.find_recent(filename, 30)
+ if args:
+ last_recent, samples, xy = args
+ if recent == last_recent:
+ return chart
- def cache_it(self, session, chart, recent):
+ def get_cached_samples(self, session, recent):
+ branch = session.branch()
+ self.samples.set(branch, False)
+ filename = self.gen_filename(branch)
+ chart, args = self.cache.get_current(filename)
+ if args:
+ return (args['samples'], args['title_xy'])
+
+ def cache_it(self, session, chart, args):
filename = self.gen_filename(session)
- writer = self.cache.create_cache_file(filename, recent)
+ writer = self.cache.create_cache_file(filename, args)
chart.write(writer)
def get_interval(self, session, duration, width):
@@ -399,18 +425,38 @@
max_samples = int(width * 1.5)
return max(int(duration / max_samples), 1)
+ def render_samples(self, session, recent, colors):
+ c = {(1,0,0): "red", (0,0,1): "blue", (0,1,0):
"green"}
+ cached_samples, title_xy = self.get_cached_samples(session, recent)
+ if cached_samples:
+ rets = dict()
+ for stat, color, xy in zip(cached_samples, colors, title_xy):
+ ret = dict()
+ ret["color"] = c[color]
+ ret["points"] = cached_samples[stat]
+ ret["xy"] = xy
+ rets[stat.name] = ret
+ return str(rets)
+
def do_render(self, session, object):
+ colors = ((1,0,0), (0,0,1), (0,1,0))
+
cls = self.class_.get(session)
stats = [getattr(cls, x) for x in self.stats.get(session)]
+ recent = None
if len(stats):
stat = stats[0]
recent = stat.recent(object)
- if recent:
- cached_png = self.get_cached(session, recent)
- if cached_png:
- return cached_png
+ if self.samples.get(session):
+ return self.render_samples(session, recent, colors)
+
+ if recent:
+ cached_png = self.get_cached(session, recent)
+ if cached_png:
+ return cached_png
+
width = self.container_width.get(session)
height = self.container_height.get(session)
chart = TimeSeriesChart(width, height)
@@ -476,10 +522,9 @@
chart.plot_x_axis(x_intervals, x_step)
chart.plot_y_axis(y_intervals, y_step)
- colors = ((1,0,0), (0,0,1), (0,1,0), (0,0,0))
-
+ points = dict()
for stat, color in zip(stats, colors):
- chart.plot_values(samples[stat], color=color)
+ points[stat] = chart.plot_values(samples[stat], color=color)
for stat, color in zip(stats, colors):
chart.plot_ticks(samples[stat], color=color)
@@ -491,9 +536,9 @@
else:
titles = [x.title for x in stats]
- chart.plot_legend(titles, colors)
+ title_xy = chart.plot_legend(titles, colors)
- self.cache_it(session, chart, recent)
+ self.cache_it(session, chart, {'recent': recent, 'samples':
points, "title_xy": title_xy})
writer = Writer()
chart.write(writer)
@@ -590,6 +635,12 @@
import sys
try:
- pass
- except:
+ connuri = sys.argv[1]
+ conn = connectionForURI(connuri)
+ sqlhub.processConnection = conn
+ except IndexError:
+ print "Usage: stat.py DATABASE-URI"
sys.exit(1)
+
+ #data = DemoData()
+ #data.load()
Modified: mgmt/trunk/cumin/python/cumin/stat.strings
===================================================================
--- mgmt/trunk/cumin/python/cumin/stat.strings 2009-06-04 20:32:05 UTC (rev 3420)
+++ mgmt/trunk/cumin/python/cumin/stat.strings 2009-06-04 20:35:18 UTC (rev 3421)
@@ -159,6 +159,9 @@
setTimeout("showLoading('"+id+"')", 1000);
setTimeout("hideLoading('"+id+"')", 1000 * 60);
+ wooly.cancelIntervalUpdate();
+ wooly.resumeIntervalUpdate();
+ cumin.expireIntervalUpdate();
return false;
}
@@ -181,7 +184,21 @@
}
});
+function gotChartPoints(text, oImg) {
+ var mImg = $(oImg);
+ mImg.store('points', eval("("+text+")"));
+ var e = {'client': {'x': mImg.retrieve("lastX")}};
+ cumin.chartMove(mImg, e);
+}
+function get_chart_points(oImg) {
+ $(oImg).store('points', null);
+ var branch = wooly.session.branch(oImg.src);
+ branch.samples = 't';
+ var req = branch.marshal();
+ wooly.setIntervalUpdate(req, gotChartPoints, 0, oImg, true);
+}
+
[StatValueChart.html]
<div>
<div class="StatValueChart{fullpageable}" id="{id}">
@@ -206,3 +223,4 @@
<span class="swatch" style="background-color:
{stat_color}"> </span>
<span class="ph" statname="{stat_name}"
statmode="{mode}">{stat_value}</span>
</li>
+
Modified: mgmt/trunk/cumin/resources/app.css
===================================================================
--- mgmt/trunk/cumin/resources/app.css 2009-06-04 20:32:05 UTC (rev 3420)
+++ mgmt/trunk/cumin/resources/app.css 2009-06-04 20:35:18 UTC (rev 3421)
@@ -565,3 +565,48 @@
z-index: 199;
}
+div.imgHighlight_red {
+ border: 1px solid red;
+ width: 12px;
+ height: 12px;
+ position: absolute;
+ opacity: 0.5;
+ z-index: 1000;
+}
+div.imgHighlight_green {
+ border: 1px solid green;
+ width: 12px;
+ height: 12px;
+ position: absolute;
+ opacity: 0.5;
+ z-index: 1000;
+}
+div.imgHighlight_blue {
+ border: 1px solid blue;
+ width: 12px;
+ height: 12px;
+ position: absolute;
+ opacity: 0.5;
+ z-index: 1000;
+}
+div.imgValues_red {
+ color: red;
+ font-size: 0.8em;
+ background-color: white;
+ position: absolute;
+ z-index: 1000;
+}
+div.imgValues_green {
+ color: green;
+ font-size: 0.8em;
+ background-color: white;
+ position: absolute;
+ z-index: 1000;
+}
+div.imgValues_blue {
+ color: blue;
+ font-size: 0.8em;
+ background-color: white;
+ position: absolute;
+ z-index: 1000;
+}
Modified: mgmt/trunk/cumin/resources/app.js
===================================================================
--- mgmt/trunk/cumin/resources/app.js 2009-06-04 20:32:05 UTC (rev 3420)
+++ mgmt/trunk/cumin/resources/app.js 2009-06-04 20:35:18 UTC (rev 3421)
@@ -92,7 +92,8 @@
chart.onfullpage = function (width, height) { cumin.chartNotify(true, width,
height, id); };
chart.onrestore = function () { cumin.chartNotify(false, width, 100, id); };
var oImg = document.images[id];
- $(oImg).addEvent('load', function () {
+ var mImg = $(oImg);
+ mImg.addEvent('load', function () {
this.style.visibility = "visible";
this.removeAttribute("width");
this.removeAttribute("height");
@@ -100,13 +101,84 @@
var loading = chart.getElement(".loading");
loading.setStyle('display', 'none');
loading.setStyle('visibility', 'visible');
- loading.loading = false
+ loading.loading = false;
+ var over = mImg.retrieve("over");
+ if (over) {
+ get_chart_points(oImg);
+ }
});
- $(oImg).addEvent('mousedown', function(event){
+ mImg.addEvent('mousedown', function(event){
event.stop();
});
+ mImg.addEvent('mouseout', function(event){
+ var oHighlight =
document.body.getElement(".imgHighlight_red");
+ if (oHighlight) oHighlight.style.display = "none";
+ oHighlight = document.body.getElement(".imgHighlight_green");
+ if (oHighlight) oHighlight.style.display = "none";
+ oHighlight = document.body.getElement(".imgHighlight_blue");
+ if (oHighlight) oHighlight.style.display = "none";
+ var oValue = document.body.getElement(".imgValues_red");
+ if (oValue) oValue.style.display = "none";
+ oValue = document.body.getElement(".imgValues_green");
+ if (oValue) oValue.style.display = "none";
+ oValue = document.body.getElement(".imgValues_blue");
+ if (oValue) oValue.style.display = "none";
+ mImg.store("over", false);
+ });
+ mImg.addEvent('mouseover', function(event){
+ mImg.store("over", true);
+ get_chart_points(mImg);
+ });
+ mImg.addEvent('mousemove', function(event){
+ cumin.chartMove(mImg, event);
+ });
}
+ this.chartMove = function (mImg, event) {
+ closestPoint = function (x, info) {
+ samples = info['points'];
+ var closest = samples[0];
+ for (var i=0; i<samples.length; i++) {
+ var coord = samples[i];
+ if (Math.abs(x - coord[0]) < Math.abs(x -closest[0]))
+ closest = coord;
+ }
+ return closest;
+ }
+ highlight = function (stat, point, xy) {
+ var oHighlight =
document.body.getElement(".imgHighlight_"+stat);
+ var oValues = document.body.getElement(".imgValues_"+stat);
+ if (!oHighlight) {
+ oHighlight = new Element('div', { 'class':
'imgHighlight_'+stat });
+ oValues = new Element('div', { 'class':
'imgValues_'+stat });
+ document.body.appendChild(oHighlight);
+ document.body.appendChild(oValues);
+ }
+ var pos = mImg.getPosition();
+ oHighlight.style.display = "block";
+ oHighlight.style.left = (pos.x + point[0] - 5) + "px";
+ oHighlight.style.top = (pos.y + point[1] - 3) + "px";
+
+ oValues.style.display = "block";
+ oValues.style.left = (pos.x + xy[0] + 32) + "px";
+ oValues.style.top = (pos.y + xy[1] - 8) + "px";
+ oValues.innerHTML = "("+point[2].toFixed(2)+")";
+ }
+
+ var points = mImg.retrieve('points');
+ if (points) {
+ for (var stat in points) {
+ var samples = points[stat];
+ var x = event.client.x;
+ mImg.store("lastX", x);
+ var pos = mImg.getPosition();
+ var point = closestPoint(x - pos.x, samples);
+ if (typeof point != "undefined")
+ highlight(points[stat]['color'], point,
points[stat]['xy']);
+ }
+ }
+ }
+
this.chartNotify = function (full, width, height, id) {
var oImg = document.images[id];
if (oImg) {
@@ -254,5 +326,6 @@
});
}
wooly.restartIntervalUpdate(branch.marshal());
+ cumin.expireIntervalUpdate();
}
}
\ No newline at end of file