All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.swtchart.Chart Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2008, 2020 SWTChart project.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 * 
 * Contributors:
 * yoshitaka - initial API and implementation
 * Christoph Läubrich - refactor for usage with a generic plot area, add method to print vectors to GC
 *******************************************************************************/
package org.eclipse.swtchart;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.Transform;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swtchart.internal.ChartLayout;
import org.eclipse.swtchart.internal.ChartLayoutData;
import org.eclipse.swtchart.internal.ChartTitle;
import org.eclipse.swtchart.internal.Legend;
import org.eclipse.swtchart.internal.PlotArea;
import org.eclipse.swtchart.internal.Title;
import org.eclipse.swtchart.internal.axis.AxisSet;
import org.eclipse.swtchart.internal.series.SeriesSet;

/**
 * A chart which are composed of title, legend, axes and plot area.
 */
public class Chart extends Canvas implements Listener {

	/** translucent areas flag */
	protected boolean translucent = true;
	/** the title */
	protected final Title title;
	/** the legend */
	protected final Legend legend;
	/** the set of axes */
	protected final AxisSet axisSet;
	/** the plot area */
	protected IPlotArea plotArea;
	/** the orientation of chart which can be horizontal or vertical */
	protected int orientation;
	/** the state indicating if compressing series is enabled */
	protected boolean compressEnabled;
	/** the state indicating if the update of chart appearance is suspended */
	protected boolean updateSuspended;
   /** show/hide multipliers */
   protected boolean useMultipliers = true;
	/** the set of plots */
	protected SeriesSet seriesSet;
   /** cached tick step on Y axis */
   protected double cachedTickStep = 0;
	private final List paintListener = new ArrayList<>();

	/**
	 * Constructor.
	 * 
	 * @param parent
	 *            the parent composite on which chart is placed
	 * @param style
	 *            the style of widget to construct
	 */
	public Chart(Composite parent, int style) {
		this(parent, style, null);
		new PlotArea(this, SWT.NONE);
	}

	/**
	 * This is a constructor allows to opt in for not creating the default plot area and is the recommend way for creating charts
	 * 
Chart c = new Chart(..., null)
	 * new PlotArea(this, SWT.NONE);
	 * 
* because that way we have full control over the creation of the charts Plot area and there is no risk of constructor init order problems * * @param parent * @param style * @param justNull * simply provide null here */ public Chart(Composite parent, int style, Void justNull) { super(parent, style | SWT.DOUBLE_BUFFERED); orientation = SWT.HORIZONTAL; compressEnabled = true; updateSuspended = false; parent.layout(); setLayout(new ChartLayout()); seriesSet = new SeriesSet(this); title = new ChartTitle(this); title.setLayoutData(new ChartLayoutData(SWT.DEFAULT, 100)); legend = new Legend(this, SWT.NONE); legend.setLayoutData(new ChartLayoutData(200, SWT.DEFAULT)); axisSet = new AxisSet(this); addListener(SWT.Resize, this); } /** * Gets the chart title. * * @return the chart title */ public ITitle getTitle() { return title; } /** * Gets the legend. * * @return the legend */ public ILegend getLegend() { return legend; } /** * Gets the set of axes. * * @return the set of axes */ public IAxisSet getAxisSet() { return axisSet; } /** * Gets the plot area. * * @return the plot area */ public IPlotArea getPlotArea() { return plotArea; } /** * Gets the plot area. * * @return the plot area */ public Canvas getPlotAreaControl() { return (Canvas)plotArea; } public void setPlotArea(IPlotArea area) { plotArea = area; updateLayout(); } /** * Gets the set of series. * * @return the set of series */ public ISeriesSet getSeriesSet() { return seriesSet; } /** * Update stack and riser data */ protected void updateStackAndRiserData() { seriesSet.updateStackAndRiserData(); } /** * @see org.eclipse.swt.widgets.Control#setBackground(org.eclipse.swt.graphics.Color) */ @Override public void setBackground(Color color) { super.setBackground(color); for(Control child : getChildren()) { if(!(child instanceof IPlotArea) && !(child instanceof Legend)) { child.setBackground(color); } } } /** * Gets the background color in plot area. This method is identical with * getPlotArea().getBackground(). * * @deprecated use {@link #getPlotArea()} instead to access the plot area directly * @return the background color in plot area */ @Deprecated public Color getBackgroundInPlotArea() { return getPlotArea().getBackground(); } /** * Sets the background color in plot area. * * @param color * the background color in plot area. If null is given, * default background color will be set. * @deprecated use {@link #getPlotArea()} instead to access the plot area directly * @exception IllegalArgumentException * if given color is disposed */ @Deprecated public void setBackgroundInPlotArea(Color color) { if(color != null && color.isDisposed()) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } getPlotArea().setBackground(color); } /** * Sets the state of chart orientation. The horizontal orientation means * that X axis is horizontal as usual, while the vertical orientation means * that Y axis is horizontal. * * @param orientation * the orientation which can be SWT.HORIZONTAL or SWT.VERTICAL */ @Override public void setOrientation(int orientation) { if(orientation == SWT.HORIZONTAL || orientation == SWT.VERTICAL) { this.orientation = orientation; } updateLayout(); } /** * Gets the state of chart orientation. The horizontal orientation means * that X axis is horizontal as usual, while the vertical orientation means * that Y axis is horizontal. * * @return the orientation which can be SWT.HORIZONTAL or SWT.VERTICAL */ @Override public int getOrientation() { return orientation; } /** * Enables compressing series. By default, compressing series is enabled, * and normally there should be no usecase to disable it. However, if you * suspect that something is wrong in compressing series, you can disable it * to isolate the issue. * * @param enabled * true if enabling compressing series */ public void enableCompress(boolean enabled) { compressEnabled = enabled; } /** * Gets the state indicating if compressing series is enabled. * * @return true if compressing series is enabled */ public boolean isCompressEnabled() { return compressEnabled; } /** * @return the translucent */ public boolean isTranslucent() { return translucent; } /** * @param translucent the translucent to set */ public void setTranslucent(boolean translucent) { this.translucent = translucent; } /** * Suspends the update of chart appearance. * *

* By default, when the chart model is changed (e.g. adding new series or * changing chart properties), the chart appearance is updated accordingly. *

* However, when doing a lot of changes in the chart model at once, it is * inefficient that the update happens many times unnecessarily. In this * case, you may want to defer the update until completing whole model * changes in order to have better performance. *

* For example, suppose there is a chart having a large number of series, * the following example code disables the update during changing the model. * *

	 * try {
	 *     // suspend update
	 *     chart.suspendUpdate(true);
	 * 
	 *     // do some changes for a large number of series
	 *     for (ISeries series : chart.getSeriesSet().getSeries()) {
	 *         series.enableStack(true);
	 *     }
	 * } finally {
	 *     // resume update
	 *     chart.suspendUpdate(false);
	 * }
	 * 
* * Note that the update has to be resumed right after completing the model * changes in order to avoid showing an incompletely updated chart. * * @param suspend * true to suspend the update of chart appearance */ public void suspendUpdate(boolean suspend) { if(updateSuspended == suspend) { return; } updateSuspended = suspend; // make sure that chart is updated if(!suspend) { updateLayout(); ((SeriesSet)getSeriesSet()).updateStackAndRiserData(); } } /** * Gets the state indicating if the update of chart appearance is suspended. * * @return true if the update of chart appearance is suspended */ public boolean isUpdateSuspended() { return updateSuspended; } @Override public void handleEvent(Event event) { switch(event.type) { case SWT.Resize: updateLayout(); redraw(); break; default: break; } } /** * Updates the layout of chart elements. */ public void updateLayout() { if(updateSuspended) { return; } if(legend != null) { legend.updateLayoutData(); } if(title != null) { title.updateLayoutData(); } if(axisSet != null) { axisSet.updateLayoutData(); } layout(); if(axisSet != null) { axisSet.refresh(); } } @Override public void update() { super.update(); for(Control child : getChildren()) { child.update(); } } @Override public void dispose() { title.dispose(); legend.dispose(); axisSet.dispose(); super.dispose(); } @Override public void redraw() { super.redraw(); for(Control child : getChildren()) { child.redraw(); } } /** * Saves to file with given format. * * @param filename * the file name * @param format * the format (SWT.IMAGE_*). The supported formats depend on OS. */ public void save(String filename, int format) { throw new UnsupportedOperationException("This method is not implemented for RWT"); } /** * Renders off-screen image. * * @param image * The image to render off-screen */ public void renderOffscreenImage(Image image) { throw new UnsupportedOperationException("This method is not implemented for RWT"); } public void printChart(GC gc, Rectangle clientArea) { Transform oldTransform = new Transform(gc.getDevice()); try { gc.getTransform(oldTransform); Point oldSize = getSize(); try { setSize(clientArea.width, clientArea.height); Event e = new Event(); e.gc = gc; e.widget = this; PaintEvent paintEvent = new PaintEvent(e); for(Control child : getChildren()) { Rectangle bounds = child.getBounds(); if(child instanceof PaintListener) { Event subEvent = new Event(); subEvent.gc = gc; subEvent.widget = child; Rectangle oldClipping = gc.getClipping(); try { gc.setClipping(bounds); PaintEvent subPaint = new PaintEvent(subEvent); Transform transform = new Transform(gc.getDevice()); try { transform.translate(bounds.x, bounds.y); gc.setTransform(transform); ((PaintListener)child).paintControl(subPaint); } finally { transform.dispose(); gc.setTransform(oldTransform); } } finally { gc.setClipping(oldClipping); } } } for(PaintListener listener : paintListener) { listener.paintControl(paintEvent); } } finally { setSize(oldSize); } } finally { oldTransform.dispose(); } } /** * @see org.eclipse.swt.widgets.Canvas#addPaintListener(org.eclipse.swt.events.PaintListener) */ @Override public void addPaintListener(PaintListener listener) { paintListener.add(listener); super.addPaintListener(listener); } /** * @see org.eclipse.swt.widgets.Canvas#removePaintListener(org.eclipse.swt.events.PaintListener) */ @Override public void removePaintListener(PaintListener listener) { paintListener.remove(listener); super.removePaintListener(listener); } /** * @return are multipliers used */ public boolean isUseMultipliers() { return useMultipliers; } /** * @param useMultipliers set to use multipliers */ public void setUseMultipliers(boolean useMultipliers) { this.useMultipliers = useMultipliers; IAxisSet axisSet = getAxisSet(); IAxis yAxis = axisSet.getYAxis(0); yAxis.setUseMultipliers(useMultipliers); } /** * Build rounded decimal value for legend. Default implementation will just return double with given precision. * * @param value value to format * @param step step of label * @param maxPrecision desired precision * @return rounded value */ public String roundDecimalValue(double value, double step, int maxPrecision) { DecimalFormat df = new DecimalFormat(); df.setMaximumFractionDigits(maxPrecision); return df.format(value); } /** * Set cached tick step on Y axis. * * @param cachedTickStep cached tick step on Y axis */ public void setCachedTickStep(double cachedTickStep) { this.cachedTickStep = cachedTickStep; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy