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
How to increase the tooltip area (hotspot)
-
- Posts: 11
- Joined: Fri Feb 03, 2006 9:27 pm
-
- Posts: 11
- Joined: Fri Feb 03, 2006 9:27 pm
Follow up: found the solution
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:
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:
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
// add an item entity, if this information is being collected
EntityCollection entities = state.getEntityCollection();
if (entities != null) {
addItemEntity(entities, dataset, row, column, bar);
}
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]);
}
}

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();
}
}
}
}