Hello All,
I have created a Gantt Chart. It is coming up fine.
As my Gantt Chart contains Subtasks, my chart is not displaying tooltips for subtasks but it is displaying for tasks.
How to display tooltips for subtasks?
Regards,
SCS
Tooltips for Subtasks in Gantt Chart
-
- JFreeChart Project Leader
- Posts: 11734
- Joined: Fri Mar 14, 2003 10:29 am
- antibot: No, of course not.
- Contact:
Unfortunately the general tooltip mechanism works at the data item level, whereas the subtasks are a level below that. It would be possible to modify the renderer to handle the tooltips, but JFreeChart doesn't do it "out of the box". Sorry.
(Note that it is probably worth scanning through the patches on the SourceForge project page - it's possible that someone already sent a patch to fix this, I don't remember one but that doesn't mean there isn't one).
(Note that it is probably worth scanning through the patches on the SourceForge project page - it's possible that someone already sent a patch to fix this, I don't remember one but that doesn't mean there isn't one).
David Gilbert
JFreeChart Project Leader
Read my blog
Support JFree via the Github sponsorship program
JFreeChart Project Leader


Hey,
I figured out a way to do this by extending the CategoryIntervalTooltipRenderer and adding a field to it so you can set the number of the subtask (which is the Problem because the TooltipGenerator does not know the actual item).
Here is the code, its just a hack, but maybe the approach is helpful.
You also need to override the Renderer to let it set the subIntervalIndex for the ToolTipGenerator:
Hope this helps,
Tom[/code]
I figured out a way to do this by extending the CategoryIntervalTooltipRenderer and adding a field to it so you can set the number of the subtask (which is the Problem because the TooltipGenerator does not know the actual item).
Here is the code, its just a hack, but maybe the approach is helpful.
Code: Select all
import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.Date;
import org.jfree.chart.labels.IntervalCategoryToolTipGenerator;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.IntervalCategoryDataset;
import org.jfree.data.gantt.Task;
import org.jfree.data.gantt.TaskSeriesCollection;
import org.jfree.data.time.TimePeriod;
public class MyIntervalCategoryGanttToolTipGenerator
extends IntervalCategoryToolTipGenerator
{
private int subTaskIndex;
public MyIntervalCategoryGanttToolTipGenerator()
{
super();
subTaskIndex = 0;
}
public MyIntervalCategoryGanttToolTipGenerator(String labelFormat,
NumberFormat format)
{
super(labelFormat, format);
subTaskIndex = 0;
}
public MyIntervalCategoryGanttToolTipGenerator(String labelFormat,
DateFormat format)
{
super(labelFormat, format);
subTaskIndex = 0;
}
/**
* Creates the array of items that can be passed to the
* <code>MessageFormat</code> class for creating labels.
*
* @param dataset the dataset (<code>null</code> not permitted).
* @param row the row index (zero-based).
* @param column the column index (zero-based).
*
* @return The items (never <code>null</code>).
*/
protected Object[] createItemArray(CategoryDataset dataset, int row,
int column)
{
Object[] result = new Object[9];
result[0] = dataset.getRowKey(row).toString();
result[1] = dataset.getColumnKey(column).toString();
Number value = dataset.getValue(row, column);
if (getNumberFormat() != null)
{
result[2] = getNumberFormat().format(value);
}
else if (getDateFormat() != null)
{
result[2] = getDateFormat().format(value);
}
if (dataset instanceof TaskSeriesCollection)
{
try
{
TaskSeriesCollection data = (TaskSeriesCollection) dataset;
Task subTask =
data.getSeries(row).get(column).getSubtask(subTaskIndex);
Date start = subTask.getDuration().getStart();
Date end = subTask.getDuration().getEnd();
if (getNumberFormat() != null)
{
result[3] = getNumberFormat().format(0.0);
result[4] = getNumberFormat().format(0.0);
result[5] = "";
}
else if (getDateFormat() != null)
{
result[3] = getDateFormat().format(start);
result[4] = getDateFormat().format(end);
result[5] =
data.getSeries(row).get(column).getSubtask(subTaskIndex).getDescription();
if (subTask instanceof MySubTask)
{
result[6] = ((MySubTask) subTask).getParam(0);
result[7] = ((MySubTask) subTask).getParam(1);
result[8] = ((MySubTask) subTask).getParam(2);
}
}
}
catch (Exception e)
{
if (getNumberFormat() != null)
{
result[3] = "NO DATA FOUND!";
result[4] = "NO DATA FOUND!";
result[5] = "NO DATA FOUND!";
result[6] = "NO DATA FOUND!";
result[7] = "NO DATA FOUND!";
}
else if (getDateFormat() != null)
{
result[3] = "NO DATA FOUND!";
result[4] = "NO DATA FOUND!";
result[5] = "NO DATA FOUND!";
result[6] = "NO DATA FOUND!";
result[7] = "NO DATA FOUND!";
result[8] = "NO DATA FOUND!";
}
e.printStackTrace();
}
}
else if (dataset instanceof IntervalCategoryDataset)
{
IntervalCategoryDataset icd =
(IntervalCategoryDataset) dataset;
Number start = icd.getStartValue(row, column);
Number end = icd.getEndValue(row, column);
if (getNumberFormat() != null)
{
result[3] = getNumberFormat().format(start);
result[4] = getNumberFormat().format(end);
}
else if (getDateFormat() != null)
{
result[3] = getDateFormat().format(start);
result[4] = getDateFormat().format(end);
}
}
return result;
}
public void setSubTaskIndex(int subTaskIndex)
{
this.subTaskIndex = subTaskIndex;
}
}
Code: Select all
package com.tp.lisa.laborlogistik.auswertung;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.geom.Rectangle2D;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.CategoryItemEntity;
import org.jfree.chart.entity.EntityCollection;
import org.jfree.chart.labels.CategoryItemLabelGenerator;
import org.jfree.chart.labels.CategoryToolTipGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.CategoryItemRendererState;
import org.jfree.chart.renderer.category.GanttRenderer;
import org.jfree.data.gantt.GanttCategoryDataset;
import org.jfree.ui.RectangleEdge;
public class MyGanttRenderer
extends GanttRenderer
{
private Paint unterlastPaint = null;
private Paint ueberlastPaint = null;
private Paint normalPaint = null;
private Paint kritischPaint = null;
public MyGanttRenderer()
{
super();
}
/**
* Draws the tasks/subtasks for one item.
*
* @param g2 the graphics device.
* @param state the renderer state.
* @param dataArea the data plot area.
* @param plot the plot.
* @param domainAxis the domain axis.
* @param rangeAxis the range axis.
* @param dataset the data.
* @param row the row index (zero-based).
* @param column the column index (zero-based).
*/
protected void drawTasks(Graphics2D g2, CategoryItemRendererState state,
Rectangle2D dataArea, CategoryPlot plot,
CategoryAxis domainAxis, ValueAxis rangeAxis,
GanttCategoryDataset dataset, int row,
int column)
{
try
{
int count = dataset.getSubIntervalCount(row, column);
if (count == 0)
{
drawTask(g2, state, dataArea, plot, domainAxis, rangeAxis,
dataset, row, column);
}
for (int subinterval = 0; subinterval < count; subinterval++)
{
RectangleEdge rangeAxisLocation = plot.getRangeAxisEdge();
// value 0
Number value0 = dataset.getStartValue(row, column, subinterval);
if (value0 == null)
{
return;
}
double translatedValue0 =
rangeAxis.valueToJava2D(value0.doubleValue(), dataArea,
rangeAxisLocation);
// value 1
Number value1 = dataset.getEndValue(row, column, subinterval);
if (value1 == null)
{
return;
}
double translatedValue1 =
rangeAxis.valueToJava2D(value1.doubleValue(), dataArea,
rangeAxisLocation);
if (translatedValue1 < translatedValue0)
{
double temp = translatedValue1;
translatedValue1 = translatedValue0;
translatedValue0 = temp;
}
double rectStart =
calculateBarW0(plot, plot.getOrientation(), dataArea,
domainAxis, state, row, column);
double rectLength = Math.abs(translatedValue1 - translatedValue0);
double rectBreadth = state.getBarWidth();
// DRAW THE BARS...
Rectangle2D bar = null;
if (plot.getOrientation() == PlotOrientation.HORIZONTAL)
{
bar =
new Rectangle2D.Double(translatedValue0, rectStart, rectLength,
rectBreadth);
}
else if (plot.getOrientation() == PlotOrientation.VERTICAL)
{
bar =
new Rectangle2D.Double(rectStart, translatedValue0, rectBreadth,
rectLength);
}
Rectangle2D completeBar = null;
Rectangle2D incompleteBar = null;
Number percent =
dataset.getPercentComplete(row, column, subinterval);
double start = getStartPercent();
double end = getEndPercent();
if (percent != null)
{
double p = percent.doubleValue();
if (plot.getOrientation() == PlotOrientation.HORIZONTAL)
{
completeBar =
new Rectangle2D.Double(translatedValue0, rectStart +
start * rectBreadth,
rectLength * p,
rectBreadth * (end - start));
incompleteBar =
new Rectangle2D.Double(translatedValue0 + rectLength *
p,
rectStart + start * rectBreadth,
rectLength * (1 - p),
rectBreadth * (end - start));
}
else if (plot.getOrientation() == PlotOrientation.VERTICAL)
{
completeBar =
new Rectangle2D.Double(rectStart + start * rectBreadth,
translatedValue0 +
rectLength * (1 - p),
rectBreadth * (end - start),
rectLength * p);
incompleteBar =
new Rectangle2D.Double(rectStart + start * rectBreadth,
translatedValue0,
rectBreadth * (end - start),
rectLength * (1 - p));
}
}
Paint seriesPaint = getItemPaint(row, column);
g2.setPaint(seriesPaint);
g2.fill(bar);
if (completeBar != null)
{
g2.setPaint(getCompletePaint());
g2.fill(completeBar);
}
if (incompleteBar != null)
{
g2.setPaint(getIncompletePaint());
g2.fill(incompleteBar);
}
if (isDrawBarOutline() &&
state.getBarWidth() > BAR_OUTLINE_WIDTH_THRESHOLD)
{
g2.setStroke(getItemStroke(row, column));
g2.setPaint(getItemOutlinePaint(row, column));
g2.draw(bar);
}
CategoryItemLabelGenerator generator =
getItemLabelGenerator(row, column);
if (generator != null && isItemLabelVisible(row, column))
{
((MyCategoryGanttItemLabelGenerator) generator).setSubTaskIndex(subinterval);
drawItemLabel(g2, dataset, row, column, plot, generator, bar,
false);
}
// collect entity and tool tip information...
if (state.getInfo() != null)
{
EntityCollection entities = state.getEntityCollection();
if (entities != null)
{
String tip = null;
CategoryToolTipGenerator tooltip = getToolTipGenerator(row, column);
if (tooltip != null)
{
/* --------------------- Here's the change ----------------------------*/
((MyIntervalCategoryGanttToolTipGenerator) tooltip).setSubTaskIndex(subinterval);
tip =
tooltip.generateToolTip( dataset,
row,
column);
}
String url = null;
if (getItemURLGenerator(row, column) != null)
{
url =
getItemURLGenerator(row, column).generateURL(dataset,
row,
column);
}
CategoryItemEntity entity =
new CategoryItemEntity(bar, tip, url, dataset, row,
dataset.getColumnKey(column),
column);
entities.add(entity);
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Hope this helps,
Tom[/code]