Hi All,
I've searched the forums and have noticed this topic popping up quite often but haven't been able to find an example on how to achieve it.
I would like to be able to give each subtask in a taskseries a separate color. At the moment all tasks and subtasks in a series inherit the color from the series.
Is it possible to do this without having to extend the gantt renderer? If so does anyone have a working example they would like to share?
Sincerely
Gary Gilbert
Gantt Chart subtask color
-
- JFreeChart Project Leader
- Posts: 11734
- Joined: Fri Mar 14, 2003 10:29 am
- antibot: No, of course not.
- Contact:
The subtasks use the series paint. You'd need to modify the GanttRenderer.drawTasks() method to make it behave differently.
A completely different approach you could try is to use the XYTaskDataset (which is more flexible about the number of tasks in a series) then override the getItemPaint() method in the renderer to change the task colours. See XYTaskDatasetDemo1 and XYTaskDatasetDemo2 in the JFreeChart Demo Collection to see how this approach (using an XYPlot and SymbolAxis) is used (you'd still have to write the code for overriding getItemPaint()).
A completely different approach you could try is to use the XYTaskDataset (which is more flexible about the number of tasks in a series) then override the getItemPaint() method in the renderer to change the task colours. See XYTaskDatasetDemo1 and XYTaskDatasetDemo2 in the JFreeChart Demo Collection to see how this approach (using an XYPlot and SymbolAxis) is used (you'd still have to write the code for overriding getItemPaint()).
David Gilbert
JFreeChart Project Leader
Read my blog
Support JFree via the Github sponsorship program
JFreeChart Project Leader
Read my blog
Support JFree via the Github sponsorship program
Hi
Using XYTaskDataset is very simple and flexible.
Unfortunately, I have to use XYBarRenderer, and I can't draw percent of complete for each task.
How can I do to fix this?
By the way, I mentioned in another post about grouping mechanism.
Is it possible, or what should I do, to implement sth like categoryAxis for XYPlot. Especially the method
Best
Martin
I think I have found simple solution:
with this "//" I have marked my changes
Using XYTaskDataset is very simple and flexible.
Unfortunately, I have to use XYBarRenderer, and I can't draw percent of complete for each task.
How can I do to fix this?
By the way, I mentioned in another post about grouping mechanism.
Is it possible, or what should I do, to implement sth like categoryAxis for XYPlot. Especially the method
Code: Select all
setCategoryItemMargin(double a);
Martin
I think I have found simple solution:
with this "//" I have marked my changes
Code: Select all
@Override
public void drawItem(Graphics2D g2, XYItemRendererState state,
Rectangle2D dataArea, PlotRenderingInfo info,
XYPlot plot, ValueAxis domainAxis, ValueAxis rangeAxis,
XYDataset dataset, int series, int item,
CrosshairState crosshairState, int pass) {
if (!getItemVisible(series, item)) {
return;
}
IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset;
//
XYTaskDataset xYTaskDataset = (XYTaskDataset) intervalDataset;
TaskSeriesCollection tsc = xYTaskDataset.getTasks();
TaskSeries ts = tsc.getSeries(series);
Task t = ts.get(item);
//
double value0;
double value1;
if (getUseYInterval()) {
value0 = intervalDataset.getStartYValue(series, item);
value1 = intervalDataset.getEndYValue(series, item);
} else {
value0 = getBase();
value1 = intervalDataset.getYValue(series, item);
}
if (Double.isNaN(value0) || Double.isNaN(value1)) {
return;
}
if (value0 <= value1) {
if (!rangeAxis.getRange().intersects(value0, value1)) {
return;
}
} else {
if (!rangeAxis.getRange().intersects(value1, value0)) {
return;
}
}
double translatedValue0 = rangeAxis.valueToJava2D(value0, dataArea,
plot.getRangeAxisEdge());
double translatedValue1 = rangeAxis.valueToJava2D(value1, dataArea,
plot.getRangeAxisEdge());
double bottom = Math.min(translatedValue0, translatedValue1);
double top = Math.max(translatedValue0, translatedValue1);
double startX = intervalDataset.getStartXValue(series, item);
if (Double.isNaN(startX)) {
return;
}
double endX = intervalDataset.getEndXValue(series, item);
if (Double.isNaN(endX)) {
return;
}
if (startX <= endX) {
if (!domainAxis.getRange().intersects(startX, endX)) {
return;
}
} else {
if (!domainAxis.getRange().intersects(endX, startX)) {
return;
}
}
RectangleEdge location = plot.getDomainAxisEdge();
double translatedStartX = domainAxis.valueToJava2D(startX, dataArea,
location);
double translatedEndX = domainAxis.valueToJava2D(endX, dataArea,
location);
double translatedWidth = Math.max(1, Math.abs(translatedEndX - translatedStartX));
double left = Math.min(translatedStartX, translatedEndX);
if (getMargin() > 0.0) {
double cut = translatedWidth * getMargin();
translatedWidth = translatedWidth - cut;
left = left + cut / 2;
}
Rectangle2D bar = null;
//
Rectangle2D barComplete = null;
//
PlotOrientation orientation = plot.getOrientation();
if (orientation == PlotOrientation.HORIZONTAL) {
// clip left and right bounds to data area
bottom = Math.max(bottom, dataArea.getMinX());
top = Math.min(top, dataArea.getMaxX());
bar = new Rectangle2D.Double(
bottom, left, top - bottom, translatedWidth);
//
barComplete = new Rectangle2D.Double(
bottom, left + translatedWidth / 4,
t.getPercentComplete() * (top - bottom),
translatedWidth / 2);
//
} else if (orientation == PlotOrientation.VERTICAL) {
// clip top and bottom bounds to data area
bottom = Math.max(bottom, dataArea.getMinY());
top = Math.min(top, dataArea.getMaxY());
bar = new Rectangle2D.Double(left, bottom, translatedWidth,
top - bottom);
}
boolean positive = (value1 > 0.0);
boolean inverted = rangeAxis.isInverted();
RectangleEdge barBase;
if (orientation == PlotOrientation.HORIZONTAL) {
if (positive && inverted || !positive && !inverted) {
barBase = RectangleEdge.RIGHT;
} else {
barBase = RectangleEdge.LEFT;
}
} else {
if (positive && !inverted || !positive && inverted) {
barBase = RectangleEdge.BOTTOM;
} else {
barBase = RectangleEdge.TOP;
}
}
/**/
if (getShadowsVisible()) {
getBarPainter().paintBarShadow(g2, this, series, item, bar, barBase,
!getUseYInterval());
}
getBarPainter().paintBar(g2, this, series, item, bar, barBase);
//
g2.setPaint(Color.green);
g2.fill(barComplete);
//
if (isItemLabelVisible(series, item)) {
XYItemLabelGenerator generator = getItemLabelGenerator(series,
item);
drawItemLabel(g2, dataset, series, item, plot, generator, bar,
value1 < 0.0);
}
/**/
// update the crosshair point
double x1 = (startX + endX) / 2.0;
double y1 = dataset.getYValue(series, item);
double transX1 = domainAxis.valueToJava2D(x1, dataArea, location);
double transY1 = rangeAxis.valueToJava2D(y1, dataArea,
plot.getRangeAxisEdge());
int domainAxisIndex = plot.getDomainAxisIndex(domainAxis);
int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis);
updateCrosshairValues(crosshairState, x1, y1, domainAxisIndex,
rangeAxisIndex, transX1, transY1, plot.getOrientation());
EntityCollection entities = state.getEntityCollection();
if (entities != null) {
addEntity(entities, bar, dataset, series, item, 0.0, 0.0);
}
}
Re: Gantt Chart subtask color
I have similar requirement. How do we use XYTaskDataset when createGanttChart expects IntervalCategoryDataset. Can you please help me.
Code: Select all
JFreeChart chart = ChartFactory.createGanttChart(
"Gantt Chart Demo", // chart title
"Task", // domain axis label
"Date", // range axis label
dataset, // data
true, // include legend
true, // tooltips
false // urls
);
Re: Gantt Chart subtask color
Hi
See my code:
Best
Martin
See my code:
Code: Select all
import java.awt.Color;
import java.awt.Font;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.swing.JPopupMenu;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.LegendItem;
import org.jfree.chart.LegendItemCollection;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickMarkPosition;
import org.jfree.chart.axis.SymbolAxis;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.gantt.TaskSeries;
import org.jfree.data.gantt.TaskSeriesCollection;
import org.jfree.data.gantt.XYTaskDataset;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.ui.GradientPaintTransformType;
import org.jfree.ui.Layer;
import org.jfree.ui.StandardGradientPaintTransformer;
import org.jfree.ui.TextAnchor;
/**
*
* @author Marcin
*/
public class JFCTotalMachineLoadTemplate extends PanningChartPanel {
private SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss");
private SimpleDateFormat axisDateFormat = new SimpleDateFormat("yy/MM/dd HH:mm:ss");
private Font font1 = new Font("Helvetica", Font.PLAIN, 22);
private Font font2 = new Font("TimesRoman", Font.PLAIN, 12);
private Font font3 = new Font("Courier", Font.PLAIN, 4);
private Font fontC12 = new Font("Courier", Font.TRUETYPE_FONT | Font.ITALIC, 12);
public JFCTotalMachineLoadTemplate() {
// super(ChartFactory.createXYBarChart(null,
// null, true, null, null,
// PlotOrientation.HORIZONTAL,
// true, false, false));
super(new JFreeChart(new PannableXYPlot()));
PannableXYPlot xYPlot = (PannableXYPlot) getChart().getXYPlot();
xYPlot.setOrientation(PlotOrientation.HORIZONTAL);
setMouseMode(PanningChartPanel.MOUSE_PAN);
prePlotConfig();
}
private void prePlotConfig() {
getChart().removeLegend();
final PannableXYPlot xyPlot = (PannableXYPlot) getChart().getXYPlot();
xyPlot.setRangeAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
xyPlot.setRangeGridlinesVisible(true);
//
EOperationsXYBarRenderer renderer = new EOperationsXYBarRenderer();
EGradientXYBarPainter barPainter = new EGradientXYBarPainter();
renderer.setBarPainter(barPainter);
renderer.setDrawBarOutline(true);
renderer.setAutoPopulateSeriesOutlinePaint(false);
renderer.setBaseOutlinePaint(Color.black, true);
// renderer.setBaseOutlineStroke(new BasicStroke(2, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND), false);
renderer.setUseYInterval(true);
renderer.setGradientPaintTransformer(
new StandardGradientPaintTransformer(GradientPaintTransformType.CENTER_HORIZONTAL));
renderer.setCompletePaint(ColorDefinition.getStateColor(CommonDefinitions.ACTUAL_AMOUNT));
renderer.setIncompletePaint(ColorDefinition.getStateColor(CommonDefinitions.DEFICIT));
xyPlot.setBackgroundAlpha(0f);
xyPlot.setRenderer(renderer);
//
xyPlot.setBackgroundPaint(new Color(0, 0, 0, 0f));
getChart().setBackgroundImageAlpha(0f);
getChart().setBackgroundPaint(new Color(0xFF, 0xFF, 0xFF, 0x00));
// setBackground(new Color(0,0,0,0f));
DateAxis dateAxis = /*(DateAxis) xyPlot.getRangeAxis();//*/ new DateAxis();
dateAxis.setDateFormatOverride(axisDateFormat);
dateAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
xyPlot.setRangeAxes(new DateAxis[]{dateAxis});
//
setInitialDelay(100);
setReshowDelay(100);
setDisplayToolTips(true);
setDismissDelay(20000);
setDoubleBuffered(true);
setAutoscrolls(false);
getChart().setAntiAlias(true);
//domain Yaxis
SymbolAxis yAxis = new SymbolAxis("", new String[]{"Maszyna"});
// yAxis.setCategoryMargin(0.1);
yAxis.setLowerMargin(0.01);
yAxis.setUpperMargin(0.01);
yAxis.setLabel(null);
yAxis.setVisible(true);
//range Xaxis
xyPlot.getRangeAxis().setLabel(null);
xyPlot.setDomainAxis(yAxis);
createLabels();
//// createLegends();
createToolTips();
addsOn();
configPopUpMenu();
/*listerner do zaznaczenia*/
// addChartMouseListener(new ChartMouseListener() {
//
// public void chartMouseClicked(ChartMouseEvent event) {
//// throw new UnsupportedOperationException("Not supported yet.");
// }
//
// public void chartMouseMoved(ChartMouseEvent event) {
//// throw new UnsupportedOperationException("Not supported yet.");
// }
// });
/**/
}
private void configPopUpMenu() {
JPopupMenu menu = getPopupMenu();
menu.add(new ResetViewAction(this));
}
private void postPlotConfig() {
Collection markers = getChart().getXYPlot().getRangeMarkers(Layer.FOREGROUND);
for (Iterator valueMarker = markers.iterator(); valueMarker.hasNext();) {
ValueMarker vm = (ValueMarker) valueMarker.next();
vm.setValue(new java.util.Date().getTime());
}
List<String> symbols = new ArrayList<String>();
// SymbolAxis yAxis = (SymbolAxis) getChart().getXYPlot().getDomainAxis();
IntervalXYDataset dataset = (IntervalXYDataset) getChart().getXYPlot().getDataset();
if (dataset != null) {
int seriesCount = dataset.getSeriesCount();
if (seriesCount > 0) {
for (int i = 0; i < seriesCount; i++) {
String seria = (String) dataset.getSeriesKey(i);
symbols.add(i, seria);
}
String sva[] = new String[symbols.size()];
symbols.toArray(sva);
SymbolAxis yAxis = new SymbolAxis("", sva);
getChart().getXYPlot().setDomainAxis(null);
getChart().getXYPlot().setDomainAxis(yAxis);
}
}
}
/**
* Jeżeli parametr <code>ISelectedTaskProperties</code> będzie nullem to załadują się domyślne ustawienia zaznaczenia.
* Przy wartościach innych niż null, nalezy pamiętać o ustawieniu:
* slected -- IllegalArgumentException, InnerPaint i OutLine Paint - NullPointerException!!
* np.<code> List tmp = new ArrayList<Pair<IOperation, ISelectedTaskProperties>>();
<br>tmp.add(new Pair(new Operations(161), null)); </br>
<br>setSelectedOperation(tmp);</br></code>
* @param iOperation
*/
public void setSelectedOperation(List<Pair<AOperation, ISelectedTaskProperties>> iOperation) {
getChart().setNotify(false);
clearSelection();
XYPlot plot = getChart().getXYPlot();
XYTaskDataset dataset = (XYTaskDataset) plot.getDataset();
TaskSeriesCollection timetable = dataset.getTasks();
for (int i = 0; i < timetable.getSeriesCount(); i++) {
TaskSeries taskSeries = timetable.getSeries(i);
for (ETask<IOperation> obj : (List<ETask<IOperation>>) taskSeries.getTasks()) {
if (obj.getObj() != null) {
for (Pair<AOperation, ISelectedTaskProperties> pair : iOperation) {
if (pair.getFirst().getId() == obj.getObj().getId()) {
if (pair.getLast() == null) {
obj.getSelectedTaskProperties().setSelected(true);
obj.getSelectedTaskProperties().setInnerTaskPaint(pair.getFirst().getStatusColor());
obj.getSelectedTaskProperties().setOutlinePaint(SelectedTaskProperties.DEFAULT_OUTLINE_PAINT);
obj.getSelectedTaskProperties().setOutlineStroke(SelectedTaskProperties.DEFAULT_OUTLINE_STROKE);
} else {
obj.getSelectedTaskProperties().setSelected(pair.getLast().isSelected());
obj.getSelectedTaskProperties().setInnerTaskPaint(pair.getLast().getInnerTaskPaint());
obj.getSelectedTaskProperties().setOutlinePaint(pair.getLast().getOutlinePaint());
obj.getSelectedTaskProperties().setOutlineStroke(pair.getLast().getOutlineStroke());
}
}
}
}
}
}
getChart().setNotify(true);
}
public void clearSelection() {
getChart().setNotify(false);
XYPlot plot = getChart().getXYPlot();
XYTaskDataset dataset = (XYTaskDataset) plot.getDataset();
TaskSeriesCollection timetable = dataset.getTasks();
for (int i = 0; i < timetable.getSeriesCount(); i++) {
TaskSeries taskSeries = timetable.getSeries(i);
for (ETask<IOperation> obj : (List<ETask<IOperation>>) taskSeries.getTasks()) {
if (obj.getObj() != null) {
obj.getSelectedTaskProperties().setSelected(false);
}
}
}
getChart().setNotify(true);
}
/**
* Creates a chart.
*
* @param timetable the timetable to display.
*/
public void updateDataset(IntervalXYDataset timetable) {
getChart().setNotify(false);
XYPlot plot = getChart().getXYPlot();
plot.setDataset(timetable);
postPlotConfig();
getChart().setNotify(true);
}
private void addsOn() {
ValueMarker valueMarker = new ValueMarker(new java.util.Date().getTime());
getChart().getXYPlot().addRangeMarker(valueMarker);
}
private LegendItemCollection createLegends() {
LegendItemCollection legenditemcollection = new LegendItemCollection();
XYPlot xyPlot = getChart().getXYPlot();
LegendItem legenditem = new LegendItem("Czas do utylizacji.", "-",
"Jest to ilość zmian pomniejszona o czasy przezbrojeń i montażu krązków.", "", Plot.DEFAULT_LEGEND_ITEM_BOX,
ColorDefinition.getStateColor(CommonDefinitions.NOMINAL));//Color.blue);
legenditemcollection.add(legenditem);
xyPlot.setFixedLegendItems(legenditemcollection);
return legenditemcollection;
}
private void createToolTips() {
EOperationsXYBarRenderer renderer = (EOperationsXYBarRenderer) (getChart().getXYPlot()).getRenderer();
renderer.setBaseToolTipGenerator(new EStandardXYToolTipGenerator(
"<html>{3}</html>", dateFormat, dateFormat));
renderer.setBaseItemLabelFont(fontC12, true);
}
private void createLabels() {
EOperationsXYBarRenderer renderer = (EOperationsXYBarRenderer) (getChart().getXYPlot()).getRenderer();
renderer.setBaseItemLabelGenerator(new EStandardXYItemLabelGenerator(
"{1} - {2}", dateFormat, dateFormat));
renderer.setBaseItemLabelsVisible(true);
renderer.setBasePositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.CENTER, TextAnchor.CENTER));
renderer.setBaseItemLabelFont(fontC12, true);
}
}
Martin
-
- Posts: 513
- Joined: Wed Sep 12, 2007 3:18 pm
Re: Gantt Chart subtask color
A complete example that overrides the renderer's getItemPaint() method, as suggested by @david.gilbert above, is examined here.