From 6bb34ae96d073917ce4d0001cb55860a8cbf7f75 Mon Sep 17 00:00:00 2001 From: Florian Mounier Date: Thu, 1 Mar 2012 12:46:00 +0100 Subject: [PATCH] Toolips represent --- pygal/config.py | 4 ++++ pygal/css/graph.css | 6 +++++- pygal/graph/bar.py | 20 ++++++++++++++------ pygal/graph/line.py | 14 +++++++++----- pygal/graph/pie.py | 20 +++++++++++--------- pygal/js/graph.coffee | 24 +++++++++++++++++++----- pygal/js/graph.js | 30 ++++++++++++++++++++++-------- 7 files changed, 84 insertions(+), 34 deletions(-) diff --git a/pygal/config.py b/pygal/config.py index 26f2dfd..c837c53 100644 --- a/pygal/config.py +++ b/pygal/config.py @@ -84,6 +84,10 @@ class Config(object): zero = 0 # Text to display when no data is given no_data_text = "No data" + # Print values when graph is in non interactive mode + print_values = True + # Print zeroes when graph is in non interactive mode + print_zeroes = False def __init__(self, **kwargs): """Can be instanciated with config kwargs""" diff --git a/pygal/css/graph.css b/pygal/css/graph.css index 04d92c2..357a49f 100644 --- a/pygal/css/graph.css +++ b/pygal/css/graph.css @@ -49,6 +49,10 @@ text.no_data { fill-opacity: 0; } +.centered { + text-anchor: middle; +} + .title { fill: {{ style.foreground_light }}; font-size: {{ font_sizes.title }}; @@ -56,7 +60,7 @@ text.no_data { } .legends .legend text { - font-family: monospace; + font-family: monospace; font-size: {{ font_sizes.legend }}; fill: {{ style.foreground }}; fill-opacity: 1; diff --git a/pygal/graph/bar.py b/pygal/graph/bar.py index 75aa041..190df72 100644 --- a/pygal/graph/bar.py +++ b/pygal/graph/bar.py @@ -74,17 +74,25 @@ class Bar(Graph): width=bar_inner_width, height=height, class_='rect reactive tooltip-trigger') - self.svg.node(bar, 'desc').text = val + self.svg.node(bar, 'desc', class_="values").text = val + self.svg.node(bar, 'desc', + class_="x centered" + ).text = str(x + bar_inner_width / 2.) + self.svg.node(bar, 'desc', + class_="y centered" + ).text = str(y + height / 2.) if self._horizontal: x += .3 * self.value_font_size y += height / 2 else: y += height / 2 + .3 * self.value_font_size - self.svg.transposable_node( - serie_node['text_overlay'], 'text', - x=x + bar_inner_width / 2, - y=y - shift - ).text = val + if self.print_values: + self.svg.transposable_node( + serie_node['text_overlay'], 'text', + class_='centered', + x=x + bar_inner_width / 2, + y=y - shift + ).text = val if self.print_zeroes or val != '0' else '' return stack_vals def _compute(self): diff --git a/pygal/graph/line.py b/pygal/graph/line.py index b66319d..6dd495f 100644 --- a/pygal/graph/line.py +++ b/pygal/graph/line.py @@ -50,11 +50,15 @@ class Line(Graph): val = self._get_value(serie.points, i) self.svg.node(dots, 'circle', cx=x, cy=y, r=2.5, class_='dot reactive tooltip-trigger') - self.svg.node(dots, 'desc').text = val - self.svg.node(serie_node['text_overlay'], 'text', - x=x + self.value_font_size, - y=y + self.value_font_size, - ).text = val + self.svg.node(dots, 'desc', class_="value").text = val + self.svg.node(dots, 'desc', class_="x").text = str(x) + self.svg.node(dots, 'desc', class_="y").text = str(y) + if self.print_values: + self.svg.node( + serie_node['text_overlay'], 'text', + x=x + self.value_font_size, + y=y + self.value_font_size, + ).text = val if self.stroke: if self.interpolate: diff --git a/pygal/graph/pie.py b/pygal/graph/pie.py index b49d15f..d15d366 100644 --- a/pygal/graph/pie.py +++ b/pygal/graph/pie.py @@ -65,15 +65,17 @@ class Pie(Graph): tooltip_position = map( str, diff(center, project( (r + small_r) / 2., start_angle + angle / 2.))) - self.svg.node(slice_, 'desc', class_="x").text = tooltip_position[0] - self.svg.node(slice_, 'desc', class_="y").text = tooltip_position[1] - - text_angle = pi / 2. - (start_angle + angle / 2.) - text_r = r * .95 - self.svg.node(serie_node['text_overlay'], 'text', - x=center[0] + text_r * cos(text_angle), - y=center[1] - text_r * sin(text_angle) - ).text = val + self.svg.node(slice_, 'desc', + class_="x centered").text = tooltip_position[0] + self.svg.node(slice_, 'desc', + class_="y centered").text = tooltip_position[1] + if self.print_values: + self.svg.node( + serie_node['text_overlay'], 'text', + class_='centered', + x=tooltip_position[0], + y=tooltip_position[1] + ).text = val if self.print_zeroes or val != '0%' else '' def _compute(self): for serie in self.series: diff --git a/pygal/js/graph.coffee b/pygal/js/graph.coffee index 3c244cf..bd12630 100644 --- a/pygal/js/graph.coffee +++ b/pygal/js/graph.coffee @@ -4,11 +4,18 @@ padding = 5 tooltip_timeout = 0 tooltip_font_size = parseInt("{{ font_sizes.tooltip }}") +has_class = (e, class_name) -> + return if not e + cn = e.getAttribute('class').split(' ') + for cls, i in cn + if cls == class_name + return true + false add_class = (e, class_name) -> return if not e cn = e.getAttribute('class').split(' ') - if class_name not in cn + if not has_class(e, class_name) cn.push(class_name) e.setAttribute('class', cn.join(' ')) @@ -52,8 +59,15 @@ tooltip = (elt) -> _rect.setAttribute('height', h) _text.setAttribute('x', padding) _text.setAttribute('y', padding + tooltip_font_size) - x = value.nextElementSibling.textContent - w / 2 - y = value.nextElementSibling.nextElementSibling.textContent - h / 2 + x_elt = value.nextElementSibling + y_elt = x_elt.nextElementSibling + x = x_elt.textContent + if has_class(x_elt, 'centered') + x -= w / 2 + + y = y_elt.textContent + if has_class(y_elt, 'centered') + y -= h / 2 _tooltip.setAttribute('transform', "translate(#{x} #{y})") untooltip = -> @@ -70,11 +84,11 @@ untooltip = -> for element in _('.text-overlay .serie-' + num) element.setAttribute('display', 'inline') for element in _('.serie-' + num + ' .reactive') - activate(element, reactive(element))), ( + activate(element)), ( -> num = this.id.replace('activate-serie-', '') for element in _('.text-overlay .serie-' + num) element.setAttribute('display', 'none') for element in _('.serie-' + num + ' .reactive') - deactivate(element, reactive(element))) + deactivate(element)) hover _('.tooltip-trigger'), (-> tooltip(@)), (-> untooltip()) diff --git a/pygal/js/graph.js b/pygal/js/graph.js index 4ceec91..3a62891 100644 --- a/pygal/js/graph.js +++ b/pygal/js/graph.js @@ -1,7 +1,6 @@ // Generated by CoffeeScript 1.2.1-pre (function() { - var activate, add_class, deactivate, hover, padding, rm_class, svg, tooltip, tooltip_font_size, tooltip_timeout, untooltip, _, __, - __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, + var activate, add_class, deactivate, has_class, hover, padding, rm_class, svg, tooltip, tooltip_font_size, tooltip_timeout, untooltip, _, __, __slice = [].slice; _ = function(x) { @@ -18,11 +17,22 @@ tooltip_font_size = parseInt("{{ font_sizes.tooltip }}"); + has_class = function(e, class_name) { + var cls, cn, i, _i, _len; + if (!e) return; + cn = e.getAttribute('class').split(' '); + for (i = _i = 0, _len = cn.length; _i < _len; i = ++_i) { + cls = cn[i]; + if (cls === class_name) return true; + } + return false; + }; + add_class = function(e, class_name) { var cn; if (!e) return; cn = e.getAttribute('class').split(' '); - if (__indexOf.call(cn, class_name) < 0) cn.push(class_name); + if (!has_class(e, class_name)) cn.push(class_name); return e.setAttribute('class', cn.join(' ')); }; @@ -83,7 +93,7 @@ }; tooltip = function(elt) { - var h, value, w, x, y, _rect, _text, _tooltip; + var h, value, w, x, x_elt, y, y_elt, _rect, _text, _tooltip; clearTimeout(tooltip_timeout); _tooltip = __('tooltip'); _text = _tooltip.getElementsByTagName('text')[0]; @@ -96,8 +106,12 @@ _rect.setAttribute('height', h); _text.setAttribute('x', padding); _text.setAttribute('y', padding + tooltip_font_size); - x = value.nextElementSibling.textContent - w / 2; - y = value.nextElementSibling.nextElementSibling.textContent - h / 2; + x_elt = value.nextElementSibling; + y_elt = x_elt.nextElementSibling; + x = x_elt.textContent; + if (has_class(x_elt, 'centered')) x -= w / 2; + y = y_elt.textContent; + if (has_class(y_elt, 'centered')) y -= h / 2; return _tooltip.setAttribute('transform', "translate(" + x + " " + y + ")"); }; @@ -131,7 +145,7 @@ _results = []; for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) { element = _ref3[_k]; - _results.push(activate(element, reactive(element))); + _results.push(activate(element)); } return _results; }), (function() { @@ -146,7 +160,7 @@ _results = []; for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) { element = _ref3[_k]; - _results.push(deactivate(element, reactive(element))); + _results.push(deactivate(element)); } return _results; }));