Skip to content

Commit

Permalink
Use transforms.
Browse files Browse the repository at this point in the history
  • Loading branch information
onyxfish committed May 18, 2016
1 parent 355624b commit b709ba4
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 35 deletions.
2 changes: 2 additions & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ YES:
* Date scales
* Color
* Null handling
* Tick formatting

NO:

Expand All @@ -30,3 +31,4 @@ MAYBE:

* Side-by-side bars
* Stacked bars
* Curved lines
19 changes: 10 additions & 9 deletions leather/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from leather.renderable import Renderable


class Axis(Renderable):
"""
A horizontal or vertical chart axis.
Expand All @@ -20,22 +21,22 @@ def __init__(self, scale, orient='bottom', ticks=5, tick_width='1px', tick_size=
self.label_color = label_color
self.zero_color = zero_color

def to_svg(self, bbox):
def to_svg(self, width, height):
"""
Render this axis to SVG elements.
"""
group = ET.Element('g')

if self.orient == 'left':
label_x = bbox.left - (self.tick_size * 2)
x1 = bbox.left - self.tick_size
x2 = bbox.right
project_range = [bbox.bottom, bbox.top]
label_x = -(self.tick_size * 2)
x1 = -self.tick_size
x2 = width
project_range = [height, 0]
elif self.orient == 'bottom':
label_y = bbox.bottom + (self.tick_size * 2)
y1 = bbox.top
y2 = bbox.bottom + self.tick_size
project_range = [bbox.left, bbox.right]
label_y = height + (self.tick_size * 2)
y1 = 0
y2 = height + self.tick_size
project_range = [0, width]

for value in self.scale.ticks(self.ticks):
projected_value = self.scale.project(value, project_range)
Expand Down
36 changes: 23 additions & 13 deletions leather/chart.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from leather.shapes.column import Column
from leather.shapes.dot import Dot
from leather.shapes.line import Line
from leather.utils import X, Y, DIMENSIONS, Box
from leather.utils import X, Y, DIMENSIONS, Box, svg_translate

DEFAULT_DOT = Dot()
DEFAULT_LINE = Line()
Expand Down Expand Up @@ -142,7 +142,11 @@ def _validate_dimension(self, dimension):

return (scale, axis)

def to_svg_group(self, width=300, height=300, margin=None):
def to_svg_group(self, width, height, margin=None):
"""
Render the completechart to an SVG group element that can be placed
inside an :code:`<svg>` tag.
"""
if not self._layers:
raise ValueError('You must add at least one series to the chart before rendering.')

Expand All @@ -158,25 +162,31 @@ def to_svg_group(self, width=300, height=300, margin=None):
elif not isinstance(margin, Box):
margin = Box(*margin)

canvas_bbox = Box(
top=margin.top,
right=width - margin.right,
bottom=height - margin.bottom,
left=margin.left
)
canvas_width = width - (margin.left + margin.right)
canvas_height = height - (margin.top + margin.bottom)

root_group = ET.Element('g')
root_group.set('transform', svg_translate(margin.left, margin.top))

# Axes
axes_group = ET.Element('g')

x_scale, x_axis = self._validate_dimension(X)
y_scale, y_axis = self._validate_dimension(Y)

group = ET.Element('g')
axes_group.append(x_axis.to_svg(canvas_width, canvas_height))
axes_group.append(y_axis.to_svg(canvas_width, canvas_height))

group.append(x_axis.to_svg(canvas_bbox))
group.append(y_axis.to_svg(canvas_bbox))
# Series
series_group = ET.Element('g')

for series, shape in self._layers:
group.append(shape.to_svg(canvas_bbox, x_scale, y_scale, series))
series_group.append(shape.to_svg(canvas_width, canvas_height, x_scale, y_scale, series))

root_group.append(axes_group)
root_group.append(series_group)

return group
return root_group

def to_svg(self, path, width=600, height=600, margin=None):
"""
Expand Down
10 changes: 8 additions & 2 deletions leather/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import six

from leather.utils import svg_translate


class Grid(object):
"""
Expand Down Expand Up @@ -41,8 +43,12 @@ def to_svg(self, path, width=1200, height=1200):
x = (i % grid_width) * chart_width
y = math.floor(i / grid_width) * chart_height

group = chart.to_svg_group(chart_width, chart_height)
group.set('transform', 'translate(%i %i)' % (x, y))
group = ET.Element('g')
group.set('transform', svg_translate(x, y))

chart = chart.to_svg_group(chart_width, chart_height)
group.append(chart)

svg.append(group)

close = True
Expand Down
2 changes: 1 addition & 1 deletion leather/renderable.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ class Renderable(object):
"""
Abstract base class for renderable chart elements.
"""
def to_svg(self):
def to_svg(self, width, height):
raise NotImplementedError()
8 changes: 4 additions & 4 deletions leather/shapes/column.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ class Column(Shape):
def __init__(self, color='green'):
self.color = color

def to_svg(self, bbox, x_scale, y_scale, series):
def to_svg(self, width, height, x_scale, y_scale, series):
"""
Render columns to SVG elements.
"""
group = ET.Element('g')

for x, y in series.data:
x1, x2 = x_scale.project_interval(x, [bbox.left, bbox.right])
proj_y = y_scale.project(y, [bbox.bottom, bbox.top])
x1, x2 = x_scale.project_interval(x, [0, width])
proj_y = y_scale.project(y, [height, 0])

# TKTK
group.append(ET.Element('rect',
x=six.text_type(x1),
y=six.text_type(proj_y),
width=six.text_type(x2 - x1),
height=six.text_type(bbox.bottom - proj_y),
height=six.text_type(height - proj_y),
fill=self.color
))

Expand Down
6 changes: 3 additions & 3 deletions leather/shapes/dot.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ def __init__(self, radius=3, color='red'):
self.radius = radius
self.color = color

def to_svg(self, bbox, x_scale, y_scale, series):
def to_svg(self, width, height, x_scale, y_scale, series):
"""
Render dots to SVG elements.
"""
group = ET.Element('g')

for x, y in series.data:
proj_x = x_scale.project(x, [bbox.left, bbox.right])
proj_y = y_scale.project(y, [bbox.bottom, bbox.top])
proj_x = x_scale.project(x, [0, width])
proj_y = y_scale.project(y, [height, 0])

group.append(ET.Element('circle',
cx=six.text_type(proj_x),
Expand Down
6 changes: 3 additions & 3 deletions leather/shapes/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def __init__(self, width='2px', color='blue'):
self.width = width
self.color = color

def to_svg(self, bbox, x_scale, y_scale, series):
def to_svg(self, width, height, x_scale, y_scale, series):
"""
Render lines to SVG elements.
"""
Expand All @@ -27,8 +27,8 @@ def to_svg(self, bbox, x_scale, y_scale, series):
d = []

for x, y in series.data:
proj_x = x_scale.project(x, [bbox.left, bbox.right])
proj_y = y_scale.project(y, [bbox.bottom, bbox.top])
proj_x = x_scale.project(x, [0, width])
proj_y = y_scale.project(y, [height, 0])

if not d:
command = 'M'
Expand Down
3 changes: 3 additions & 0 deletions leather/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@

#: Data structure for representing margins or other CSS-edge like properties
Box = namedtuple('Box', ['top', 'right', 'bottom', 'left'])

def svg_translate(x, y):
return 'translate(%i %i)' % (x, y)

0 comments on commit b709ba4

Please sign in to comment.