Skip to content

Commit

Permalink
Fix margin and bottom legend spacing + pretty_print off by default to…
Browse files Browse the repository at this point in the history
… avoid extra space in tooltip in firefox
  • Loading branch information
paradoxxxzero committed Apr 30, 2012
1 parent c97edbb commit 48bcf5c
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 21 deletions.
13 changes: 7 additions & 6 deletions demo/simple_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,18 +178,19 @@
# 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()
Expand Down
2 changes: 1 addition & 1 deletion pygal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"""

__version__ = '0.10.0'
__version__ = '0.10.1'

from pygal.config import Config
from pygal.graph.bar import Bar
Expand Down
2 changes: 2 additions & 0 deletions pygal/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"""
Expand Down
7 changes: 5 additions & 2 deletions pygal/graph/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ def _compute_margin(self):
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

Expand Down Expand Up @@ -188,7 +190,8 @@ def _render(self):
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"""
Expand Down
15 changes: 10 additions & 5 deletions pygal/graph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,9 @@ def _legend(self):
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))
Expand All @@ -203,7 +204,8 @@ def _legend(self):
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
Expand All @@ -214,7 +216,10 @@ def _legend(self):
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)
Expand All @@ -224,8 +229,8 @@ def _legend(self):
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:
Expand Down
15 changes: 9 additions & 6 deletions pygal/svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
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__


Expand Down Expand Up @@ -68,12 +68,14 @@ def add_styles(self):
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"""
Expand Down Expand Up @@ -184,15 +186,16 @@ def pre_render(self, no_data=False):
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:
Expand Down
23 changes: 22 additions & 1 deletion pygal/test/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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 changes: 30 additions & 0 deletions pygal/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from decimal import Decimal
from math import floor, pi, log, log10, ceil
from itertools import cycle
import re
ORDERS = u"yzafpnµm kMGTPEZY"


Expand Down Expand Up @@ -243,3 +244,32 @@ def __get__(self, obj, type_=None):
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()

0 comments on commit 48bcf5c

Please sign in to comment.