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

org.pepstock.charba.client.impl.plugins.ChartPointer Maven / Gradle / Ivy

There is a newer version: 6.5-gwt
Show newest version
/**
    Copyright 2017 Andrea "Stock" Stocchero

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

	    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/
package org.pepstock.charba.client.impl.plugins;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.pepstock.charba.client.IsChart;
import org.pepstock.charba.client.ScaleType;
import org.pepstock.charba.client.defaults.IsDefaultScaledOptions;
import org.pepstock.charba.client.dom.BaseNativeEvent;
import org.pepstock.charba.client.dom.enums.CursorType;
import org.pepstock.charba.client.enums.DefaultPluginId;
import org.pepstock.charba.client.impl.plugins.ChartPointerOptionsFactory.ChartPointerDefaultsOptionsFactory;
import org.pepstock.charba.client.impl.plugins.enums.PointerElement;
import org.pepstock.charba.client.items.LegendHitBoxItem;
import org.pepstock.charba.client.items.PluginEventArgument;
import org.pepstock.charba.client.items.PluginUpdateArgument;
import org.pepstock.charba.client.plugins.AbstractPlugin;

/**
 * This plugin is changing the cursor when mouse over on dataset, title on canvas if a dataset selection, title handler have been defined.
 * 
 * @author Andrea "Stock" Stocchero
 * @see CursorType
 */
public final class ChartPointer extends AbstractPlugin {

	/**
	 * Plugin ID {@value ID}.
	 */
	public static final String ID = "charbacursorpointer";
	/**
	 * The factory to create options for plugin.
	 */
	public static final ChartPointerOptionsFactory FACTORY = new ChartPointerOptionsFactory();
	// singleton instance
	private static final ChartPointer INSTANCE = new ChartPointer();
	// defaults global options factory
	static final ChartPointerDefaultsOptionsFactory DEFAULTS_FACTORY = new ChartPointerDefaultsOptionsFactory();
	// cache to store options in order do not load every time the options
	private final Map pluginOptions = new HashMap<>();

	/**
	 * To avoid any instantiation
	 */
	private ChartPointer() {
		super(ID);
	}

	/**
	 * Returns the singleton instance of plugin.
	 * 
	 * @return the singleton instance of plugin
	 */
	public static ChartPointer get() {
		return INSTANCE;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.pepstock.charba.client.Plugin#onBeforeUpdate(org.pepstock.charba.client.IsChart, org.pepstock.charba.client.items.PluginUpdateArgument)
	 */
	@Override
	public boolean onBeforeUpdate(IsChart chart, PluginUpdateArgument argument) {
		// checks if chart is consistent
		if (IsChart.isConsistent(chart)) {
			// creates options instance
			ChartPointerOptions pOptions = null;
			// loads chart options for the chart
			IsDefaultScaledOptions options = chart.getWholeOptions();
			// creates the plugin options checking if exists ot not
			if (options.getPlugins().hasOptions(ID)) {
				pOptions = options.getPlugins().getOptions(ID, FACTORY);
			} else {
				pOptions = new ChartPointerOptions(ChartPointerDefaultOptions.INSTANCE);
			}
			// stores option on the cache
			pluginOptions.put(chart.getId(), pOptions);
			// sets the initial cursor of chart
			pOptions.setCurrentCursor(chart.getInitialCursor());
		}
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.pepstock.charba.client.Plugin#onAfterEvent(org.pepstock.charba.client.IsChart, org.pepstock.charba.client.items.PluginEventArgument)
	 */
	@Override
	public void onAfterEvent(IsChart chart, PluginEventArgument argument) {
		// checks if chart is consistent and options of plugin has been stored
		if (IsChart.isConsistent(chart) && pluginOptions.containsKey(chart.getId())) {
			// gets base native event
			BaseNativeEvent event = argument.getEventContext().getNativeEvent();
			// gets options instance
			ChartPointerOptions pOptions = pluginOptions.get(chart.getId());
			// gets the scope
			List scope = pOptions.getElements();
			// DATASET SELECTION
			if (hasDatasetSelection(chart, event, scope)) {
				chart.getChartElement().getStyle().setCursorType(pOptions.getCursorPointer());
			} else if (hasTitleSelection(chart, event, scope)) {
				// TITLE SELECTION
				chart.getChartElement().getStyle().setCursorType(pOptions.getCursorPointer());
			} else if (hasScaleSelection(chart, event, scope)) {
				// AXIS SELECTION
				chart.getChartElement().getStyle().setCursorType(pOptions.getCursorPointer());
			} else if (hasLegendSelection(chart, event, scope)) {
				// LEGEND SELECTION
				chart.getChartElement().getStyle().setCursorType(pOptions.getCursorPointer());
			} else {
				// if null, sets the default cursor
				chart.getChartElement().getStyle().setCursorType(chart.getInitialCursor());
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.pepstock.charba.client.Plugin#onDestroy(org.pepstock.charba.client.IsChart)
	 */
	@Override
	public void onDestroy(IsChart chart) {
		// checks if chart is valid
		if (IsChart.isValid(chart)) {
			// removes the stored options for chart
			pluginOptions.remove(chart.getId());
		}
	}

	/**
	 * Returns true if the cursor is over to a dataset, otherwise false.
	 * 
	 * @param chart chart instance
	 * @param event event form CHART.js
	 * @param scope the scope with all activated scope of the plugin
	 * @return true if the cursor is over to a dataset, otherwise false
	 */
	private boolean hasDatasetSelection(IsChart chart, BaseNativeEvent event, List scope) {
		// checks if the datasets is in scope
		if (chart.getOptions().hasDatasetSelectionHandlers() && isElementInScope(scope, PointerElement.DATASET)) {
			// if yes, asks the dataset item by event
			// if consistent, is over a dataset
			return chart.getElementAtEvent(event) != null;
		}
		return false;
	}

	/**
	 * Returns true if the cursor is over to the title, otherwise false.
	 * 
	 * @param chart chart instance
	 * @param event event form CHART.js
	 * @param scope the scope with all activated scope of the plugin
	 * @return true if the cursor is over to the title, otherwise false
	 */
	private boolean hasTitleSelection(IsChart chart, BaseNativeEvent event, List scope) {
		// checks if title display is activated or title plugin is activated
		boolean isTitleEnabled = chart.getOptions().getTitle().isDisplay();
		// checks if there is any title click handler and title is in scope
		// and the cursor is over the title element
		return isTitleEnabled && chart.getOptions().hasTitleClickHandlers() && isElementInScope(scope, PointerElement.TITLE) && chart.getNode().getTitle().isInside(event);
	}

	/**
	 * Returns true if the cursor is over to a scale, otherwise false.
	 * 
	 * @param chart chart instance
	 * @param event event form CHART.js
	 * @param scope the scope with all activated scope of the plugin
	 * @return true if the cursor is over to a scale, otherwise false
	 */
	private boolean hasScaleSelection(IsChart chart, BaseNativeEvent event, List scope) {
		// checks if there is any axis click handler and axis is in scope
		// and the cursor is over the axis element
		return chart.getOptions().hasAxisClickHandlers() && isElementInScope(scope, PointerElement.AXES) && !ScaleType.NONE.equals(chart.getType().scaleType()) && chart.getNode().getScales().isInside(event);
	}

	/**
	 * Returns true if the cursor is over to the legend, otherwise false.
	 * 
	 * @param chart chart instance
	 * @param event event form CHART.js
	 * @param scope the scope with all activated scope of the plugin
	 * @return true if the cursor is over to the legend, otherwise false
	 */
	private boolean hasLegendSelection(IsChart chart, BaseNativeEvent event, List scope) {
		// checks if legend display is activated or legend plugin is activated
		boolean isLegendEnabled = chart.getOptions().getLegend().isDisplay() && chart.getOptions().getPlugins().isEnabled(DefaultPluginId.LEGEND);
		// checks if legend is in scope
		// and the cursor is over the legend element
		if (isLegendEnabled && isElementInScope(scope, PointerElement.LEGEND) && chart.getNode().getLegend().isInside(event)) {
			// LEGEND SELECTION
			// checks if cursor is over the hit box
			List legendItems = chart.getNode().getLegend().getHitBoxes();
			// scans all legend item box
			for (LegendHitBoxItem legendItem : legendItems) {
				// if cursor inside the legend item
				if (legendItem.isInside(event)) {
					// confirms is on legend
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Returns true if the element is configured in order to apply cursor when mouse is over.
	 * 
	 * @param scope list of pointer elements configured as in scope
	 * @param element the element to be checked
	 * @return true if the element is configured in order to apply cursor when mouse is over
	 */
	private boolean isElementInScope(List scope, PointerElement element) {
		// scans all elements in scope
		for (PointerElement scopeElement : scope) {
			// if equals, return true
			if (element.equals(scopeElement)) {
				return true;
			}
		}
		// if here, the element is not in scope
		return false;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy