📄 chart.java
字号:
if ( this.legend != null ) { throw new IllegalStateException("Legend already set: " + this.legend); } // Check if the legend is OK if ( legend == null || legend.isEmpty()) { throw new IllegalArgumentException("Legend can't be null or empty"); } // Check if all the elements of the legend are strings for ( Iterator i = legend.iterator(); i.hasNext(); ) { if ( !( i.next() instanceof String ) ) { throw new IllegalArgumentException("All legend entries must be strings: " + legend); } } this.legend = legend; for ( Iterator i = legend.iterator(); i.hasNext(); ) { Object name = i.next(); name2data.put(name, new DataSet(chartLength)); } } public void record(String name, long millis, double value) { DataSet ds = (DataSet)name2data.get(name); if ( ds == null ) { throw new IllegalStateException("Data set not defined for '" + name + "'"); } ds.record(millis, value); adjustVerticalLimits(value); repaint(); lastUpdate = System.currentTimeMillis(); } /** * Adjust the vertical limits, if necessary. * * @param value Incoming data element. * * @see #chartTop * @see #chartBottom */ private void adjustVerticalLimits(double value) { if ( chartTop == null ) { chartTop = new Double(value); } if ( value > chartTop.doubleValue() ) { chartTop = new Double(value); } if ( chartBottom == null ) { chartBottom = new Double(value); } if ( value < chartBottom.doubleValue() ) { chartBottom = new Double(value); } } private class TheChart extends JPanel { TheChart() { setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); } public synchronized void paintComponent(Graphics g) { long startTime = System.currentTimeMillis(); // Draw background super.paintComponent(g); Graphics2D g2d = (Graphics2D)g; // Prepare the background. It is important to remember that the // actual paintable area is the whole panel less the borders, if // any. g2d.setPaint(bgColor); Dimension d = getSize(); Insets i = getInsets(); // Parameters are x0, y0, width, height Rectangle2D.Double background = new Rectangle2D.Double(i.left, i.top, d.width - i.right - i.left, d.height - i.bottom - i.top); g2d.fill(background); // Draw the grid. First goes the horizontal grid (vertical // lines), because it is known. Then, if the data is available, // the placement of the vertical grid (horizontal lines) is // calculated, and the vertical grid is painted. BasicStroke originalStroke = (BasicStroke)g2d.getStroke(); g2d.setPaint(gridColor); float gridDash[] = { 2, 2 }; BasicStroke gridStroke = new BasicStroke(originalStroke.getLineWidth(), originalStroke.getEndCap(), originalStroke.getLineJoin(), originalStroke.getMiterLimit(), gridDash, originalStroke.getDashPhase()); // Vertical lines (horizontal grid) long now = System.currentTimeMillis(); double x_scale = ((double)(d.width - i.left - i.right)) / ((double)chartLength); long x_offset = now - chartLength; Line2D gridLine = null; g2d.setStroke(gridStroke); for ( long timeOffset = now - timeSpacing; timeOffset > now - chartLength; timeOffset -= timeSpacing ) { double gridX = (timeOffset - x_offset) * x_scale + i.left; gridLine = new Line2D.Double(gridX, i.top, gridX, d.height - i.bottom - 1); g2d.draw(gridLine); } if ( legend == null || chartTop == null || chartBottom == null ) { // There's no data yet return; } // Horizontal lines (vertical grid) // VT: FIXME: Nice algorithm has to be engaged here, I don't have it // now... double hi_value = chartTop.doubleValue() + 0.5; double lo_value = chartBottom.doubleValue() - 0.5; double y_scale = ((double)(d.height - i.bottom - i.top)) / (hi_value - lo_value); double y_offset = hi_value; // The zero line gets painted with the default stroke g2d.setStroke(originalStroke); double gridY = y_offset * y_scale + i.top; gridLine = new Line2D.Double(i.left, gridY, d.width - i.right - 1, gridY); g2d.draw(gridLine); // All the rest of the grid lines get painted with a dashed line g2d.setStroke(gridStroke); double valueOffset = 0; for ( valueOffset = valueSpacing; valueOffset < hi_value; valueOffset += valueSpacing ) { gridY = (y_offset - valueOffset) * y_scale + i.top; gridLine = new Line2D.Double(i.left, gridY, d.width - i.right - 1, gridY); g2d.draw(gridLine); } for ( valueOffset = -valueSpacing; valueOffset > lo_value; valueOffset -= valueSpacing ) { gridY = (y_offset - valueOffset) * y_scale + i.top; gridLine = new Line2D.Double(i.left, gridY, d.width - i.right - 1, gridY); g2d.draw(gridLine); } // Paint the curves g2d.setStroke(originalStroke); int legendOffset = i.top + 5; Map values = new HashMap(); for ( Iterator li = legend.iterator(); li.hasNext(); ) { String name = (String)li.next(); DataSet ds = (DataSet)name2data.get(name); if ( ds == null ) { continue; } // Set the color properly Color currentColor = (Color)name2color.get(name); if ( currentColor == null ) { // Normally, this wouldn't happen // VT: FIXME: Maybe allow to set the default "missing" color? currentColor = Color.white; } // Color to paint the dead intervals with Color deadColor = currentColor.darker().darker(); // Flag to reduce the color changes boolean dead = false; g2d.setPaint(currentColor); synchronized ( ds ) { Long time_trailer = null; Double value_trailer = null; for ( Iterator di = ds.iterator(); di.hasNext(); ) { long time_now = ((Long)di.next()).longValue(); double value_now = ds.get(time_now); if ( time_trailer != null ) { double x0 = (time_trailer.longValue() - x_offset) * x_scale + i.left; double y0 = (y_offset - value_trailer.doubleValue()) * y_scale + i.top; double x1 = (time_now - x_offset) * x_scale + i.left; double y1 = (y_offset - value_now) * y_scale + i.top; // Decide whether the line is alive or dead if ( time_now - time_trailer.longValue() > deadTimeout ) { if ( !dead ) { dead = true; g2d.setPaint(deadColor); } // Paint the horizontal line in dead color // and skew the x0 so the next part will be // painted vertical Line2D deadLine = new Line2D.Double(x0, y0, x1, y0); g2d.draw(deadLine); x0 = x1; } if ( dead ) { dead = false; g2d.setPaint(currentColor); } Line2D line = new Line2D.Double(x0, y0, x1, y1); g2d.draw(line); } time_trailer = new Long(time_now); value_trailer = new Double(value_now); } if ( time_trailer != null && now - time_trailer.longValue() > deadTimeout ) { // There's a gap on the right, let's fill it double x0 = (time_trailer.longValue() - x_offset) * x_scale + i.left; double x1 = (now - x_offset) * x_scale + i.left; double y = (y_offset - value_trailer.doubleValue()) * y_scale + i.top; Line2D line = new Line2D.Double(x0, y, x1, y); g2d.setPaint(deadColor); g2d.draw(line); } // Store the values so the readings can be displayed // over the curves if ( value_trailer != null ) { values.put(name, value_trailer); } } } // Draw the current readings for ( Iterator li = legend.iterator(); li.hasNext(); ) { String name = li.next().toString(); Double value = (Double)values.get(name); if ( value != null ) { Color currentColor = (Color)name2color.get(name); if ( currentColor == null ) { // Normally, this wouldn't happen // VT: FIXME: Maybe allow to set the default "missing" color? currentColor = Color.white; } currentColor = currentColor.brighter().brighter(); g2d.setPaint(currentColor); g2d.setFont(smallFont); g2d.drawString(name + " " + net.sf.dz.util.Round.round3(value.doubleValue()), 5, legendOffset += FONT_SIZE); } } g2d.setStroke(originalStroke); //System.err.println("Chart:painted in " + (System.currentTimeMillis() - startTime) + "ms"); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -