diff --git a/python/views/bar_chart.py b/python/views/bar_chart.py index 6139512fdc43c1b4db48ab79d3ce4e1e3ed11fdd..df23c042cc9c137edd03215db3fe4a4714b83d84 100644 --- a/python/views/bar_chart.py +++ b/python/views/bar_chart.py @@ -97,10 +97,10 @@ class BarChart(QGraphicsItem): # headers painter.drawText(QRectF(0, self.bar_chart_h - 20, - self.value_header_width, 20), + self.header_width, 20), Qt.AlignCenter, self.bar_header) painter.drawText(QRectF(0, self.bar_chart_h - 40, - self.value_header_width, 20), + self.header_width, 20), Qt.AlignCenter, self.value_header) # bar names diff --git a/python/views/gantt_chart.py b/python/views/gantt_chart.py new file mode 100644 index 0000000000000000000000000000000000000000..4a9eb3c15ed259a3cb7245502a7293fbc26df5dd --- /dev/null +++ b/python/views/gantt_chart.py @@ -0,0 +1,136 @@ +from PyQt5.QtCore import QPoint, QRectF, Qt +from PyQt5.QtGui import QPainterPath +from PyQt5.QtGui import QFontMetrics +from PyQt5.QtGui import QFont +from PyQt5.QtWidgets import QGraphicsItem +from next_graphics_index import next_graphics_index + +MAX_BAR_W = 200 +BAR_H = 20 +CHART_Y = 20 + 20 + 20 # 2 titles and spacing + +def _text_width(text): + fm = QFontMetrics(QFont()) # use default font since we do not set it + return fm.horizontalAdvance(text) + +class GanttChart(QGraphicsItem): + Type = next_graphics_index() + + def __init__(self, json_data, default_x, default_y): + super(GanttChart, self).__init__() + + # graphicsItem mode + self.setFlag(QGraphicsItem.ItemIsMovable) + self.setFlag(QGraphicsItem.ItemIsSelectable) + self.setZValue(2) + + # json_data + self._json_data = json_data # keep for export + + # x,y + if json_data["x"] == 0 and json_data["y"] == 0: + self.setPos(QPoint(default_x, default_y)) + else: + self.setPos(QPoint(json_data["x"], json_data["y"])) + + # graph data + data = json_data["data"] + + # title, legend + self.title = data["title"] + self.legend = ", ".join(data["tabs"]) + + # bar values + bars = data["rows"] + self.bar_names = list() + bar_name_widths = list() + self.bar_starts = list() + self.bar_stops = list() + for name, start, stop in bars: + self.bar_names.append(name) + bar_name_widths.append(_text_width(name)) + self.bar_starts.append(start) + self.bar_stops.append(stop) + self.max_bar_value = max(self.bar_stops) + self.max_bar_name_w = max(bar_name_widths) + 4 + self.num_bars = len(bars) + if self.bar_stops: + _max = max(self.bar_stops) + if _max: + self.bar_scale = MAX_BAR_W / _max + else: + self.bar_scale = None + + # chart dimensions + self.gantt_chart_w = max([_text_width(self.title), + _text_width(self.legend), + self.max_bar_name_w + MAX_BAR_W]) + self.gantt_chart_h = CHART_Y + BAR_H * self.num_bars + + # rectangle for mouse sense + self.bounding_path = QPainterPath() + self.bounding_path.addRect(QRectF(0, 0, + self.gantt_chart_w, self.gantt_chart_h)) + + def json_data(self): + self._json_data["x"] = self.x() + self._json_data["y"] = self.y() + return self._json_data + + def type(self): + return GanttChart.Type + + # draw inside this rectangle + def boundingRect(self): + return self.bounding_path.boundingRect().adjusted(-1, -1, 1, 1) + + # mouse hovers when inside this rectangle + def shape(self): + return self.bounding_path + + def paint(self, painter, _option, _widget): + + # title + painter.drawText(QRectF(0, 0, self.gantt_chart_w, 20), Qt.AlignCenter, + self.title) + + # legend + painter.drawText(QRectF(0, 20, self.gantt_chart_w, 20), Qt.AlignCenter, + self.legend) + + # bars + for i in range(len(self.bar_names)): + + # bar names + painter.drawText(QRectF(2, + CHART_Y + BAR_H * i, + self.max_bar_name_w, + BAR_H), + Qt.AlignCenter, self.bar_names[i]) + + # non-zero start time bar value labels + start = self.bar_starts[i] + start_x = start * self.bar_scale + + if start > 0: + painter.drawText(QRectF(self.max_bar_name_w, + CHART_Y + BAR_H * i, + start_x, + BAR_H), + Qt.AlignCenter, "%s"%self.bar_starts[i]) + + # stop time bar value labels + stop = self.bar_stops[i] + stop_x = stop * self.bar_scale + painter.drawText(QRectF(self.max_bar_name_w + start_x, + CHART_Y + BAR_H * i, + stop_x, + BAR_H), + Qt.AlignCenter, "%s"%self.bar_stops[i]) + + # stop time bar + painter.drawRect(self.max_bar_name_w + start_x, + CHART_Y + BAR_H * i, + stop_x, + BAR_H) + diff --git a/python/views/make_views.py b/python/views/make_views.py index 1907dc653dce395aee70ca843b0acbfcebbffa2c..957fe839565da688296987cd3929bf0a6186a9f5 100644 --- a/python/views/make_views.py +++ b/python/views/make_views.py @@ -10,6 +10,7 @@ from views.table import Table from views.activity_diagram import ActivityDiagram from views.graph import Graph from views.bar_chart import BarChart +from views.gantt_chart import GanttChart VIEW_TYPES = {"REPORT", "TABLE", "AD", "GRAPH", "BAR_CHART"} def make_json_views(generated_views): @@ -44,7 +45,14 @@ def make_view(json_view, default_x, default_y): elif json_view["type"] == "GRAPH": view = Graph(json_view, default_x, default_y) elif json_view["type"] == "BAR_CHART": - view = BarChart(json_view, default_x, default_y) + data = json_view["data"] + print("data",data) + if data["ROTATE"] == 0: + view = BarChart(json_view, default_x, default_y) + elif data["ROTATE"] == 1: + view = GanttChart(json_view, default_x, default_y) + else: + print("Unrecognized chart type: %s"%data["ROTATE"]) else: print("Unrecognized view type: %s"%view_type, json_view["type"])