Browse Source

Toolips represent

pull/8/head
Florian Mounier 13 years ago
parent
commit
6bb34ae96d
  1. 4
      pygal/config.py
  2. 6
      pygal/css/graph.css
  3. 20
      pygal/graph/bar.py
  4. 14
      pygal/graph/line.py
  5. 20
      pygal/graph/pie.py
  6. 24
      pygal/js/graph.coffee
  7. 30
      pygal/js/graph.js

4
pygal/config.py

@ -84,6 +84,10 @@ class Config(object):
zero = 0 zero = 0
# Text to display when no data is given # Text to display when no data is given
no_data_text = "No data" 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): def __init__(self, **kwargs):
"""Can be instanciated with config kwargs""" """Can be instanciated with config kwargs"""

6
pygal/css/graph.css

@ -49,6 +49,10 @@ text.no_data {
fill-opacity: 0; fill-opacity: 0;
} }
.centered {
text-anchor: middle;
}
.title { .title {
fill: {{ style.foreground_light }}; fill: {{ style.foreground_light }};
font-size: {{ font_sizes.title }}; font-size: {{ font_sizes.title }};
@ -56,7 +60,7 @@ text.no_data {
} }
.legends .legend text { .legends .legend text {
font-family: monospace; font-family: monospace;
font-size: {{ font_sizes.legend }}; font-size: {{ font_sizes.legend }};
fill: {{ style.foreground }}; fill: {{ style.foreground }};
fill-opacity: 1; fill-opacity: 1;

20
pygal/graph/bar.py

@ -74,17 +74,25 @@ class Bar(Graph):
width=bar_inner_width, width=bar_inner_width,
height=height, height=height,
class_='rect reactive tooltip-trigger') 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: if self._horizontal:
x += .3 * self.value_font_size x += .3 * self.value_font_size
y += height / 2 y += height / 2
else: else:
y += height / 2 + .3 * self.value_font_size y += height / 2 + .3 * self.value_font_size
self.svg.transposable_node( if self.print_values:
serie_node['text_overlay'], 'text', self.svg.transposable_node(
x=x + bar_inner_width / 2, serie_node['text_overlay'], 'text',
y=y - shift class_='centered',
).text = val x=x + bar_inner_width / 2,
y=y - shift
).text = val if self.print_zeroes or val != '0' else ''
return stack_vals return stack_vals
def _compute(self): def _compute(self):

14
pygal/graph/line.py

@ -50,11 +50,15 @@ class Line(Graph):
val = self._get_value(serie.points, i) val = self._get_value(serie.points, i)
self.svg.node(dots, 'circle', cx=x, cy=y, r=2.5, self.svg.node(dots, 'circle', cx=x, cy=y, r=2.5,
class_='dot reactive tooltip-trigger') class_='dot reactive tooltip-trigger')
self.svg.node(dots, 'desc').text = val self.svg.node(dots, 'desc', class_="value").text = val
self.svg.node(serie_node['text_overlay'], 'text', self.svg.node(dots, 'desc', class_="x").text = str(x)
x=x + self.value_font_size, self.svg.node(dots, 'desc', class_="y").text = str(y)
y=y + self.value_font_size, if self.print_values:
).text = val 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.stroke:
if self.interpolate: if self.interpolate:

20
pygal/graph/pie.py

@ -65,15 +65,17 @@ class Pie(Graph):
tooltip_position = map( tooltip_position = map(
str, diff(center, project( str, diff(center, project(
(r + small_r) / 2., start_angle + angle / 2.))) (r + small_r) / 2., start_angle + angle / 2.)))
self.svg.node(slice_, 'desc', class_="x").text = tooltip_position[0] self.svg.node(slice_, 'desc',
self.svg.node(slice_, 'desc', class_="y").text = tooltip_position[1] class_="x centered").text = tooltip_position[0]
self.svg.node(slice_, 'desc',
text_angle = pi / 2. - (start_angle + angle / 2.) class_="y centered").text = tooltip_position[1]
text_r = r * .95 if self.print_values:
self.svg.node(serie_node['text_overlay'], 'text', self.svg.node(
x=center[0] + text_r * cos(text_angle), serie_node['text_overlay'], 'text',
y=center[1] - text_r * sin(text_angle) class_='centered',
).text = val x=tooltip_position[0],
y=tooltip_position[1]
).text = val if self.print_zeroes or val != '0%' else ''
def _compute(self): def _compute(self):
for serie in self.series: for serie in self.series:

24
pygal/js/graph.coffee

@ -4,11 +4,18 @@ padding = 5
tooltip_timeout = 0 tooltip_timeout = 0
tooltip_font_size = parseInt("{{ font_sizes.tooltip }}") 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) -> add_class = (e, class_name) ->
return if not e return if not e
cn = e.getAttribute('class').split(' ') cn = e.getAttribute('class').split(' ')
if class_name not in cn if not has_class(e, class_name)
cn.push(class_name) cn.push(class_name)
e.setAttribute('class', cn.join(' ')) e.setAttribute('class', cn.join(' '))
@ -52,8 +59,15 @@ tooltip = (elt) ->
_rect.setAttribute('height', h) _rect.setAttribute('height', h)
_text.setAttribute('x', padding) _text.setAttribute('x', padding)
_text.setAttribute('y', padding + tooltip_font_size) _text.setAttribute('y', padding + tooltip_font_size)
x = value.nextElementSibling.textContent - w / 2 x_elt = value.nextElementSibling
y = value.nextElementSibling.nextElementSibling.textContent - h / 2 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})") _tooltip.setAttribute('transform', "translate(#{x} #{y})")
untooltip = -> untooltip = ->
@ -70,11 +84,11 @@ untooltip = ->
for element in _('.text-overlay .serie-' + num) for element in _('.text-overlay .serie-' + num)
element.setAttribute('display', 'inline') element.setAttribute('display', 'inline')
for element in _('.serie-' + num + ' .reactive') for element in _('.serie-' + num + ' .reactive')
activate(element, reactive(element))), ( activate(element)), (
-> ->
num = this.id.replace('activate-serie-', '') num = this.id.replace('activate-serie-', '')
for element in _('.text-overlay .serie-' + num) for element in _('.text-overlay .serie-' + num)
element.setAttribute('display', 'none') element.setAttribute('display', 'none')
for element in _('.serie-' + num + ' .reactive') for element in _('.serie-' + num + ' .reactive')
deactivate(element, reactive(element))) deactivate(element))
hover _('.tooltip-trigger'), (-> tooltip(@)), (-> untooltip()) hover _('.tooltip-trigger'), (-> tooltip(@)), (-> untooltip())

30
pygal/js/graph.js

@ -1,7 +1,6 @@
// Generated by CoffeeScript 1.2.1-pre // Generated by CoffeeScript 1.2.1-pre
(function() { (function() {
var activate, add_class, deactivate, hover, padding, rm_class, svg, tooltip, tooltip_font_size, tooltip_timeout, untooltip, _, __, var activate, add_class, deactivate, has_class, 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; },
__slice = [].slice; __slice = [].slice;
_ = function(x) { _ = function(x) {
@ -18,11 +17,22 @@
tooltip_font_size = parseInt("{{ font_sizes.tooltip }}"); 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) { add_class = function(e, class_name) {
var cn; var cn;
if (!e) return; if (!e) return;
cn = e.getAttribute('class').split(' '); 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(' ')); return e.setAttribute('class', cn.join(' '));
}; };
@ -83,7 +93,7 @@
}; };
tooltip = function(elt) { 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); clearTimeout(tooltip_timeout);
_tooltip = __('tooltip'); _tooltip = __('tooltip');
_text = _tooltip.getElementsByTagName('text')[0]; _text = _tooltip.getElementsByTagName('text')[0];
@ -96,8 +106,12 @@
_rect.setAttribute('height', h); _rect.setAttribute('height', h);
_text.setAttribute('x', padding); _text.setAttribute('x', padding);
_text.setAttribute('y', padding + tooltip_font_size); _text.setAttribute('y', padding + tooltip_font_size);
x = value.nextElementSibling.textContent - w / 2; x_elt = value.nextElementSibling;
y = value.nextElementSibling.nextElementSibling.textContent - h / 2; 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 + ")"); return _tooltip.setAttribute('transform', "translate(" + x + " " + y + ")");
}; };
@ -131,7 +145,7 @@
_results = []; _results = [];
for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) { for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
element = _ref3[_k]; element = _ref3[_k];
_results.push(activate(element, reactive(element))); _results.push(activate(element));
} }
return _results; return _results;
}), (function() { }), (function() {
@ -146,7 +160,7 @@
_results = []; _results = [];
for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) { for (_k = 0, _len3 = _ref3.length; _k < _len3; _k++) {
element = _ref3[_k]; element = _ref3[_k];
_results.push(deactivate(element, reactive(element))); _results.push(deactivate(element));
} }
return _results; return _results;
})); }));

Loading…
Cancel
Save