blob: 438909c65867510c5820e44fa1862b672fbb5f90 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.test.performance.ui;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Display;
public class BarGraph {
private static final int MARGIN= 5; // margin on all four sides
private static final int BARHEIGHT= 8; // height of bar
private static final int GAP= 10; // gap between bars
private static final int TGAP= 5; // gap between lines and labels
private static final boolean NO_SCALE= true; //
// if NO_SCALE is true the following values are used:
private static final double RATIO= 0.6; // fraction of width reserved for bar graph; needs tweaking
private static final int FROM_END= 20; // a break (//) is shown this far from end of bar
private static final int SLANT= 8; // slant of break
private static final int GAP2= 5; // width of break
private StringBuffer fAreaBuffer;
private static class BarItem {
String title;
double value;
String url;
String slowdownExpected;
boolean significant;
BarItem(String t, double[] stats, String u, String slow, boolean sig) {
this.title= t;
this.value= stats[0]==0 ? 0 : -stats[0] * 100;
this.url= u;
this.slowdownExpected= slow;
this.significant= sig;
}
}
private String fTitle;
private List fItems;
BarGraph(String title) {
this.fTitle= title;
this.fItems= new ArrayList();
}
public void addItem(String name, double[] stats, String url, String slow, boolean significant) {
this.fItems.add(new BarItem(name, stats, url, slow, significant));
}
public int getHeight() {
int n= this.fItems.size();
int textHeight= 16;
int titleHeight= 0;
if (this.fTitle != null)
titleHeight= textHeight + GAP;
return MARGIN + titleHeight + n * (GAP + BARHEIGHT) + GAP + textHeight + MARGIN;
}
public void paint(Display display, int width, int height, GC gc) {
NumberFormat nf= NumberFormat.getInstance();
BarItem[] bars= (BarItem[]) this.fItems.toArray(new BarItem[this.fItems.size()]);
// draw white background
Color bg= display.getSystemColor(SWT.COLOR_WHITE);
gc.setBackground(bg);
gc.fillRectangle(0, 0, width, height);
// determine the widths of the bar and the label areas
int w;
if (NO_SCALE) {
// we use a fixed width
w= (int) (RATIO * width);
} else {
// we calculate the max width
int maxNameLength= 0;
for (int i= 0; i < bars.length; i++) {
Point es= gc.stringExtent(bars[i].title);
maxNameLength= Math.max(maxNameLength, es.x);
}
w= width - maxNameLength - TGAP - 2 * MARGIN;
}
Color fg= display.getSystemColor(SWT.COLOR_BLACK);
int vstart= 0; // start rows here
if (this.fTitle != null) {
vstart= gc.stringExtent(this.fTitle).y + GAP;
gc.drawString(this.fTitle, MARGIN, MARGIN, true); // draw title left aligned
}
int center= MARGIN + w / 2;
int w2= w / 2 - gc.stringExtent("-999.9").x - TGAP; // reserve space //$NON-NLS-1$
// determine maximum of values
double max= 0.0;
for (int i= 0; i < bars.length; i++)
max= Math.max(max, Math.abs(bars[i].value));
double d;
if (NO_SCALE) {
d= 25;
max= 125;
} else {
if (max > 400.0) {
d= 200;
} else if (max > 200.0) {
d= 100;
} else if (max > 100.0) {
d= 50;
} else if (max > 50) {
d= 25;
} else if (max > 25) {
d= 10;
} else if (max > 10) {
d= 5;
} else if (max > 5) {
d= 2.5;
} else {
d= 1.0;
}
}
// draw striped background
int y= MARGIN + vstart;
Color lightblue= new Color(display, 237, 243, 254);
gc.setBackground(lightblue);
for (int i= 0; i < bars.length; i++)
if (i % 2 == 0)
gc.fillRectangle(0, y + i * (BARHEIGHT + GAP), width, BARHEIGHT + GAP);
// draw grid
int yy= y + bars.length * (BARHEIGHT + GAP);
gc.drawLine(center, y, center, yy + TGAP);
Color grey= display.getSystemColor(SWT.COLOR_GRAY);
for (int i= 1; d * i < max; i++) {
double xx= d * i;
int x= (int) ((xx / max) * w2);
gc.setForeground(grey);
gc.drawLine(center - x, y, center - x, yy + TGAP);
gc.drawLine(center + x, y, center + x, yy + TGAP);
gc.setForeground(fg);
String s3= nf.format(-xx) + "%"; //$NON-NLS-1$
Point es3= gc.stringExtent(s3);
gc.drawString(s3, center - x - es3.x / 2, yy + TGAP, true);
String s4= nf.format(xx) + "%"; //$NON-NLS-1$
Point es4= gc.stringExtent(s4);
gc.drawString(s4, center + x - es4.x / 2, yy + TGAP, true);
}
gc.drawLine(0, yy, w, yy);
nf.setMaximumFractionDigits(1);
// link color
Color blue= display.getSystemColor(SWT.COLOR_BLUE);
// draw bars
// Color green= display.getSystemColor(SWT.COLOR_GREEN);
// Color red= display.getSystemColor(SWT.COLOR_RED);
Color green = new Color(display, 95, 191, 95);
Color red = new Color(display, 225, 50, 50);
Color gray= display.getSystemColor(SWT.COLOR_GRAY);
Color yellow= display.getSystemColor(SWT.COLOR_YELLOW);
Color white= display.getSystemColor(SWT.COLOR_WHITE);
for (int i= 0; i < bars.length; i++) {
BarItem bar= bars[i];
double delta = bar.value;
double orgDelta= delta;
boolean clamped= false;
if (NO_SCALE) {
if (delta > max) {
delta= max;
clamped= true;
} else if (delta < -max) {
delta= -max;
clamped= true;
}
}
int barLength= (int) (delta / max * w2);
if (delta < 0) {
if (bar.slowdownExpected != null) {
gc.setBackground(gray);
} else if (!bar.significant) {
gc.setBackground(yellow);
} else {
gc.setBackground(red);
}
} else if (!bar.significant) {
gc.setBackground(yellow);
} else {
gc.setBackground(green);
}
if (barLength > 0) {
gc.fillRectangle(center, y + (GAP / 2), barLength, BARHEIGHT);
gc.drawRectangle(center, y + (GAP / 2), barLength, BARHEIGHT);
} else if (barLength < 0) {
gc.fillRectangle(center+barLength, y + (GAP / 2), -barLength, BARHEIGHT);
gc.drawRectangle(center+barLength, y + (GAP / 2), -barLength, BARHEIGHT);
}
if (clamped) {
int h2= (BARHEIGHT + GAP);
int x= center + barLength;
if (barLength > 0)
x-= FROM_END;
else
x+= FROM_END - GAP2 - SLANT;
int[] pts= new int[] { x, y + h2 - 1, x + SLANT, y + 1, x + SLANT + GAP2, y + 1, x + GAP2, y + h2 - 1};
if (i % 2 == 0)
gc.setBackground(lightblue);
else
gc.setBackground(white);
gc.fillPolygon(pts);
gc.drawLine(pts[0], pts[1], pts[2], pts[3]);
gc.drawLine(pts[4], pts[5], pts[6], pts[7]);
}
String label= nf.format(orgDelta);
Point labelExtent= gc.stringExtent(label);
int labelxpos= center + barLength;
int labelvpos= y + (BARHEIGHT + GAP - labelExtent.y) / 2;
if (orgDelta > 0.0) {
gc.drawString(label, labelxpos + TGAP, labelvpos, true);
} else {
gc.drawString(label, labelxpos - TGAP - labelExtent.x, labelvpos, true);
}
int x= MARGIN + w + TGAP;
String title= bar.title;
boolean hasURL= bar.url != null;
Color oldfg= gc.getForeground();
if (hasURL) {
gc.setForeground(blue);
Point e= gc.stringExtent(title);
gc.drawLine(x, labelvpos + e.y - 1, x + e.x, labelvpos + e.y - 1);
}
gc.drawString(title, x, labelvpos, true);
if (hasURL)
gc.setForeground(oldfg);
int y0= y;
y+= BARHEIGHT + GAP;
if (hasURL) {
if (this.fAreaBuffer == null)
this.fAreaBuffer= new StringBuffer();
this.fAreaBuffer.append(" echo '<area shape=\"RECT\" coords=\"0," + y0 + ',' + width + ',' + y + "\" href=\"" + bar.url + "\">';\n");
}
}
lightblue.dispose();
red.dispose();
green.dispose();
}
public String getAreas() {
if (this.fAreaBuffer != null) {
String s= this.fAreaBuffer.toString();
this.fAreaBuffer= null;
return s;
}
return null;
}
}