def on_draw(self, widget: Gtk.Widget, cr: cairo.Context) -> bool: if self.frozen: return False if not self.row.valid(): if self.sig is not None: self.tw.disconnect(self.sig) self.sig = None return False path = self.row.get_path() color = self.stylecontext.get_background_color(Gtk.StateFlags.NORMAL) if not self.columns: self.columns = self.tw.get_columns() assert self.columns is not None for col in self.columns: rect = self.tw.get_background_area(path, col) cr.rectangle(rect.x, rect.y, rect.width, rect.height) cr.clip() cr.set_source_rgba(color.red, color.green, color.blue, 1.0 - self.get_state()) cr.set_operator(cairo.OPERATOR_OVER) cr.paint() return False
def on_draw(self, widget: Widget, context: cairo.Context): if not self.is_shape_set: self.layout(context) context.set_font_size(self.font_size) self.shape.draw_on_context(context) context.set_source_rgb(1, 1, 1) context.fill_preserve() context.set_source_rgb(0, 0, 0) context.stroke() shape = self.shape label = self.label if len(label) > 0 and label[-1] == ' ': label += '.' xb, yb, w, h, xa, ya = context.text_extents(label) context.rectangle(shape.start.x + self.padding, shape.start.y, shape.width - self.padding, shape.height) context.clip() context.move_to(shape.start.x + (shape.width - self.padding - w)/2, shape.start.y + shape.height - self.padding) context.show_text(self.label)
def create_surface(self): bw, bh = self.size old_backing = self._backing #should we honour self.depth here? self._backing = None if bw==0 or bh==0: #this can happen during cleanup return None backing = ImageSurface(FORMAT_ARGB32, bw, bh) self._backing = backing cr = Context(backing) if self._alpha_enabled: cr.set_operator(OPERATOR_CLEAR) cr.set_source_rgba(1, 1, 1, 0) else: cr.set_operator(OPERATOR_SOURCE) cr.set_source_rgba(1, 1, 1, 1) cr.rectangle(0, 0, bw, bh) cr.fill() if COPY_OLD_BACKING and old_backing is not None: oldw, oldh = old_backing.get_width(), old_backing.get_height() sx, sy, dx, dy, w, h = self.gravity_copy_coords(oldw, oldh, bw, bh) cr.translate(dx-sx, dy-sy) cr.rectangle(sx, sy, w, h) cr.clip() cr.set_operator(OPERATOR_SOURCE) cr.set_source_surface(old_backing, 0, 0) cr.paint() backing.flush() return cr
def cairo_paint_from_source(self, set_source_fn, source, x: int, y: int, iw: int, ih: int, width: int, height: int, options): """ must be called from UI thread """ backing = self._backing log("cairo_paint_surface%s backing=%s, paint box line width=%i", (set_source_fn, source, x, y, iw, ih, width, height, options), backing, self.paint_box_line_width) if not backing: return gc = Context(backing) if self.paint_box_line_width: gc.save() gc.rectangle(x, y, width, height) gc.clip() gc.set_operator(OPERATOR_CLEAR) gc.rectangle(x, y, width, height) gc.fill() gc.set_operator(OPERATOR_SOURCE) gc.translate(x, y) if iw != width or ih != height: gc.scale(width / iw, height / ih) gc.rectangle(0, 0, width, height) set_source_fn(gc, source, 0, 0) gc.paint() if self.paint_box_line_width: gc.restore() encoding = options.get("encoding") self.cairo_paint_box(gc, encoding, x, y, width, height)
def draw_crown(ctx: cairo.Context, pos_x: float, pos_y: float, radius: float): ctx.arc(pos_x, pos_y, radius, 0, tau) ctx.stroke_preserve() ctx.clip() crown_eclipse = -0.2 eclipse_cy = pos_y + crown_eclipse * 2.0 * radius ctx.arc(pos_x, eclipse_cy, radius, 0, tau) ctx.fill() ctx.reset_clip()
def on_draw(self, widget: Widget, context: cairo.Context): for child in self.list: if child.visible: context.save() context.transform(child.fromWidgetCoords) if child.is_clip_set(): rectangle = child.clip_rectangle context.rectangle(rectangle.start.x, rectangle.start.y, rectangle.width, rectangle.height) context.clip() child.on_draw(self, context) context.restore()
def on_draw(self, widget: Widget, context: cairo.Context): for child in self.list: if child.visible: context.save() context.transform(child.fromWidgetCoords) if child.is_clip_set(): rectangle = child.clip_rectangle context.rectangle(rectangle.start.x,rectangle.start.y, rectangle.width,rectangle.height) context.clip() child.on_draw(self,context) context.restore()
def on_draw(self, _widget: Gtk.Widget, cr: cairo.Context) -> bool: if self.frozen: return False if not self.row.valid(): if self.sig is not None: self.tw.disconnect(self.sig) self.sig = None assert self.tw.liststore is not None path = self.row.get_path() if path is None: return False path = self.tw.filter.convert_child_path_to_path(path) if path is None: return False # FIXME Use Gtk.render_background to render background. # However it does not use the correct colors/gradient. for col in self.columns: bg_rect = self.tw.get_background_area(path, col) rect = self.tw.get_cell_area(path, col) rect.y = bg_rect.y rect.height = bg_rect.height cr.rectangle(rect.x, rect.y, rect.width, rect.height) cr.clip() maybe_selected = self.tw.selected() if maybe_selected is not None: selected = self.tw.liststore.get_path(maybe_selected) == path else: selected = False stylecontext = self.tw.get_style_context() if selected: bg_color = stylecontext.get_background_color( Gtk.StateFlags.SELECTED) else: bg_color = stylecontext.get_background_color(Gtk.StateFlags.NORMAL) cr.set_source_rgb(bg_color.red, bg_color.green, bg_color.blue) cr.paint_with_alpha(1.0 - self.get_state()) return False
def paint_image(self, img, x, y, w, h): #roundtrip via png (yuk) from io import BytesIO png = BytesIO() img.save(png, format="PNG") reader = BytesIO(png.getvalue()) png.close() img = ImageSurface.create_from_png(reader) gc = Context(self.backing) gc.rectangle(x, y, w, h) gc.clip() gc.set_operator(OPERATOR_CLEAR) gc.rectangle(x, y, w, h) gc.fill() gc.set_operator(OPERATOR_SOURCE) gc.translate(x, y) gc.rectangle(0, 0, w, h) gc.set_source_surface(img, x, y) gc.paint()
def draw(self, cr: cairo.Context, drawing_options: DrawingOptions): if self.direction == CurveDirection.left: cy = -self.radius angle1, angle2 = math.pi / 2 - math.tau / self.per_circle, math.pi / 2 else: cy = self.radius angle1, angle2 = -math.pi / 2, math.tau / self.per_circle - math.pi / 2 cr.save() cr.set_source_rgb(0.9, 0.9, 0.9) cr.move_to(0, cy) cr.arc(0, cy, self.radius + 5, angle1, angle2) cr.line_to(0, cy) cr.clip() for i in range(0, self.sleepers + 1): angle = (math.tau / self.per_circle) * (i / self.sleepers) if self.direction == CurveDirection.left: angle = -math.pi / 2 - angle else: angle = angle + math.pi / 2 cr.move_to( -math.cos(angle) * (self.radius - 4), cy - math.sin(angle) * (self.radius - 4), ) cr.line_to( -math.cos(angle) * (self.radius + 4), cy - math.sin(angle) * (self.radius + 4), ) cr.set_line_width(2) cr.set_source_rgb(*drawing_options.sleeper_color) cr.stroke() cr.set_line_width(1) cr.set_source_rgb(*drawing_options.rail_color) cr.arc(0, cy, self.radius - 2.5, angle1, angle2) cr.stroke() cr.arc(0, cy, self.radius + 2.5, angle1, angle2) cr.stroke() cr.restore()
def draw(self, ctx: cairo.Context, eye_radius: float, relative_to=(0, 0)): pos = self.pos - relative_to top_intersection = pos + np.array([0, self.opening / 2]) bottom_intersection = pos - np.array([0, self.opening / 2]) right_point = pos + np.array([self.size, 0]) left_point = pos - np.array([self.size, 0]) center_1, rad_1 = circle_from_3_points(left_point, top_intersection, right_point) center_2, rad_2 = circle_from_3_points(left_point, bottom_intersection, right_point) # Eyelid 1: ctx.push_group() with source(ctx, self.color.to_pattern()): # Restrict drawing area to eyeball: ctx.arc(pos[0], pos[1], eye_radius + 1, 0, math.tau) ctx.clip() ctx.paint() # Sub circle 1: with operator(ctx, cairo.Operator.CLEAR): ctx.arc(center_1[0], center_1[1], rad_1, 0, math.tau) ctx.fill() ctx.reset_clip() with source(ctx, ctx.pop_group()): ctx.paint() # Eyelid 2: ctx.push_group() with source(ctx, self.color.to_pattern()): # Restrict drawing area to eyeball: ctx.arc(pos[0], pos[1], eye_radius + 1, 0, math.tau) ctx.clip() ctx.paint() # Sub circle 2: with operator(ctx, cairo.Operator.CLEAR): ctx.arc(center_2[0], center_2[1], rad_2, 0, math.tau) ctx.fill() ctx.reset_clip() with source(ctx, ctx.pop_group()): ctx.paint()
def do_draw(self, cr: cairo.Context) -> None: viewport_widget_extents = self.props.viewport_widget_extents with cairo_saved(cr): cr.rectangle(*viewport_widget_extents.position, *viewport_widget_extents.size) cr.clip() for ro in self._render_objects: ro.draw(cr) if self.has_focus(): # Draw focus indicator stroke_width = 1 rectangle_pos = viewport_widget_extents.position + ( stroke_width / 2, stroke_width / 2) rectangle_size = viewport_widget_extents.size - (stroke_width, stroke_width) cr.rectangle(*rectangle_pos, *rectangle_size) cr.set_source_rgb(70 / 255, 142 / 255, 220 / 255) cr.set_line_width(stroke_width) cr.stroke()
def draw(self, ctx: cairo.Context, relative_to=(0, 0)): pos = self.pos - relative_to top_intersection = pos + np.array([0, self.size]) bottom_intersection = pos - np.array([0, self.size]) right_edge = pos + np.array([self.width / 2, 0]) left_edge = pos - np.array([self.width / 2, 0]) center_1, rad_1 = circle_from_3_points(top_intersection, right_edge, bottom_intersection) center_2, rad_2 = circle_from_3_points(top_intersection, left_edge, bottom_intersection) ctx.arc(center_1[0], center_1[1], rad_1, 0, math.tau) ctx.clip() ctx.arc(center_2[0], center_2[1], rad_2, 0, math.tau) ctx.clip() ctx.paint() ctx.reset_clip()
def on_draw(self, widget: Widget, context: cairo.Context): if not self.is_shape_set: self.layout(context) context.set_font_size(self.font_size) self.shape.draw_on_context(context) context.set_source_rgb(1, 1, 1) context.fill_preserve() context.set_source_rgb(0, 0, 0) context.stroke() shape = self.shape label = self.label if len(label) > 0 and label[-1] == ' ': label += '.' xb, yb, w, h, xa, ya = context.text_extents(label) context.rectangle(shape.start.x + self.padding, shape.start.y, shape.width - self.padding, shape.height) context.clip() context.move_to(shape.start.x + (shape.width - self.padding - w) / 2, shape.start.y + shape.height - self.padding) context.show_text(self.label)
def on_draw(self, _widget: Gtk.Widget, cr: cairo.Context) -> bool: if self.frozen: return False if not self.row.valid(): self.tw.disconnect(self.sig) self.sig = None path = self.row.get_path() # FIXME Use Gtk.render_background to render background. # However it does not use the correct colors/gradient. for col in self.columns: bg_rect = self.tw.get_background_area(path, col) rect = self.tw.get_cell_area(path, col) rect.y = bg_rect.y rect.height = bg_rect.height cr.rectangle(rect.x, rect.y, rect.width, rect.height) cr.clip() selected = self.selection.get_selected()[1] and \ self.tw.props.model.get_path(self.selection.get_selected()[1]) == path stylecontext = self.tw.get_style_context() if selected: bg_color = stylecontext.get_background_color( Gtk.StateFlags.SELECTED) else: bg_color = stylecontext.get_background_color(Gtk.StateFlags.NORMAL) cr.set_source_rgb(bg_color.red, bg_color.green, bg_color.blue) cr.paint_with_alpha(1.0 - self.get_state()) return False
def draw_moon( ctx: cairo.Context, pos_x: float, pos_y: float, radius: float, eclipse_pct: float = -1.0, ): moon_color = Color(0.9, 0.9, 0.9) ctx.arc(pos_x, pos_y, radius, 0, tau) ctx.stroke_preserve() with source( ctx, moon_color.to_pattern(), ): ctx.fill_preserve() ctx.clip() with source(ctx, Color(0.0, 0.0, 0.0).to_pattern()): eclipse_cx = pos_x + eclipse_pct * 2.0 * radius ctx.arc(eclipse_cx, pos_y, radius, 0, tau) ctx.fill() ctx.reset_clip()
class Canvas: def __init__(self, width: int, height: Optional[int] = None, *, normalise: bool = True): if height is None: height = width self._width = width self._height = height self._surface = ImageSurface(FORMAT_ARGB32, width, height) self._context = Context(self._surface) self._normalise = normalise if self._normalise: self.scale(self._width, self._height) @property def width(self) -> int: return self._width if not self._normalise else 1 @property def height(self) -> int: return self._height if not self._normalise else 1 # TODO depreciate @property def context(self) -> Context: # pragma: no cover return self._context def save(self) -> None: self._context.save() def restore(self) -> None: self._context.restore() # Transformation def rotate(self, angle: float) -> None: self._context.rotate(angle) def translate(self, x: float, y: float) -> None: self._context.translate(x, y) def scale(self, width: int, height: int) -> None: self._context.scale(width, height) def set_line_width(self, width: float) -> None: self._context.set_line_width(width) # Colour functionality def set_colour(self, colour: Colour) -> None: self._context.set_source_rgba(colour.red, colour.blue, colour.green, colour.alpha) def set_grey(self, colour_value: float, alpha: float = 1) -> None: colour = Colour(*(colour_value, ) * 3, alpha) self.set_colour(colour) def set_black(self) -> None: self.set_colour(BLACK) def set_white(self) -> None: self.set_colour(WHITE) def set_background(self, colour: Colour) -> None: self._context.rectangle(0, 0, self.width, self.height) self.set_colour(colour) self._context.fill() def set_line_cap(self, line_cap: LineCap) -> None: self._context.set_line_cap(line_cap.value) def set_line_join(self, line_join: LineJoin) -> None: self._context.set_line_join(line_join.value) def set_fill_rule(self, file_rule: FillRule) -> None: self._context.set_fill_rule(file_rule.value) # Render methods def fill(self, preserve: bool = False) -> None: if not preserve: self._context.fill() else: self._context.fill_preserve() def stroke(self, preserve: bool = False) -> None: if not preserve: self._context.stroke() else: self._context.stroke_preserve() def clip(self) -> None: self._context.clip() def _draw_path(self, path: Iterable[Point], close_path: bool) -> None: self._context.new_sub_path() for p in path: self._context.line_to(*p) if close_path: self._context.close_path() def draw_path(self, path: Iterable[PointType], close_path: bool = False) -> None: points = (p if isinstance(p, Point) else Point(*p) for p in path) self._draw_path(points, close_path) def draw_polygon(self, polygon: Polygon) -> None: self._draw_path(polygon.points, close_path=True) def draw_circle(self, circle: Circle, fill: bool = False, stroke: bool = True) -> None: self._context.new_sub_path() self._context.arc(*circle.centre, circle.radius, 0, 2 * pi) def write_to_png(self, file_name: str) -> None: self._surface.write_to_png(file_name)
def on_draw(self, widget: Widget, context: cairo.Context): self.min_size = 200, 150 super().on_draw(widget, context) context.save() context.set_font_size(self.font_size) if self._table_extents is None: self._update_table_extents(context) skip = max(self.skip, 0) how_many = self.how_many table_extents = self._table_extents title_extents = self._table_extents.title_extents expected_height = title_extents.total_height + self.margin entries = self.entries base = skip up_to = skip over = False while up_to < len(entries) and not over: expected_height += table_extents[up_to].total_height over = expected_height >= self._max_height if not over: up_to += 1 while base > 0 and not over: expected_height += table_extents[base-1].total_height over = expected_height >= self._max_height if not over: base -= 1 how_many = up_to - base skip = base self.base = base entries = self.entries[skip:skip + how_many] def table_extents_iterator(): return table_extents.iter_over( skip, how_many ) start_x, start_y = context.get_current_point() start_y += title_extents.total_height h = title_extents.total_height self.title_height = h for (index, cell), data in zip(enumerate(title_extents), self.title): context.save() offset = title_extents.get_cell_data_left(index) context.rectangle(start_x + offset, start_y - h, cell.width, 2*h) context.clip() context.move_to( start_x + offset, start_y ) context.show_text(data) context.restore() # start_y += self.margin curr_x, curr_y = start_x, start_y# + title_extents.total_height for line_index, (line_extent, entry) in enumerate(zip(table_extents_iterator(), entries)): h = line_extent.total_height curr_y += h if curr_y + self.margin >= self._max_height: break for (cell_index, cell), data in zip(enumerate(line_extent), entry): context.save() offset = line_extent.get_cell_data_left(cell_index) context.rectangle(curr_x + offset, curr_y - h, cell.width, 2*h) context.clip() context.move_to( curr_x + offset, curr_y ) context.show_text(data) context.restore() curr_x = start_x end_x = table_extents.entries_width curr_y = start_y + self.margin end_y = table_extents.get_height_up_to(skip, how_many) + start_y + self.margin + 1 self.table_height = end_y self.table_width = end_x for line in table_extents_iterator(): context.move_to(curr_x, curr_y) context.line_to(end_x, curr_y) context.stroke() curr_y += line.total_height context.move_to(curr_x, curr_y) context.line_to(end_x, curr_y) context.stroke() curr_x = start_x curr_y = start_y - 1 + self.margin if self._how_many > 0: line = table_extents[0] for cell in line: context.move_to(curr_x, curr_y) context.line_to(curr_x, end_y) context.stroke() curr_x += cell.total_width + 2 * self.margin context.move_to(curr_x, curr_y) context.line_to(curr_x, end_y) context.stroke() if self._to_highlight is not None: r, g, b = global_constants.highlight context.set_source_rgba(r, g, b, .6) index = self._to_highlight base = start_y + table_extents.get_height_up_to(skip, index) + self.margin h = table_extents.get_height_of(skip, how_many, index) context.rectangle(start_x, base, table_extents.entries_width, h) context.fill() context.restore() self._shown = how_many
def draw(self, cr: cairo.Context, drawing_options: DrawingOptions): cr.set_source_rgb(*drawing_options.sleeper_color) cr.set_line_width(2) # Main sleepers cr.save() cr.move_to(0, 0) cr.line_to(25, 4 * self.coordinate_sign) cr.line_to(32, 4 * self.coordinate_sign) cr.line_to(32, -4 * self.coordinate_sign) cr.line_to(0, -4 * self.coordinate_sign) cr.close_path() cr.clip() for i in range(0, 36, 4): cr.move_to(i, -4) cr.line_to(i, 4) cr.stroke() cr.restore() # Branch sleepers cr.save() cr.move_to(0, 0) cr.line_to(25, 4 * self.coordinate_sign) cr.line_to(32, 4 * self.coordinate_sign) cr.line_to(40, 4 * self.coordinate_sign) cr.line_to(40, 32 * self.coordinate_sign) cr.line_to(0, 32 * self.coordinate_sign) cr.close_path() cr.clip() # cr.stroke() for i in range(0, 10): x, y, theta = self.point_position("in", i / 9 * self.branch_length, out_anchor="branch") theta += -math.pi / 2 x_off, y_off = math.cos(theta) * 4, math.sin(theta) * 4 cr.move_to(x + x_off, y + y_off) cr.line_to(x - x_off, y - y_off) cr.stroke() cr.restore() if self.state == "out": rail_draw_order = ("branch", "out") else: rail_draw_order = ("out", "branch") cr.save() mask = cairo.ImageSurface( cairo.FORMAT_ARGB32, math.ceil(40 * drawing_options.scale), math.ceil(80 * drawing_options.scale), ) mask_cr = cairo.Context(mask) mask_cr.scale(drawing_options.scale, drawing_options.scale) mask_cr.translate(0, 40) mask_cr.set_source_rgb(0, 1, 0) for anchor_name in rail_draw_order: self.draw_rails_path(mask_cr, anchor_name) mask_cr.set_operator(cairo.OPERATOR_CLEAR) mask_cr.set_line_width(8) mask_cr.stroke_preserve() mask_cr.set_operator(cairo.OPERATOR_SOURCE) mask_cr.set_line_width(6) mask_cr.stroke_preserve() mask_cr.set_operator(cairo.OPERATOR_CLEAR) mask_cr.set_line_width(4) mask_cr.stroke() cr.set_source_rgb(*drawing_options.rail_color) cr.scale(1 / drawing_options.scale, 1 / drawing_options.scale) cr.mask_surface(mask, 0, -40 * drawing_options.scale) cr.restore()
def _paint_panel(self, key, width, height, panel_h): self.db.IUD("update web_stat_panels set HEIGHT = %s where ID = %s" % (panel_h, key)) self.db.commit() color_x_line = (0.7, 0.7, 0.7) color_x_line_2 = (0.9, 0.9, 0.9) color_y_line = (0.9, 0.9, 0.9) color_y_line_date = (0.7, 0.7, 0.7) color_border = (0.5, 0.5, 0.5) left = 40 right = 10 bottom = 15 var_ids = "0" series = [0, 0, 0, 0] typ = 0 for row in self.db.select( "select SERIES_1, SERIES_2, SERIES_3, SERIES_4, TYP " " from web_stat_panels " " where ID = " + str(key) ): series = row var_ids = "%s, %s, %s, %s" % row[0:4] typ = row[4] width, height = int(width), int(height) if width <= 0: width = 300 if height <= 0: height = 150 interval = self.param("range") delta_x = 1 if interval == "-6 hour": delta_x = 6 * 3600 elif interval == "-12 hour": delta_x = 12 * 3600 elif interval == "-1 day": delta_x = 24 * 3600 elif interval == "-3 day": delta_x = 3 * 24 * 3600 elif interval == "-7 day": delta_x = 7 * 24 * 3600 elif interval == "-14 day": delta_x = 14 * 24 * 3600 elif interval == "-30 day": delta_x = 30 * 24 * 3600 elif interval == "-90 day": delta_x = 3 * 30 * 24 * 3600 elif interval == "-180 day": delta_x = 6 * 30 * 24 * 3600 elif interval == "-360 day": delta_x = 12 * 30 * 24 * 3600 min_x = int(self.param("start")) - delta_x // 2 max_x = min_x + delta_x min_x_q = min_x - delta_x # // 100 max_x_q = max_x + delta_x # // 100 max_y = -9999 min_y = 9999 # Делаем полную выборку данных. Выкидываем подозрительные точки и # собираем статистику. prev_vals = [-9999] * 4 chart_data = [[], [], [], []] zoom_step = delta_x / (width * 5) if zoom_step < 1 or typ != 0: zoom_step = 1 x_min_max_values = [] mi_x = max_x_q ma_x = min_x_q tt = -100 for row in self.db.select( "select UNIX_TIMESTAMP(CHANGE_DATE) D, MIN(VALUE) + (MAX(VALUE) - MIN(VALUE)) VALUE, VARIABLE_ID " " from core_variable_changes " " where VARIABLE_ID in (%s) " " and CHANGE_DATE >= FROM_UNIXTIME(%s) " " and CHANGE_DATE <= FROM_UNIXTIME(%s) " " group by 3, ROUND(UNIX_TIMESTAMP(CHANGE_DATE) / %s)" " order by 3, 1 " % (var_ids, min_x_q, max_x_q, zoom_step) ): ind = series.index(row[2]) chart_data[ind] += [row] if row[0] > min_x and row[0] < max_x: max_y = max(max_y, row[1]) min_y = min(min_y, row[1]) if tt == -100: tt = row[2] if tt != row[2]: v = [tt, mi_x, ma_x] x_min_max_values += [v] mi_x = max_x_q ma_x = min_x_q tt = row[2] if row[0] < mi_x: mi_x = row[0] if row[0] > ma_x: ma_x = row[0] if tt != -1: v = [tt, mi_x, ma_x] x_min_max_values += [v] # print(x_min_max_values) # print(series) """ for row in self.db.select("select UNIX_TIMESTAMP(CHANGE_DATE) D, VALUE, VARIABLE_ID, ID " " from core_variable_changes " " where VARIABLE_ID in (" + var_ids + ") " " and CHANGE_DATE >= FROM_UNIXTIME(%s) " " and CHANGE_DATE <= FROM_UNIXTIME(%s) " "order by CHANGE_DATE " % (min_x_q, max_x_q)): """ """ try: self.db.IUD("set @rn := 0") sql = ("select UNIX_TIMESTAMP(CHANGE_DATE) D, VALUE, VARIABLE_ID, ID " " from core_variable_changes " " where VARIABLE_ID in (" + var_ids + ") " " and CHANGE_DATE >= FROM_UNIXTIME(%s) " " and CHANGE_DATE <= FROM_UNIXTIME(%s) " "order by CHANGE_DATE " % (min_x_q, max_x_q)) for c in self.db.select("select count(*) c " " from core_variable_changes " " where VARIABLE_ID in (" + var_ids + ") " " and CHANGE_DATE >= FROM_UNIXTIME(%s) " " and CHANGE_DATE <= FROM_UNIXTIME(%s) " % (min_x_q, max_x_q)): cou = c[0] ccc = 1000 * 4 if cou > ccc: sql = ("select UNIX_TIMESTAMP(CHANGE_DATE) D, VALUE, VARIABLE_ID, ID, @rn := @rn + 1 rownum " " from core_variable_changes " " where VARIABLE_ID in (" + var_ids + ") " " and CHANGE_DATE >= FROM_UNIXTIME(%s) " " and CHANGE_DATE <= FROM_UNIXTIME(%s) " "having mod(rownum, %s) = 0 " "order by VARIABLE_ID, CHANGE_DATE " % (min_x_q, max_x_q, math.ceil(cou / ccc))) for row in self.db.select(sql): ind = series.index(row[2]) prev_vals[ind] = row[1] if abs(prev_vals[ind] - row[1]) < 10: chart_data[ind] += [row] if row[0] > min_x and row[0] < max_x: max_y = max(max_y, row[1]) min_y = min(min_y, row[1]) prev_vals[ind] = row[1] except: pass """ if min_y is None or max_y is None or min_y == 9999 or max_y == -9999 or min_y == max_y: max_y = 1 min_y = 0 min_y = math.floor(min_y) max_y = math.ceil(max_y) if typ == 2: if min_y < 0 and max_y < 0: max_y = 0 elif min_y > 0 and max_y > 0: min_y = 0 # Определяем цвета colors = [[1, 0, 0], [0, 0.65, 0.31], [0, 0, 1], [1, 0, 1]] off_y = (max_y - min_y) / 10 min_y -= off_y max_y += off_y try: kx = (max_x - min_x) / (width - left - right) ky = (max_y - min_y) / (height - bottom) if ky == 0: ky = 1 except: kx, ky = 1, 1 img = ImageSurface(FORMAT_ARGB32, width, height) ctx = Context(img) width -= right ctx.set_line_width(1) # Рисуем сетку ctx.set_font_size(12) try: b_w, b_h = ctx.text_extents("00-00-0000")[2:4] # Метки на оси Y count = math.ceil(max_y) - math.ceil(min_y) space_count = math.ceil(count / ((height - bottom) / (b_h * 1.5))) sc = 0 for i in range(math.ceil(min_y), math.ceil(max_y)): if sc == 0: y = height - bottom + (min_y - i) / ky ctx.set_source_rgb(*(color_x_line)) ctx.move_to(left, y) ctx.line_to(width, y) ctx.stroke() ctx.set_source_rgb(0, 0, 0) num = str(i) tw, th = ctx.text_extents(num)[2:4] ctx.move_to(left - 5 - tw, y + th // 2) ctx.show_text(num) sc = space_count sc -= 1 # Метки на оси Х x_step = 3600 if interval == "-6 hour" or interval == "-12 hour" or interval == "-1 day": # Дополнительно метки часов x_step = 3600 for i in range(math.ceil(min_x / x_step), math.ceil(max_x / x_step)): x = (i * x_step - min_x) / kx + left ctx.set_source_rgb(*(color_x_line_2)) ctx.move_to(x, 0) ctx.line_to(x, height - bottom) ctx.stroke() num = datetime.datetime.fromtimestamp(i * x_step).strftime("%H") tw, th = ctx.text_extents(num)[2:4] ctx.move_to(x + 2, height - bottom - 3) ctx.set_source_rgb(*(color_x_line)) ctx.show_text(num) x_step = 3600 * 24 space_count = 1 count = math.ceil(max_x / x_step) - math.ceil(min_x / x_step) try: if (width / count) < b_w: space_count = 2 except: pass sc = 0 tz = 3600 * 2 tx_prev = -100 for i in range(math.ceil(min_x / x_step), math.ceil(max_x / x_step) + 1): if sc == 0: d_i = datetime.datetime.fromtimestamp(i * x_step) x = (i * x_step - min_x - tz) / kx + left ctx.set_source_rgb(0, 0, 0) num = d_i.strftime("%d-%m-%Y %H") x -= (int(d_i.strftime("%H")) * 3600 - tz) / kx tw, th = ctx.text_extents(num)[2:4] tx = x - tw // 2 ctx.move_to(tx, height - bottom + th + 5) if tx - tx_prev > tw: ctx.show_text(num) tx_prev = tx ctx.set_source_rgb(*(color_y_line_date)) else: ctx.set_source_rgb(*(color_y_line)) if x >= left and x < width: ctx.move_to(x, 0) ctx.line_to(x, height - bottom) ctx.stroke() sc = space_count sc -= 1 except Exception as e: pass # Рисуем верхний и правый бордер ctx.set_source_rgb(*color_border) ctx.move_to(left, 0) ctx.line_to(width, 0) ctx.line_to(width, height - bottom) ctx.stroke() # Рисуем сами графики ctx.rectangle(left, 0, width - left, height) ctx.clip() is_first = True currVarID = -1 prevX = -1 if typ == 0: # Линейная for ind in range(4): """ if len(chart_data[ind]) > 0: for i in range(len(chart_data[ind]) - 1): chart_data[ind][i] = list(chart_data[ind][i]) r1 = chart_data[ind][i] r2 = chart_data[ind][i + 1] chart_data[ind][i][0] += (r2[0] - r1[0]) / 2 chart_data[ind][i][1] += (r2[1] - r1[1]) / 2 """ ctx.set_source_rgb(*colors[ind]) is_first = True for row in chart_data[ind]: x = (row[0] - min_x) / kx + left y = height - bottom - (row[1] - min_y) / ky if is_first: ctx.move_to(x, y) else: if row[0] - prevX > 10000: ctx.move_to(x, y) else: ctx.line_to(x, y) prevX = row[0] is_first = False ctx.stroke() elif typ == 1: # Точечная for ind in range(4): if chart_data[ind]: ctx.set_source_rgb(*colors[ind]) for row in chart_data[ind]: x = (row[0] - min_x) / kx + left y = height - bottom - (row[1] - min_y) / ky ctx.rectangle(x - 3, y - 3, 6, 6) ctx.fill() elif typ == 2: # Столбчатая cy = height - bottom - (-min_y) / ky for ind in range(4): for row in chart_data[ind]: if currVarID != row[2]: ctx.fill() for i in range(4): if series[i] == row[2]: ctx.set_source_rgb(*colors[i]) x = (row[0] - min_x) / kx + left y = height - bottom - (row[1] - min_y) / ky ctx.rectangle(x - 5, y, 10, cy - y) currVarID = row[2] ctx.fill() else: # Линейчастая # one_vals = self._get_one_val(series, min_x_q, max_x_q) one_vals = self._get_one_val(series, x_min_max_values, min_x_q, max_x_q) for ind in range(4): if series[ind]: is_now = True for r in one_vals[ind]: if r[4] == 1: chart_data[ind].insert(0, r) else: chart_data[ind] += [r] is_now = False if is_now: if len(chart_data[ind]) > 0: r = list(chart_data[ind][len(chart_data[ind]) - 1]) r[0] = datetime.datetime.now().timestamp() chart_data[ind] += [r] color = colors[ind] color_fill = color.copy() color_fill += [0.3] is_first = True y0 = height - bottom + min_y / ky for row in chart_data[ind]: x = (row[0] - min_x) / kx + left y = height - bottom - (row[1] - min_y) / ky if is_first: is_first = False else: ctx.set_source_rgb(*color) ctx.move_to(prevX, prevY) ctx.line_to(x, prevY) ctx.line_to(x, y) ctx.stroke() ctx.set_source_rgba(*color_fill) rx, ry, rw, rh = prevX, y0, x - prevX, prevY - y0 ctx.rectangle(rx, ry, rw, rh) ctx.fill() prevX, prevY = x, y # Рисуем оси ctx.set_source_rgb(0, 0, 0) ctx.move_to(left, 0) ctx.line_to(left, height - bottom) ctx.line_to(width, height - bottom) ctx.stroke() # --------------------------- del ctx byt = BytesIO() img.write_to_png(byt) byt.seek(0) return byt.read()