Panning multiple charts


#1

Hi Shinobi,

I have two charts that I am plotting one below the other (with the grid lines matching). When the user pans or zooms on one chart, I need the other to pan and zoom the same amount.

Currently I have delegate methods implemented as follows to closely mimic the chart being zoomed/panned:

  •  (void)sChartIsPanning:(ShinobiChart *)chart withChartMovementInformation:(const SChartMovementInformation *)information {

   [self.OtherDataChart.xAxissetRangeWithMinimum:chart.xAxis.axisRange.minimumandMaximum:chart.xAxis.axisRange.maximumwithAnimation:YES];

}

  • (void)sChartIsZooming:(ShinobiChart *)chart withChartMovementInformation:(constSChartMovementInformation *)information {

 [self.OtherDataChart.xAxis setRangeWithMinimum:chart.xAxis.axisRange.minimum andMaximum:chart.xAxis.axisRange.maximum withAnimation:YES];

}

They do the job but there is a lag as the second chart catches up with the first. Is there a better way to update the two charts simultaneously?

Thanks!


#2

Try updating the range without animation - the charts should then be fully synchronised.

Jan


#3

Any suggestions on how to implement this with animation?


#4

I actually haven’t been able to get this working to my satistisfaction. Let’s say I have two charts. For simplicity’s sake, lets pretend that I have two charts, and the top chart is always the master, and the bottom always the slave.

If i implement the delegate method

- (void)sChartIsPanning:(ShinobiChart *)chart withChartMovementInformation:(const SChartMovementInformation *)information {

and call something like the following inside the callback,

[axis setRangeWithMinimum:theRange.minimum andMaximum:theRange.maximum withAnimation:NO];

(and ‘axis’ is the xAxis in the slave) nothing actually happens in the slave chart for me. That’s not entirely true though - i can briefly get slave following the master if I fling the slave, and then quickly switch to master and start moving it. But once slave graph momentum gets below a certain threshold, the slave slows to a stop even though I’ll madly be moving the master. As Jan suggested, it seems like this should work  (a bug that it doesn’t? or just me?)

What works much better, is as OP suggested setting ‘withAnimation:YES’.  However, as OP noted, there’s then a noticeable lag betwen master+slave.

Buckle up for my work-around. (which is scary and still not quite satisfactory)  Find the chart’s pan gestures and remove the target/action. Then add yourself to be called instead. In your handler, explicitly call the SDK’s gesture handler (which we disconnected from the gestures) ‘handlePinchAndPanGesture’.  Then make the same call to the *slaves* chart.   This is a bit like (almost?) mirroring the gesture calls in both the master+slave charts.  Unfortunately, with that alone, the panning gets quite out of synch between the two. To nearly solve this problem, I *also* did what the OP suggested, which was to still explicitly set the range in the slave from the sChartIsPanning delegate method  (still with  ‘withAnimation:YES’).

This crazy/dangerous work-around seems ‘good enough’, but iOS users (myself included) are never happy with ‘good enough’. I still notice a lag, although much less than with OP’s solution. Of interest, if I use my crazy work-around, and use ‘withAnimation:NO’, it mostly behaves the same, except that the slave doesn’t bounce off out of bounds pans, but the master does.

Has anybody gotten panning multiple charts working to their satisfaction?

Cheers!


#5

Hey Tomshinobi,

I’m going to have a look into this for you. I tried this previously and managed to get it working well a few releases ago. I’ll let you know how I get on!

Thanks,
Jan


#6

Right! So I’ve managed to get this working using the method I suggested above.

Here is the implementation of my delegate method.

-(void)sChartIsPanning:(ShinobiChart *)chart withChartMovementInformation:(const SChartMovementInformation *)information
{
    [_chart2.xAxis setRangeWithMinimum:chart.xAxis.axisRange.minimum andMaximum:chart.xAxis.axisRange.maximum];
    [_chart2.yAxis setRangeWithMinimum:chart.yAxis.axisRange.minimum andMaximum:chart.yAxis.axisRange.maximum];
    [_chart2 redrawChart];
}

When I tested this, the slave chart stays fully in sync with the master chart (dragging, bouncing & momentum). A few common pitfalls I’ve seen people fall into when doing this follow:

  • They don’t redraw their chart after they’ve updated its range. You need to do this if you aren’t updating the range in an animated fashion. If you want to animate, it is implcit that you want the chart to redraw.
  • They use sChartIsPanning: rather than sChartIsPanning:withChartMovementInformation:. The former is called only  when the user is dragging, the latter is called when the user is dragging  and when the chart is moving with momentum & animation.

I hope the above helps! I look forward to seeing what you end up building with our framework!

Thanks,
Jan


#7

Jan - lifesaver.  I was missing the redrawChart.  Now I can delete my gesture hacks. Cheers!


#8

No problem - good luck with the rest of your development!  :laughing: