Android - Crosshair Tooltips


#1

Is it possible to overwrite the default tooptip of a crosshair in Android?


#2

Such as to add things such as units.  instead of displaying X,Y I really need to do “Y <units>”


#3

Hi AEB,

It’s not currently possible to override the default crosshair tooltip in ShinobiCharts for Android, though there are a number of styling options available via the CrosshairStyle class.

What’s happening is that the tooltip is taking the x and y values for the point the crosshair is at, running them through the same format as is on the X and Y axes respectively and then displaying it as “X, Y” (where X and Y are the formatted values).

You can add your own label format to an axis which could include your units - the TickLabelFormattingActivity sample project gives an example of this. This will add the units to the tooltip but will include both the X and Y values and will mean each tick mark label on the axis will display the units as well.

I hope that helps!


#4

Hi Patrick,

Thanks for your help.  I think i may be in a little bit of a Catch-22 situation due to the current state of the API PLEASE let me know if I am mistaken, as it would make my day :slight_smile:

Heres the problem:

Currently I graph multiple series on a single chart, since multiple Y-Axis are not supported for a chart yet I am forced to scale my data series, so basially I maintain 2 sets, a log/array which contains the real Numerical data, and then I normalize that to graph it.

I normalize because the data being graphed have very differnt ranges, say 0-100 for some, while others are 0-10000.

Since the data is normalized, when I use the default tooltip I get the normalized data, not the real values. and since they are all differnt, and only 1 Y-Axis is currently supported I cannot use the Tick styling, as each is differnt :frowning:

I’ve been trying quite a bit to solve this, and work with the current API state to but I just seem to hit massive trade offs on each.  In a prive/protected method of your JAR file is a function which does exactly what I need (at least I think it does =D), and was hoping that there could possibly be access provided to this before the next major release.  

Without posting to much here, the function in question has this prototype:

void a(bk resolvedDataPoint, CartesianSeries<?> series, ShinobiChart chart)

and modifies the textbox which is used in the labels.

Please let me know if you have anything to add, I really love Shinobi and the work you all are doing.


#5

Hi AEB,

It’s great to hear your such a fan of Shinobi. In the interest of giving you a quick answer here are some ideas you could try which might help with your issue:

  • Extend the type of your Y-axis and override the transformChartValueToUserValue and transformUserValueToChartValue methods, doing your normaization/de-normalization there
  • Hide the Tooltip and use something like a TextView to display what you need. Its position could be updated as the Crosshair is moved by hooking into the ShinobiChart.OnCrosshairListener and possibly the ShinobiChart.OnInternalLayoutListener callback interfaces, and the methods on the Crosshair itself (getTrackingSeries()getUserYValue() etc.).

To hide the Tooltip you’d need to make the color of it and its text etc. transparent through the CrosshairStyle - admittedly this is a bit of a hack but once it is made more extensible this wouldn’t be necessary!

I’ll have a proper think tomorrow but just wanted to throw you some ideas before I finish for the day.

Hope that helps.


#6

I got this working using the onCrossHairListener, and more hacking than i care to admit… One thing i cant seem to figure out is how to hide the default tooltip… Ive tried setting all the colors to transparent or sizes to 0 but seems to have no affect :frowning:

any advice?  Im to close to give up now!


#7

Nevermind… got it done.

Thanks for the help Patrick, but still wiating on the official way :slight_smile:  To many things necessary to achieve the needed results!


#8

Glad to hear you found a solution - can certainly appreciate it can be a bit frustrating while we’re building out the API!

For the benefit of anyone else coming across this post, to hide the Crosshair Tooltip, assuming you’ve not changed the default CrosshairStyle, you just need to do the following:

  • Get the crosshair’s style object: 
    CrosshairStyle style = shinobiChart.getCrosshair().getStyle();

  • Set the following colors:
    style.setTooltipBackgroundColor(Color.TRANSPARENT);
    style.setTooltipBorderColor(Color.TRANSPARENT);
    style.setTooltipTextColor(Color.TRANSPARENT);

  • Redraw the chart:
    chart.redrawChart();

Don’t forget that last bit!  :smile:


#9

Hi AEB, 

Could you share your workaround code? Everybody can use while waiting official ways. :smile:

Thanks.


#10

Hi thanhbinh84.

Heres what I’ve done… havent touched in a few months, so I’m not sure if theres a better solution in the most recent release.

I’ve edited it out a little, to remove anything specific to my solution.  Hopefully this can help set you right.   

@Override
	public void onCrosshairActivationChanged(ShinobiChart chart) {
		flLandscapeGraph = (FrameLayout) mView
				.findViewById(R.id.landscape_graph);

		if (chart.getCrosshair().isShown()) {
			tvToolTip = new TextView(getActivity());
			flLandscapeGraph.addView(tvToolTip);
		} else {
			flLandscapeGraph.removeView(tvToolTip);
		}

	}

	private Item activeItem;
	private TextView tvToolTip;
	private FrameLayout flLandscapeGraph;

	@Override
	public void onCrosshairPositionChanged(ShinobiChart chart) {
		Logger.logDebug("XHAIR: Position changed");

		LineSeries activeSeries = (LineSeries) chart.getCrosshair()
				.getTrackingSeries();

		for (Item item : mDataLogger.getLoggedItems()) {
			if (activeSeries.getTitle().equalsIgnoreCase(item.getDescription())) {
				activeItem = item;
			}
		}

		if (activeItem != null) {
			float screenX = chart.getCrosshair().getPixelXValue();
			float screenY = chart.getCrosshair().getPixelYValue();
			
			Double time = (Double) chart.getCrosshair().getUserXValue();
			Double realY = mDataLogger.getExtrapolatedValue(activeItem.getId(),
					time );
			String formattedTime;
			if (time > 60){
				formattedTime = String.format("%.0f m, %.02f s", time / 60, time % 60);
			}else{
				formattedTime = String.format("%.02f s", time);
			}
			
			Logger.logDebug(String.format("XHAIR: RealX: %02f, RealY: %02f",
					(Double) chart.getCrosshair().getUserXValue(), realY));
			String title;
			double value = realY;
			String units = "x";

			String formatString = "%." + activeItem.getDecimalPlaces() + "f %s (%s)";
			title = String.format(formatString,	realY,	units, formattedTime);
			
			tvToolTip.setText(title);
			tvToolTip.measure(0, 0);
			float txtWidth = tvToolTip.getMeasuredWidth();
			float txtHeight = tvToolTip.getMeasuredHeight();
			float maxX = flLandscapeGraph.getX() + flLandscapeGraph.getWidth();

			if (screenX - txtWidth / 2 < 0) {
				tvToolTip.setX(0);
			} else if (screenX + txtWidth / 2 > maxX) {
				tvToolTip.setX(maxX - txtWidth);
			} else {
				tvToolTip.setX(screenX - txtWidth / 2);
			}

			tvToolTip.setY(screenY - txtHeight);

		}

	}

#11

Hi guys,

Just wanted to let you know we’ve now released ShinobiCharts for Android v1.5.1 which adds functionality for customising the tooltip. Hopefully this should make it much easier to achieve the above!

If you’ve got an up-to-date support package the download will be available in the Customer Portal. You can also download a trial.

Kind regards,

Patrick