def draw_chart(self): view_rect = Rect(0, 0, *self.view_size) title = self.title _, title_height = self.view.text_size(title, 1) titley = view_rect.h - title_height - self.PADDING title_rect = (0, titley, view_rect.w, title_height) self.view.draw_text(title, title_rect, FontID.Title) if not hasattr(self, 'pie1'): return # circle coords # circle_bounds is the area in which the circle is allowed to be drawn (important for legend text) circle_bounds = view_rect.scaled_rect(-self.PADDING, -self.PADDING) circle_bounds.h -= title_height if circle_bounds.w > circle_bounds.h: circle_bounds.w = (circle_bounds.w - self.PADDING) / 2 circle_bounds2 = Rect(circle_bounds.right + self.PADDING, circle_bounds.y, circle_bounds.w, circle_bounds.h) else: circle_bounds.h = (circle_bounds.h - self.PADDING) / 2 # We want the first circle to be on top circle_bounds.y += circle_bounds.h + self.PADDING # hscommon.geometry has a top-left origin, we use "top" when we mean "bottom". circle_bounds2 = Rect( circle_bounds.x, circle_bounds.top - circle_bounds.h - self.PADDING, circle_bounds.w, circle_bounds.h) self.draw_pie(self.pie1, circle_bounds) self.draw_pie(self.pie2, circle_bounds2)
def draw_chart(self): view_rect = Rect(0, 0, *self.view_size) title = self.title _, title_height = self.view.text_size(title, 1) titley = view_rect.h - title_height - self.PADDING title_rect = (0, titley, view_rect.w, title_height) self.view.draw_text(title, title_rect, FontID.Title) if not hasattr(self, 'pie1'): return # circle coords # circle_bounds is the area in which the circle is allowed to be drawn (important for legend text) circle_bounds = view_rect.scaled_rect(-self.PADDING, -self.PADDING) circle_bounds.h -= title_height if circle_bounds.w > circle_bounds.h: circle_bounds.w = (circle_bounds.w - self.PADDING) / 2 circle_bounds2 = Rect(circle_bounds.right + self.PADDING, circle_bounds.y, circle_bounds.w, circle_bounds.h) else: circle_bounds.h = (circle_bounds.h - self.PADDING) / 2 # We want the first circle to be on top circle_bounds.y += circle_bounds.h + self.PADDING # hscommon.geometry has a top-left origin, we use "top" when we mean "bottom". circle_bounds2 = Rect(circle_bounds.x, circle_bounds.top - circle_bounds.h - self.PADDING, circle_bounds.w, circle_bounds.h) self.draw_pie(self.pie1, circle_bounds) self.draw_pie(self.pie2, circle_bounds2)
def draw_graph(self, context): for x1, x2, h1, h2 in self.data: x1 *= context.xfactor x2 *= context.xfactor h1 *= context.yfactor h2 *= context.yfactor # Compute and fill past and future rectangles different_side = (h1 >= 0) != (h2 >= 0) past_rect = Rect(x1, 0, x2 - x1, abs(h1)) if h2: future_height = abs(h2 if different_side else h2 - h1) else: future_height = 0 future_rect = Rect(x1, 0, x2 - x1, future_height) if h1 >= 0: past_rect.bottom = h1 else: past_rect.top = h1 if h2 >= 0: future_rect.bottom = h2 else: future_rect.top = h2 self.view.draw_rect(context.trrect(past_rect), None, BrushID.NormalBar) self.view.draw_rect(context.trrect(future_rect), None, BrushID.FutureBar) # Compute and draw rect lines union = past_rect.united(future_rect) if (union.top < 0) and (union.bottom > 0): # we draw 4 sides instead of 3 self.view.draw_rect(context.trrect(union), PenID.Bar, None) else: # One of bottom and top is 0. Use the other one. We're working with floats here, # comparison with 0 are hazardous, so I'm avoiding them. h = union.top if abs(union.top) >= abs( union.bottom) else union.bottom points = [ Point(x1, 0), Point(x1, h), Point(x2, h), Point(x2, 0) ] self.view.draw_polygon(context.trpoints(points), PenID.Bar, None) # draw red line if (h1 != 0) and (h2 != 0): lineY = 0 if different_side else h1 p1 = context.trpoint(Point(x1, lineY)) p2 = context.trpoint(Point(x2, lineY)) context.today_line = ( p1, p2) # will be drawn in draw_graph_after_axis() # We don't draw the X overlay in a bar graph self.draw_axis_overlay_y(context)
def create_element(layout_element): rect = Rect(layout_element.x0, layout_element.y0, layout_element.width, layout_element.height) chars = extract_chars(layout_element) fontsize = get_avg_text_height(chars) text = fix_text(layout_element.get_text()) return TextElement(rect, fontsize, text)
def _draw_mouse_selection(self): if self._last_mouse_down and self._last_mouse_pos: if self._reorder_mode: p1 = self._last_mouse_down p2 = self._last_mouse_pos linewidth = 5 self.view.draw_arrow(Line(p1, p2), linewidth, PageColor.MouseSelection) else: r = Rect.from_corners(self._last_mouse_down, self._last_mouse_pos) self.view.draw_rectangle(r, None, PageColor.MouseSelection)
def _handle_drag_completion(self): if self._reorder_mode: reorder_line = Line(self._last_mouse_down, self._last_mouse_pos) if self.shift_key_held: self._reorder_line_buffer.append(reorder_line) else: self._reorder_following_line([reorder_line]) else: r = Rect.from_corners(self._last_mouse_down, self._last_mouse_pos) self._select_elems_in_rect(r)
def _draw_order_arrows(self): elems = list(self._ordered_elems()) if not elems: return # mark the starting pos firstelem = elems[0] center = self._elem2drawrect[firstelem].center() r = Rect.from_center(center, 10, 10) self.view.draw_rectangle(r, PageColor.ElemOrderArrow, None) linewidth = 1 for elem1, elem2 in trailiter(elems, skipfirst=True): p1 = self._elem2drawrect[elem1].center() p2 = self._elem2drawrect[elem2].center() self.view.draw_arrow(Line(p1, p2), linewidth, PageColor.ElemOrderArrow) linewidth = 5 for line in self._reorder_line_buffer: self.view.draw_arrow(line, linewidth, PageColor.ElemOrderArrow)
def draw_graph(self, context): for x1, x2, h1, h2 in self.data: x1 *= context.xfactor x2 *= context.xfactor h1 *= context.yfactor h2 *= context.yfactor # Compute and fill past and future rectangles different_side = (h1 >= 0) != (h2 >= 0) past_rect = Rect(x1, 0, x2-x1, abs(h1)) if h2: future_height = abs(h2 if different_side else h2-h1) else: future_height = 0 future_rect = Rect(x1, 0, x2-x1, future_height) if h1 >= 0: past_rect.bottom = h1 else: past_rect.top = h1 if h2 >= 0: future_rect.bottom = h2 else: future_rect.top = h2 self.view.draw_rect(context.trrect(past_rect), None, BrushID.NormalBar) self.view.draw_rect(context.trrect(future_rect), None, BrushID.FutureBar) # Compute and draw rect lines union = past_rect.united(future_rect) if (union.top < 0) and (union.bottom > 0): # we draw 4 sides instead of 3 self.view.draw_rect(context.trrect(union), PenID.Bar, None) else: # One of bottom and top is 0. Use the other one. We're working with floats here, # comparison with 0 are hazardous, so I'm avoiding them. h = union.top if abs(union.top) >= abs(union.bottom) else union.bottom points = [Point(x1, 0), Point(x1, h), Point(x2, h), Point(x2, 0)] self.view.draw_polygon(context.trpoints(points), PenID.Bar, None) # draw red line if (h1 != 0) and (h2 != 0): lineY = 0 if different_side else h1 p1 = context.trpoint(Point(x1, lineY)) p2 = context.trpoint(Point(x2, lineY)) context.today_line = (p1, p2) # will be drawn in draw_graph_after_axis() # We don't draw the X overlay in a bar graph self.draw_axis_overlay_y(context)
def _compute_elem_drawrect(self, page_boundaries): if self._last_page_boundaries == page_boundaries: return self._last_page_boundaries = page_boundaries px, py, pw, ph = page_boundaries self._elem2drawrect = {} xratio = pw / self.page.width yratio = ph / self.page.height for elem in self.elements: if elem.state == ElementState.Ignored and self.app.hide_ignored: continue # we don't draw the elem rect = elem.rect adjx = px + (rect.x * xratio) # don't forget that ypos in pdfminer are inverted adjy = py + (ph - ((rect.y+rect.h) * yratio)) adjw = rect.w * xratio adjh = rect.h * yratio self._elem2drawrect[elem] = Rect(adjx, adjy, adjw, adjh)
def trrect(self, r): x, y, w, h = r x += self.xoffset y += self.yoffset return Rect(x, y, w, h)
def draw_chart(self): if not hasattr(self, 'xmax'): # we haven't computed yet return view_rect = Rect(0, 0, *self.view_size) data_width = self.xmax - self.xmin data_height = self.ymax - self.ymin y_labels_width = max( self.view.text_size(label['text'], FontID.AxisLabel)[0] for label in self.ylabels) labels_height = self.view.text_size('', FontID.AxisLabel)[1] title = "{} ({})".format(self.title, self.currency.code) title_width, title_height = self.view.text_size(title, FontID.Title) titley = view_rect.h - self.TITLE_PADDING - title_height graphx = y_labels_width + self.PADDING graphy = labels_height + self.PADDING graph_width = view_rect.w - graphx - self.PADDING graph_height = view_rect.h - graphy - title_height - self.TITLE_PADDING graph_rect = Rect(graphx, graphy, graph_width, graph_height) xfactor = graph_width / data_width yfactor = graph_height / data_height graph_left = round(self.xmin * xfactor) graph_bottom = round(self.ymin * yfactor) if graph_bottom < 0: # We have a graph with negative values and we need some extra space to draw the lowest values graph_bottom -= self.YAXIS_EXTRA_SPACE_ON_NEGATIVE graph_top = round(self.ymax * yfactor) xoffset = graph_rect.left yoffset = -(graph_bottom - graph_rect.y) context = GraphContext(xfactor, yfactor, xoffset, yoffset) self.draw_graph(context) # X/Y axis p1 = context.trpoint(Point(0, graph_bottom)) p2 = context.trpoint(Point(graph_width, graph_bottom)) p3 = context.trpoint(Point(0, graph_top)) self.view.draw_line(p1, p2, PenID.Axis) self.view.draw_line(p1, p3, PenID.Axis) if graph_bottom < 0: p1 = context.trpoint(Point(0, 0)) p2 = context.trpoint(Point(graph_width, 0)) self.view.draw_line(p1, p2, PenID.Axis) # X tickmarks tickBottomY = graph_bottom - self.TICKMARKS_LENGTH for tickPos in self.xtickmarks: tickX = tickPos * xfactor p1 = context.trpoint(Point(tickX, graph_bottom)) p2 = context.trpoint(Point(tickX, tickBottomY)) self.view.draw_line(p1, p2, PenID.Axis) # Y tickmarks tickLeftX = graph_left - self.TICKMARKS_LENGTH for tickPos in self.ytickmarks: tickY = tickPos * yfactor p1 = context.trpoint(Point(graph_left, tickY)) p2 = context.trpoint(Point(tickLeftX, tickY)) self.view.draw_line(p1, p2, PenID.Axis) # X Labels labelY = graph_bottom - labels_height - self.XLABELS_PADDING for label in self.xlabels: labelText = label['text'] labelWidth = self.view.text_size(labelText, FontID.AxisLabel)[0] labelX = (label['pos'] * xfactor) - (labelWidth / 2) text_rect = context.trrect( Rect(labelX, labelY, labelWidth, labels_height)) self.view.draw_text(labelText, text_rect, FontID.AxisLabel) # Y Labels for label in self.ylabels: labelText = label['text'] labelWidth = self.view.text_size(labelText, FontID.AxisLabel)[0] labelX = graph_left - self.YLABELS_PADDING - labelWidth labelY = (label['pos'] * yfactor) - (labels_height / 2) text_rect = context.trrect( Rect(labelX, labelY, labelWidth, labels_height)) self.view.draw_text(labelText, text_rect, FontID.AxisLabel) # Title self.view.draw_text(title, Rect(0, titley, view_rect.w, title_height), FontID.Title) self.draw_graph_after_axis(context)
def rect_from_center(center, size): # Returns a Rect centered on `center` with size `size` w, h = size x = center.x - w / 2 y = center.y - h / 2 return Rect(x, y, w, h)
def str2rect(s): elems = s.split(' ') assert len(elems) == 4 return Rect(*map(float, elems))