SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, iOS Chart, Android Chart and JavaScript Chart Components
Please note! These examples are new to SciChart iOS v4 release! SciChart’s OpenGL ES and Metal iOS and Metal macOS Chart library ships with hundred of Objective-C and Swift iOS&macOS Chart Examples which you can browse, play with and view the source-code. All of this is possible with the new and improved SciChart iOS Examples Suite and demo application for Mac, which ships as part of the SciChart SDK.
Demonstrates the difference between FIFO and standard DataSeries. A FIFO series discards old data-points once a predefined number of points is met. This type of data-series is extremely efficient for scrolling charts, where you do not care about discarded (off-screen) data.
FIFO Series can be used in more ways than just scrolling a chart. For instance, reload the entire FIFO buffer each frame to get a Spectrum Analyzer style chart. Or, use FIFO series and set the XAxis.VisibleRange to achieve an ECG style chart.
The Swift and Objective-C source code for the iOS and macOS FIFO Scrolling Chart example is included below (Scroll down!).
Did you know that we have the source code for all our example available for free on Github?
Clone the SciChart.iOS.Examples from Github.
Also the SciChart iOS and Scichart macOS Trials contain the full source for the examples (link below).
//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2019. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales: sales@scichart.com
//
// FifoScrollingChartView.m is part of the SCICHART® Examples. Permission is hereby granted
// to modify, create derivative works, distribute and publish any part of this source
// code whether for commercial, private or personal use.
//
// The SCICHART® examples are distributed in the hope that they will be useful, but
// without any warranty. It is provided "AS IS" without warranty of any kind, either
// expressed or implied.
//******************************************************************************
#import "FifoScrollingChartView.h"
#import "SCDToolbarItem.h"
#import "SCDRandomUtil.h"
#import "SCDToolbarButtonsGroup.h"
static int const FifoCapacicty = 50;
static double const TimeInterval = 30.0;
static double const OneOverTimeInterval = 1.0 / TimeInterval;
static double const VisibleRangeMax = FifoCapacicty * OneOverTimeInterval;
static double const GrowBy = VisibleRangeMax * 0.1;
@implementation FifoScrollingChartView {
NSTimer *_timer;
SCIXyDataSeries *_ds1;
SCIXyDataSeries *_ds2;
SCIXyDataSeries *_ds3;
double _t;
BOOL _isRunning;
}
- (Class)associatedType { return SCIChartSurface.class; }
- (NSArray<id<ISCDToolbarItem>> *)provideExampleSpecificToolbarItems {
__weak typeof(self) wSelf = self;
return @[[[SCDToolbarButtonsGroup alloc] initWithToolbarItems:@[
[[SCDToolbarItem alloc] initWithTitle:@"Start" image:[SCIImage imageNamed:@"chart.play"] andAction:^{ self->_isRunning = YES; }],
[[SCDToolbarItem alloc] initWithTitle:@"Pause" image:[SCIImage imageNamed:@"chart.pause"] andAction:^{ self->_isRunning = NO; }],
[[SCDToolbarItem alloc] initWithTitle:@"Stop" image:[SCIImage imageNamed:@"chart.stop"] andAction:^{
self->_isRunning = NO;
[wSelf resetChart];
}],
]]];
}
- (void)initExample {
id<ISCIAxis> xAxis = [SCINumericAxis new];
xAxis.autoRange = SCIAutoRange_Never;
xAxis.visibleRange = [[SCIDoubleRange alloc] initWithMin:-GrowBy max:VisibleRangeMax + GrowBy];
id<ISCIAxis> yAxis = [SCINumericAxis new];
yAxis.autoRange = SCIAutoRange_Always;
_ds1 = [[SCIXyDataSeries alloc] initWithXType:SCIDataType_Double yType:SCIDataType_Double];
_ds1.fifoCapacity = FifoCapacicty;
_ds2 = [[SCIXyDataSeries alloc] initWithXType:SCIDataType_Double yType:SCIDataType_Double];
_ds2.fifoCapacity = FifoCapacicty;
_ds3 = [[SCIXyDataSeries alloc] initWithXType:SCIDataType_Double yType:SCIDataType_Double];
_ds3.fifoCapacity = FifoCapacicty;
SCIFastLineRenderableSeries *rSeries1 = [SCIFastLineRenderableSeries new];
rSeries1.dataSeries = _ds1;
rSeries1.strokeStyle = [[SCISolidPenStyle alloc] initWithColorCode:0xFF4083B7 thickness:2];
SCIFastLineRenderableSeries *rSeries2 = [SCIFastLineRenderableSeries new];
rSeries2.dataSeries = _ds2;
rSeries2.strokeStyle = [[SCISolidPenStyle alloc] initWithColorCode:0xFFFFA500 thickness:2];
SCIFastLineRenderableSeries *rSeries3 = [SCIFastLineRenderableSeries new];
rSeries3.dataSeries = _ds3;
rSeries3.strokeStyle = [[SCISolidPenStyle alloc] initWithColorCode:0xFFE13219 thickness:2];
[SCIUpdateSuspender usingWithSuspendable:self.surface withBlock:^{
[self.surface.xAxes add:xAxis];
[self.surface.yAxes add:yAxis];
[self.surface.renderableSeries add:rSeries1];
[self.surface.renderableSeries add:rSeries2];
[self.surface.renderableSeries add:rSeries3];
}];
_timer = [NSTimer scheduledTimerWithTimeInterval:TimeInterval / 1000.0 target:self selector:@selector(updateData:) userInfo:nil repeats:YES];
_isRunning = YES;
}
- (void)updateData:(NSTimer *)timer {
if (!_isRunning) return;
double y1 = 3.0 * sin(((2 * M_PI) * 1.4) * _t) + [SCDRandomUtil nextDouble] * 0.5;
double y2 = 2.0 * cos(((2 * M_PI) * 0.8) * _t) + [SCDRandomUtil nextDouble] * 0.5;
double y3 = 1.0 * sin(((2 * M_PI) * 2.2) * _t) + [SCDRandomUtil nextDouble] * 0.5;
[_ds1 appendX:@(_t) y:@(y1)];
[_ds2 appendX:@(_t) y:@(y2)];
[_ds3 appendX:@(_t) y:@(y3)];
_t += OneOverTimeInterval;
id<ISCIAxis> xAxis = [self.surface.xAxes itemAt:0];
if (_t > VisibleRangeMax) {
[xAxis.visibleRange setDoubleMinTo:xAxis.visibleRange.minAsDouble + OneOverTimeInterval maxTo:xAxis.visibleRange.maxAsDouble + OneOverTimeInterval];
}
}
- (void)resetChart {
[SCIUpdateSuspender usingWithSuspendable:self.surface withBlock:^{
[self->_ds1 clear];
[self->_ds2 clear];
[self->_ds3 clear];
}];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[_timer invalidate];
_timer = nil;
}
@end
//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2019. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales: sales@scichart.com
//
// FifoScrollingChartView.swift is part of the SCICHART® Examples. Permission is hereby granted
// to modify, create derivative works, distribute and publish any part of this source
// code whether for commercial, private or personal use.
//
// The SCICHART® examples are distributed in the hope that they will be useful, but
// without any warranty. It is provided "AS IS" without warranty of any kind, either
// expressed or implied.
//******************************************************************************
private let FifoCapacicty: Int = 50
private let TimeInterval = 30.0
private let OneOverTimeInterval = 1.0 / 30
private let VisibleRangeMax = 50.0 * 1.0 / 30.0
private let GrowBy = 50.0 * 1.0 / 30.0 * 0.1
class FifoScrollingChartView: SCDSingleChartViewController<SCIChartSurface> {
private var _timer: Timer?
private var _ds1: SCIXyDataSeries!
private var _ds2: SCIXyDataSeries!
private var _ds3: SCIXyDataSeries!
private var _t = 0.0
private var _isRunning = false
override var associatedType: AnyClass { return SCIChartSurface.self }
override func provideExampleSpecificToolbarItems() -> [ISCDToolbarItem] {
return [SCDToolbarButtonsGroup(toolbarItems: [
SCDToolbarButton(title: "Start", image: SCIImage(named: "chart.play"), andAction: { [weak self] in self?._isRunning = true }),
SCDToolbarButton(title: "Pause", image: SCIImage(named: "chart.pause"), andAction: { [weak self] in self?._isRunning = false }),
SCDToolbarButton(title: "Stop", image: SCIImage(named: "chart.stop"), andAction: { [weak self] in
self?._isRunning = false
self?.resetChart()
})
])]
}
override func initExample() {
let xAxis = SCINumericAxis()
xAxis.autoRange = .never
xAxis.visibleRange = SCIDoubleRange.init(min: -GrowBy, max: VisibleRangeMax + GrowBy)
let yAxis = SCINumericAxis()
yAxis.autoRange = .always
_ds1 = SCIXyDataSeries(xType: .double, yType: .double)
_ds1.fifoCapacity = FifoCapacicty
_ds2 = SCIXyDataSeries(xType: .double, yType: .double)
_ds2.fifoCapacity = FifoCapacicty
_ds3 = SCIXyDataSeries(xType: .double, yType: .double)
_ds3.fifoCapacity = FifoCapacicty
let rSeries1 = SCIFastLineRenderableSeries()
rSeries1.dataSeries = _ds1
rSeries1.strokeStyle = SCISolidPenStyle(color: 0xFF4083B7, thickness: 2)
let rSeries2 = SCIFastLineRenderableSeries()
rSeries2.dataSeries = _ds2
rSeries2.strokeStyle = SCISolidPenStyle(color: 0xFFFFA500, thickness: 2)
let rSeries3 = SCIFastLineRenderableSeries()
rSeries3.dataSeries = _ds3
rSeries3.strokeStyle = SCISolidPenStyle(color: 0xFFE13219, thickness: 2)
SCIUpdateSuspender.usingWith(surface) {
self.surface.xAxes.add(xAxis)
self.surface.yAxes.add(yAxis)
self.surface.renderableSeries.add(rSeries1)
self.surface.renderableSeries.add(rSeries2)
self.surface.renderableSeries.add(rSeries3)
}
_timer = Timer.scheduledTimer(timeInterval: TimeInterval / 1000, target: self, selector: #selector(updateData), userInfo: nil, repeats: true)
_isRunning = true
}
@objc func updateData(_ timer: Timer) {
if (!_isRunning) { return }
let y1: Double = 3.0 * sin(((2 * .pi) * 1.4) * _t) + SCDRandomUtil.nextDouble() * 0.5
let y2: Double = 2.0 * cos(((2 * .pi) * 0.8) * _t) + SCDRandomUtil.nextDouble() * 0.5
let y3: Double = 1.0 * sin(((2 * .pi) * 2.2) * _t) + SCDRandomUtil.nextDouble() * 0.5
_ds1.append(x: _t, y: y1)
_ds2.append(x: _t, y: y2)
_ds3.append(x: _t, y: y3)
_t += OneOverTimeInterval;
let xAxis = surface.xAxes.item(at: 0)
if (_t > VisibleRangeMax) {
xAxis.visibleRange.setDoubleMinTo(xAxis.visibleRange.minAsDouble + OneOverTimeInterval, maxTo: xAxis.visibleRange.maxAsDouble + OneOverTimeInterval)
}
}
fileprivate func resetChart() {
SCIUpdateSuspender.usingWith(surface) {
self._ds1.clear()
self._ds2.clear()
self._ds3.clear()
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
_timer?.invalidate()
_timer = nil
}
}