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.
This example shows persistence of old traces giving a ‘ghosted’ or digital phosphor effect.
The example updates 10 series each with 1,000 points in realtime while setting the opacity of series on each timer tick. As new series are drawn older series are made increasingly transparent until they become invisible.
The Swift and Objective-C source code for the iOS and macOS Realtime Ghosted Traces 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
//
// RealTimeGhostTracesChartView.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 "RealTimeGhostTracesChartView.h"
#import "SCDRealTimeGhostTracesToolbarItem.h"
#import "SCDDataManager.h"
#import "SCDRandomUtil.h"
@interface RealTimeGhostTracesChartView ()
@property (nonatomic, strong) SCDRealTimeGhostTracesToolbarItem *actionItem;
@property (nonatomic) NSTimer *timer;
@end
@implementation RealTimeGhostTracesChartView {
double _lastAmplitude;
double _phase;
}
- (Class)associatedType { return SCIChartSurface.class; }
- (BOOL)showDefaultModifiersInToolbar { return NO; }
#if TARGET_OS_OSX
- (NSArray<id<ISCDToolbarItem>> *)provideExampleSpecificToolbarItems {
return @[self.actionItem];
}
#elif TARGET_OS_IOS
- (SCIView *)providePanel {
return [self.actionItem createView];
}
#endif
- (SCDRealTimeGhostTracesToolbarItem *)actionItem {
if (!_actionItem) {
__weak typeof(self) wSelf = self;
_actionItem = [[SCDRealTimeGhostTracesToolbarItem alloc] initWithAction:^(double doubleValue) {
if (doubleValue > 0) {
if (wSelf.timer != nil) {
[wSelf.timer invalidate];
}
[wSelf p_SCD_startTimerWithValue:doubleValue];
}
}];
}
return _actionItem;
}
- (void)initExample {
_lastAmplitude = 1.0;
id<ISCIAxis> xAxis = [SCINumericAxis new];
xAxis.autoRange = SCIAutoRange_Always;
id<ISCIAxis> yAxis = [SCINumericAxis new];
yAxis.autoRange = SCIAutoRange_Never;
yAxis.visibleRange = [[SCIDoubleRange alloc] initWithMin:-2.0 max:2.0];
[self.surface.xAxes add:xAxis];
[self.surface.yAxes add:yAxis];
uint limeGreen = 0xFF32CD32;
[self p_SCD_addLineRenderableSeries:limeGreen opacity:1.0];
[self p_SCD_addLineRenderableSeries:limeGreen opacity:0.9];
[self p_SCD_addLineRenderableSeries:limeGreen opacity:0.8];
[self p_SCD_addLineRenderableSeries:limeGreen opacity:0.7];
[self p_SCD_addLineRenderableSeries:limeGreen opacity:0.62];
[self p_SCD_addLineRenderableSeries:limeGreen opacity:0.55];
[self p_SCD_addLineRenderableSeries:limeGreen opacity:0.45];
[self p_SCD_addLineRenderableSeries:limeGreen opacity:0.35];
[self p_SCD_addLineRenderableSeries:limeGreen opacity:0.25];
[self p_SCD_addLineRenderableSeries:limeGreen opacity:0.15];
[self p_SCD_startTimerWithValue:_actionItem.sliderValue];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[_timer invalidate];
_timer = nil;
}
- (void)p_SCD_startTimerWithValue:(double)value {
_timer = [NSTimer scheduledTimerWithTimeInterval:value / 1000.0 target:self selector:@selector(p_SCD_updateData:) userInfo:nil repeats:YES];
}
- (void)p_SCD_updateData:(NSTimer *)timer {
[SCIUpdateSuspender usingWithSuspendable:self.surface withBlock:^{
SCIXyDataSeries *dataSeries = [[SCIXyDataSeries alloc] initWithXType:SCIDataType_Double yType:SCIDataType_Double];
double randomAmplitude = self->_lastAmplitude + ([SCDRandomUtil nextDouble] - 0.5);
if (randomAmplitude < -2.0) {
randomAmplitude = -2.0;
} else if (randomAmplitude > 2.0) {
randomAmplitude = 2.0;
}
SCDDoubleSeries *noisySinewave = [SCDDataManager getNoisySinewaveWithAmplitude:randomAmplitude Phase:self->_phase PointCount:1000 NoiseAmplitude:0.25];
self->_lastAmplitude = randomAmplitude;
[dataSeries appendValuesX:noisySinewave.xValues y:noisySinewave.yValues];
[self p_SCD_reassignRenderSeriesWithDataSeries:dataSeries];
}];
}
- (void)p_SCD_reassignRenderSeriesWithDataSeries:(SCIXyDataSeries *)dataSeries {
SCIRenderableSeriesCollection *rSeries = self.surface.renderableSeries;
// shift old dataSeries
[rSeries itemAt:9].dataSeries = [rSeries itemAt:8].dataSeries;
[rSeries itemAt:8].dataSeries = [rSeries itemAt:7].dataSeries;
[rSeries itemAt:7].dataSeries = [rSeries itemAt:6].dataSeries;
[rSeries itemAt:6].dataSeries = [rSeries itemAt:5].dataSeries;
[rSeries itemAt:5].dataSeries = [rSeries itemAt:4].dataSeries;
[rSeries itemAt:4].dataSeries = [rSeries itemAt:3].dataSeries;
[rSeries itemAt:3].dataSeries = [rSeries itemAt:2].dataSeries;
[rSeries itemAt:2].dataSeries = [rSeries itemAt:1].dataSeries;
[rSeries itemAt:1].dataSeries = [rSeries itemAt:0].dataSeries;
// use new dataSeries to draw first renderableSeries
[rSeries itemAt:0].dataSeries = dataSeries;
}
- (void)p_SCD_addLineRenderableSeries:(uint)color opacity:(float)opacity {
SCIFastLineRenderableSeries *lineRenerableSeries = [SCIFastLineRenderableSeries new];
lineRenerableSeries.opacity = opacity;
lineRenerableSeries.strokeStyle = [[SCISolidPenStyle alloc] initWithColorCode:color thickness:1];
[self.surface.renderableSeries add:lineRenerableSeries];
}
@end
//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2019. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales: sales@scichart.com
//
// RealTimeGhostTracesChartView.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.
//******************************************************************************
class RealTimeGhostTracesChartView: SCDSingleChartWithTopPanelViewController<SCIChartSurface> {
private lazy var actionItem: SCDRealTimeGhostTracesToolbarItem = {
let item = SCDRealTimeGhostTracesToolbarItem { [weak self] doubleValue in
guard let self = self else { return }
if (doubleValue > 0) {
self._timer?.invalidate()
self.startTimer(with: doubleValue)
}
}
return item
}()
private var _timer: Timer?
private var _lastAmplitude = 1.0
private var _phase = 0.0
override var associatedType: AnyClass { return SCIChartSurface.self }
override var showDefaultModifiersInToolbar: Bool { return false }
#if os(OSX)
override func provideExampleSpecificToolbarItems() -> [ISCDToolbarItem] {
return [actionItem]
}
#elseif os(iOS)
override func providePanel() -> SCIView {
return actionItem.createView()
}
#endif
override func initExample() {
let xAxis = SCINumericAxis()
xAxis.autoRange = .always
let yAxis = SCINumericAxis()
yAxis.autoRange = .never
yAxis.visibleRange = SCIDoubleRange.init(min: -2, max: 2)
surface.xAxes.add(xAxis)
surface.yAxes.add(yAxis)
let limeGreen: uint = 0xFF32CD32
addLineRenderableSeries(limeGreen, opacity: 1.0)
addLineRenderableSeries(limeGreen, opacity: 0.9)
addLineRenderableSeries(limeGreen, opacity: 0.8)
addLineRenderableSeries(limeGreen, opacity: 0.7)
addLineRenderableSeries(limeGreen, opacity: 0.62)
addLineRenderableSeries(limeGreen, opacity: 0.55)
addLineRenderableSeries(limeGreen, opacity: 0.45)
addLineRenderableSeries(limeGreen, opacity: 0.35)
addLineRenderableSeries(limeGreen, opacity: 0.25)
addLineRenderableSeries(limeGreen, opacity: 0.15)
startTimer(with: actionItem.sliderValue)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
_timer?.invalidate()
_timer = nil
}
private func startTimer(with sliderValue: Double) {
_timer = Timer.scheduledTimer(timeInterval: sliderValue / 1000, target: self, selector: #selector(updateData), userInfo: nil, repeats: true)
}
@objc private func updateData(_ timer: Timer) {
SCIUpdateSuspender.usingWith(surface) {
let dataSeries = SCIXyDataSeries.init(xType: .double, yType: .double)
var randomAmplitude:Double = self._lastAmplitude + (SCDRandomUtil.nextDouble() - 0.5)
if (randomAmplitude < -2.0) {
randomAmplitude = -2.0
} else if (randomAmplitude > 2.0) {
randomAmplitude = 2.0;
}
let noisySinewave = SCDDataManager.getNoisySinewave(withAmplitude: randomAmplitude, phase: self._phase, pointCount: 1000, noiseAmplitude: 0.25)
self._lastAmplitude = randomAmplitude;
dataSeries.append(x: noisySinewave.xValues, y: noisySinewave.yValues)
self.reassignRenderSeriesWith(dataSeries: dataSeries)
}
}
private func reassignRenderSeriesWith(dataSeries: SCIXyDataSeries) {
let rSeries = surface.renderableSeries
// shift old dataSeries
rSeries.item(at: 9).dataSeries = rSeries.item(at: 8).dataSeries
rSeries.item(at: 8).dataSeries = rSeries.item(at: 7).dataSeries
rSeries.item(at: 7).dataSeries = rSeries.item(at: 6).dataSeries
rSeries.item(at: 6).dataSeries = rSeries.item(at: 5).dataSeries
rSeries.item(at: 5).dataSeries = rSeries.item(at: 4).dataSeries
rSeries.item(at: 4).dataSeries = rSeries.item(at: 3).dataSeries
rSeries.item(at: 3).dataSeries = rSeries.item(at: 2).dataSeries
rSeries.item(at: 2).dataSeries = rSeries.item(at: 1).dataSeries
rSeries.item(at: 1).dataSeries = rSeries.item(at: 0).dataSeries
// use new dataSeries to draw first renderableSeries
rSeries.item(at: 0).dataSeries = dataSeries
}
private func addLineRenderableSeries(_ colorCode: UInt32, opacity: Float) {
let lineRenderSeries = SCIFastLineRenderableSeries()
lineRenderSeries.opacity = opacity
lineRenderSeries.strokeStyle = SCISolidPenStyle.init(color: colorCode, thickness: 1)
surface.renderableSeries.add(lineRenderSeries)
}
}