How to increase the tooltip area (hotspot)

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
prolaznik22
Posts: 11
Joined: Fri Feb 03, 2006 9:27 pm

How to increase the tooltip area (hotspot)

Post by prolaznik22 » Wed Feb 08, 2006 3:46 pm

Hi,

I have implemented a stacked bar chart with very thin bars. Since the bars are very thin, the tooltip hotspot is very thin. I would like to increase it. Is there any way to this nicely?

Thanks,

Vlad

prolaznik22
Posts: 11
Joined: Fri Feb 03, 2006 9:27 pm

Follow up: found the solution

Post by prolaznik22 » Thu Feb 09, 2006 5:11 pm

For people who may have a similar problem, I have posted my solution to this problem. Basically, the tooltip hotspot is collected from the entities, which are retrieved int the method body of a drawItem, which is located in a renderer class. The piece of code that does this retrieval is:

Code: Select all

 // add an item entity, if this information is being collected
           EntityCollection entities = state.getEntityCollection();
           if (entities != null) {

             addItemEntity(entities, dataset, row, column, bar);
             
           }
In my case, I was using a stackedbarrenderer, so this piece of code comes from that renderer. The hotspot area is based on the width of the bar rectangle (as you can see, this bar gets called in addItemEntity method). Since I am not happy with the width of the bar, I replaced the bar rectangle with my own rectangle, which gets retrieved from my custom hotspot aray. Thus the above code becomes:

Code: Select all

// add an item entity, if this information is being collected
           EntityCollection entities = state.getEntityCollection();
           if (entities != null) {

             addItemEntity(entities, dataset, row, column, [b]hotSpotAreas[column][/b]);
             
           }
       }
My hotSpotAreas array gets populated by calling buildHotSpotAreas, which is located in my customRenderer. The solution looks a little bit messy, but I couldn't do anything simpler. I tried putting invisible panels over hotspot areas, but for some reason the tooltip does not show when I created tooltip listeners on them. It looked like a defect to me (I did find defects swing, and they do happen :)) I tried other ways too, but they didn't work neither. In any case, I hope this helps somebody. My custom renderer is

Code: Select all

class MyStackedBarRenderer extends StackedBarRenderer
  implements
  Cloneable,
  Serializable {

     private boolean renderAsPercentages = false;
     private Rectangle2D [] hotSpotAreas;
     
     MyStackedBarRenderer () {

       super();

     }
     
     private double calculateCategorySize
     (int columnCount, double dataAreaHeight, double margin, double categoryMargin) {
       
       double result = 0.0;
       double available = dataAreaHeight;
       result = available * (1 - 2*margin - categoryMargin);
       return result/columnCount;
       
     }
     
     private double calculateCategoryGapSize (int columnCount, double dataAreaHeight, double categoryMargin) {
       
       double result = 0.0;
       double available = dataAreaHeight;
       result = available * categoryMargin / (columnCount - 1);
       return result;
       
     }

     public void  buildHotSpotAreas
    (int columnCount, double dataAreaWidth, double dataAreaHeight, 
     double dataAreaMinX, double dataAreaMinY, double baseMargin, 
     double categoryBaseMargin,int basis) {

       hotSpotAreas = new Rectangle2D [columnCount];
       double margin = (columnCount/basis)*baseMargin;
       double categoryMargin = (columnCount/basis)*categoryBaseMargin;
       double categorySize = calculateCategorySize(columnCount, dataAreaHeight, margin, categoryMargin);
       double categoryGapWidth = calculateCategoryGapSize (columnCount,dataAreaHeight, categoryMargin);
       double hotSpotYPosition = dataAreaMinY + dataAreaHeight * margin;
       
       for (int i = 0; i < columnCount; i ++) {
       
          hotSpotYPosition = hotSpotYPosition + i * (categorySize + categoryGapWidth);
          hotSpotAreas[i] = new Rectangle ((int)dataAreaMinX, (int)hotSpotYPosition,(int)dataAreaWidth,(int)categorySize);
        
       }
       

     }

    public void
     drawItem(Graphics2D g2, CategoryItemRendererState state, Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis, ValueAxis rangeAxis, CategoryDataset dataset, int row, int column, int pass) {

       Object oldValue = g2.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
       Object newValue = RenderingHints.VALUE_ANTIALIAS_OFF;
       boolean valueChanged = false;
       if (oldValue == null || !oldValue.equals(newValue)) {
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, newValue);
        valueChanged = true;
      }

       System.out.println ("Calling drawItem");
      // nothing is drawn for null values...
       Number dataValue = dataset.getValue(row, column);
       if (dataValue == null) {
           return;
       }

       double value = dataValue.doubleValue();
       double total = 0.0;  // only needed if calculating percentages
       if (this.renderAsPercentages) {
           total = DataUtilities.calculateColumnTotal(dataset, column);
           value = value / total;
       }

       PlotOrientation orientation = plot.getOrientation();
       double barW0 = domainAxis.getCategoryMiddle(
           column, getColumnCount(), dataArea, plot.getDomainAxisEdge()
       ) - state.getBarWidth() / 2.0;

       double positiveBase = getBase();
       double negativeBase = positiveBase;

       for (int i = 0; i < row; i++) {
           Number v = dataset.getValue(i, column);
           if (v != null) {
               double d = v.doubleValue();
               if (this.renderAsPercentages) {
                   d = d / total;
               }
               if (d > 0) {
                   positiveBase = positiveBase + d;
               }
               else {
                   negativeBase = negativeBase + d;
               }
           }
       }

       double translatedBase;
       double translatedValue;
       RectangleEdge location = plot.getRangeAxisEdge();
       if (value >= 0.0) {
           translatedBase = rangeAxis.valueToJava2D(
               positiveBase, dataArea, location
           );
           translatedValue = rangeAxis.valueToJava2D(
               positiveBase + value, dataArea, location
           );
       }
       else {
           translatedBase = rangeAxis.valueToJava2D(
               negativeBase, dataArea, location
           );
           translatedValue = rangeAxis.valueToJava2D(
               negativeBase + value, dataArea, location
           );
       }
       double barL0 = Math.min(translatedBase, translatedValue);
       double barLength = Math.max(
           Math.abs(translatedValue - translatedBase), getMinimumBarLength()
       );

       Rectangle2D bar = null;
       if (orientation == PlotOrientation.HORIZONTAL) {
           bar = new Rectangle2D.Double(
               barL0, barW0, barLength, state.getBarWidth());
       }
       else {
           bar = new Rectangle2D.Double(
               barW0, barL0, state.getBarWidth(), barLength
           );
       }
       if (pass == 0) {
           Paint itemPaint = getItemPaint(row, column);
           GradientPaintTransformer t = getGradientPaintTransformer();
           if (t != null && itemPaint instanceof GradientPaint) {
               itemPaint = t.transform((GradientPaint) itemPaint, bar);
           }
           g2.setPaint(itemPaint);
           g2.fill(bar);
           if (isDrawBarOutline()
                   && state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD) {
               g2.setStroke(getItemOutlineStroke(row, column));
               g2.setPaint(getItemOutlinePaint(row, column));
               g2.draw(bar);
           }

           // add an item entity, if this information is being collected
           EntityCollection entities = state.getEntityCollection();
           if (entities != null) {

             addItemEntity(entities, dataset, row, column, hotSpotAreas[column]);
             
           }
       }
       else if (pass == 1) {
           CategoryItemLabelGenerator generator
               = getItemLabelGenerator(row, column);
           if (generator != null && isItemLabelVisible(row, column)) {
               drawItemLabel(
                   g2, dataset, row, column, plot, generator, bar,
                   (value < 0.0)
               );
           }
       }


     if (valueChanged) {
       g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldValue);
     }

    }


  }

    class ScrollBarListener implements AdjustmentListener {
            public void adjustmentValueChanged(AdjustmentEvent evt) {

     try {

      int val = scrollBar.getValue();
      Plot plot = stackedbarchartpanel.getChart().getPlot();
      CategoryPlot cplot = (CategoryPlot) plot;
      ValueAxis axis = cplot.getRangeAxis();


      if (val > previousVal) {

         axis.setRange
         (axis.getLowerBound() + (val-previousVal)*moveFactor,
          axis.getUpperBound()  + (val-previousVal)*moveFactor);
          currentPosition += (val-previousVal)*moveFactor;
      }else{

         axis.setRange
         (axis.getLowerBound() - (previousVal-val)*moveFactor,
          axis.getUpperBound() - (previousVal-val)*moveFactor);
          currentPosition -= (previousVal-val)*moveFactor;

      }

       previousVal = val;

    } catch (Exception e) {

      e.printStackTrace();

    }
   }
  }
}


Locked