📄 rrdgraph.java
字号:
/* ============================================================
* JRobin : Pure java implementation of RRDTool's functionality
* ============================================================
*
* Project Info: http://www.jrobin.org
* Project Lead: Sasa Markovic (saxon@jrobin.org)
*
* Developers: Sasa Markovic (saxon@jrobin.org)
*
*
* (C) Copyright 2003-2005, by Sasa Markovic.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*/
package org.jrobin.graph;
import org.jrobin.core.RrdException;
import org.jrobin.core.Util;
import org.jrobin.data.DataProcessor;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
/**
* Class which actually creates JRobin graphs (does the hard work).
*/
public class RrdGraph implements RrdGraphConstants {
RrdGraphDef gdef;
ImageParameters im = new ImageParameters();
DataProcessor dproc;
ImageWorker worker;
Mapper mapper;
RrdGraphInfo info = new RrdGraphInfo();
/**
* Creates graph from the corresponding {@link RrdGraphDef} object.
*
* @param gdef Graph definition
* @throws IOException Thrown in case of I/O error
* @throws RrdException Thrown in case of JRobin related error
*/
public RrdGraph(RrdGraphDef gdef) throws IOException, RrdException {
this.gdef = gdef;
worker = new ImageWorker(100, 100); // Dummy worker, just to start with something
try {
createGraph();
}
finally {
worker.dispose();
worker = null;
dproc = null;
}
}
/**
* Returns complete graph information in a single object.
*
* @return Graph information (width, height, filename, image bytes, etc...)
*/
public RrdGraphInfo getRrdGraphInfo() {
return info;
}
private void createGraph() throws RrdException, IOException {
boolean lazy = lazyCheck();
if (!lazy || gdef.printStatementCount() != 0) {
fetchData();
resolveTextElements();
if (gdef.shouldPlot() && !lazy) {
calculatePlotValues();
findMinMaxValues();
identifySiUnit();
expandValueRange();
removeOutOfRangeRules();
initializeLimits();
placeLegends();
createImageWorker();
drawBackground();
drawAxis();
drawData();
drawGrid();
drawText();
drawLegend();
drawRules();
gator();
drawOverlay();
saveImage();
}
}
collectInfo();
}
private void collectInfo() {
info.filename = gdef.filename;
info.width = im.xgif;
info.height = im.ygif;
for (CommentText comment : gdef.comments) {
if (comment instanceof PrintText) {
PrintText pt = (PrintText) comment;
if (pt.isPrint()) {
info.addPrintLine(pt.resolvedText);
}
}
}
if (gdef.imageInfo != null) {
info.imgInfo = Util.sprintf(gdef.imageInfo, gdef.filename, im.xgif, im.ygif);
}
}
private void saveImage() throws IOException {
if (!gdef.filename.equals("-")) {
info.bytes = worker.saveImage(gdef.filename, gdef.imageFormat, gdef.imageQuality);
}
else {
info.bytes = worker.getImageBytes(gdef.imageFormat, gdef.imageQuality);
}
}
private void drawOverlay() throws IOException {
if (gdef.overlayImage != null) {
worker.loadImage(gdef.overlayImage);
}
}
private void gator() {
if (!gdef.onlyGraph && gdef.showSignature) {
Font font = new Font(DEFAULT_FONT_NAME, Font.PLAIN, 9);
int x = (int) (im.xgif - 2 - worker.getFontAscent(font));
int y = 4;
worker.transform(x, y, Math.PI / 2);
worker.drawString("Created with JRobin", 0, 0, font, Color.LIGHT_GRAY);
worker.reset();
}
}
private void drawRules() {
worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2);
for (PlotElement pe : gdef.plotElements) {
if (pe instanceof HRule) {
HRule hr = (HRule) pe;
if (hr.value >= im.minval && hr.value <= im.maxval) {
int y = mapper.ytr(hr.value);
worker.drawLine(im.xorigin, y, im.xorigin + im.xsize, y, hr.color, new BasicStroke(hr.width));
}
}
else if (pe instanceof VRule) {
VRule vr = (VRule) pe;
if (vr.timestamp >= im.start && vr.timestamp <= im.end) {
int x = mapper.xtr(vr.timestamp);
worker.drawLine(x, im.yorigin, x, im.yorigin - im.ysize, vr.color, new BasicStroke(vr.width));
}
}
}
worker.reset();
}
private void drawText() {
if (!gdef.onlyGraph) {
if (gdef.title != null) {
int x = im.xgif / 2 - (int) (worker.getStringWidth(gdef.title, gdef.largeFont) / 2);
int y = PADDING_TOP + (int) worker.getFontAscent(gdef.largeFont);
worker.drawString(gdef.title, x, y, gdef.largeFont, gdef.colors[COLOR_FONT]);
}
if (gdef.verticalLabel != null) {
int x = PADDING_LEFT;
int y = im.yorigin - im.ysize / 2 + (int) worker.getStringWidth(gdef.verticalLabel, gdef.smallFont) / 2;
int ascent = (int) worker.getFontAscent(gdef.smallFont);
worker.transform(x, y, -Math.PI / 2);
worker.drawString(gdef.verticalLabel, 0, ascent, gdef.smallFont, gdef.colors[COLOR_FONT]);
worker.reset();
}
}
}
private void drawGrid() {
if (!gdef.onlyGraph) {
Paint shade1 = gdef.colors[COLOR_SHADEA], shade2 = gdef.colors[COLOR_SHADEB];
Stroke borderStroke = new BasicStroke(1);
worker.drawLine(0, 0, im.xgif - 1, 0, shade1, borderStroke);
worker.drawLine(1, 1, im.xgif - 2, 1, shade1, borderStroke);
worker.drawLine(0, 0, 0, im.ygif - 1, shade1, borderStroke);
worker.drawLine(1, 1, 1, im.ygif - 2, shade1, borderStroke);
worker.drawLine(im.xgif - 1, 0, im.xgif - 1, im.ygif - 1, shade2, borderStroke);
worker.drawLine(0, im.ygif - 1, im.xgif - 1, im.ygif - 1, shade2, borderStroke);
worker.drawLine(im.xgif - 2, 1, im.xgif - 2, im.ygif - 2, shade2, borderStroke);
worker.drawLine(1, im.ygif - 2, im.xgif - 2, im.ygif - 2, shade2, borderStroke);
if (gdef.drawXGrid) {
new TimeAxis(this).draw();
}
if (gdef.drawYGrid) {
boolean ok;
if (gdef.altYMrtg) {
ok = new ValueAxisMrtg(this).draw();
}
else if (gdef.logarithmic) {
ok = new ValueAxisLogarithmic(this).draw();
}
else {
ok = new ValueAxis(this).draw();
}
if (!ok) {
String msg = "No Data Found";
worker.drawString(msg,
im.xgif / 2 - (int) worker.getStringWidth(msg, gdef.largeFont) / 2,
(2 * im.yorigin - im.ysize) / 2,
gdef.largeFont, gdef.colors[COLOR_FONT]);
}
}
}
}
private void drawData() throws RrdException {
worker.setAntiAliasing(gdef.antiAliasing);
worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2);
double areazero = mapper.ytr((im.minval > 0.0) ? im.minval : (im.maxval < 0.0) ? im.maxval : 0.0);
double[] x = xtr(dproc.getTimestamps()), lastY = null;
// draw line, area and stack
for (PlotElement plotElement : gdef.plotElements) {
if (plotElement instanceof SourcedPlotElement) {
SourcedPlotElement source = (SourcedPlotElement) plotElement;
double[] y = ytr(source.getValues());
if (source instanceof Line) {
worker.drawPolyline(x, y, source.color, new BasicStroke(((Line) source).width));
}
else if (source instanceof Area) {
worker.fillPolygon(x, areazero, y, source.color);
}
else if (source instanceof Stack) {
Stack stack = (Stack) source;
float width = stack.getParentLineWidth();
if (width >= 0F) {
// line
worker.drawPolyline(x, y, stack.color, new BasicStroke(width));
}
else {
// area
worker.fillPolygon(x, lastY, y, stack.color);
worker.drawPolyline(x, lastY, stack.getParentColor(), new BasicStroke(0));
}
}
else {
// should not be here
throw new RrdException("Unknown plot source: " + source.getClass().getName());
}
lastY = y;
}
}
worker.reset();
worker.setAntiAliasing(false);
}
private void drawAxis() {
if (!gdef.onlyGraph) {
Paint gridColor = gdef.colors[COLOR_GRID];
Paint fontColor = gdef.colors[COLOR_FONT];
Paint arrowColor = gdef.colors[COLOR_ARROW];
Stroke stroke = new BasicStroke(1);
worker.drawLine(im.xorigin + im.xsize, im.yorigin, im.xorigin + im.xsize, im.yorigin - im.ysize,
gridColor, stroke);
worker.drawLine(im.xorigin, im.yorigin - im.ysize, im.xorigin + im.xsize, im.yorigin - im.ysize,
gridColor, stroke);
worker.drawLine(im.xorigin - 4, im.yorigin, im.xorigin + im.xsize + 4, im.yorigin,
fontColor, stroke);
worker.drawLine(im.xorigin, im.yorigin, im.xorigin, im.yorigin - im.ysize,
gridColor, stroke);
worker.drawLine(im.xorigin + im.xsize + 4, im.yorigin - 3, im.xorigin + im.xsize + 4, im.yorigin + 3,
arrowColor, stroke);
worker.drawLine(im.xorigin + im.xsize + 4, im.yorigin - 3, im.xorigin + im.xsize + 9, im.yorigin,
arrowColor, stroke);
worker.drawLine(im.xorigin + im.xsize + 4, im.yorigin + 3, im.xorigin + im.xsize + 9, im.yorigin,
arrowColor, stroke);
}
}
private void drawBackground() throws IOException {
worker.fillRect(0, 0, im.xgif, im.ygif, gdef.colors[COLOR_BACK]);
if (gdef.backgroundImage != null) {
worker.loadImage(gdef.backgroundImage);
}
worker.fillRect(im.xorigin, im.yorigin - im.ysize, im.xsize, im.ysize, gdef.colors[COLOR_CANVAS]);
}
private void createImageWorker() {
worker.resize(im.xgif, im.ygif);
}
private void placeLegends() {
if (!gdef.noLegend && !gdef.onlyGraph) {
int border = (int) (getSmallFontCharWidth() * PADDING_LEGEND);
LegendComposer lc = new LegendComposer(this, border, im.ygif, im.xgif - 2 * border);
im.ygif = lc.placeComments() + PADDING_BOTTOM;
}
}
private void initializeLimits() throws RrdException {
im.xsize = gdef.width;
im.ysize = gdef.height;
im.unitslength = gdef.unitsLength;
if (gdef.onlyGraph) {
if (im.ysize > 64) {
throw new RrdException("Cannot create graph only, height too big");
}
im.xorigin = 0;
}
else {
im.xorigin = (int) (PADDING_LEFT + im.unitslength * getSmallFontCharWidth());
}
if (gdef.verticalLabel != null) {
im.xorigin += getSmallFontHeight();
}
if (gdef.onlyGraph) {
im.yorigin = im.ysize;
}
else {
im.yorigin = PADDING_TOP + im.ysize;
}
mapper = new Mapper(this);
if (gdef.title != null) {
im.yorigin += getLargeFontHeight() + PADDING_TITLE;
}
if (gdef.onlyGraph) {
im.xgif = im.xsize;
im.ygif = im.yorigin;
}
else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -