SciChart® the market leader in Fast WPF Charts, WPF 3D Charts, and iOS Chart & Android Chart Components
SciChart’s OpenGLES iOS Chart library ships with ~60 Objective-C and Swift 4 iOS Chart Examples which you can browse, play with, view the source-code and even export each iOS Objective-C / Swift Chart Example to a stand-alone XCode project. All of this is possible with the new and improved SciChart iOS Examples Suite, which ships as part of the SciChart iOS 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 4 and Objective-C source code for the iOS Realtime Ghosted Traces Chart example is included below (Scroll down!).
Did you know you can also view the source code from one of the following sources as well?
//****************************************************************************** // SCICHART® Copyright SciChart Ltd. 2011-2018. 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 "DataManager.h" #import "RandomUtil.h" @implementation RealTimeGhostTracesChartView { NSTimer * _timer; double _lastAmplitude; double _phase; } - (void)commonInit { __weak typeof(self) wSelf = self; self.speedChanged = ^(UISlider * sender) { [wSelf onSpeedChanged:sender]; }; } - (void)initExample { _lastAmplitude = 1.0; id<SCIAxis2DProtocol> xAxis = [SCINumericAxis new]; xAxis.autoRange = SCIAutoRange_Always; id<SCIAxis2DProtocol> yAxis = [SCINumericAxis new]; yAxis.autoRange = SCIAutoRange_Never; yAxis.visibleRange = [[SCIDoubleRange alloc] initWithMin:SCIGeneric(-2.0) Max:SCIGeneric(2.0)]; [self.surface.xAxes add:xAxis]; [self.surface.yAxes add:yAxis]; uint limeGreen = 0xFF32CD32; [self addLineRenderableSeries:limeGreen opacity:1.0]; [self addLineRenderableSeries:limeGreen opacity:0.9]; [self addLineRenderableSeries:limeGreen opacity:0.8]; [self addLineRenderableSeries:limeGreen opacity:0.7]; [self addLineRenderableSeries:limeGreen opacity:0.62]; [self addLineRenderableSeries:limeGreen opacity:0.55]; [self addLineRenderableSeries:limeGreen opacity:0.45]; [self addLineRenderableSeries:limeGreen opacity:0.35]; [self addLineRenderableSeries:limeGreen opacity:0.25]; [self addLineRenderableSeries:limeGreen opacity:0.15]; _timer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(updateData:) userInfo:nil repeats:YES]; } - (void)willMoveToWindow:(UIWindow *)newWindow{ [super willMoveToWindow: newWindow]; if (newWindow == nil) { [_timer invalidate]; _timer = nil; } } - (void)onSpeedChanged:(UISlider *) sender { if (sender.value > 0) { if (_timer != nil) { [_timer invalidate]; } _timer = [NSTimer scheduledTimerWithTimeInterval:sender.value / 1000.0 target:self selector:@selector(updateData:) userInfo:nil repeats:YES]; } } - (void)updateData:(NSTimer *)timer { [SCIUpdateSuspender usingWithSuspendable:self.surface withBlock:^{ SCIXyDataSeries * dataSeries = [[SCIXyDataSeries alloc] initWithXType:SCIDataType_Double YType:SCIDataType_Double]; double randomAmplitude = _lastAmplitude + ([RandomUtil nextDouble] - 0.5); if (randomAmplitude < -2.0) { randomAmplitude = -2.0; } else if (randomAmplitude > 2.0) { randomAmplitude = 2.0; } DoubleSeries * noisySinewave = [DataManager getNoisySinewaveWithAmplitude:randomAmplitude Phase:_phase PointCount:1000 NoiseAmplitude:0.25]; _lastAmplitude = randomAmplitude; [dataSeries appendRangeX:noisySinewave.xValues Y:noisySinewave.yValues Count:noisySinewave.size]; [self reassignRenderSeriesWithDataSeries:dataSeries]; }]; } - (void)reassignRenderSeriesWithDataSeries:(SCIXyDataSeries *)dataSeries { SCIRenderableSeriesCollection * rs = self.surface.renderableSeries; // shift old dataSeries [rs itemAt:9].dataSeries = [rs itemAt:8].dataSeries; [rs itemAt:8].dataSeries = [rs itemAt:7].dataSeries; [rs itemAt:7].dataSeries = [rs itemAt:6].dataSeries; [rs itemAt:6].dataSeries = [rs itemAt:5].dataSeries; [rs itemAt:5].dataSeries = [rs itemAt:4].dataSeries; [rs itemAt:4].dataSeries = [rs itemAt:3].dataSeries; [rs itemAt:3].dataSeries = [rs itemAt:2].dataSeries; [rs itemAt:2].dataSeries = [rs itemAt:1].dataSeries; [rs itemAt:1].dataSeries = [rs itemAt:0].dataSeries; // use new dataSeries to draw first renderableSeries [rs itemAt:0].dataSeries = dataSeries; } - (void)addLineRenderableSeries:(uint)color opacity:(float)opacity { SCIFastLineRenderableSeries * lineRenerableSeries = [SCIFastLineRenderableSeries new]; lineRenerableSeries.opacity = opacity; lineRenerableSeries.strokeStyle = [[SCISolidPenStyle alloc] initWithColorCode:color withThickness:1]; [self.surface.renderableSeries add:lineRenerableSeries]; } @end
<?xml version="1.0" encoding="UTF-8"?> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> <device id="retina5_9" orientation="portrait"> <adaptation id="fullscreen"/> </device> <dependencies> <deployment identifier="iOS"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <objects> <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="RealtimeGhostTracesLayout"> <connections> <outlet property="millisecondsLabel" destination="roQ-7N-DOG" id="uu7-E3-Ndl"/> <outlet property="slider" destination="gH6-rU-ZzA" id="FSx-QX-7Rc"/> <outlet property="surface" destination="h4c-V7-xn5" id="lfI-Vv-A6Z"/> </connections> </placeholder> <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> <view contentMode="scaleToFill" id="iN0-l3-epB"> <rect key="frame" x="0.0" y="0.0" width="375" height="812"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Speed" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="COS-e2-m9X"> <rect key="frame" x="8" y="52" width="41.333333333333336" height="17"/> <fontDescription key="fontDescription" type="system" pointSize="14"/> <color key="textColor" red="0.91675920050000004" green="0.91675920050000004" blue="0.91675920050000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="20 ms" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="roQ-7N-DOG"> <rect key="frame" x="327" y="52" width="40" height="17"/> <fontDescription key="fontDescription" type="system" pointSize="14"/> <color key="textColor" red="0.91675920050000004" green="0.91675920050000004" blue="0.91675920050000004" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <nil key="highlightedColor"/> </label> <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="20" minValue="1" maxValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="gH6-rU-ZzA"> <rect key="frame" x="55.333333333333343" y="45.666666666666664" width="265.66666666666663" height="30.999999999999993"/> <connections> <action selector="sliderValueChanged:" destination="-1" eventType="valueChanged" id="JN6-HO-bb3"/> </connections> </slider> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="h4c-V7-xn5" customClass="SCIChartSurface"> <rect key="frame" x="0.0" y="83.666666666666686" width="375" height="694.33333333333326"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> </view> </subviews> <color key="backgroundColor" red="0.10980392156862745" green="0.10980392156862745" blue="0.10980392156862745" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <constraints> <constraint firstItem="COS-e2-m9X" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="8" id="1k8-yG-Tc8"/> <constraint firstItem="h4c-V7-xn5" firstAttribute="top" secondItem="gH6-rU-ZzA" secondAttribute="bottom" constant="8" id="1qw-1C-u7q"/> <constraint firstItem="gH6-rU-ZzA" firstAttribute="centerY" secondItem="COS-e2-m9X" secondAttribute="centerY" id="61d-rU-gzY"/> <constraint firstItem="h4c-V7-xn5" firstAttribute="trailing" secondItem="iN0-l3-epB" secondAttribute="trailing" id="6u1-rq-lJX"/> <constraint firstItem="h4c-V7-xn5" firstAttribute="bottom" secondItem="vUN-kp-3ea" secondAttribute="bottom" id="HbW-Jh-H4x"/> <constraint firstItem="gH6-rU-ZzA" firstAttribute="trailing" secondItem="roQ-7N-DOG" secondAttribute="leading" constant="-8" id="JJe-iR-hXa"/> <constraint firstItem="h4c-V7-xn5" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="W9q-Ed-isI"/> <constraint firstItem="roQ-7N-DOG" firstAttribute="trailing" secondItem="vUN-kp-3ea" secondAttribute="trailing" constant="-8" id="ab6-j9-JaH"/> <constraint firstItem="COS-e2-m9X" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="8" id="inL-Yf-cqM"/> <constraint firstItem="gH6-rU-ZzA" firstAttribute="leading" secondItem="COS-e2-m9X" secondAttribute="trailing" constant="8" id="x1j-72-Xxp"/> <constraint firstItem="roQ-7N-DOG" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="8" id="zLq-az-2wd"/> </constraints> <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/> </view> </objects> </document>
//****************************************************************************** // SCICHART® Copyright SciChart Ltd. 2011-2018. 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: RealtimeGhostTracesLayout { private var _timer: Timer? private var _lastAmplitude = 1.0 private var _phase = 0.0 override func commonInit() { weak var wSelf = self self.speedChanged = { sender in wSelf?.onSpeedChanged(sender!) } } override func initExample() { let xAxis = SCINumericAxis() xAxis.autoRange = .always let yAxis = SCINumericAxis() yAxis.autoRange = .never yAxis.visibleRange = SCIDoubleRange.init(min: SCIGeneric(-2), max: SCIGeneric(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) _timer = Timer.scheduledTimer(timeInterval: 0.02, target: self, selector: #selector(updateData), userInfo: nil, repeats: true) } override func willMove(toWindow newWindow: UIWindow?) { super.willMove(toWindow: newWindow) if newWindow == nil { _timer?.invalidate() _timer = nil } } private func onSpeedChanged(_ sender:UISlider) { _timer?.invalidate() _timer = Timer.scheduledTimer(timeInterval: Double(sender.value) / 1000.0, target: self, selector: #selector(updateData), userInfo: nil, repeats: true) } @objc fileprivate func updateData(_ timer:Timer) { SCIUpdateSuspender.usingWithSuspendable(surface) { let dataSeries = SCIXyDataSeries.init(xType: .double, yType: .double) var randomAmplitude:Double = self._lastAmplitude + (RandomUtil.nextDouble() - 0.5) if (randomAmplitude < -2.0) { randomAmplitude = -2.0 } else if (randomAmplitude > 2.0) { randomAmplitude = 2.0; } let noisySinewave = DataManager.getNoisySinewave(withAmplitude: randomAmplitude, phase: self._phase, pointCount: 1000, noiseAmplitude: 0.25) self._lastAmplitude = randomAmplitude; dataSeries.appendRangeX(noisySinewave!.xValues, y: noisySinewave!.yValues, count: noisySinewave!.size) self.reassignRenderSeriesWith(dataSeries: dataSeries) } } fileprivate func reassignRenderSeriesWith(dataSeries: SCIXyDataSeries) { let rs = surface.renderableSeries // shift old dataSeries rs.item(at: 9).dataSeries = rs.item(at: 8).dataSeries rs.item(at: 8).dataSeries = rs.item(at: 7).dataSeries rs.item(at: 7).dataSeries = rs.item(at: 6).dataSeries rs.item(at: 6).dataSeries = rs.item(at: 5).dataSeries rs.item(at: 5).dataSeries = rs.item(at: 4).dataSeries rs.item(at: 4).dataSeries = rs.item(at: 3).dataSeries rs.item(at: 3).dataSeries = rs.item(at: 2).dataSeries rs.item(at: 2).dataSeries = rs.item(at: 1).dataSeries rs.item(at: 1).dataSeries = rs.item(at: 0).dataSeries // use new dataSeries to draw first renderableSeries rs.item(at: 0).dataSeries = dataSeries } fileprivate func addLineRenderableSeries(_ colorCode: UInt32, opacity: Float){ let lineRenderSeries = SCIFastLineRenderableSeries() lineRenderSeries.opacity = opacity lineRenderSeries.strokeStyle = SCISolidPenStyle.init(colorCode: colorCode, withThickness: 1) surface.renderableSeries.add(lineRenderSeries) } }