/********************************************************************** * Copyright (c) 2015 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bernd Hufmann - Initial API and implementation **********************************************************************/ package org.eclipse.tracecompass.tmf.ui.viewers.xycharts; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseTrackListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.widgets.Display; import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp; import org.swtchart.IAxis; import org.swtchart.ISeries; /** * Abstract tooltip provider for xy chart viewers. It displays the y value and y * value of the data point of the mouse position. Extending classes can provide * a custom tooltip text. * * @author Bernd Hufmann * @since 2.0 */ public class TmfClosestDataPointTooltipProvider extends TmfBaseProvider implements MouseTrackListener, MouseMoveListener, PaintListener { // ------------------------------------------------------------------------ // Constants // ------------------------------------------------------------------------ private static final int ALPHA = 128; private static final int HIGHLIGHT_RADIUS = 5; // ------------------------------------------------------------------------ // Attributes // ------------------------------------------------------------------------ /** X coordinate for highlighting */ private int fHighlightX; /** y coordinate for highlighting */ private int fHighlightY; /** Flag to do highlighting or not */ private boolean fIsHighlight; // ------------------------------------------------------------------------ // Constructors // ------------------------------------------------------------------------ /** * Constructor for a tool tip provider. * * @param tmfChartViewer * - the parent chart viewer */ public TmfClosestDataPointTooltipProvider(ITmfChartTimeProvider tmfChartViewer) { super(tmfChartViewer); register(); } // ------------------------------------------------------------------------ // TmfBaseProvider // ------------------------------------------------------------------------ @Override public void register() { getChart().getPlotArea().addMouseTrackListener(this); getChart().getPlotArea().addMouseMoveListener(this); getChart().getPlotArea().addPaintListener(this); } @Override public void deregister() { if ((getChartViewer().getControl() != null) && !getChartViewer().getControl().isDisposed()) { getChart().getPlotArea().removeMouseTrackListener(this); getChart().getPlotArea().removeMouseMoveListener(this); getChart().getPlotArea().removePaintListener(this); } } @Override public void refresh() { // nothing to do } // ------------------------------------------------------------------------ // MouseTrackListener // ------------------------------------------------------------------------ @Override public void mouseEnter(MouseEvent e) { } @Override public void mouseExit(MouseEvent e) { } @Override public void mouseHover(MouseEvent e) { if ((getChartViewer().getWindowDuration() != 0) && (e != null)) { IAxis xAxis = getChart().getAxisSet().getXAxis(0); IAxis yAxis = getChart().getAxisSet().getYAxis(0); ISeries[] series = getChart().getSeriesSet().getSeries(); double smallestDistance = Double.MAX_VALUE; Parameter param = null; // go over all series for (int k = 0; k < series.length; k++) { ISeries serie = series[k]; double[] xS = serie.getXSeries(); double[] yS = serie.getYSeries(); if ((xS == null) || (yS == null)) { continue; } // go over all data points for (int i = 0; i < xS.length; i++) { int xs = xAxis.getPixelCoordinate(xS[i]) - e.x; int ys = yAxis.getPixelCoordinate(yS[i]) - e.y; double currentDistance = xs * xs + ys * ys; /* * Check for smallest distance to mouse position and only * consider it if the mouse is close the data point. */ if ((currentDistance < smallestDistance) && (currentDistance < (HIGHLIGHT_RADIUS * HIGHLIGHT_RADIUS))) { smallestDistance = currentDistance; fHighlightX = xs + e.x; fHighlightY = ys + e.y; if (param == null) { param = new Parameter(); } param.setSeriesIndex(k); param.setDataIndex(i); } } } String tooltip = null; if (param != null) { tooltip = createToolTipText(param); if (tooltip != null) { fIsHighlight = true; getChart().redraw(); } } /* * Note that tooltip might be null which will clear the previous * tooltip string. This is intentional. */ getChart().getPlotArea().setToolTipText(tooltip); } } // ------------------------------------------------------------------------ // MouseMoveListener // ------------------------------------------------------------------------ @Override public void mouseMove(@Nullable MouseEvent e) { if (fIsHighlight) { fIsHighlight = false; getChart().redraw(); } } // ------------------------------------------------------------------------ // PaintListener // ------------------------------------------------------------------------ @Override public void paintControl(PaintEvent e) { if (fIsHighlight && e != null) { e.gc.setBackground(Display.getDefault().getSystemColor( SWT.COLOR_RED)); e.gc.setAlpha(ALPHA); e.gc.fillOval(fHighlightX - HIGHLIGHT_RADIUS, fHighlightY - HIGHLIGHT_RADIUS, 2 * HIGHLIGHT_RADIUS, 2 * HIGHLIGHT_RADIUS); } } /** * Creates the tooltip based on the given parameter. * * @param param * parameter to create the tooltip string * @return the tooltip based on the given parameter. */ protected String createToolTipText(@NonNull Parameter param) { ISeries[] series = getChart().getSeriesSet().getSeries(); int seriesIndex = param.getSeriesIndex(); int dataIndex = param.getDataIndex(); if ((series != null) && (seriesIndex < series.length)) { ISeries serie = series[seriesIndex]; double[] xS = serie.getXSeries(); double[] yS = serie.getYSeries(); if ((xS != null) && (yS != null) && (dataIndex < xS.length) && (dataIndex < yS.length)) { StringBuffer buffer = new StringBuffer(); buffer.append("x="); //$NON-NLS-1$ buffer.append(TmfTimestamp.fromNanos((long) xS[dataIndex] + getChartViewer().getTimeOffset()).toString()); buffer.append('\n'); buffer.append("y="); //$NON-NLS-1$ buffer.append((long) yS[dataIndex]); return buffer.toString(); } } return null; } /** * Parameter class */ protected static class Parameter { /* A series index */ private int seriesIndex; /* A data point index within a series */ private int dataIndex; /** * @return the series index */ public int getSeriesIndex() { return seriesIndex; } /** * @param seriesIndex * index the seriesIndex to set */ public void setSeriesIndex(int seriesIndex) { this.seriesIndex = seriesIndex; } /** * @return the data index */ public int getDataIndex() { return dataIndex; } /** * @param dataIndex * the data index to set */ public void setDataIndex(int dataIndex) { this.dataIndex = dataIndex; } } }