ReloadData with SetRangeWithMinimum:andMaximum:withAnimation:true


#1

Hi there, I’m trying to let the user press on some default ranges to use (1 month, 1 day, 1 hour), and then animate the chart to that range while also making a call to the database to update the datasource. The way I’m doing this right now is to make an async call to the database to update its data, and then call reloadData on completion, and then try and call the setRange… but it doesn’t animate at all. If I try to call the setRange first, it will animate, but then get cut off once reloadData is called. Is there some way to achieve this?


#2

Hey,

In your first case, have you set allowPanningOutOfDefaultRange and allowPanningOutOfMaxRange to YES for each axis? If not, this would explain why the chart refuses to animate when moving to a larger range - it would take the axes past their bounds. The axes should still animate OK when you go from, for example, a month to a day’s view of your data - as this is within the range of the data.

In your second case, are you calling redraw on the chart as soon as your reload completes? If so, can you delay this call until after the animation has completed? There may, again, be issues with restricting the range to that of the data, without the aforementioned BOOLs set to YES, cutting the animation short.

Let me know how you get on :slight_smile:

Simon


#3

Hey Simon,

Yep so I have both flags set to true. I’ve tried the redrawing after the animation, but it’s hard to do consistently. If you’re animating from very different scales, it takes a while to animate and will still cut it short. :frowning: Know of any reliable way to do this?


#4

If you’ve got those flags set to true, I’m not sure why your setRange call isn’t animating when you call it - have you got any code you can share that I can have a look at?

To prevent cutting the animation short using method 2, you could try implementing the  sChartRenderFinished  delegate method and only trigger your redraw when you can see that your range has finished animating to the target range?

Simon


#5

Hey Simon your idea for method 2 sounds like a great solution, will let you know how it goes! Re your first question, here’s a little code below. [refreshCharts] is basically a wrapper function that does a reloadData call and a redrawChart call for multiple charts we have. Where I’m directly setting the xAxis range is where I used to try doing the animated setRange call, but that didn’t work for some reason. I’m probably going to give your DidEndRender delegate a shot. Thanks!

/** @brief Set xAxis range for graphs */

  • (void)setXAxisRange:(MGChartViewControllerDrawerButton)buttonType {
        NSDate* endDate = [NSDate date];
        NSDate* startDate = [endDate dateByAddingTimeInterval:-[self timeIntervalForDrawerButton:buttonType]];

    // Set range & update data
    SChartDateRange* range = [[SChartDateRange alloc] initWithDateMinimum:startDate andDateMaximum:endDate];
    [self refreshData:range completion:^(bool success) {
        if (success) {
            self.valueChart.xAxis.defaultRange = range;
            self.volumeChart.xAxis.defaultRange = range;
            [self refreshCharts:false];
        }
    }];
}


#6

I just updated my post - I meant the sChartRenderFinished delegate method… there is no sChartDidRender method, I made it up! This is what I get for not checking the API before writing  :blush:

Apologies for that! Let me know how you get on  :grin:


#7

Hey Simon,

So unfortunately that still doesn’t work. :frowning: It still cuts the animation short, especially when I’m animating big changes like from 7 days to an hour range. I’m using the following code now:

SChartDateRange* range = [[SChartDateRange alloc] initWithDateMinimum:startDate andDateMaximum:endDate];
[self.valueChart.xAxis setRangeWithMinimum:range.minimumAsDate andMaximum:range.maximumAsDate withAnimation:true usingBounceLimits:true];
[self.volumeChart.xAxis setRangeWithMinimum:range.minimumAsDate andMaximum:range.maximumAsDate withAnimation:true usingBounceLimits:true];
[self refreshData:range completion:^(bool success) {
    if (success) {
        self.refreshOnRenderFinished = true;
    }
}];

/** @brief Catch when rendering movement ends */

  • (void)sChartRenderFinished:(ShinobiChart *)chart
    {
        if (self.refreshOnRenderFinished) {
            self.refreshOnRenderFinished = false;
            [selfrefreshCharts:true];
        }
    }

#8

I’m running into the same problem myself. It would be tremendously helpful to have a completion block on the animated -setRange: call.


#9

Seriously. I suggested it to their support. Hoping they build one at some point!


#10

Until the folks at Shinobi figure things out, I’ve resolved the problem as follows. I wrote a little class that performs a block after a throttled time interval. (see here: https://gist.github.com/jwilling/6012128)

Using that, I run it in the rendering completion delegate method and use that to determine when all animations have completed.

- (void)sChartRenderFinished:(ShinobiChart *)chart {
    // Since Shinobi doesn't offer a way to receive a callback after setting a new range,
    // we have to improvise. When the range has completed its animation the rendering should stop.
    // This sets up a throttled block so that as soon as 0.1 seconds elapse since the last rendering
    // pass, we assume that the animation has completed.
    [JNWThrottledBlock runBlock:^{
        [self chartAnimationCompleted];
    } withIdentifier:@"ChartRenderingCompletionBuffer" throttle:0.1];
}

- (void)chartAnimationCompleted {
    if (![self.lastCompletelyRenderedXRange.minimum isEqualToNumber:self.chart.xAxis.axisRange.minimum] ||
        ![self.lastCompletelyRenderedXRange.maximum isEqualToNumber:self.chart.xAxis.axisRange.maximum]) {
        // do something
    }

    self.lastCompletelyRenderedXRange = self.chart.xAxis.axisRange;
}

I’m doing some adjustments to the range in the completion, so I store the last x range to make sure we don’t enter an infinite update block. Seems to work ok, although it’s frustrating not having this built-in.


#11

Hey that looks great, will give it a shot myself tomorrow. Thanks!


#12

Hi all,

Just wanted to say that we’re aware that this is something you guys want, completion blocks, and we’ll see what we can do :slight_smile: Also, if there are any other, similar, things you find that you think would be helpful additions to the API then don’t hesitate to let us know about them!

Simon


#13

Thanks, Simon!