Call the display of a crosshair without touching the screen


#1

I have two charts on the same view and if I drag a slider i want the crosshair line move at the same time. On the touch event of the slider I want display the crosshair of another chart and when the slider move, I want the crosshair move too.


Make crosshair appear when chart loaded? (1)
Make crosshair appear when chart loaded?
Programmatically showing chart crosshair + tooltip
#2

Hi Rouquier.mickael,

To position your chart’s crosshair programmatically you would have to calculate which datapoint you want to show from your slider’s value. Once you have the index of the datapoint you want to show you can move your crosshair into position using the following code:

//Get datapoint
SChartDataPoint *dataPoint = [barChart.datasource sChart:barChart dataPointAtIndex:index forSeriesAtIndex:0];

SChartPoint point;
point.x = [dataPoint.xValue doubleValue];
point.y = [dataPoint.yValue doubleValue];

// Position crosshair
[barChart.crosshair moveToFloatingPosition:point onXAxis:barChart.xAxis onYAxis:barChart.yAxis];

// Update text in crosshair
barChart.crosshair.tooltip.label.text = [NSString stringWithFormat:@"%d", (int)point.y];

 If you use a SChartCategoryAxis for your chart’s X-Axis then make sure you pass in the index of the chosen category rather than the category string value.

Then on your touch event to swap charts you can simply apply the above code to another chart to move a different charts crosshair.

Let me know how you get on.

Kind Regards,
Andrew Polkinghorn


#3

Thank you for your answer but my xAxis is composed of Dates and I haven’t any integer datavalue for this axis.


#4

Hi Rouquier.mickael,

To pass an NSDate object as your SChartPoint’s “x” value you need your datapoint’s date value at index 0. Then you can get an NSTimeInterval object from your zero index date to each of your datapoint’s date values then assign your SChartPoint’s “x” value to that NSTimeInterval.

An example below shows how this can be done:

// Get Datapoints
SChartDataPoint *currentDataPoint = [barChart.datasource sChart:barChart dataPointAtIndex:index forSeriesAtIndex:0];
SChartDataPoint *firstDataPoint = [barChart.datasource sChart:barChart dataPointAtIndex:0 forSeriesAtIndex:0];

// Get Date Values
NSDate *currentDate = currentDataPoint.xValue;
NSDate *startDate = firstDataPoint.xValue;

// Get Date Interval
NSTimeInterval dateInterval = [currentDate timeIntervalSinceDate:startDate];

// Create SChartPoint With Date Interval
SChartPoint point;   
point.x = dateInterval;
point.y = [dataPoint.yValue doubleValue];

 Let me know how you get on.

Kind Regards,
Andrew Polkinghorn


#5

It’s works great !!! Thank you.


#6

One more question I have overrided the drawCrossHairLines methods like this :

-(void)drawCrosshairLines {
       
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    CGContextSetLineWidth(context, 1.0);
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
    CGColorRef color = CGColorCreate(colorspace, components);
    CGContextSetStrokeColorWithColor(context, color);
    
    CGContextMoveToPoint(context, m_coords.x, 0);
    CGContextAddLineToPoint(context, m_coords.x, [m_chart getGLFrame].size.height);
    
    CGContextStrokePath(context);
    CGColorSpaceRelease(colorspace);
    CGColorRelease(color);
}

When I longTouch the chart the crosshair appears but when I move the slider nothing happens.


#7

Hi Rouquier.mickael,

The crosshair lines should appear when you programatically move your crosshair, however, you can turn them on by setting the “enableCrosshairLines” property to YES as shown in the code below:

chart.crosshair.enableCrosshairLines = YES;

You can also style your crosshair’s line color and width using the following code:

chart.crosshair.style.lineColor = [UIColor redColor];
chart.crosshair.style.lineWidth = @5;

Let me know how you get on.

Kind Regards,
Andrew Polkinghorn


#8

Hi, and thanks for your answer.

However, setting the chart.crosshair.enableCrosshairLines to yes doesn’t work: the crosshair still don’t show up.

I redefined the drawCrosshairLines method because I don’t simply want to change the color, I also want to display only the vertical part of the crosshair, and I want it to take the full chart height. Maybe there’s a simplest way to change this than redefining the full method?

Regards,

Mickaël.


#9

Hi Mickaël,

I have a solution to get the effect you require.

First create a subclass of SChartCrosshairTooltip adding a BOOL property and overriding the “-setPosition:onCanvas:” method. Below shows how I implemented this:

@implementation CustomToolTip{
    BOOL positionToolTip;
}

- (id)init
{
    self = [super init];
    if (self) {
        positionToolTip = YES;
    }
    return self;
}

-(void)setPosition:(struct SChartPoint)pos onCanvas:(SChartCanvas *)canvas {
    if(positionToolTip){
        positionToolTip = NO;
        [super setPosition:pos onCanvas:canvas];
    } else {
        positionToolTip = YES;
    }

}

Then assign your CustomToolTip subclass to your charts “crosshair.tooltip” property as shown below:

yourChart.crosshair.tooltip = [[CustomToolTip alloc] init];

 Then in your “onChange” method for your slider call the “-moveToFloatingPosition:onXAxis:onYAxis:” twice. The first time passing in the point with your datapoint values. The second time change your SChartPoint’s “y” value to the maximum Y-Axis value on your chart. Your “onChange” method should look something like this(where you define MAX_Y_Value to whatever the maximum value is on your Y-axis):

-(void)onChange:(UISlider*)slider{
    ...
    // Create SChartPoint With Date Interval
    SChartPoint point;   
    point.x = dateInterval;
    point.y = [dataPoint.yValue doubleValue];

    // Position Tooltip and crosshair lines
    [barChart.crosshair moveToFloatingPosition:point onXAxis:barChart.xAxis onYAxis:barChart.yAxis];

    // Just position crosshair lines
    point.y = MAX_Y_VALUE;
    [barChart.crosshair moveToFloatingPosition:point onXAxis:barChart.xAxis onYAxis:barChart.yAxis];
    
    barChart.crosshair.tooltip.label.text = [NSString stringWithFormat:@"%d", [dataPoint.yValue intValue]];
}

Let me know how you get on.

Kind Regards,
Andrew Polkinghorn


#10

Thanks for your help, the date interval method has already worked, so there is no need to redefine the tooltip. We couldn’t see the crosshair because the time interval is in second and the crosshair was displayed out of the screen. I wonder if there is a way to know the size in pixel of an xAxis point ?

Regards,

Mickaël.


#11

Hi Mickael,

The redefining of the tooltip was to create the effect where the horizontal crosshair line disappeared just showing a vertical crosshair line to the top of the chart keeping the tool tip near its datapoint. Apologies if I misunderstood your requirments or if you have already achieved this effect.  

Unfortunately there isn’t currently a way to get the pixel values of a datapoint.

Kind Regards,
Andrew Polkinghorn 


#12

No worries, and thank your for all but I don’t want the tooltip visible. Your solution with date interval works but I need to add 45 px to the result otherwise the crosshair 0 value is out of the chart. 

Kind Regards,
Mickael Rouquier.


#13

Hi Mickael,

It’s hard to work find a solution for this issue without seeing your code.

If you can cut down your project so it just shows your chart containing your issue and a detailed description of what’s happening and what you want to happen. Then send it to us at info@shinobicontrols.com someone will be able to take a look and get back to you.

Kind Regards,
Andrew Polkinghorn


#14

First the view controller :

The slider listener :

// Get Datapoints
        SChartDataPoint *currentDataPoint = [m_courbe.chart.datasource sChart:m_courbe.chart dataPointAtIndex:m_actualSlot forSeriesAtIndex:0];
        SChartDataPoint *firstDataPoint = [m_courbe.chart.datasource sChart:m_courbe.chart dataPointAtIndex:0 forSeriesAtIndex:0];
        
        // Get Date Values
        NSDate *currentDate = currentDataPoint.xValue;
        NSDate *startDate = firstDataPoint.xValue;
        
        // Get Date Interval
        NSTimeInterval dateInterval = [currentDate timeIntervalSinceDate:startDate];
        
        // Create SChartPoint With Date Interval
        SChartPoint point;   
        
        //####################################################################
        //45 is the size between the 0 on xAxis and the bordure of the chart and
        //218 is a size factor to transform interval (seconds)
        //###################################################################
        point.x = (dateInterval / 218) + 45;
        point.y = 0;
        
        [m_courbe.chart.crosshair moveToFloatingPosition:point onXAxis:m_courbe.chart.xAxis onYAxis:m_courbe.chart.yAxis];

To finish my redefinition of Crosshair :

//
// CChartCrosshair.m
// CorseReso
//
// Created by DevIneo on 16/10/12.
//
//

#import "CChartCrosshair.h"

#import "CChartCrosshairTooltip.h"

@implementation CChartCrosshair

-(id)initWithChart:(ShinobiChart *)parentChart andDelegate:(id)delegate andCallback:(SEL)callback {
    self = [super initWithChart:parentChart];
    m_chart = parentChart;
    CChartCrosshairTooltip* cr = [[CChartCrosshairTooltip alloc] initWithDelegate:delegate andCallback:callback];
    [self setTooltip:cr];
    return self;
}

-(void)drawCrosshairLines {
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    CGContextSetLineWidth(context, 1.0);
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
    CGColorRef color = CGColorCreate(colorspace, components);
    CGContextSetStrokeColorWithColor(context, color);
    
    CGContextMoveToPoint(context, m_coords.x, 0);
    CGContextAddLineToPoint(context, m_coords.x, [m_chart getGLFrame].size.height);
    
    CGContextStrokePath(context);
    CGColorSpaceRelease(colorspace);
    CGColorRelease(color);
}

-(void)moveToPosition:(SChartPoint)coords andDisplayDataPoint:(SChartPoint)dataPoint fromSeries:(SChartSeries *)series andSeriesDataPoint:(id<SChartData>)datapoint {
    [super moveToPosition:coords andDisplayDataPoint:dataPoint fromSeries:series andSeriesDataPoint:datapoint];
    m_coords = coords;
}

-(void)moveToFloatingPosition:(SChartPoint)point onXAxis:(SChartAxis *)xAxis onYAxis:(SChartAxis *)yAxis {    
    [super moveToFloatingPosition:point onXAxis:xAxis onYAxis:yAxis];
    m_coords = point;
}

@end

Kind Regards,
Mickael Rouquier.


#15

Hi Mickael,

Can you email us a zipped version of your project rather than pasting code on the forum it would make finding a solution for you a lot quicker.

If you can cut down your project, zip it and add a detailed description of what’s happening and what you want to happen. Then email this to us at info@shinobicontrols.com and someone will be able to take a look and get back to you.

Kind Regards,
Andrew Polkinghorn


#16

Sorry but my project is under non disclosure agreement, this is why I can’t send my source code. My issue is fixed and only minor details remains.

Thank you for all.

Kind Regards,
Mickael Rouquier.


#17

Hi Andrew,

This post is useful. I successfully display crosshair at the first time chart render.

But how to enter crosshair mode for chart because I can still pan around the chart and cannot sliding crosshair tooltip to left/right.

Thank you for your support,

Chawalit


#18

Hi Chawalit,

Can I get you to clarify your issue?

I understand you got the crosshair to display when the chart is rendered. Is the problem when you now try to use the crosshair by doing a long press gesture the crosshair isn’t moving, is that correct? 

Kind Regards,
Andrew Polkinghorn