|
Thanks for your fix! Actually the current code works as designed, it's a low-quality painter with extremely low overhead which paints in almost constant time no matter how many items are to be displayed. Your change implements a better-quality painter which is more sensitive to items count in terms of performance. We're thinking of providing more painters to give the user a choice between performance and display quality, you code might be a basis for the other painters. BTW your changes are hard to read, there's a lot of whitespace and formatting changes in the file which are unrelated to the algorithm modifications. A simple diff without reformatting would be easier to understand. I am not sure if it works as intented. Have a look at the screenshots taken in intervals of few seconds. 1. graph vs graph1: The shape shifts with each tick. Graphs appear or vanish. The cause for broken graphsThe broken graphs results from wrong calculation of deltas in TransformableCanvasComponent.setDataBounds(...) which is invoked when the data starts shifting. Since the values for dx (and dy?) are totaly bogus, I provide a patch which omitts the shifting since dx and dy are set to 0. diff -r d7d9af603a28 lib.profiler.charts/src/org/netbeans/lib/profiler/charts/canvas/TransformableCanvasComponent.java
--- a/lib.profiler.charts/src/org/netbeans/lib/profiler/charts/canvas/TransformableCanvasComponent.java Fri Nov 18 04:06:47 2011 +0100
+++ b/lib.profiler.charts/src/org/netbeans/lib/profiler/charts/canvas/TransformableCanvasComponent.java Tue Dec 06 20:18:44 2011 +0100
@@ -430,9 +430,12 @@
dataBoundsChanged(dataOffsetX, dataOffsetY, dataWidth, dataHeight,
oldDataOffsetX, oldDataOffsetY, oldDataWidth, oldDataHeight);
- dx = dxx + (oldContentsOffsetX - contentsOffsetX) - (offsetX - oldOffsetX);
- dy = dyy + (oldContentsOffsetY - contentsOffsetY) - (offsetY - oldOffsetY);
+// dx = dxx + (oldContentsOffsetX - contentsOffsetX) - (offsetX - oldOffsetX);
+// dy = dyy + (oldContentsOffsetY - contentsOffsetY) - (offsetY - oldOffsetY);
+ // shifting does not work correctly - set it to zero
+ dx = dy = 0;
+
oldScaleX = scaleX;
oldScaleY = scaleY;
XYPainter.javaThere is only a rewrite of one function. Here is again the code for that rewritten function. (Using a diff-ignore-white-space or reformat with your own formatter would show it too). private static int[][] createPoints(XYItem item, Rectangle dirtyArea, SynchronousXYChartContext context, int type, int maxValueOffset) { // even if this looks like a getter - it updates the context and is needed for mouse over info! context.getVisibleBounds(dirtyArea); int valuesCount = item.getValuesCount(); double itemValueFactor = type == TYPE_RELATIVE ? getItemValueFactor(context, maxValueOffset, item.getBounds().height) : 0; int maxValueIndex = 0; int extrema = Integer.MIN_VALUE; for (int x = 0; x < valuesCount; ++x) { int v = Utils.checkedInt(Math.ceil(getYValue(item, x, type, context, itemValueFactor))); if (v > extrema) { extrema = v; maxValueIndex = x; } } // more values than visible? use the visible width int visibleCount = valuesCount; if (visibleCount > context.getViewWidth()) visibleCount = (int) context.getViewWidth(); // use only integers to scale the diagram int valsPerPixel = valuesCount / visibleCount; if (valuesCount > visibleCount * valsPerPixel) { ++valsPerPixel; visibleCount = valuesCount / valsPerPixel; } // + 2 for the polygon - copy this later to match the clip int[] xPoints = new int[visibleCount + 2]; int[] yPoints = new int[visibleCount + 2]; // calculate an offset to get a stable graph. int offset = 0; if (valsPerPixel > 1) { offset = (-maxValueIndex % valsPerPixel); } // start from max at median to the right and in 2nd pass to the left int median = (maxValueIndex + offset) / valsPerPixel; for (int pass = 0, add = 1; pass < 2; ++pass) { int lastExt = Integer.MAX_VALUE; boolean isMax = true; int lastMean = extrema; for (int index = median; index >= 0 && index < visibleCount; index += add) { int dataIndex = index * valsPerPixel; xPoints[index] = Utils.checkedInt(Math.ceil(context.getViewX(item.getXValue(dataIndex)))); dataIndex -= offset; // get the min, max and sum for the values per pixel. int min = Integer.MAX_VALUE; int max = Integer.MIN_VALUE; long sum = 0; for (int delta = 0; delta < valsPerPixel; ++delta) { int effectiveIndex = dataIndex + delta; // skip index out of bounds if (effectiveIndex < 0 || effectiveIndex >= valuesCount) continue; int v = Utils .checkedInt(Math.ceil(getYValue(item, effectiveIndex, type, context, itemValueFactor))); if (v < min) min = v; if (v > max) max = v; sum += v; } if (sum == 0) min = max = lastMean + 0; if (isMax) { // the last was a maximum if (max - lastExt > lastExt - min) { // maximum difference wins - patch previous pixel with mean value yPoints[index - add] = lastMean; yPoints[index] = max; lastExt = max; } else { // first maximum - use it. yPoints[index] = min; lastExt = min; isMax = false; } } else { // last was a minimum if (max - lastExt < lastExt - min) { // minimum difference wins - patch the previous pixel with mean value yPoints[index - add] = lastMean; yPoints[index] = min; lastExt = min; } else { // first minimum - use it yPoints[index] = max; lastExt = max; isMax = true; } } // update the lastMean lastMean = (int) (sum / valsPerPixel); } // change direction add = -add; } return new int[][] { xPoints, yPoints }; } The code style differs from your code since I added comments and applied my formatting. You can also download a patched visualvm at http://franke.ms/download/visualvm_133b1.zip Thanks for your fix! Actually the current code works as designed, Find my most recent fix here: http://franke.ms/download/visualvm_133b2.zip The bug still exists in 1.3.4. To see the bug in action watch this: http://franke.ms/download/20120410_1505_48.avi You can download a patched version at http://franke.ms/download/visualvm_134b1.zip |
||||||||||||||||||||||||||||||||||||||||||||||||||
More improved version - max details and stable graph