/* * create evenly spread out ticks along the y axis. * The ticks are labeled as it goes */ void set_yticks(struct plot *plot, int num_ticks, int first, int last, char *units) { int pixels_per_tick = graph_height / num_ticks; int step = (last - first) / num_ticks; int i; int tick_y = 0; int text_x = axis_x() - 6; int tick_x = axis_x(); char *anchor = "end"; for (i = 0; i < num_ticks; i++) { if (i != 0) { snprintf(line, line_len, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" " "style=\"stroke:lightgray;stroke-width:2;stroke-dasharray:9,12;\"/>\n", tick_x, axis_y_off(tick_y), axis_x_off(graph_width), axis_y_off(tick_y)); write_check(plot->fd, line, strlen(line)); } snprintf(line, line_len, "<text x=\"%d\" y=\"%d\" font-family=\"%s\" font-size=\"%d\" " "fill=\"black\" style=\"text-anchor: %s\">%d%s</text>\n", text_x, axis_y_off(tick_y - tick_font_size / 2), font_family, tick_font_size, anchor, first + step * i, units); write_check(plot->fd, line, strlen(line)); tick_y += pixels_per_tick; } snprintf(line, line_len, "<text x=\"%d\" y=\"%d\" font-family=\"%s\" font-size=\"%d\" " "fill=\"black\" style=\"text-anchor: %s\">%d%s</text>\n", text_x, axis_y_off(graph_height), font_family, tick_font_size, anchor, last, units); write_check(plot->fd, line, strlen(line)); }
/* * this draws a backing rectangle for the plot and it * also creates a new svg element so our offsets can * be relative to this one plot. */ void setup_axis(struct plot *plot) { int len; int fd = plot->fd; int bump_height = tick_font_size * 3 + axis_label_font_size; int local_legend_width = legend_width; if (plot->no_legend) local_legend_width = 0; plot->total_width = axis_x_off(graph_width) + graph_left_pad / 2 + local_legend_width; plot->total_height = axis_y() + tick_label_pad + tick_font_size; if (plot->add_xlabel) plot->total_height += bump_height; /* backing rect */ snprintf(line, line_len, "<rect x=\"%d\" y=\"%d\" width=\"%d\" " "height=\"%d\" fill=\"white\" stroke=\"none\"/>", plot->start_x_offset, plot->start_y_offset, plot->total_width + 40, plot->total_height + 20); len = strlen(line); write_check(fd, line, len); snprintf(line, line_len, "<rect x=\"%d\" y=\"%d\" width=\"%d\" " "filter=\"url(#shadow)\" " "height=\"%d\" fill=\"white\" stroke=\"none\"/>", plot->start_x_offset + 15, plot->start_y_offset, plot->total_width, plot->total_height); len = strlen(line); write_check(fd, line, len); plot->total_height += 20; plot->total_width += 20; if (plot->total_height + plot->start_y_offset > final_height) final_height = plot->total_height + plot->start_y_offset; if (plot->start_x_offset + plot->total_width + 40 > final_width) final_width = plot->start_x_offset + plot->total_width + 40; /* create an svg object for all our coords to be relative against */ snprintf(line, line_len, "<svg x=\"%d\" y=\"%d\">\n", plot->start_x_offset, plot->start_y_offset); write_check(fd, line, strlen(line)); snprintf(line, 1024, "<path d=\"M%d %d h %d V %d H %d Z\" stroke=\"black\" stroke-width=\"2\" fill=\"none\"/>\n", axis_x(), axis_y(), graph_width + graph_inner_x_margin * 2, axis_y_off(graph_height) - graph_inner_y_margin, axis_x()); len = strlen(line); write_check(fd, line, len); }
void set_plot_label(struct plot *plot, char *label) { int len; int fd = plot->fd; snprintf(line, line_len, "<text x=\"%d\" y=\"%d\" font-family=\"%s\" " "font-size=\"%d\" fill=\"black\" style=\"text-anchor: %s\">%s</text>\n", axis_x() + graph_width / 2, plot_label_height / 2, font_family, plot_label_font_size, "middle", label); len = strlen(line); write_check(fd, line, len); }
/* * create evenly spread out ticks along the xaxis. if tick only is set * this just makes the ticks, otherwise it labels each tick as it goes */ void set_xticks(struct plot *plot, int num_ticks, int first, int last) { int pixels_per_tick; double step; int i; int tick_y = axis_y_off(graph_tick_len) + graph_inner_y_margin; int tick_x = axis_x(); int tick_only = plot->add_xlabel == 0; int text_y = axis_y() + tick_label_pad; char *middle = "middle"; char *start = "start"; step = find_step(first, last, num_ticks); /* * We don't want last two ticks to be too close together so subtract * 20% of the step from the interval */ num_ticks = (double)(last - first - step) / step + 1; pixels_per_tick = graph_width * step / (double)(last - first); for (i = 0; i < num_ticks; i++) { char *anchor; if (i != 0) { snprintf(line, line_len, "<rect x=\"%d\" y=\"%d\" width=\"2\" height=\"%d\" style=\"stroke:none;fill:black;\"/>\n", tick_x, tick_y, graph_tick_len); write_check(plot->fd, line, strlen(line)); anchor = middle; } else { anchor = start; } if (!tick_only) { if (step >= 1) snprintf(line, line_len, "<text x=\"%d\" y=\"%d\" font-family=\"%s\" font-size=\"%d\" " "fill=\"black\" style=\"text-anchor: %s\">%d</text>\n", tick_x, text_y, font_family, tick_font_size, anchor, (int)(first + step * i)); else snprintf(line, line_len, "<text x=\"%d\" y=\"%d\" font-family=\"%s\" font-size=\"%d\" " "fill=\"black\" style=\"text-anchor: %s\">%.2f</text>\n", tick_x, text_y, font_family, tick_font_size, anchor, first + step * i); write_check(plot->fd, line, strlen(line)); } tick_x += pixels_per_tick; } if (!tick_only) { if (step >= 1) snprintf(line, line_len, "<text x=\"%d\" y=\"%d\" font-family=\"%s\" font-size=\"%d\" " "fill=\"black\" style=\"text-anchor: middle\">%d</text>\n", axis_x_off(graph_width - 2), text_y, font_family, tick_font_size, last); else snprintf(line, line_len, "<text x=\"%d\" y=\"%d\" font-family=\"%s\" font-size=\"%d\" " "fill=\"black\" style=\"text-anchor: middle\">%.2f</text>\n", axis_x_off(graph_width - 2), text_y, font_family, tick_font_size, (double)last); write_check(plot->fd, line, strlen(line)); } }
QImage Plotter::makePlot() { QImage img=QImage(width,height,QImage::Format_RGB32); img.fill(0xffffff); QPainter painter(&img); painter.setFont(QFont(painter.font().family(),_fs)); //Отступы QFontMetrics metrics(painter.font()); std::vector<int> lens; foreach(QString str,_text_y) lens.push_back(str.size()); float ident_left; std::vector<int>::const_iterator it, it2; for(int i=0;i<lens.size(); i++) { it2 = std::max_element(lens.begin(), lens.end()); if(lens.at(i)==*it2) { ident_left=metrics.width(_text_y[i])+metrics.width(_text_y[i])/5; break; } } float ident_right=metrics.width(_text_x[_text_x.size()-1])+metrics.width(_text_x[_text_x.size()-1])/5; //Шаги и отступы снизу и сверху float step_x=(width-ident_right-ident_left)/_text_x.size(); float step_y=height/(_text_y.size()+1); float ident_bottom=step_y+_fs; float ident_top=step_y+_fs; step_y=(height-ident_top-ident_bottom)/(_text_y.size()); //Оси QLineF axis_x(ident_left,height-ident_bottom,width-ident_right,height-ident_bottom); QLineF axis_y(ident_left,height-ident_bottom,ident_left,ident_top); //Черточки и подписи QVector<QLineF> x_hyphen; float hx_size=step_x/10; float hy_size=step_y/10; QList<QRectF> text_x_pos; QStringList sl_x = _text_x.split(";",QString::SkipEmptyParts); for(int i=0; i<sl_x.size();i++) { if(i<sl_x.size()-1) x_hyphen.append(QLineF(ident_left+(i+1)*step_x,height-ident_bottom-hx_size,ident_left+(i+1)*step_x,height-ident_bottom)); QFontMetrics metrics(painter.font()); if(i==sl_x.size()-1) { text_x_pos.append(QRectF(ident_left+(i+1)*step_x,height-ident_bottom+_fs+hy_size*2,step_x,ident_bottom-_fs-hy_size*2)); //text_x_pos.append(QRectF(x,y,w,h)) } else { //text_x_pos.append(QPointF(ident_left+(i+1)*step_x-metrics.width(text_x[i])/2,height-ident_bottom+font+hy_size*2)) text_x_pos.append(QRectF(ident_left+(i+1)*step_x-metrics.width(sl_x[i])/2,height-ident_bottom+_fs+hy_size*2,step_x,ident_bottom-_fs-hy_size*2)); } } QVector<QLineF> y_hyphen; QList<QPointF> text_y_pos; QStringList sl_y = _text_y.split(";",QString::SkipEmptyParts); for(int i=0; i<sl_y.size();i++) { if(i<sl_y.size()-1) y_hyphen.append(QLineF(ident_left,height-ident_bottom-(i+1)*step_y,ident_left+hy_size,height-ident_bottom-(i+1)*step_y)); QFontMetrics metrics(painter.font()); if(i==sl_y.size()-1) text_y_pos.append(QPointF(ident_left-metrics.width(sl_y[i])/2,ident_top/2+_fs/2)); else text_y_pos.append(QPointF(ident_left-metrics.width(sl_y[i])-hy_size,height-ident_bottom-(i+1)*step_y+_fs/2)); } //Точки графика QVector<QPoint> graph_points; QVector<QLineF> dot_line_x; QVector<QLineF> dot_line_y; int dataCount = scriptEngine->evaluate("results.length").toInteger(); for(int i=0;i<dataCount; i++) { QScriptValue index = QScriptValue(i); scriptEngine->globalObject().setProperty("index",index); float curResult = (float)scriptEngine->evaluate("results[index]").toNumber(); graph_points.append(QPoint(ident_left+step_x*(i+1),height-(ident_bottom+curResult*step_y))); dot_line_x.append(QLineF(QPointF(ident_left,graph_points[graph_points.size()-1].y()),graph_points[graph_points.size()-1])); dot_line_y.append(QLineF(QPointF(graph_points[graph_points.size()-1].x(),height-ident_bottom),graph_points[graph_points.size()-1])); } //Перья для рисования QPen axis_pen(Qt::black); axis_pen.setWidth(4); QPen dot_pen(Qt::black); dot_pen.setWidth(1); dot_pen.setStyle(Qt::DotLine); QPen main_pen(Qt::black); main_pen.setWidth(2); QPen point_pen(Qt::red); point_pen.setWidth(4); //Рисуем //Оси painter.setRenderHint(QPainter::Antialiasing); painter.setPen(axis_pen); painter.drawLine(axis_x); painter.drawLine(axis_y); //Черточки и подписи painter.setPen(main_pen); painter.drawLines(x_hyphen); painter.drawLines(y_hyphen); for(int i=0; i<text_x_pos.size(); i++) { if(i==text_x_pos.size()-1) { QFont nf(painter.font()); nf.setWeight(QFont::Bold); painter.setFont(nf); painter.drawText(text_x_pos[i],QString(sl_x[i])); nf.setWeight(QFont::Normal); painter.setFont(nf); } else painter.drawText(text_x_pos[i],Qt::TextWordWrap,QString(sl_x[i])); } for(int i=0;i<text_y_pos.size();i++) { if(i==text_y_pos.size()-1) { QFont nf(painter.font()); nf.setWeight(QFont::Bold); painter.setFont(nf); painter.drawText(text_y_pos[i],QString(sl_y[i])); nf.setWeight(QFont::Normal); painter.setFont(nf); } else painter.drawText(text_y_pos[i],QString(sl_y[i])); } //График QPolygon p(graph_points); painter.drawPolyline(p); //Пунктирные линии painter.setRenderHint(QPainter::Antialiasing,false); painter.setPen(dot_pen); painter.drawLines(dot_line_x); painter.drawLines(dot_line_y); //Точки графика painter.setRenderHint(QPainter::Antialiasing); painter.setPen(point_pen); painter.drawPoints(p); return img; }