Browse Source

Fix margin and bottom legend spacing + pretty_print off by default to avoid extra space in tooltip in firefox

pull/8/head
Florian Mounier 13 years ago
parent
commit
48bcf5cb1e
  1. 13
      demo/simple_test.py
  2. 2
      pygal/__init__.py
  3. 2
      pygal/config.py
  4. 7
      pygal/graph/base.py
  5. 15
      pygal/graph/graph.py
  6. 15
      pygal/svg.py
  7. 23
      pygal/test/test_util.py
  8. 30
      pygal/util.py

13
demo/simple_test.py

@ -178,18 +178,19 @@ pie = Pie(Config(style=NeonStyle))
# pie.add('test4', [20, lnk(18), 9])
# pie.add('test5', [17, 5, 10])
# pie.add('test6', [None, None, 10])
for i in range(30):
pie.add(str(i) + '!' * i, [i, 30 - i])
for i in range(10):
pie.add('P' + str(i) + '!' * i, [i, 30 - i])
# pie.included_js = []
# pie.external_js = [
# 'http://localhost:7575/svg.jquery.js',
# 'http://localhost:7575/pygal.js',
# pie.js = [
# 'http://localhost:9898/svg.jquery.js',
# 'http://localhost:9898/pygal-tooltips.js',
# ]
# pie.add('test', {'value': 11, 'xlink': 'javascript:alert("lol 11")'})
# pie.add('test2', 1)
# pie.add('test3', 5)
# pie.title = "Pie test"
pie.legend_at_bottom = True
pie.legend_box_size = 100
pie.render_to_file('out-pie.svg')
config = Config()

2
pygal/__init__.py

@ -21,7 +21,7 @@ Pygal - A python svg graph plotting library
"""
__version__ = '0.10.0'
__version__ = '0.10.1'
from pygal.config import Config
from pygal.graph.bar import Bar

2
pygal/config.py

@ -110,6 +110,8 @@ class Config(object):
truncate_legend = None
#: Label string length truncation threshold (None = auto)
truncate_label = None
#: Pretty print the svg
pretty_print = False
def __init__(self, **kwargs):
"""Can be instanciated with config kwargs"""

7
pygal/graph/base.py

@ -90,7 +90,9 @@ class BaseGraph(object):
cut(self.series, 'title')),
self.legend_font_size)
if self.legend_at_bottom:
self.margin.bottom += 10 + h * int(sqrt(len(self.series)))
h_max = max(h, self.legend_box_size)
self.margin.bottom += 10 + h_max * round(
sqrt(len(self.series)) - 1) * 1.5 + h_max
else:
self.margin.right += 10 + w + self.legend_box_size
@ -188,7 +190,8 @@ class BaseGraph(object):
def render(self, is_unicode=False):
"""Render the graph, and return the svg string"""
self._render()
return self.svg.render(is_unicode=is_unicode)
return self.svg.render(
is_unicode=is_unicode, pretty_print=self.pretty_print)
def render_tree(self):
"""Render the graph, and return lxml tree"""

15
pygal/graph/graph.py

@ -187,8 +187,9 @@ class Graph(BaseGraph):
y = (self.margin.top + self.view.height +
self._x_labels_height + 10)
cols = ceil(sqrt(len(self.series)))
if not truncation:
available_space = self.width / cols - (
available_space = self.view.width / cols - (
self.legend_box_size + 5)
truncation = int(reverse_text_len(
available_space, self.legend_font_size))
@ -203,7 +204,8 @@ class Graph(BaseGraph):
self.nodes['graph'], class_='legends',
transform='translate(%d, %d)' % (x, y))
x_step = self.width / cols
h = max(self.legend_box_size, self.legend_font_size)
x_step = self.view.width / cols
for i, title in enumerate(self._legends):
col = i % cols
row = i // cols
@ -214,7 +216,10 @@ class Graph(BaseGraph):
self.svg.node(
legend, 'rect',
x=col * x_step,
y=1.5 * row * self.legend_box_size,
y=1.5 * row * h + (
self.legend_font_size - self.legend_box_size
if self.legend_font_size > self.legend_box_size else 0
) / 2,
width=self.legend_box_size,
height=self.legend_box_size,
class_="color-%d reactive" % (i % 16)
@ -224,8 +229,8 @@ class Graph(BaseGraph):
self.svg.node(
legend, 'text',
x=col * x_step + self.legend_box_size + 5,
y=1.5 * row * self.legend_box_size
+ .5 * self.legend_box_size
y=1.5 * row * h
+ .5 * h
+ .3 * self.legend_font_size
).text = truncated
if truncated != title:

15
pygal/svg.py

@ -28,7 +28,7 @@ import json
from lxml import etree
from math import cos, sin, pi
from urlparse import urlparse
from pygal.util import template, coord_format
from pygal.util import template, coord_format, minify_css
from pygal import __version__
@ -68,12 +68,14 @@ class Svg(object):
css = os.path.join(
os.path.dirname(__file__), 'css', css)
with io.open(css, encoding='utf-8') as f:
templ = template(
css_text = template(
f.read(),
style=self.graph.style,
font_sizes=self.graph.font_sizes())
if not self.graph.pretty_print:
css_text = minify_css(css_text)
self.node(
self.defs, 'style', type='text/css').text = templ
self.defs, 'style', type='text/css').text = css_text
def add_scripts(self):
"""Add the js to the svg"""
@ -184,15 +186,16 @@ class Svg(object):
class_='no_data')
no_data.text = self.graph.no_data_text
def render(self, is_unicode=False):
def render(self, is_unicode=False, pretty_print=False):
"""Last thing to do before rendering"""
svg = etree.tostring(
self.root, pretty_print=True,
self.root, pretty_print=pretty_print,
xml_declaration=False,
encoding='utf-8')
if not self.graph.disable_xml_declaration:
svg = b'\n'.join(
[etree.tostring(pi, encoding='utf-8', pretty_print=True)
[etree.tostring(
pi, encoding='utf-8', pretty_print=pretty_print)
for pi in self.processing_instructions]
) + b'\n' + svg
if self.graph.disable_xml_declaration or is_unicode:

23
pygal/test/test_util.py

@ -18,7 +18,7 @@
# along with pygal. If not, see <http://www.gnu.org/licenses/>.
from pygal.util import (
round_to_int, round_to_float, _swap_curly, template, humanize,
is_major, truncate)
is_major, truncate, minify_css)
from pytest import raises
@ -121,3 +121,24 @@ def test_truncate():
assert truncate('1234567890', 10) == '1234567890'
assert truncate('1234567890', 0) == '1234567890'
assert truncate('1234567890', -1) == '1234567890'
def test_minify_css():
css = '''
/*
* Font-sizes from config, override with care
*/
.title {
font-family: sans;
font-size: 12 ;
}
.legends .legend text {
font-family: monospace;
font-size: 14 ;}
'''
assert minify_css(css) == (
'.title{font-family:sans;font-size:12}'
'.legends .legend text{font-family:monospace;font-size:14}')

30
pygal/util.py

@ -25,6 +25,7 @@ from __future__ import division
from decimal import Decimal
from math import floor, pi, log, log10, ceil
from itertools import cycle
import re
ORDERS = u"yzafpnµm kMGTPEZY"
@ -243,3 +244,32 @@ class cached_property(object):
return self
value = obj.__dict__[self.__name__] = self.getter(obj)
return value
css_comments = re.compile(r'/\*.*?\*/', re.MULTILINE | re.DOTALL)
def minify_css(css):
# Inspired by slimmer by Peter Bengtsson
remove_next_comment = 1
for css_comment in css_comments.findall(css):
if css_comment[-3:] == '\*/':
remove_next_comment = 0
continue
if remove_next_comment:
css = css.replace(css_comment, '')
else:
remove_next_comment = 1
# >= 2 whitespace becomes one whitespace
css = re.sub(r'\s\s+', ' ', css)
# no whitespace before end of line
css = re.sub(r'\s+\n', '', css)
# Remove space before and after certain chars
for char in ('{', '}', ':', ';', ','):
css = re.sub(char + r'\s', char, css)
css = re.sub(r'\s' + char, char, css)
css = re.sub(r'}\s(#|\w)', r'}\1', css)
# no need for the ; before end of attributes
css = re.sub(r';}', r'}', css)
css = re.sub(r'}//-->', r'}\n//-->', css)
return css.strip()

Loading…
Cancel
Save