|
|
|
@ -26,8 +26,10 @@ import os
|
|
|
|
|
import json |
|
|
|
|
from datetime import date, datetime |
|
|
|
|
from numbers import Number |
|
|
|
|
from math import cos, sin, pi |
|
|
|
|
from pygal.util import template, minify_css |
|
|
|
|
from math import pi |
|
|
|
|
from pygal.util import ( |
|
|
|
|
template, minify_css, |
|
|
|
|
coord_project, coord_diff, coord_format, coord_dual, coord_abs_project) |
|
|
|
|
from pygal import __version__ |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -255,14 +257,6 @@ class Svg(object):
|
|
|
|
|
self, serie_node, node, radius, small_radius, |
|
|
|
|
angle, start_angle, center, val, i, metadata): |
|
|
|
|
"""Draw a pie slice""" |
|
|
|
|
project = lambda rho, alpha: ( |
|
|
|
|
rho * sin(-alpha), rho * cos(-alpha)) |
|
|
|
|
diff = lambda x, y: (x[0] - y[0], x[1] - y[1]) |
|
|
|
|
fmt = lambda x: '%f %f' % x |
|
|
|
|
get_radius = lambda r: fmt(tuple([r] * 2)) |
|
|
|
|
absolute_project = lambda rho, theta: fmt( |
|
|
|
|
diff(center, project(rho, theta))) |
|
|
|
|
|
|
|
|
|
if angle == 2 * pi: |
|
|
|
|
rv = self.node( |
|
|
|
|
node, 'circle', |
|
|
|
@ -271,21 +265,21 @@ class Svg(object):
|
|
|
|
|
r=radius, |
|
|
|
|
class_='slice reactive tooltip-trigger') |
|
|
|
|
elif angle > 0: |
|
|
|
|
to = [absolute_project(radius, start_angle), |
|
|
|
|
absolute_project(radius, start_angle + angle), |
|
|
|
|
absolute_project(small_radius, start_angle + angle), |
|
|
|
|
absolute_project(small_radius, start_angle)] |
|
|
|
|
to = [coord_abs_project(center,radius, start_angle), |
|
|
|
|
coord_abs_project(center,radius, start_angle + angle), |
|
|
|
|
coord_abs_project(center,small_radius, start_angle + angle), |
|
|
|
|
coord_abs_project(center,small_radius, start_angle)] |
|
|
|
|
rv = self.node( |
|
|
|
|
node, 'path', |
|
|
|
|
d='M%s A%s 0 %d 1 %s L%s A%s 0 %d 0 %s z' % ( |
|
|
|
|
to[0], |
|
|
|
|
get_radius(radius), int(angle > pi), to[1], |
|
|
|
|
coord_dual(radius), int(angle > pi), to[1], |
|
|
|
|
to[2], |
|
|
|
|
get_radius(small_radius), int(angle > pi), to[3]), |
|
|
|
|
coord_dual(small_radius), int(angle > pi), to[3]), |
|
|
|
|
class_='slice reactive tooltip-trigger') |
|
|
|
|
else: |
|
|
|
|
rv = None |
|
|
|
|
x, y = diff(center, project( |
|
|
|
|
x, y = coord_diff(center, coord_project( |
|
|
|
|
(radius + small_radius) / 2, start_angle + angle / 2)) |
|
|
|
|
|
|
|
|
|
self.graph._tooltip_data( |
|
|
|
@ -295,66 +289,66 @@ class Svg(object):
|
|
|
|
|
self.graph._static_value(serie_node, val, x, y, metadata) |
|
|
|
|
return rv |
|
|
|
|
|
|
|
|
|
def solidgauge( |
|
|
|
|
def gauge_background( |
|
|
|
|
self, serie_node, start_angle, center, radius, small_radius, |
|
|
|
|
end_angle, half_pie): |
|
|
|
|
to_shade = [ |
|
|
|
|
coord_abs_project(center, radius, start_angle), |
|
|
|
|
coord_abs_project(center, radius, end_angle), |
|
|
|
|
coord_abs_project(center, small_radius, end_angle), |
|
|
|
|
coord_abs_project(center, small_radius, start_angle)] |
|
|
|
|
|
|
|
|
|
self.node( |
|
|
|
|
serie_node['plot'], 'path', |
|
|
|
|
d='M%s A%s 0 1 1 %s L%s A%s 0 1 0 %s z' % ( |
|
|
|
|
to_shade[0], |
|
|
|
|
coord_dual(radius), |
|
|
|
|
to_shade[1], |
|
|
|
|
to_shade[2], |
|
|
|
|
coord_dual(small_radius), |
|
|
|
|
to_shade[3]), |
|
|
|
|
class_='gauge-background reactive') |
|
|
|
|
|
|
|
|
|
def solid_gauge( |
|
|
|
|
self, serie_node, node, radius, small_radius, |
|
|
|
|
angle, start_angle, center, val, i, metadata, half_pie, endangle, |
|
|
|
|
angle, start_angle, center, val, i, metadata, half_pie, end_angle, |
|
|
|
|
maxvalue): |
|
|
|
|
"""Draw a solid gauge slice and background slice""" |
|
|
|
|
project = lambda rho, alpha: ( |
|
|
|
|
rho * sin(-alpha), rho * cos(-alpha)) |
|
|
|
|
diff = lambda x, y: (x[0] - y[0], x[1] - y[1]) |
|
|
|
|
fmt = lambda x: '%f %f' % x |
|
|
|
|
get_radius = lambda r: fmt(tuple([r] * 2)) |
|
|
|
|
absolute_project = lambda rho, theta: fmt( |
|
|
|
|
diff(center, project(rho, theta))) |
|
|
|
|
|
|
|
|
|
if angle == 2 * pi: |
|
|
|
|
to = [absolute_project(radius, start_angle), |
|
|
|
|
absolute_project(radius, start_angle + angle - 0.0001), |
|
|
|
|
absolute_project(small_radius, start_angle + angle - 0.0001), |
|
|
|
|
absolute_project(small_radius, start_angle)] |
|
|
|
|
to = [coord_abs_project(center, radius, start_angle), |
|
|
|
|
coord_abs_project( |
|
|
|
|
center, radius, start_angle + angle - 0.0001), |
|
|
|
|
coord_abs_project( |
|
|
|
|
center, small_radius, start_angle + angle - 0.0001), |
|
|
|
|
coord_abs_project(center, small_radius, start_angle)] |
|
|
|
|
self.node( |
|
|
|
|
node, 'path', |
|
|
|
|
d='M%s A%s 0 %d 1 %s L%s A%s 0 %d 0 %s z' % ( |
|
|
|
|
to[0], |
|
|
|
|
get_radius(radius), |
|
|
|
|
coord_dual(radius), |
|
|
|
|
int(angle > pi), |
|
|
|
|
to[1], |
|
|
|
|
to[2], |
|
|
|
|
get_radius(small_radius), |
|
|
|
|
coord_dual(small_radius), |
|
|
|
|
int(angle > pi), |
|
|
|
|
to[3]), |
|
|
|
|
class_='slice reactive tooltip-trigger') |
|
|
|
|
elif angle > 0: |
|
|
|
|
to_shade = [absolute_project(radius, start_angle+angle), |
|
|
|
|
absolute_project(radius, endangle), |
|
|
|
|
absolute_project(small_radius, endangle), |
|
|
|
|
absolute_project(small_radius, start_angle+angle)] |
|
|
|
|
|
|
|
|
|
self.node( |
|
|
|
|
node, 'path', |
|
|
|
|
d='M%s A%s 0 %d 1 %s L%s A%s 0 %d 0 %s z' % ( |
|
|
|
|
to_shade[0], |
|
|
|
|
get_radius(radius), |
|
|
|
|
int(angle > pi) if half_pie else int(angle < pi), |
|
|
|
|
to_shade[1], |
|
|
|
|
to_shade[2], |
|
|
|
|
get_radius(small_radius), |
|
|
|
|
int(angle > pi) if half_pie else int(angle < pi), |
|
|
|
|
to_shade[3]), |
|
|
|
|
class_='background-shade reactive') |
|
|
|
|
|
|
|
|
|
to = [absolute_project(radius, start_angle), |
|
|
|
|
absolute_project(radius, start_angle + angle), |
|
|
|
|
absolute_project(small_radius, start_angle + angle), |
|
|
|
|
absolute_project(small_radius, start_angle)] |
|
|
|
|
to = [coord_abs_project(center, radius, start_angle), |
|
|
|
|
coord_abs_project(center, radius, start_angle + angle), |
|
|
|
|
coord_abs_project(center, small_radius, start_angle + angle), |
|
|
|
|
coord_abs_project(center, small_radius, start_angle)] |
|
|
|
|
|
|
|
|
|
if half_pie: |
|
|
|
|
begin_end = [ |
|
|
|
|
diff(center, |
|
|
|
|
project(radius-(radius-small_radius)/2, start_angle)), |
|
|
|
|
diff(center, |
|
|
|
|
project(radius-(radius-small_radius)/2, endangle))] |
|
|
|
|
coord_diff( |
|
|
|
|
center, |
|
|
|
|
coord_project( |
|
|
|
|
radius-(radius-small_radius)/2, start_angle)), |
|
|
|
|
coord_diff( |
|
|
|
|
center, |
|
|
|
|
coord_project( |
|
|
|
|
radius-(radius-small_radius)/2, end_angle))] |
|
|
|
|
pos = 0 |
|
|
|
|
for i in begin_end: |
|
|
|
|
self.node( |
|
|
|
@ -367,43 +361,49 @@ class Svg(object):
|
|
|
|
|
).text = '{}'.format(0 if pos == 0 else maxvalue) |
|
|
|
|
pos += 1 |
|
|
|
|
else: |
|
|
|
|
to_labels = [absolute_project(radius-(radius-small_radius)/2, 0), |
|
|
|
|
absolute_project(radius-(radius-small_radius)/2, 2*359.5/360*pi)] |
|
|
|
|
self.node(self.defs, 'path', id='valuePath-%s%s' % center, |
|
|
|
|
d='M%s A%s 0 1 1 %s' % ( |
|
|
|
|
to_labels[0], get_radius(radius-(radius-small_radius)/2), |
|
|
|
|
to_labels[1] |
|
|
|
|
), stroke='#000000', width='3px') |
|
|
|
|
to_labels = [ |
|
|
|
|
coord_abs_project( |
|
|
|
|
center, radius-(radius-small_radius)/2, 0), |
|
|
|
|
coord_abs_project( |
|
|
|
|
center, radius-(radius-small_radius)/2, 2*359.5/360*pi) |
|
|
|
|
] |
|
|
|
|
self.node( |
|
|
|
|
self.defs, 'path', id='valuePath-%s%s' % center, |
|
|
|
|
d='M%s A%s 0 1 1 %s' % ( |
|
|
|
|
to_labels[0], |
|
|
|
|
coord_dual(radius-(radius-small_radius)/2), |
|
|
|
|
to_labels[1] |
|
|
|
|
), stroke='#000000', width='3px') |
|
|
|
|
text_ = self.node(node, 'text', x=10, y=100, stroke='black') |
|
|
|
|
self.node(text_, 'textPath', class_='maxvalue reactive', |
|
|
|
|
attrib={'href': '#valuePath-%s%s' % center, |
|
|
|
|
'startOffset': '%s' % (97-1.2*len(str(maxvalue))) + '%', |
|
|
|
|
'text-anchor': 'start', |
|
|
|
|
'font-size': (radius-small_radius)/2, |
|
|
|
|
'fill': '#999999'} |
|
|
|
|
).text = maxvalue |
|
|
|
|
self.node( |
|
|
|
|
text_, 'textPath', class_='maxvalue reactive', |
|
|
|
|
attrib={ |
|
|
|
|
'href': '#valuePath-%s%s' % center, |
|
|
|
|
'startOffset': '%s' % ( |
|
|
|
|
97-1.2*len(str(maxvalue))) + '%', |
|
|
|
|
'text-anchor': 'start', |
|
|
|
|
'font-size': (radius-small_radius)/2, |
|
|
|
|
'fill': '#999999'} |
|
|
|
|
).text = maxvalue |
|
|
|
|
|
|
|
|
|
self.node( |
|
|
|
|
node, 'path', |
|
|
|
|
d='M%s A%s 0 %d 1 %s L%s A%s 0 %d 0 %s z' % ( |
|
|
|
|
to[0], |
|
|
|
|
get_radius(radius), |
|
|
|
|
coord_dual(radius), |
|
|
|
|
int(angle > pi), |
|
|
|
|
to[1], |
|
|
|
|
to[2], |
|
|
|
|
get_radius(small_radius), |
|
|
|
|
coord_dual(small_radius), |
|
|
|
|
int(angle > pi), |
|
|
|
|
to[3]), |
|
|
|
|
class_='slice reactive tooltip-trigger') |
|
|
|
|
else: |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
x, y = center |
|
|
|
|
self.graph._static_value(serie_node, val, x, y, metadata, 'middle') |
|
|
|
|
|
|
|
|
|
x, y = diff(center, project( |
|
|
|
|
x, y = coord_diff(center, coord_project( |
|
|
|
|
(radius + small_radius) / 2, start_angle + angle / 2)) |
|
|
|
|
self.graph._static_value(serie_node, val, x, y, metadata, 'middle') |
|
|
|
|
self.graph._tooltip_data( |
|
|
|
|
node, val, x, y, "centered", |
|
|
|
|
self.graph._x_labels and self.graph._x_labels[i][0]) |
|
|
|
|