odoo/bin/reportlab/graphics/charts/dotbox.py

165 lines
6.5 KiB
Python

from reportlab.lib.colors import blue, _PCMYK_black
from reportlab.graphics.charts.textlabels import Label
from reportlab.graphics.shapes import Circle, Drawing, Group, Line, Rect, String
from reportlab.graphics.widgetbase import Widget
from reportlab.lib.attrmap import *
from reportlab.lib.validators import *
from reportlab.lib.units import cm
from reportlab.pdfbase.pdfmetrics import getFont
from reportlab.graphics.charts.lineplots import _maxWidth
class DotBox(Widget):
"""Returns a dotbox widget."""
#Doesn't use TypedPropertyCollection for labels - this can be a later improvement
_attrMap = AttrMap(
xlabels = AttrMapValue(isNoneOrListOfNoneOrStrings,
desc="List of text labels for boxes on left hand side"),
ylabels = AttrMapValue(isNoneOrListOfNoneOrStrings,
desc="Text label for second box on left hand side"),
labelFontName = AttrMapValue(isString,
desc="Name of font used for the labels"),
labelFontSize = AttrMapValue(isNumber,
desc="Size of font used for the labels"),
labelOffset = AttrMapValue(isNumber,
desc="Space between label text and grid edge"),
strokeWidth = AttrMapValue(isNumber,
desc='Width of the grid and dot outline'),
gridDivWidth = AttrMapValue(isNumber,
desc="Width of each 'box'"),
gridColor = AttrMapValue(isColor,
desc='Colour for the box and gridding'),
dotDiameter = AttrMapValue(isNumber,
desc="Diameter of the circle used for the 'dot'"),
dotColor = AttrMapValue(isColor,
desc='Colour of the circle on the box'),
dotXPosition = AttrMapValue(isNumber,
desc='X Position of the circle'),
dotYPosition = AttrMapValue(isNumber,
desc='X Position of the circle'),
x = AttrMapValue(isNumber,
desc='X Position of dotbox'),
y = AttrMapValue(isNumber,
desc='Y Position of dotbox'),
)
def __init__(self):
self.xlabels=["Value", "Blend", "Growth"]
self.ylabels=["Small", "Medium", "Large"]
self.labelFontName = "Helvetica"
self.labelFontSize = 6
self.labelOffset = 5
self.strokeWidth = 0.5
self.gridDivWidth=0.5*cm
self.gridColor=colors.Color(25/255.0,77/255.0,135/255.0)
self.dotDiameter=0.4*cm
self.dotColor=colors.Color(232/255.0,224/255.0,119/255.0)
self.dotXPosition = 1
self.dotYPosition = 1
self.x = 30
self.y = 5
def _getDrawingDimensions(self):
leftPadding=rightPadding=topPadding=bottomPadding=5
#find width of grid
tx=len(self.xlabels)*self.gridDivWidth
#add padding (and offset)
tx=tx+leftPadding+rightPadding+self.labelOffset
#add in maximum width of text
tx=tx+_maxWidth(self.xlabels, self.labelFontName, self.labelFontSize)
#find height of grid
ty=len(self.ylabels)*self.gridDivWidth
#add padding (and offset)
ty=ty+topPadding+bottomPadding+self.labelOffset
#add in maximum width of text
ty=ty+_maxWidth(self.ylabels, self.labelFontName, self.labelFontSize)
#print (tx, ty)
return (tx,ty)
def demo(self,drawing=None):
if not drawing:
tx,ty=self._getDrawingDimensions()
drawing = Drawing(tx,ty)
drawing.add(self.draw())
return drawing
def draw(self):
g = Group()
#box
g.add(Rect(self.x,self.y,len(self.xlabels)*self.gridDivWidth,len(self.ylabels)*self.gridDivWidth,
strokeColor=self.gridColor,
strokeWidth=self.strokeWidth,
fillColor=None))
#internal gridding
for f in range (1,len(self.ylabels)):
#horizontal
g.add(Line(strokeColor=self.gridColor,
strokeWidth=self.strokeWidth,
x1 = self.x,
y1 = self.y+f*self.gridDivWidth,
x2 = self.x+len(self.xlabels)*self.gridDivWidth,
y2 = self.y+f*self.gridDivWidth))
for f in range (1,len(self.xlabels)):
#vertical
g.add(Line(strokeColor=self.gridColor,
strokeWidth=self.strokeWidth,
x1 = self.x+f*self.gridDivWidth,
y1 = self.y,
x2 = self.x+f*self.gridDivWidth,
y2 = self.y+len(self.ylabels)*self.gridDivWidth))
# draw the 'dot'
g.add(Circle(strokeColor=self.gridColor,
strokeWidth=self.strokeWidth,
fillColor=self.dotColor,
cx = self.x+(self.dotXPosition*self.gridDivWidth),
cy = self.y+(self.dotYPosition*self.gridDivWidth),
r = self.dotDiameter/2.0))
#used for centering y-labels (below)
ascent=getFont(self.labelFontName).face.ascent
if ascent==0:
ascent=0.718 # default (from helvetica)
ascent=ascent*self.labelFontSize # normalize
#do y-labels
if self.ylabels != None:
for f in range (len(self.ylabels)-1,-1,-1):
if self.ylabels[f]!= None:
g.add(String(strokeColor=self.gridColor,
text = self.ylabels[f],
fontName = self.labelFontName,
fontSize = self.labelFontSize,
fillColor=_PCMYK_black,
x = self.x-self.labelOffset,
y = self.y+(f*self.gridDivWidth+(self.gridDivWidth-ascent)/2.0),
textAnchor = 'end'))
#do x-labels
if self.xlabels != None:
for f in range (0,len(self.xlabels)):
if self.xlabels[f]!= None:
l=Label()
l.x=self.x+(f*self.gridDivWidth)+(self.gridDivWidth+ascent)/2.0
l.y=self.y+(len(self.ylabels)*self.gridDivWidth)+self.labelOffset
l.angle=90
l.textAnchor='start'
l.fontName = self.labelFontName
l.fontSize = self.labelFontSize
l.fillColor = _PCMYK_black
l.setText(self.xlabels[f])
l.boxAnchor = 'sw'
l.draw()
g.add(l)
return g
if __name__ == "__main__":
d = DotBox()
d.demo().save(fnRoot="dotbox")