iOS & macOS charts - Examples
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.
The iOS Realtime Ticking Stock Charts example demonstrates how SciChart iOS is suitable for real-time trading and stock chart apps even in demanding, live markets.
An Ohlc or Candlestick chart is added by using SciChart’s SCIFastCandlestickRenderableSeries or SCIFastOhlcRenderableSeries respectively. Two line series using SCIFastLineRenderableSeries draw the moving averages.
Price data is updated in a SCIOhlcDataSeries in a timer callback. When the data updates, SciChart automatically redraws. Scrolling to the latest bar is handled in code by manipulating the Axis.VisibleRange property.
The Swift and Objective-C source code for the iOS and macOS Realtime Ticking Stock Chartsexample 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).
RealtimeTickingStockChartView.m
View source code//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2019. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales: sales@scichart.com
//
// RealtimeTickingStockChartView.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 "RealtimeTickingStockChartView.h"
#import "SCDDataManager.h"
#import "SCDPriceSeries.h"
#import "SCDMovingAverage.h"
#import "SCDMarketDataService.h"
static int const DefaultPointCount = 150;
static unsigned int const SmaSeriesColor = 0xFFe97064;
static unsigned int const StrokeUpColor = 0xFF68bcae;
static unsigned int const StrokeDownColor = 0xFFae418d;
@implementation RealtimeTickingStockChartView {
SCIOhlcDataSeries *_ohlcDataSeries;
SCIXyDataSeries *_xyDataSeries;
SCIAxisMarkerAnnotation *_smaAxisMarker;
SCIAxisMarkerAnnotation *_ohlcAxisMarker;
SCDMarketDataService *_marketDataService;
SCDMovingAverage *_sma50;
SCDPriceBar *_lastPrice;
id<ISCIAxis> mainXAxis, mainYAxis;
SCIRangeSelectorAnnotation *rangeSelectorAnnotation;
BOOL isDragging;
}
- (void)initExample {
_marketDataService = [[SCDMarketDataService alloc] initWithStartDate:[NSDate dateWithYear:2000 month:8 day:01 hour:12 minute:0 second:0] TimeFrameMinutes:5 TickTimerIntervals:0.02];
_sma50 = [[SCDMovingAverage alloc] initWithLength:50];
[self initDataWithService:_marketDataService];
[self createMainPriceChart];
[self createOverviewChart];
id<ISCIAxisCore> axis = [self.mainSurface.xAxes itemAt:0];
__weak typeof(self) wSelf = self;
axis.visibleRangeChangeListener = ^(id<ISCIAxisCore> axis, id<ISCIRange> oldRange, id<ISCIRange> newRange, BOOL isAnimating) {
RealtimeTickingStockChartView *strongPointer = wSelf;
if (!strongPointer->isDragging) {
strongPointer->rangeSelectorAnnotation.x1 = @(axis.visibleRange.minAsDouble);
strongPointer->rangeSelectorAnnotation.x2 = @(axis.visibleRange.maxAsDouble);
}
};
}
- (void)initDataWithService:(SCDMarketDataService *)marketDataService {
_ohlcDataSeries = [[SCIOhlcDataSeries alloc] initWithXType:SCIDataType_Date yType:SCIDataType_Double];
_ohlcDataSeries.seriesName = @"Price Series";
_xyDataSeries = [[SCIXyDataSeries alloc] initWithXType:SCIDataType_Date yType:SCIDataType_Double];
_xyDataSeries.seriesName = @"50-Period SMA";
SCDPriceSeries *prices = [marketDataService getHistoricalData:DefaultPointCount];
_lastPrice = [prices lastObject];
[_ohlcDataSeries appendValuesX:prices.dateData open:prices.openData high:prices.highData low:prices.lowData close:prices.closeData];
[_xyDataSeries appendValuesX:prices.dateData y:[self getSmaCurrentValues:prices]];
[self subscribePriceUpdate];
}
- (SCIDoubleValues *)getSmaCurrentValues:(SCDPriceSeries *)prices {
SCIDoubleValues *result = [SCIDoubleValues new];
SCIDoubleValues *closeData = prices.closeData;
for (NSInteger i = 0, count = closeData.count; i < count; i++) {
double close = [prices itemAt:i].close.doubleValue;
[result add:[_sma50 push:close].current];
}
return result;
}
- (void)createMainPriceChart {
mainXAxis = [SCICategoryDateAxis new];
mainXAxis.growBy = [[SCIDoubleRange alloc] initWithMin:0.0 max:0.1];
mainXAxis.drawMajorGridLines = NO;
mainYAxis = [SCINumericAxis new];
mainYAxis.autoRange = SCIAutoRange_Always;
SCIFastOhlcRenderableSeries *ohlcSeries = [SCIFastOhlcRenderableSeries new];
ohlcSeries.dataSeries = _ohlcDataSeries;
SCIFastLineRenderableSeries *ma50Series = [SCIFastLineRenderableSeries new];
ma50Series.dataSeries = _xyDataSeries;
ma50Series.strokeStyle = [[SCISolidPenStyle alloc] initWithColorCode:0xFFe97064 thickness:1];
_smaAxisMarker = [SCIAxisMarkerAnnotation new];
_smaAxisMarker.y1 = @(0);
_smaAxisMarker.borderPen = [[SCISolidPenStyle alloc] initWithColorCode:SmaSeriesColor thickness:1];
_smaAxisMarker.backgroundBrush = [[SCISolidBrushStyle alloc] initWithColorCode:SmaSeriesColor];
_ohlcAxisMarker = [SCIAxisMarkerAnnotation new];
_ohlcAxisMarker.y1 = @(0);
_ohlcAxisMarker.borderPen = [[SCISolidPenStyle alloc] initWithColorCode:StrokeUpColor thickness:1];
_ohlcAxisMarker.backgroundBrush = [[SCISolidBrushStyle alloc] initWithColorCode:StrokeUpColor];
SCIZoomPanModifier *zoomPanModifier = [SCIZoomPanModifier new];
zoomPanModifier.direction = SCIDirection2D_XDirection;
SCILegendModifier *legendModifier = [SCILegendModifier new];
legendModifier.orientation = SCIOrientationHorizontal;
legendModifier.position = SCIAlignment_Bottom | SCIAlignment_CenterHorizontal;
legendModifier.margins = (SCIEdgeInsets){.left = 10, .top = 10, .right = 10, .bottom = 10};
[SCIUpdateSuspender usingWithSuspendable:self.mainSurface withBlock:^{
[self.mainSurface.xAxes add:self->mainXAxis];
[self.mainSurface.yAxes add:self->mainYAxis];
[self.mainSurface.renderableSeries addAll:ma50Series, ohlcSeries, nil];
[self.mainSurface.annotations addAll:self->_smaAxisMarker, self->_ohlcAxisMarker, nil];
[self.mainSurface.chartModifiers addAll:[SCIXAxisDragModifier new], zoomPanModifier, [SCIZoomExtentsModifier new], legendModifier, [SCIPinchZoomModifier new], nil];
}];
}
- (void)createOverviewChart {
id<ISCIAxis> xAxis = [SCICategoryDateAxis new];
xAxis.autoRange = SCIAutoRange_Always;
id<ISCIAxis> yAxis = [SCINumericAxis new];
yAxis.growBy = [[SCIDoubleRange alloc] initWithMin:0.1 max:0.1];
yAxis.autoRange = SCIAutoRange_Always;
SCIFastMountainRenderableSeries *mountainSeries = [SCIFastMountainRenderableSeries new];
mountainSeries.dataSeries = _ohlcDataSeries;
mountainSeries.areaStyle = [[SCILinearGradientBrushStyle alloc] initWithStart:CGPointZero end:CGPointMake(0, 1) startColorCode:0x883a668f endColorCode:0xff20384f];
[self configureRangeSelectorAnnotation];
[SCIUpdateSuspender usingWithSuspendable:self.overviewSurface withBlock:^{
[self.overviewSurface.xAxes add:xAxis];
[self.overviewSurface.yAxes add:yAxis];
[self.overviewSurface.renderableSeries add:mountainSeries];
}];
}
- (void)onNewPrice:(SCDPriceBar *)price {
double smaLastValue;
if (_lastPrice.date == price.date) {
[_ohlcDataSeries updateOpen:price.open high:price.high low:price.low close:price.close at:_ohlcDataSeries.count - 1];
smaLastValue = [_sma50 update:price.close.doubleValue].current;
[_xyDataSeries updateY:@(smaLastValue) at:_xyDataSeries.count - 1];
} else {
[_ohlcDataSeries appendX:price.date open:price.open high:price.high low:price.low close:price.close];
smaLastValue = [_sma50 push:price.close.doubleValue].current;
[_xyDataSeries appendX:price.date y:@(smaLastValue)];
id<ISCIRange> visibleRange = self.mainSurface.xAxes[0].visibleRange;
if (visibleRange.maxAsDouble > _ohlcDataSeries.count) {
[visibleRange setDoubleMinTo:visibleRange.minAsDouble + 1 maxTo:visibleRange.maxAsDouble + 1];
}
}
unsigned int color = [price.close compare:price.open] == NSOrderedDescending ? StrokeUpColor : StrokeDownColor;
_ohlcAxisMarker.borderPen = [[SCISolidPenStyle alloc] initWithColorCode:color thickness:1];
_ohlcAxisMarker.backgroundBrush = [[SCISolidBrushStyle alloc] initWithColorCode:color];
_ohlcAxisMarker.y1 = price.close;
_smaAxisMarker.y1 = @(smaLastValue);
_lastPrice = price;
}
- (void)subscribePriceUpdate {
__weak typeof(self) wSelf = self;
[_marketDataService subscribePriceUpdate:^(SCDPriceBar * _Nonnull priceBar) { [wSelf onNewPrice:priceBar]; }];
}
- (void)clearSubscribtions {
[_marketDataService clearSubscriptions];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[_marketDataService clearSubscriptions];
}
-(void)configureRangeSelectorAnnotation {
rangeSelectorAnnotation = [SCIRangeSelectorAnnotation new];
rangeSelectorAnnotation.y1 = @(0);
rangeSelectorAnnotation.y2 = @(1);
rangeSelectorAnnotation.x1 = @(mainXAxis.visibleRange.minAsDouble);
rangeSelectorAnnotation.x2 = @(mainXAxis.visibleRange.maxAsDouble);
rangeSelectorAnnotation.xAxisId = mainXAxis.axisId;
rangeSelectorAnnotation.yAxisId = mainYAxis.axisId;
rangeSelectorAnnotation.coordinateMode = SCIAnnotationCoordinateMode_RelativeY;
rangeSelectorAnnotation.dragDirections = SCIDirection2D_XDirection;
rangeSelectorAnnotation.fillBrush = [[SCISolidBrushStyle alloc] initWithColorCode:0x33FFFFFF];
SCIOverviewAnnotationDragListener *dragListener = [SCIOverviewAnnotationDragListener new];
dragListener.dragDelegate = self;
rangeSelectorAnnotation.annotationDragListener = dragListener;
[self.overviewSurface.annotations addAll:rangeSelectorAnnotation, nil];
}
-(void)changeVisibleRange:(id<ISCIAnnotation>)annotation isFromOnDrag:(BOOL)isFromOnDrag {
#if TARGET_OS_IOS
[SCIView animateWithDuration:2.0
delay:0
options:UIViewAnimationOptionOverrideInheritedCurve
animations:^{
self->mainXAxis.visibleRange.min = annotation.x1;
self->mainXAxis.visibleRange.max = annotation.x2;
}
completion:^(BOOL finished) {
if (!isFromOnDrag) {
self->isDragging = NO;
}
self->rangeSelectorAnnotation.isSelected = YES;
}];
#else
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:2.0];
[[NSAnimationContext currentContext] setCompletionHandler:^{
if (!isFromOnDrag) {
self->isDragging = NO;
}
self->rangeSelectorAnnotation.isSelected = YES;
}];
self->mainXAxis.visibleRange.min = annotation.x1;
self->mainXAxis.visibleRange.max = annotation.x2;
[NSAnimationContext endGrouping];
#endif
}
#pragma mark - Drag Delegates
- (void)onDragStarted:(id<ISCIAnnotation>)annotation {
isDragging = YES;
}
- (void)onDragAnnotation:(id<ISCIAnnotation>)annotation byXDelta:(CGFloat)xDelta yDelta:(CGFloat)yDelta {
[self changeVisibleRange:annotation isFromOnDrag:YES];
}
- (void)onDragEnded:(id<ISCIAnnotation>)annotation {
[self changeVisibleRange:annotation isFromOnDrag:NO];
}
@end
RealtimeTickingStockChartView.swift
View source code//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2019. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales: sales@scichart.com
//
// RealtimeTickingStockChartView.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.
//******************************************************************************
let DefaultPointCount = 150
let SmaSeriesColor: uint = 0xFFe97064
let StrokeUpColor: uint = 0xFF68bcae
let StrokeDownColor: uint = 0xFFae418d
class RealtimeTickingStockChartView: SCDRealtimeTickingStockChartViewControllerBase {
let _ohlcDataSeries = SCIOhlcDataSeries(xType: .date, yType: .double)
let _xyDataSeries = SCIXyDataSeries(xType: .date, yType: .double)
let _smaAxisMarker = SCIAxisMarkerAnnotation()
let _ohlcAxisMarker = SCIAxisMarkerAnnotation()
let _marketDataService = SCDMarketDataService(start: NSDate(year: 2000, month: 8, day: 01, hour: 12, minute: 0, second: 0) as Date, timeFrameMinutes: 5, tickTimerIntervals: 0.02)
let _sma50 = SCDMovingAverage(length: 50)
var _lastPrice: SCDPriceBar?
let mainXAxis = SCICategoryDateAxis()
let mainYAxis = SCINumericAxis()
let rangeSelectorAnnotation = SCIRangeSelectorAnnotation();
var isDragging: Bool = false;
override func initExample() {
initDataWithService(_marketDataService)
createMainPriceChart()
createOverviewChart()
mainXAxis.visibleRangeChangeListener = { [weak self] (axis, oldRange, newRange, isAnimating) in
guard let self = self else { return }
if (!isDragging) {
rangeSelectorAnnotation.set(x1: axis.visibleRange.minAsDouble);
rangeSelectorAnnotation.set(x2: axis.visibleRange.maxAsDouble);
}
}
}
fileprivate func initDataWithService(_ SCDMarketDataService: SCDMarketDataService) {
_ohlcDataSeries.seriesName = "Price Series"
_xyDataSeries.seriesName = "50-Period SMA";
let prices = SCDMarketDataService.getHistoricalData(DefaultPointCount)
_lastPrice = prices.lastObject()
_ohlcDataSeries.append(x: prices.dateData, open: prices.openData, high: prices.highData, low: prices.lowData, close: prices.closeData)
_xyDataSeries.append(x: prices.dateData, y: getSmaCurrentValues(prices: prices))
subscribePriceUpdate()
}
fileprivate func getSmaCurrentValues(prices: SCDPriceSeries) -> SCIDoubleValues {
let count = Int(prices.count)
let result = SCIDoubleValues(capacity: count)
for i in 0 ..< count {
let close = prices.closeData.getValueAt(i)
result.add(_sma50.push(close).current())
}
return result;
}
fileprivate func createMainPriceChart() {
mainXAxis.growBy = SCIDoubleRange(min: 0.0, max: 0.1)
mainXAxis.drawMajorGridLines = false
mainYAxis.autoRange = .always
let ohlcSeries = SCIFastOhlcRenderableSeries()
ohlcSeries.dataSeries = _ohlcDataSeries
let ma50Series = SCIFastLineRenderableSeries()
ma50Series.dataSeries = _xyDataSeries
ma50Series.strokeStyle = SCISolidPenStyle(color: 0xFFe97064, thickness: 1)
_smaAxisMarker.set(y1: 0)
_smaAxisMarker.borderPen = SCISolidPenStyle(color: SmaSeriesColor, thickness: 1)
_smaAxisMarker.backgroundBrush = SCISolidBrushStyle(color: SmaSeriesColor)
_ohlcAxisMarker.set(y1: 0)
_ohlcAxisMarker.borderPen = SCISolidPenStyle(color: StrokeUpColor, thickness: 1)
_ohlcAxisMarker.backgroundBrush = SCISolidBrushStyle(color: StrokeUpColor)
let zoomPanModifier = SCIZoomPanModifier()
zoomPanModifier.direction = .xDirection
let legendModifier = SCILegendModifier()
legendModifier.orientation = .horizontal
legendModifier.position = [.centerHorizontal, .bottom]
legendModifier.margins = SCIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
SCIUpdateSuspender.usingWith(mainSurface) {
self.mainSurface.xAxes.add(self.mainXAxis)
self.mainSurface.yAxes.add(self.mainYAxis)
self.mainSurface.renderableSeries.add(ma50Series)
self.mainSurface.renderableSeries.add(ohlcSeries)
self.mainSurface.annotations.add(items: self._smaAxisMarker, self._ohlcAxisMarker)
self.mainSurface.chartModifiers.add(items: SCIXAxisDragModifier(), SCIZoomPanModifier(), SCIPinchZoomModifier(), SCIZoomExtentsModifier(), legendModifier)
}
}
fileprivate func createOverviewChart() {
let xAxis = SCICategoryDateAxis()
xAxis.autoRange = .always
let yAxis = SCINumericAxis()
yAxis.growBy = SCIDoubleRange(min: 0.1, max: 0.1)
yAxis.autoRange = .always
let mountainSeries = SCIFastMountainRenderableSeries()
mountainSeries.dataSeries = _ohlcDataSeries
mountainSeries.areaStyle = SCILinearGradientBrushStyle(__start: CGPoint(x: 0.5, y: 0), end: CGPoint(x: 0.5, y: 1), startColorCode: 0x883a668f, endColorCode: 0xff20384f)
self.configureRangeSelectorAnnotation()
SCIUpdateSuspender.usingWith(overviewSurface) {
self.overviewSurface.xAxes.add(xAxis)
self.overviewSurface.yAxes.add(yAxis)
self.overviewSurface.renderableSeries.add(mountainSeries)
}
}
fileprivate func onNewPrice(_ price: SCDPriceBar) {
let smaLastValue: Double
if (_lastPrice!.date == price.date) {
_ohlcDataSeries.update(open: price.open.doubleValue, high: price.high.doubleValue, low: price.low.doubleValue, close: price.close.doubleValue, at: _ohlcDataSeries.count - 1)
smaLastValue = _sma50.update(price.close.doubleValue).current()
_xyDataSeries.update(y: smaLastValue, at: _xyDataSeries.count - 1)
} else {
_ohlcDataSeries.append(x: price.date, open: price.open.doubleValue, high: price.high.doubleValue, low: price.low.doubleValue, close: price.close.doubleValue)
smaLastValue = _sma50.push(price.close.doubleValue).current()
_xyDataSeries.append(x: price.date, y: smaLastValue)
let visibleRange = mainSurface.xAxes[0].visibleRange
if (visibleRange.maxAsDouble > Double(_ohlcDataSeries.count)) {
visibleRange.setDoubleMinTo(visibleRange.minAsDouble + 1, maxTo: visibleRange.maxAsDouble + 1)
}
}
let color = price.close.compare(price.open) == .orderedDescending ? StrokeUpColor : StrokeDownColor
_ohlcAxisMarker.backgroundBrush = SCISolidBrushStyle(color: color)
_ohlcAxisMarker.set(y1: price.close.doubleValue)
_smaAxisMarker.set(y1: smaLastValue)
_lastPrice = price;
}
override func subscribePriceUpdate() {
_marketDataService.subscribePriceUpdate({ [weak self] (price) in self?.onNewPrice(price) })
}
override func clearSubscribtions() {
_marketDataService.clearSubscriptions()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
_marketDataService.clearSubscriptions()
}
fileprivate func configureRangeSelectorAnnotation() {
rangeSelectorAnnotation.set(y1: 0)
rangeSelectorAnnotation.set(y2: 1)
rangeSelectorAnnotation.set(x1: mainXAxis.visibleRange.minAsDouble)
rangeSelectorAnnotation.set(x2: mainXAxis.visibleRange.maxAsDouble)
rangeSelectorAnnotation.xAxisId = mainXAxis.axisId;
rangeSelectorAnnotation.yAxisId = mainYAxis.axisId;
rangeSelectorAnnotation.coordinateMode = .relativeY;
rangeSelectorAnnotation.dragDirections = .xDirection;
rangeSelectorAnnotation.fillBrush = SCISolidBrushStyle(color: 0x33FFFFFF)
let dragListener = SCIOverviewAnnotationDragListener();
dragListener.dragDelegate = self;
rangeSelectorAnnotation.annotationDragListener = dragListener;
self.overviewSurface.annotations.add(items: rangeSelectorAnnotation)
}
func changeVisibleRange(annotation: ISCIAnnotation, isFromOnDrag: Bool) {
let x1: Double = annotation.getX1()
let x2: Double = annotation.getX2()
#if os(iOS)
UIView.animate(withDuration: 2.0, delay: 0, options: [.overrideInheritedCurve], animations: {
self.mainXAxis.visibleRange = SCIDoubleRange(min: x1, max: x2)
}, completion: { finished in
if !isFromOnDrag {
self.isDragging = false
}
self.rangeSelectorAnnotation.isSelected = true
})
#elseif os(macOS)
NSAnimationContext.beginGrouping()
NSAnimationContext.current.duration = 2.0
NSAnimationContext.current.completionHandler = {
if !isFromOnDrag {
self.isDragging = false
}
self.rangeSelectorAnnotation.isSelected = true
}
self.mainXAxis.visibleRange = SCIDoubleRange(min: x1, max: x2)
NSAnimationContext.endGrouping()
#endif
}
}
extension RealtimeTickingStockChartView: SCIOverviewAnnotationDragDelegate {
func onDragStarted(_ annotation: any ISCIAnnotation) {
isDragging = true
}
func onDrag(_ annotation: any ISCIAnnotation, byXDelta xDelta: CGFloat, yDelta: CGFloat) {
changeVisibleRange(annotation: annotation, isFromOnDrag: true)
}
func onDragEnded(_ annotation: any ISCIAnnotation) {
changeVisibleRange(annotation: annotation, isFromOnDrag: false)
}
}
SCDRealtimeTickingStockChartViewControllerBase.m
View source code//******************************************************************************
// SCICHART® Copyright SciChart Ltd. 2011-2020. All rights reserved.
//
// Web: http://www.scichart.com
// Support: support@scichart.com
// Sales: sales@scichart.com
//
// SCDRealtimeTickingStockChartViewController.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 "SCDRealtimeTickingStockChartViewControllerBase.h"
#import <SciChart/NSObject+ExceptionUtil.h>
#import "SCDToolbarPopupItem.h"
#import "SCDToolbarButton.h"
#import "SCDToolbarButtonsGroup.h"
#import "SCIStackView.h"
@interface SCDRealtimeTickingStockChartViewControllerBase()
@property (nonatomic) NSArray<Class> *seriesTypes;
@end
@implementation SCDRealtimeTickingStockChartViewControllerBase {
NSArray<NSString *> *_seriesNames;
NSInteger _initialSeriesIndex;
SCDToolbarPopupItem *_changeSeriesItem;
}
- (void)tryUpdateChartTheme:(SCIChartTheme)theme {
[SCIThemeManager applyTheme:theme toThemeable:self.mainSurface];
[SCIThemeManager applyTheme:theme toThemeable:self.overviewSurface];
}
- (void)commonInit {
_seriesNames = @[@"CandlestickRenderableSeries", @"OhlcRenderableSeries", @"MountainRenderableSeries"];
_seriesTypes = @[SCIFastCandlestickRenderableSeries.class, SCIFastOhlcRenderableSeries.class, SCIFastMountainRenderableSeries.class];
_initialSeriesIndex = 1;
_changeSeriesItem = [self p_SCD_createToolbarPopupItem];
}
- (SCDToolbarPopupItem *)p_SCD_createToolbarPopupItem {
__weak typeof(self) wSelf = self;
return [[SCDToolbarPopupItem alloc] initWithTitles:_seriesNames selectedIndex:_initialSeriesIndex andAction:^(NSUInteger selectedIndex) {
[wSelf p_SCD_changeSeriesType:wSelf.seriesTypes[selectedIndex]];
}];
}
- (void)loadView {
[super loadView];
self.view = [SCIView new];
self.view.autoresizingMask = SCIAutoresizingFlexible;
SCIStackView *stackView = [SCIStackView new];
stackView.axis = SCILayoutConstraintAxisVertical;
stackView.spacing = 0;
#if TARGET_OS_IOS
[stackView addArrangedSubview:[self providePanel]];
#endif
SCIChartSurface *mainSurface = [[SCIChartSurface alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
[stackView addArrangedSubview:mainSurface];
SCIChartSurface *overviewSurface = [[SCIChartSurface alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
[stackView addArrangedSubview:overviewSurface];
_mainSurface = mainSurface;
_overviewSurface = overviewSurface;
stackView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:stackView];
[self.view addConstraints:@[
[stackView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
[stackView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
[stackView.topAnchor constraintEqualToAnchor:self.view.topAnchor],
[stackView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
[overviewSurface.heightAnchor constraintEqualToConstant:100]
]];
}
- (NSArray<id<ISCDToolbarItem>> *)provideExampleSpecificToolbarItems {
__weak typeof(self) wSelf = self;
return @[
#if TARGET_OS_OSX
_changeSeriesItem,
#endif
[[SCDToolbarButtonsGroup alloc] initWithToolbarItems:@[
[[SCDToolbarButton alloc] initWithTitle:@"Start" image:[SCIImage imageNamed:@"chart.play"] andAction:^{
[wSelf subscribePriceUpdate];
}],
[[SCDToolbarButton alloc] initWithTitle:@"Stop" image:[SCIImage imageNamed:@"chart.stop"] andAction:^{
[wSelf clearSubscribtions];
}]
]]
];
}
#if TARGET_OS_IOS
- (SCIView *)providePanel {
return [_changeSeriesItem createView];
}
#endif
- (void)subscribePriceUpdate {
@throw [self notImplementedExceptionFor:_cmd];
}
- (void)clearSubscribtions {
@throw [self notImplementedExceptionFor:_cmd];
}
- (void)p_SCD_changeSeriesType:(Class)seriesType {
__weak typeof(self) wSelf = self;
[SCIUpdateSuspender usingWithSuspendable:wSelf.mainSurface withBlock:^{
id<ISCIRenderableSeries> oldSeries = [wSelf.mainSurface.renderableSeries itemAt:1];
[wSelf.mainSurface.renderableSeries removeAt:1];
id<ISCIRenderableSeries> rSeries = [seriesType new];
rSeries.dataSeries = oldSeries.dataSeries;
[wSelf.mainSurface.renderableSeries add:rSeries];
}];
}
@end
Back to iOS & macOS charts Examples


