Crosshair positioned wrongly and reports incorrect data points when a second Y axis is added


#1

I’ve been using the crosshair successfully on other charts but the following chart I have uses a second y-axis (left).

For some reason when I add the second y-axis the position of the crosshair vertical line and datapoint values are out of position by a large margin.

The issue is amplifed when zoomed out as shown in the following screenshot:

As you can see above the crosshar tooltop (which value comes from the reported datapoint) shows 9th Sept, yet clearly the vertical line is on August as shown on the x axis.

The crosshair can be moved out of range so that the crosshair vertical line appears over the second (left) y-axis (see first screenshot) but and the crosshair will not move to the end of the range but stops short (by the looks of it the same amount as it moves to far left).

Removing the second (left) y-axis fixes the problem and things work line normally and the crosshair aligns correctly.

It’s worth noting that I have subclassed SChartCrosshair and changed it’s mode to SChartCrosshairModeFloating and the outOfRangeBehaviour is set to SChartCrosshairOutOfRangeBehaviorKeepAtEdge.

That said it works correcly and as expected if the chart has a single X and a single Y axis so I doubt it’s my customisation that is causing the issue. 

Any help would be apreciated.


#2

So I’ve just downloaded the latest version of Shinobi 2.5.7 previouslly was running 2.5.6 as it mentioned in the release notes there are fixes for floating crosshairs but now my custom crosshair subclass is not working at all.

It appears that moveToFloatingPixelPosition: method in sChartCrosshair is no longer called! I need this hook to implemented by custom functionality.

It’s still mentions it in the docs but it’s not being called in my subclass, any ideas?


#3

Hi Camsoft,

I’ve had a go at attempting to recreate this problem and can’t seem to reproduce it.

I have tried a chart with:

  • two y axes - one on the left and one on the right
  • datetime x-axis with a monthly tick frequency

The resulting tooltip appears to track the x-axis ok even when stopping to zoom in and out sometimes - please see the attached image.

It is clear from the images that you have posted that there is definitely an issue. In order to diagnose the issue you are seeing it may be best to send us your tooltip subclass and your code that sets up your chart and axes.


#4

I’ve now managed to resolve this issue, here is my code:

- (id)initWithChart:(ShinobiChart *)parentChart
{
    self = [super initWithChart:parentChart];
    if (self) {
        
        self.tooltip = [[BTTrackerCrosshairTooltip alloc] init];
        self.mode = SChartCrosshairModeFloating;
        self.outOfRangeBehavior = SChartCrosshairOutOfRangeBehaviorKeepAtEdge;
    }
    return self;
}


- (void)drawCrosshairLines
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    CGContextSetStrokeColorWithColor(context, [UIColor lightGrayColor].CGColor);
    CGContextMoveToPoint(context, self.x, 0.f);
    CGContextAddLineToPoint(context, self.x, self.chart.canvas.glView.frame.size.height);
    CGContextStrokePath(context);
}


- (void)moveToPosition:(SChartPoint)coords andDisplayDataPoint:(SChartPoint)dataPoint fromSeries:(SChartCartesianSeries *)series andSeriesDataPoint:(id<SChartData>)dataseriesPoint
{
    // apply limits to the coords and dataPoint x values
    CGFloat max = self.chart.canvas.glView.frame.size.width + self.chart.canvas.glView.frame.origin.x;
    CGFloat min = self.chart.canvas.glView.frame.origin.x;
    
    SChartPoint newCoords = coords;
    newCoords.x = newCoords.x;
    newCoords.x = MIN(newCoords.x, max);
    newCoords.x = MAX(newCoords.x, min);
    self.x = newCoords.x;
    
    SChartPoint newDataPoint = dataPoint;
    newDataPoint.x = MIN(newDataPoint.x, self.chart.xAxis.axisRange.maximum.integerValue);
    newDataPoint.x = MAX(newDataPoint.x, self.chart.xAxis.axisRange.minimum.integerValue);
    
    // get data for current datapoint
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:newDataPoint.x];
    NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSCalendarUnitDay|NSCalendarUnitMonth|NSCalendarUnitYear fromDate:date];
    date = [[NSCalendar currentCalendar] dateFromComponents:dateComponents];
    self.trackingDate = date;
    
    NSLog(@"coords=%f newCoords=%f, min=%f, max=%f, date=%@", coords.x, newCoords.x, min, max, date);
    
    
    // update the dataseriesPoint.xValue with our new date, we do this because the
    // default implementation does not return pixel price values when zoomed out
    ((SChartDataPoint *)dataseriesPoint).xValue = date;
    
    // call super implementation which in turn updates the label and draws the crosshair
    [super moveToPosition:newCoords andDisplayDataPoint:newDataPoint fromSeries:series andSeriesDataPoint:dataseriesPoint];
}

Basiclly when reading the _coord _argument I needed to compenstate for the origin of the glView which is usually zero when the y-axis is on the right but because I have a second y-axis on the left the origin was 35px.

The purpose of this subclass is two achive two goals:

  • Draw the crosshair as a vertical line that does not visually track a series
  • Limit the crosshair to within the limits of the glView.

As you can see in my custom subclass I’m appling a limit to the _coord _and dataPoint so that the line that is drawn and the date appears is limited to the visible range.

I think the issues I had was because my use-case was not available out of the box and without a proper understanding of what this class does internally it was a lot of guess work but I now have it working.

It might be cool to have a crosshair mode that does what I’m trying to achive in a future release that just tracks along an axis, we’re using this to show a dialog when you let go showing all the datapoint values for all series for the date the crosshair is on.

Thanks!


#5

Hi Camsoft,

Glad that you got it working. Sounds like an interesting use case! We’d like to consider adding your request to our list of possible future features. In order to do this it would be great if you have any videos or screenshots of the finished feature so we can better understand the behaviour you have implemented. Feel free to post here or email them in!

Kind regards

Ryan


#6

Email sent to info@shinobicontrols.com, thanks.