Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package de.gsi.chart;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.javafx.charts.ChartLayoutAnimator;
import com.sun.javafx.css.converters.BooleanConverter;
import com.sun.javafx.css.converters.EnumConverter;
import de.gsi.chart.axes.Axis;
import de.gsi.chart.axes.spi.DefaultNumericAxis;
import de.gsi.dataset.DataSet;
import de.gsi.dataset.event.EventListener;
import de.gsi.chart.legend.Legend;
import de.gsi.chart.legend.spi.DefaultLegend;
import de.gsi.chart.plugins.ChartPlugin;
import de.gsi.chart.renderer.Renderer;
import de.gsi.chart.renderer.spi.LabelledMarkerRenderer;
import de.gsi.chart.ui.HiddenSidesPane;
import de.gsi.chart.ui.ResizableCanvas;
import de.gsi.chart.ui.SidesPane;
import de.gsi.chart.ui.css.StylishBooleanProperty;
import de.gsi.chart.ui.css.StylishObjectProperty;
import de.gsi.chart.ui.geometry.Corner;
import de.gsi.chart.ui.geometry.Side;
import de.gsi.chart.utils.FXUtils;
import de.gsi.dataset.utils.AssertUtils;
import de.gsi.dataset.utils.ProcessingProfiler;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.property.StringPropertyBase;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.WritableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.css.CssMetaData;
import javafx.css.Styleable;
import javafx.css.StyleableObjectProperty;
import javafx.css.StyleableProperty;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.CacheHint;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import javafx.scene.control.Label;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.RowConstraints;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.util.Duration;
/**
* Chart designed primarily to display data traces using DataSet interfaces which are more flexible and efficient than
* the observable lists used by XYChart. Brief history: original design inspired by Oracle, extended by CERN (i.e.
* plugin concept/zoomer), modified to mitigate JavaFX performance issues and extended renderer
* concept/canvas-concept/interfaces/+more plugins by GSI. Refactored and re-write in 2018 to make it compatible with
* GPLv3 which -- in the spirit of 'Ship of Theseus' -- makes it de-facto a new development. Contributions, bug-fixes,
* and modifications are welcome. Hope you find this library useful and enjoy!
*
* @author original conceptual design by Oracle (2010, 2014)
* @author hbraeun, rstein, major refactoring, re-implementation and re-design
*/
public abstract class Chart extends SidesPane implements Observable {
private static final Logger LOGGER = LoggerFactory.getLogger(Chart.class);
private static final String CHART_CSS = Chart.class.getResource("chart.css").toExternalForm();
private static final int DEFAULT_TRIGGER_DISTANCE = 50;
protected static boolean DEBUG = false; // for more verbose debugging
protected BooleanBinding showingBinding;
protected final BooleanProperty showing = new SimpleBooleanProperty(this, "showing", false);
/** When true any data changes will be animated. */
private final BooleanProperty animated = new SimpleBooleanProperty(this, "animated", true);
// TODO: Check whether 'this' or chart contents need to be added
/** Animator for animating stuff on the chart */
protected final ChartLayoutAnimator animator = new ChartLayoutAnimator(this);
/**
* When true the chart will display a legend if the chart implementation supports a legend.
*/
private final BooleanProperty legendVisible = new StylishBooleanProperty(StyleableProperties.LEGEND_VISIBLE, this,
"legendVisible", true, () -> {
updateLegend(getDatasets(), getRenderers());
requestLayout();
});
// isCanvasChangeRequested is a recursion guard to update canvas only once
protected boolean isCanvasChangeRequested = false;
// layoutOngoing is a recursion guard to update canvas only once
protected boolean layoutOngoing = false;
protected final ObservableList axesList = FXCollections.observableArrayList();
private final Map pluginGroups = new ConcurrentHashMap<>();
private final ObservableList plugins = FXCollections.observableList(new LinkedList<>());
private final ObservableList datasets = FXCollections.observableArrayList();
protected final ObservableList allDataSets = FXCollections.observableArrayList();
protected final List listeners = new ArrayList<>();
protected final BooleanProperty autoNotification = new SimpleBooleanProperty(this, "autoNotification", true);
private final ObservableList renderers = FXCollections.observableArrayList();
{
getRenderers().addListener(this::rendererChanged);
}
protected final ResizableCanvas canvas = new ResizableCanvas();
// contains axes (left, bottom, top, right) panes & HiddenSidePane with the Canvas at it's centre
protected final GridPane axesAndCanvasPane = new GridPane();
protected final Group pluginsArea = Chart.createChildGroup();
protected boolean isAxesUpdate = false;
// containing the plugin handler/modifier
protected final FlowPane toolBar = new FlowPane();
protected final HiddenSidesPane hiddenPane = new HiddenSidesPane();
protected final Pane plotBackground = new Pane();
protected final Pane plotForeGround = new Pane();
protected final Pane canvasForeground = new Pane();
protected final Map axesCorner = new ConcurrentHashMap<>(4);
protected final Map axesPane = new ConcurrentHashMap<>(4);
protected final Map parameterDisplayPane = new ConcurrentHashMap<>(4);
protected final Map titleLegendCorner = new ConcurrentHashMap<>(4);
protected final Map titleLegendPane = new ConcurrentHashMap<>(4);
{
for (final Corner corner : Corner.values()) {
axesCorner.put(corner, new StackPane()); // NOPMD - default init
titleLegendCorner.put(corner, new StackPane()); // NOPMD - default init
}
for (final Side side : Side.values()) {
titleLegendPane.put(side, side.isVertical() ? new ChartHBox() : new ChartVBox()); // NOPMD - default init
axesPane.put(side, side.isVertical() ? new ChartHBox() : new ChartVBox()); // NOPMD - default init
if (side == Side.CENTER_HOR || side == Side.CENTER_VER) {
axesPane.get(side).setMouseTransparent(true);
}
// Stack multiple Measurements on top of each other by using a vertical FlowPane
if (side == Side.RIGHT) {
final FlowPane flowPane = new FlowPane(Orientation.VERTICAL); // NOPMD - default init
flowPane.setAlignment(Pos.TOP_LEFT);
flowPane.setPrefSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
parameterDisplayPane.put(side, flowPane);
continue;
}
parameterDisplayPane.put(side, side.isVertical() ? new ChartHBox() : new ChartVBox()); // NOPMD - default init
}
}
private final InvalidationListener axisChangeListener = this::axesInvalidated;
protected final ListChangeListener axesChangeListenerLocal = this::axesChangedLocal;
protected final ListChangeListener axesChangeListener = this::axesChanged;
protected final ListChangeListener datasetChangeListener = this::datasetsChanged;
protected final EventListener dataSetDataListener = obs -> FXUtils.runFX(this::dataSetInvalidated);
protected final ListChangeListener pluginsChangedListener = this::pluginsChanged;
{
getDatasets().addListener(datasetChangeListener);
getAxes().addListener(axesChangeListener);
// update listener to propagate axes changes to chart changes
getAxes().addListener(axesChangeListenerLocal);
}
protected final Label titleLabel = new Label();
protected final StringProperty title = new StringPropertyBase() {
@Override
public Object getBean() {
return Chart.this;
}
@Override
public String getName() {
return "title";
}
@Override
protected void invalidated() {
titleLabel.setText(get());
}
};
/**
* The side of the chart where the title is displayed
* default Side.TOP
*/
private final ObjectProperty titleSide = new StylishObjectProperty(StyleableProperties.TITLE_SIDE, this,
"titleSide", Side.TOP, this::requestLayout) {
@Override
public void set(final Side side) {
AssertUtils.notNull("Side must not be null", side);
for (final Side s : Side.values()) {
getMeasurementBar(s).getChildren().remove(titleLabel);
}
getMeasurementBar(side).getChildren().add(titleLabel);
super.set(side);
}
};
/**
* The side of the chart where the title is displayed
* default Side.TOP
*/
private final ObjectProperty measurementBarSide = new StyleableObjectProperty(Side.RIGHT) {
@Override
public Object getBean() {
return Chart.this;
}
@Override
public CssMetaData getCssMetaData() {
return StyleableProperties.MEASUREMENT_SIDE_BAR;
}
@Override
public String getName() {
return "measurementBarSide";
}
@Override
public void set(final Side side) {
AssertUtils.notNull("Side must not be null", side);
super.set(side);
}
@Override
protected void invalidated() {
requestLayout();
}
};
/**
* The node to display as the Legend. Subclasses can set a node here to be displayed on a side as the legend. If no
* legend is wanted then this can be set to null
*/
private final ObjectProperty