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

de.gsi.chart.plugins.ChartPlugin Maven / Gradle / Ivy

package de.gsi.chart.plugins;

import java.util.LinkedList;
import java.util.List;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import javafx.scene.input.InputEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.util.Pair;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.gsi.chart.Chart;
import de.gsi.chart.XYChart;
import de.gsi.chart.axes.Axis;
import de.gsi.dataset.spi.utils.Tuple;

/**
 * Represents an add-on to a Chart that can either annotate/decorate the chart or perform some interactions with it.
 * 

* Concrete plugin implementations may add custom nodes to the chart via {@link #getChartChildren()} which returns an * observable and modifiable list of nodes that will be added to the {@code XYChartPane} on top of charts. *

* Plugins may also listen and react to events (e.g. mouse events) generated on the {@code XYChartPane} via * {@link #registerInputEventHandler(EventType, EventHandler)} method. * * @author Grzegorz Kruk * @author braeun - modified to be able to use XYChart class * @author rstein - modified to new Chart, XYChart API */ public abstract class ChartPlugin { private static final Logger LOGGER = LoggerFactory.getLogger(ChartPlugin.class); private final ObservableList chartChildren = FXCollections.observableArrayList(); private final List, EventHandler>> mouseEventHandlers = new LinkedList<>(); /** * The associated {@link Chart}. Initialised when the plug-in is added to the Chart, set to {@code null} when * removed. */ private final ObjectProperty chart = new SimpleObjectProperty<>(this, "chart"); // whether to add (or not) the corresponding control buttons to chart tool // bar private final BooleanProperty addButtonsToToolBar = new SimpleBooleanProperty(this, "addButtonsToToolBar", true); /** * Creates a new instance of the ChartPlugin. */ protected ChartPlugin() { chartProperty().addListener((obs, oldChart, newChart) -> { if (oldChart != null) { removeEventHandlers(oldChart.getPlotArea()); removeEventHandlers(oldChart.getPlotBackground()); } if (newChart != null) { addEventHandlers(newChart.getPlotArea()); addEventHandlers(newChart.getPlotBackground()); } }); } /** * When {@code true} the corresponding control buttons are added to the chart tool bar * * @return the sliderVisible property */ public final BooleanProperty addButtonsToToolBarProperty() { return addButtonsToToolBar; } @SuppressWarnings("unchecked") private void addEventHandlers(final Node node) { if (node == null) { return; } for (final Pair, EventHandler> pair : mouseEventHandlers) { final EventType type = (EventType) pair.getKey(); final EventHandler handler = (EventHandler) pair.getValue(); node.addEventHandler(type, handler); node.sceneProperty().addListener((ch, o, n) -> { if (o == n) { return; } if (o != null) { o.removeEventHandler(type, handler); } if (n != null) { n.addEventHandler(type, handler); } }); } } /** * The associated {@link Chart}. Initialised when the plug-in is added to the Chart, set to {@code null} when * removed. * * @return the chart property */ public final ObjectProperty chartProperty() { return chart; } /** * Returns the value of the {@link #chartProperty()}. * * @return the associated Chart or {@code null} */ public final Chart getChart() { return chartProperty().get(); } /** * Returns a list containing nodes that should be added to the list of child nodes of the associated XYChart's plot * area children. *

* The method should be used by concrete implementations to add nodes that should be added to the chart area. * * @return non-null list of nodes to be added to the chart's plot area */ public final ObservableList getChartChildren() { return chartChildren; } /** * Converts mouse location within the scene to the location relative to the plot area. * * @param event mouse event * @return location within the plot area */ protected final Point2D getLocationInPlotArea(final MouseEvent event) { final Point2D mouseLocationInScene = new Point2D(event.getSceneX(), event.getSceneY()); final Chart chart = getChart(); if (!(chart instanceof XYChart)) { return null; } final XYChart xyChart = (XYChart) chart; final double xInAxis = ((Node) xyChart.getXAxis()).sceneToLocal(mouseLocationInScene).getX(); final double yInAxis = ((Node) xyChart.getYAxis()).sceneToLocal(mouseLocationInScene).getY(); return new Point2D(xInAxis, yInAxis); } /** * Tests whether the event coordinates are within the bounding box of the canvas. * * @param event source event * @return true if the event is within bounds */ protected boolean isMouseEventWithinCanvas(final MouseEvent event) { final Canvas canvas = getChart().getCanvas(); var local = canvas.sceneToLocal(event.getSceneX(), event.getSceneY()); return canvas.getBoundsInLocal().contains(local); } /** * Tests whether the event coordinates are within the bounding box of the canvas. * * @param event source event * @return true if the event is within bounds */ protected boolean isMouseEventWithinCanvas(final ScrollEvent event) { final Canvas canvas = getChart().getCanvas(); var local = canvas.sceneToLocal(event.getSceneX(), event.getSceneY()); return canvas.getBoundsInLocal().contains(local); } /** * Returns the value of the {@link #addButtonsToToolBarProperty()}. * * @return {@code true} the corresponding control buttons are added to the chart tool bar */ public final boolean isAddButtonsToToolBar() { return addButtonsToToolBarProperty().get(); } /** * Optional method that allows the plug-in to react in case the size of the chart that it belongs to has changed. */ public void layoutChildren() { // #NOPMD // empty by default } /** * Registers event handlers that should be added to the {@code XYChartPane} node when the plugin is added to the * pane and are removed once the plugin is removed from the pane. * * @param eventType the event type on which the handler should be called * @param handler the event handler to be added to the chart */ protected final void registerInputEventHandler(final EventType eventType, final EventHandler handler) { mouseEventHandlers.add(new Pair<>(eventType, handler)); } @SuppressWarnings("unchecked") private void removeEventHandlers(final Node node) { if (node == null) { return; } for (final Pair, EventHandler> pair : mouseEventHandlers) { final EventType type = (EventType) pair.getKey(); final EventHandler handler = (EventHandler) pair.getValue(); node.removeEventHandler(type, handler); if (node.getScene() != null) { node.getScene().removeEventFilter(type, handler); } } } /** * Sets the value of the {@link #addButtonsToToolBarProperty()}. * * @param state if {@code true} the corresponding control buttons are added to the chart tool bar */ public final void setAddButtonsToToolBar(final boolean state) { addButtonsToToolBarProperty().set(state); } /** * Called by the {@link Chart} when the plugin is added to it. * * @param chart the chart pane */ public final void setChart(final Chart chart) { chartProperty().set(chart); } /** * Converts given display point within the plot area coordinates to the corresponding data point within data * coordinates. * * @param yAxis the number-based y axis * @param displayPoint the display point to be converted * @return the data point */ protected final Tuple toDataPoint(final Axis yAxis, final Point2D displayPoint) { final Chart chart = getChart(); if (!(chart instanceof XYChart)) { if (LOGGER.isWarnEnabled()) { LOGGER.atWarn().addArgument(chart).log("chart '{}' is not of type XYChart returning null"); } return null; } final XYChart xyChart = (XYChart) chart; return new Tuple<>(xyChart.getXAxis().getValueForDisplay(displayPoint.getX()), yAxis.getValueForDisplay(displayPoint.getY())); } /** * Converts given point in data coordinates to a point in display coordinates. * * @param yAxis the corresponding y-axis (number axis) * @param x the X coordinate (can be generic non-number, ie. CategoryAxis) * @param y the Y coordinate on the yAxis (Number based) * @return corresponding display point within the plot area */ protected final Point2D toDisplayPoint(final Axis yAxis, final double x, final double y) { return new Point2D(((XYChart) getChart()).getXAxis().getDisplayPosition(x), yAxis.getDisplayPosition(y)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy