Return-Path: Delivered-To: apmail-jakarta-avalon-cvs-archive@apache.org Received: (qmail 27891 invoked from network); 5 Mar 2002 03:53:00 -0000 Received: from unknown (HELO nagoya.betaversion.org) (192.18.49.131) by daedalus.apache.org with SMTP; 5 Mar 2002 03:53:00 -0000 Received: (qmail 11650 invoked by uid 97); 5 Mar 2002 03:53:09 -0000 Delivered-To: qmlist-jakarta-archive-avalon-cvs@jakarta.apache.org Received: (qmail 11603 invoked by uid 97); 5 Mar 2002 03:53:08 -0000 Mailing-List: contact avalon-cvs-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Avalon CVS List" Reply-To: "Avalon Developers List" Delivered-To: mailing list avalon-cvs@jakarta.apache.org Received: (qmail 11586 invoked by uid 97); 5 Mar 2002 03:53:07 -0000 Date: 5 Mar 2002 03:52:56 -0000 Message-ID: <20020305035256.64557.qmail@icarus.apache.org> From: leif@apache.org To: jakarta-avalon-excalibur-cvs@apache.org Subject: cvs commit: jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/gui LineChart.java X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N leif 02/03/04 19:52:56 Modified: src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/gui LineChart.java Log: Made a lot of changes to variable names. Added a bunch of comments and reworked the code a bit. All to make the code actually be readable, Fixed a problem with charts that were displaying very large numbers. They were wrapping when hitting the limits of integer numbers when multiplied by the chart height. Added better formatting of large numbers in labels so that they are more readable. Revision Changes Path 1.4 +196 -153 jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/gui/LineChart.java Index: LineChart.java =================================================================== RCS file: /home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/altprofile/profiler/gui/LineChart.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- LineChart.java 4 Mar 2002 09:17:02 -0000 1.3 +++ LineChart.java 5 Mar 2002 03:52:56 -0000 1.4 @@ -15,6 +15,7 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; +import java.text.DecimalFormat; import java.text.MessageFormat; import java.util.Calendar; import java.util.Date; @@ -24,7 +25,7 @@ * Draws a nice pretty chart given a set of data. * * @author Leif Mortenson - * @version CVS $Revision: 1.3 $ $Date: 2002/03/04 09:17:02 $ + * @version CVS $Revision: 1.4 $ $Date: 2002/03/05 03:52:56 $ * @since 4.1 */ @@ -80,6 +81,12 @@ /** Maximum value in m_values. */ private int m_max; + /** Integer number format. */ + private DecimalFormat m_intFormat = new DecimalFormat( "###,###,###,##0" ); + + /** Decimal number format. */ + private DecimalFormat m_floatFormat = new DecimalFormat( "###,###,###,##0.00" ); + private boolean m_mouseOver; private boolean m_mousePressed; private int m_mouseX; @@ -276,6 +283,11 @@ return format; } + /** + * Paints the component. + * + * @param g Graphics to paint the chart onto. + */ public synchronized void paintComponent( Graphics g ) { Dimension size = getSize(); @@ -286,38 +298,43 @@ size.height - insets.top - insets.bottom ); // Resolve the vertical interval - int vInt = 1; - while ( ( m_max - m_min ) / vInt > 20) + int yLabelInterval = 1; + while ( ( m_max - m_min ) / yLabelInterval > 20) { - vInt *= 10; + yLabelInterval *= 10; } - FontMetrics fm = g.getFontMetrics(); - int hlw = fm.stringWidth( Integer.toString( m_max ) ); - int fh = fm.getAscent(); - int hh = fh / 2; + FontMetrics fontMetrics = g.getFontMetrics(); + int maxYLabelWidth = fontMetrics.stringWidth( m_intFormat.format( m_max ) ); + int fontHeight = fontMetrics.getAscent(); + int fontHalfHeight = fontHeight / 2; - int l = insets.left + hlw + 5; - int t = insets.top + 5; - int w = size.width - l - insets.right - 1 - 5; - int h = size.height - t - insets.bottom - 1 - fh; + int chartLeft = insets.left + maxYLabelWidth + 5; + int chartTop = insets.top + 5; + int chartWidth = size.width - chartLeft - insets.right - 1 - 5; + int chartHeight = size.height - chartTop - insets.bottom - 1 - fontHeight; - // Draw the vertical grid (Left to Right lines) - int lInt = (int)Math.ceil( (float)fh / ( vInt * h / ( m_max - m_min ) ) ); - int lNum = 0; - for ( int i = ( (int)Math.ceil( (float)m_min / vInt ) ) * vInt; i < m_max; i += vInt ) - { - int y = t + h - ( h * ( i - m_min ) / ( m_max - m_min ) ); + // Draw the horizontal grid (Left to Right lines) + int horizonalLineLabeledInterval = (int)Math.ceil( + (float)fontHeight / ( yLabelInterval * chartHeight / ( m_max - m_min ) ) ); + int horizontalLineNumber = 0; + for ( int i = ( (int)Math.ceil( (float)m_min / yLabelInterval ) ) * yLabelInterval; + i < m_max; i += yLabelInterval ) + { + // Calculate the location of the line on the y-axis. Be careful of very large numbers + int y = chartTop + chartHeight - + (int)( (long)chartHeight * ( i - m_min ) / ( m_max - m_min ) ); - if ( lNum >= lInt ) + if ( horizontalLineNumber >= horizonalLineLabeledInterval ) { - lNum = 0; + horizontalLineNumber = 0; } - if ( lNum == 0 ) + if ( horizontalLineNumber == 0 ) { - String lbl = Integer.toString( i ); + String lbl = m_intFormat.format( i ); g.setColor( m_frameColor ); - g.drawString( lbl, l - 5 - fm.stringWidth( lbl ), y + hh ); + g.drawString( lbl, chartLeft - 5 - fontMetrics.stringWidth( lbl ), + y + fontHalfHeight ); g.setColor( m_darkGridColor ); } @@ -325,27 +342,29 @@ { g.setColor( m_lightGridColor ); } - lNum++; + horizontalLineNumber++; - g.drawLine( l, y, l + w, y ); + g.drawLine( chartLeft, y, chartLeft + chartWidth, y ); } - // Draw the horizontal grid (Top to Bottom lines) + // Draw the vertical grid (Top to Bottom lines) // Figure out how wide a label is for formatting. String format = MessageFormat.format( m_format, new String[] { "00", "00","00", "00" } ); - int fw = fm.stringWidth( format ) + 10; + int fw = fontMetrics.stringWidth( format ) + 10; // Figure out what internal of lines we can place labels under. - if ( ( m_values.length > 0 ) && ( w > 0 ) ) + int verticalLineLabeledInterval; + if ( ( m_values.length > 0 ) && ( chartWidth > 0 ) ) { - lInt = (int)Math.ceil( (float)fw / ( m_lineSampleInterval * w / ( m_values.length ) ) ); + verticalLineLabeledInterval = (int)Math.ceil( (float)fw / + ( m_lineSampleInterval * chartWidth / ( m_values.length ) ) ); } else { - lInt = 1; + verticalLineLabeledInterval = 1; } // Calculate a base time for drawing the vertical lines. @@ -354,26 +373,28 @@ ( m_sampleInterval * m_lineSampleInterval ); // Draw each of the lines. - lNum = 0; + int verticalLineNumber = 0; for ( int i = 0; i < m_values.length; i++ ) { long time = m_time - ( m_values.length - i - 1 ) * m_sampleInterval; if ( ( ( ( time - baseTime ) / m_sampleInterval ) % m_lineSampleInterval ) == 0 ) { - int x = l + i * w / ( m_values.length - 1 ); + int x = chartLeft + i * chartWidth / ( m_values.length - 1 ); // Draw a label under the line if line should have a label. - if ( ( lNum >= lInt ) || ( lNum == 0 ) ) + if ( ( verticalLineNumber >= verticalLineLabeledInterval ) || + ( verticalLineNumber == 0 ) ) { format = getFormattedTime( new Date( time ), false ); - if ( x - fm.stringWidth( format ) / 2 >= l ) + if ( x - fontMetrics.stringWidth( format ) / 2 >= chartLeft ) { g.setColor( m_frameColor ); - g.drawString( format, x - fm.stringWidth( format ) / 2, t + h + fh ); + g.drawString( format, x - fontMetrics.stringWidth( format ) / 2, + chartTop + chartHeight + fontHeight ); g.setColor( m_darkGridColor ); - lNum = 1; + verticalLineNumber = 1; } else { @@ -383,11 +404,11 @@ else { g.setColor( m_lightGridColor ); - lNum++; + verticalLineNumber++; } // Draw the vertical line - g.drawLine( x, t, x, t + h ); + g.drawLine( x, chartTop, x, chartTop + chartHeight ); } } @@ -395,10 +416,13 @@ // Draw the frame g.setColor( m_frameColor ); - g.drawLine( l, t, l, t + h ); - g.drawLine( l, t + h, l + w, t + h ); + g.drawLine( chartLeft, chartTop, chartLeft, chartTop + chartHeight ); + g.drawLine( chartLeft, chartTop + chartHeight, chartLeft + chartWidth, + chartTop + chartHeight ); - // Draw the counts + + + // Draw the the values that make up the data of the chart. if ( ( m_averageWindow > 0 ) && ( m_mousePressed ) ) { g.setColor( m_lightLineColor ); @@ -408,164 +432,183 @@ g.setColor( m_lineColor ); } - int lx = 0; - int ly = 0; + int lastX = 0; + int lastY = 0; for ( int i = 0; i < m_values.length; i++ ) { - int x = l + i * w / ( m_values.length - 1 ); - int y = t + h - ( h * ( m_values[i] - m_min ) / ( m_max - m_min ) ); + // Calculate the location of the point on the x-axis. + int x = chartLeft + i * chartWidth / ( m_values.length - 1 ); + + // Calculate the location of the line on the y-axis. Be careful of very large numbers + int y = chartTop + chartHeight - + (int)( (long)chartHeight * ( m_values[i] - m_min ) / ( m_max - m_min ) ); if ( i > 0 ) { - g.drawLine( lx, ly, x, y ); + g.drawLine( lastX, lastY, x, y ); } - lx = x; - ly = y; + lastX = x; + lastY = y; } - // Draw the average chart + // Draw the averaged values of the chart if ( ( m_averageWindow > 0 ) && ( m_mousePressed ) ) { g.setColor( m_lineColor ); - lx = 0; - ly = 0; + lastX = 0; + lastY = 0; for ( int i = m_averageWindow; i < m_averageWindowValues.length; i++ ) { - int x = l + i * w / ( m_averageWindowValues.length - 1 ); - int y = t + h - (int)( h * ( m_averageWindowValues[i] - m_min ) / + // Calculate the location of the point on the x-axis. + int x = chartLeft + i * chartWidth / ( m_averageWindowValues.length - 1 ); + + // Calculate the location of the line on the y-axis. Be careful of very large + // numbers. The float value average valus makes this easy here. + int y = chartTop + chartHeight - + (int)( chartHeight * ( m_averageWindowValues[i] - m_min ) / ( m_max - m_min ) ); if ( i > m_averageWindow ) { - g.drawLine( lx, ly, x, y ); + g.drawLine( lastX, lastY, x, y ); } - lx = x; - ly = y; + lastX = x; + lastY = y; } } // Make the label visible if the user tracks over any part of the chart. - if ( ( m_mouseOver ) && ( m_mouseX >= l ) && ( m_mouseX <= l + w ) ) + if ( ( m_mouseOver ) && ( m_mouseX >= chartLeft ) && + ( m_mouseX <= chartLeft + chartWidth ) ) { - // Figure out where the mouse is - int index = (int)Math.round( (float)( m_values.length - 1 ) * ( m_mouseX - l ) / w ); + // Figure out the index of the data point where the mouse is. + int index = (int)Math.round( + (float)( m_values.length - 1 ) * ( m_mouseX - chartLeft ) / chartWidth ); + + // Draw the label + int mouseDataPointX = 0; + int mouseDataPointY = 0; + String mouseDataPointValue = null; + long mouseDataPointTime = 0; + boolean showLabel = false; + if ( ( m_averageWindow > 0 ) && ( m_mousePressed ) ) { - // Draw the label for the average data if ( ( index >= m_averageWindow ) && ( index < m_averageWindowValues.length ) ) { - int mx = l + index * w / ( m_averageWindowValues.length - 1 ); - int my = t + h - (int)( h * ( m_averageWindowValues[index] - m_min ) / + // Draw the label for the average data + + // Calculate the location of the point on the x-axis. + mouseDataPointX = chartLeft + index * chartWidth / + ( m_averageWindowValues.length - 1 ); + + // Calculate the location of the line on the y-axis. Be careful of very large + // numbers. The float value average valus makes this easy here. + mouseDataPointY = chartTop + chartHeight - + (int)( chartHeight * ( m_averageWindowValues[index] - m_min ) / ( m_max - m_min ) ); - float mc = (float)( (int)( m_averageWindowValues[index] * 100 ) ) / 100; - long mt = m_time - ( m_averageWindowValues.length - index - 1 ) * m_sampleInterval; - g.setColor( m_crossColor ); - g.drawLine( mx, t, mx, t + h ); - g.drawLine( l, my, l + w, my ); - format = mc + " : " + getFormattedTime( new Date( mt ), true ); - int tw = fm.stringWidth( format ); - int ll, lt; + // Round the average value to 2 decimal places. + mouseDataPointValue = m_floatFormat.format( m_averageWindowValues[index] ); - // Decide where to put the label - if ( mx + 5 + tw < l + w ) - { - // Ok on the right - ll = mx + 4; - if ( my + 5 + fh < t + h ) - { - // Ok on the bottom - lt = my + 4; - } - else - { - // Must go on the top - lt = my - 4 - fh; - } - } - else - { - // Must go on the left - ll = mx - 4 - tw; - if ( my + 5 + fh < t + h ) - { - // Ok on the bottom - lt = my + 4; - } - else - { - // Must go on the top - lt = my - 4 - fh; - } - } + // Get the time at the mouse data point + mouseDataPointTime = m_time - + ( m_averageWindowValues.length - index - 1 ) * m_sampleInterval; - // Paint the label - g.setColor( m_maskFrameColor ); - g.drawRect( ll - 1, lt - 1, tw + 2, fh + 2 ); - g.setColor( m_maskColor ); - g.fillRect( ll - 1, lt - 1, tw + 2, fh + 2 ); - g.setColor( m_crossColor ); - g.drawString( format, ll, lt + fh ); + showLabel = true; } } else { - // Draw the label for the regular data if ( ( index >= 0 ) && ( index < m_values.length ) ) { - int mx = l + index * w / ( m_values.length - 1 ); - int my = t + h - ( h * ( m_values[index] - m_min ) / ( m_max - m_min ) ); - int mc = m_values[index]; - long mt = m_time - ( m_values.length - index - 1 ) * m_sampleInterval; - - g.setColor( m_crossColor ); - g.drawLine( mx, t, mx, t + h ); - g.drawLine( l, my, l + w, my ); - format = mc + " : " + getFormattedTime( new Date( mt ), true ); - int tw = fm.stringWidth( format ); - int ll, lt; + // Draw the label for the regular data. + + // Calculate the location of the point on the x-axis. + mouseDataPointX = chartLeft + index * chartWidth / ( m_values.length - 1 ); + + // Calculate the location of the line on the y-axis. Be careful of very large + // numbers. + mouseDataPointY = chartTop + chartHeight - + (int)( (long)chartHeight * ( m_values[index] - m_min ) / + ( m_max - m_min ) ); + + // Get the average value. + mouseDataPointValue = m_intFormat.format( m_values[index] ); + + // Get the time at the mouse data point + mouseDataPointTime = m_time - ( m_values.length - index - 1 ) * + m_sampleInterval; - // Decide where to put the label - if ( mx + 5 + tw < l + w ) + showLabel = true; + } + } + + if ( showLabel ) + { + // Draw a cross at the point being to be labeled. + g.setColor( m_crossColor ); + g.drawLine( mouseDataPointX, chartTop, mouseDataPointX, chartTop + chartHeight ); + g.drawLine( chartLeft, mouseDataPointY, chartLeft + chartWidth, mouseDataPointY ); + + // Get the text of the label + String mouseDataPointLabel = mouseDataPointValue + " : " + + getFormattedTime( new Date( mouseDataPointTime ), true ); + int mouseDataPointLabelWidth = fontMetrics.stringWidth( mouseDataPointLabel ); + int mouseDataPointLabelLeft; + int mouseDataPointLabelTop; + + // If the point is near the edges of the chart, then it would run off the chart. + // To avoid this, the label is moved around relative to the location of the cross. + // Decide where it should go. + if ( mouseDataPointX + 5 + mouseDataPointLabelWidth < chartLeft + chartWidth ) + { + // Ok on the right + mouseDataPointLabelLeft = mouseDataPointX + 4; + if ( mouseDataPointY + 5 + fontHeight < chartTop + chartHeight ) { - // Ok on the right - ll = mx + 4; - if ( my + 5 + fh < t + h ) - { - // Ok on the bottom - lt = my + 4; - } - else - { - // Must go on the top - lt = my - 4 - fh; - } + // Ok on the bottom + mouseDataPointLabelTop = mouseDataPointY + 4; } else { - // Must go on the left - ll = mx - 4 - tw; - if ( my + 5 + fh < t + h ) - { - // Ok on the bottom - lt = my + 4; - } - else - { - // Must go on the top - lt = my - 4 - fh; - } + // Must go on the top + mouseDataPointLabelTop = mouseDataPointY - 4 - fontHeight; } - // Paint the label - g.setColor( m_maskFrameColor ); - g.drawRect( ll - 1, lt - 1, tw + 2, fh + 2 ); - g.setColor( m_maskColor ); - g.fillRect( ll - 1, lt - 1, tw + 2, fh + 2 ); - g.setColor( m_crossColor ); - g.drawString( format, ll, lt + fh ); } + else + { + // Must go on the left + mouseDataPointLabelLeft = mouseDataPointX - 4 - mouseDataPointLabelWidth; + if ( mouseDataPointY + 5 + fontHeight < chartTop + chartHeight ) + { + // Ok on the bottom + mouseDataPointLabelTop = mouseDataPointY + 4; + } + else + { + // Must go on the top + mouseDataPointLabelTop = mouseDataPointY - 4 - fontHeight; + } + } + + // Draw an outline around the location of the label. + g.setColor( m_maskFrameColor ); + g.drawRect( mouseDataPointLabelLeft - 1, mouseDataPointLabelTop - 1, + mouseDataPointLabelWidth + 2, fontHeight + 2 ); + + // Draw the background of the label. By default this is partly transparent and + // looks better on top of the outline. + g.setColor( m_maskColor ); + g.fillRect( mouseDataPointLabelLeft - 1, mouseDataPointLabelTop - 1, + mouseDataPointLabelWidth + 2, fontHeight + 2 ); + + // Draw the text of the label. + g.setColor( m_crossColor ); + g.drawString( mouseDataPointLabel, mouseDataPointLabelLeft, + mouseDataPointLabelTop + fontHeight ); } } } -- To unsubscribe, e-mail: For additional commands, e-mail: