slidebox.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. from reportlab.lib.colors import Color, white, black
  2. from reportlab.graphics.charts.textlabels import Label
  3. from reportlab.graphics.shapes import Polygon, Line, Circle, String, Drawing, PolyLine, Group, Rect
  4. from reportlab.graphics.widgetbase import Widget, TypedPropertyCollection
  5. from reportlab.lib.attrmap import *
  6. from reportlab.lib.validators import *
  7. from reportlab.lib.units import cm
  8. from reportlab.pdfbase.pdfmetrics import stringWidth, getFont
  9. from reportlab.graphics.widgets.grids import ShadedRect, Grid
  10. class SlideBox(Widget):
  11. """Returns a slidebox widget"""
  12. _attrMap = AttrMap(
  13. labelFontName = AttrMapValue(isString, desc="Name of font used for the labels"),
  14. labelFontSize = AttrMapValue(isNumber, desc="Size of font used for the labels"),
  15. labelStrokeColor = AttrMapValue(isColorOrNone, desc="Colour for for number outlines"),
  16. labelFillColor = AttrMapValue(isColorOrNone, desc="Colour for number insides"),
  17. startColor = AttrMapValue(isColor, desc='Color of first box'),
  18. endColor = AttrMapValue(isColor, desc='Color of last box'),
  19. numberOfBoxes = AttrMapValue(isInt, desc='How many boxes there are'),
  20. trianglePosition = AttrMapValue(isInt, desc='Which box is highlighted by the triangles'),
  21. triangleHeight = AttrMapValue(isNumber, desc="Height of indicator triangles"),
  22. triangleWidth = AttrMapValue(isNumber, desc="Width of indicator triangles"),
  23. triangleFillColor = AttrMapValue(isColor, desc="Colour of indicator triangles"),
  24. triangleStrokeColor = AttrMapValue(isColorOrNone, desc="Colour of indicator triangle outline"),
  25. triangleStrokeWidth = AttrMapValue(isNumber, desc="Colour of indicator triangle outline"),
  26. boxHeight = AttrMapValue(isNumber, desc="Height of the boxes"),
  27. boxWidth = AttrMapValue(isNumber, desc="Width of the boxes"),
  28. boxSpacing = AttrMapValue(isNumber, desc="Space between the boxes"),
  29. boxOutlineColor = AttrMapValue(isColorOrNone, desc="Colour used to outline the boxes (if any)"),
  30. boxOutlineWidth = AttrMapValue(isNumberOrNone, desc="Width of the box outline (if any)"),
  31. leftPadding = AttrMapValue(isNumber, desc='Padding on left of drawing'),
  32. rightPadding = AttrMapValue(isNumber, desc='Padding on right of drawing'),
  33. topPadding = AttrMapValue(isNumber, desc='Padding at top of drawing'),
  34. bottomPadding = AttrMapValue(isNumber, desc='Padding at bottom of drawing'),
  35. background = AttrMapValue(isColorOrNone, desc='Colour of the background to the drawing (if any)'),
  36. sourceLabelText = AttrMapValue(isNoneOrString, desc="Text used for the 'source' label (can be empty)"),
  37. sourceLabelOffset = AttrMapValue(isNumber, desc='Padding at bottom of drawing'),
  38. sourceLabelFontName = AttrMapValue(isString, desc="Name of font used for the 'source' label"),
  39. sourceLabelFontSize = AttrMapValue(isNumber, desc="Font size for the 'source' label"),
  40. sourceLabelFillColor = AttrMapValue(isColorOrNone, desc="Colour ink for the 'source' label (bottom right)"),
  41. )
  42. def __init__(self):
  43. self.labelFontName = "Helvetica-Bold"
  44. self.labelFontSize = 10
  45. self.labelStrokeColor = black
  46. self.labelFillColor = white
  47. self.startColor = colors.Color(232/255.0,224/255.0,119/255.0)
  48. self.endColor = colors.Color(25/255.0,77/255.0,135/255.0)
  49. self.numberOfBoxes = 7
  50. self.trianglePosition = 7
  51. self.triangleHeight = 0.12*cm
  52. self.triangleWidth = 0.38*cm
  53. self.triangleFillColor = white
  54. self.triangleStrokeColor = black
  55. self.triangleStrokeWidth = 0.58
  56. self.boxHeight = 0.55*cm
  57. self.boxWidth = 0.73*cm
  58. self.boxSpacing = 0.075*cm
  59. self.boxOutlineColor = black
  60. self.boxOutlineWidth = 0.58
  61. self.leftPadding=5
  62. self.rightPadding=5
  63. self.topPadding=5
  64. self.bottomPadding=5
  65. self.background=None
  66. self.sourceLabelText = "Source: ReportLab"
  67. self.sourceLabelOffset = 0.2*cm
  68. self.sourceLabelFontName = "Helvetica-Oblique"
  69. self.sourceLabelFontSize = 6
  70. self.sourceLabelFillColor = black
  71. def _getDrawingDimensions(self):
  72. tx=(self.numberOfBoxes*self.boxWidth)
  73. if self.numberOfBoxes>1: tx=tx+((self.numberOfBoxes-1)*self.boxSpacing)
  74. tx=tx+self.leftPadding+self.rightPadding
  75. ty=self.boxHeight+self.triangleHeight
  76. ty=ty+self.topPadding+self.bottomPadding+self.sourceLabelOffset+self.sourceLabelFontSize
  77. return (tx,ty)
  78. def _getColors(self):
  79. # for calculating intermediate colors...
  80. numShades = self.numberOfBoxes+1
  81. fillColorStart = self.startColor
  82. fillColorEnd = self.endColor
  83. colorsList =[]
  84. for i in range(0,numShades):
  85. colorsList.append(colors.linearlyInterpolatedColor(fillColorStart, fillColorEnd, 0, numShades-1, i))
  86. return colorsList
  87. def demo(self,drawing=None):
  88. from reportlab.lib import colors
  89. if not drawing:
  90. tx,ty=self._getDrawingDimensions()
  91. drawing = Drawing(tx,ty)
  92. drawing.add(self.draw())
  93. return drawing
  94. def draw(self):
  95. g = Group()
  96. ys = self.bottomPadding+(self.triangleHeight/2)+self.sourceLabelOffset+self.sourceLabelFontSize
  97. if self.background:
  98. x,y = self._getDrawingDimensions()
  99. g.add(Rect(-self.leftPadding,-ys,x,y,
  100. strokeColor=None,
  101. strokeWidth=0,
  102. fillColor=self.background))
  103. ascent=getFont(self.labelFontName).face.ascent/1000.
  104. if ascent==0: ascent=0.718 # default (from helvetica)
  105. ascent=ascent*self.labelFontSize # normalize
  106. colorsList = self._getColors()
  107. # Draw the boxes - now uses ShadedRect from grids
  108. x=0
  109. for f in range (0,self.numberOfBoxes):
  110. sr=ShadedRect()
  111. sr.x=x
  112. sr.y=0
  113. sr.width=self.boxWidth
  114. sr.height=self.boxHeight
  115. sr.orientation = 'vertical'
  116. sr.numShades = 30
  117. sr.fillColorStart = colorsList[f]
  118. sr.fillColorEnd = colorsList[f+1]
  119. sr.strokeColor = None
  120. sr.strokeWidth = 0
  121. g.add(sr)
  122. g.add(Rect(x,0,self.boxWidth,self.boxHeight,
  123. strokeColor=self.boxOutlineColor,
  124. strokeWidth=self.boxOutlineWidth,
  125. fillColor=None))
  126. g.add(String(x+self.boxWidth/2.,(self.boxHeight-ascent)/2.,
  127. text = str(f+1),
  128. fillColor = self.labelFillColor,
  129. strokeColor=self.labelStrokeColor,
  130. textAnchor = 'middle',
  131. fontName = self.labelFontName,
  132. fontSize = self.labelFontSize))
  133. x=x+self.boxWidth+self.boxSpacing
  134. #do triangles
  135. xt = (self.trianglePosition*self.boxWidth)
  136. if self.trianglePosition>1:
  137. xt = xt+(self.trianglePosition-1)*self.boxSpacing
  138. xt = xt-(self.boxWidth/2)
  139. g.add(Polygon(
  140. strokeColor = self.triangleStrokeColor,
  141. strokeWidth = self.triangleStrokeWidth,
  142. fillColor = self.triangleFillColor,
  143. points=[xt,self.boxHeight-(self.triangleHeight/2),
  144. xt-(self.triangleWidth/2),self.boxHeight+(self.triangleHeight/2),
  145. xt+(self.triangleWidth/2),self.boxHeight+(self.triangleHeight/2),
  146. xt,self.boxHeight-(self.triangleHeight/2)]))
  147. g.add(Polygon(
  148. strokeColor = self.triangleStrokeColor,
  149. strokeWidth = self.triangleStrokeWidth,
  150. fillColor = self.triangleFillColor,
  151. points=[xt,0+(self.triangleHeight/2),
  152. xt-(self.triangleWidth/2),0-(self.triangleHeight/2),
  153. xt+(self.triangleWidth/2),0-(self.triangleHeight/2),
  154. xt,0+(self.triangleHeight/2)]))
  155. #source label
  156. if self.sourceLabelText != None:
  157. g.add(String(x-self.boxSpacing,0-(self.triangleHeight/2)-self.sourceLabelOffset-(self.sourceLabelFontSize),
  158. text = self.sourceLabelText,
  159. fillColor = self.sourceLabelFillColor,
  160. textAnchor = 'end',
  161. fontName = self.sourceLabelFontName,
  162. fontSize = self.sourceLabelFontSize))
  163. g.shift(self.leftPadding, ys)
  164. return g
  165. if __name__ == "__main__":
  166. d = SlideBox()
  167. d.demo().save(fnRoot="slidebox")