├── README.md
├── ShinpuruImage.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
├── ShinpuruImage
├── AppDelegate.swift
├── Base.lproj
│ ├── LaunchScreen.xib
│ └── Main.storyboard
├── Charts
│ ├── Charts.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── xcshareddata
│ │ │ └── xcschemes
│ │ │ │ └── Charts.xcscheme
│ │ └── xcuserdata
│ │ │ └── sgladman.xcuserdatad
│ │ │ └── xcschemes
│ │ │ └── xcschememanagement.plist
│ ├── Classes
│ │ ├── Animation
│ │ │ ├── ChartAnimationEasing.swift
│ │ │ └── ChartAnimator.swift
│ │ ├── Charts
│ │ │ ├── BarChartView.swift
│ │ │ ├── BarLineChartViewBase.swift
│ │ │ ├── BubbleChartView.swift
│ │ │ ├── CandleStickChartView.swift
│ │ │ ├── ChartViewBase.swift
│ │ │ ├── CombinedChartView.swift
│ │ │ ├── HorizontalBarChartView.swift
│ │ │ ├── LineChartView.swift
│ │ │ ├── PieChartView.swift
│ │ │ ├── PieRadarChartViewBase.swift
│ │ │ ├── RadarChartView.swift
│ │ │ └── ScatterChartView.swift
│ │ ├── Components
│ │ │ ├── ChartAxisBase.swift
│ │ │ ├── ChartComponentBase.swift
│ │ │ ├── ChartLegend.swift
│ │ │ ├── ChartLimitLine.swift
│ │ │ ├── ChartMarker.swift
│ │ │ ├── ChartXAxis.swift
│ │ │ └── ChartYAxis.swift
│ │ ├── Data
│ │ │ ├── BarChartData.swift
│ │ │ ├── BarChartDataEntry.swift
│ │ │ ├── BarChartDataSet.swift
│ │ │ ├── BarLineScatterCandleChartData.swift
│ │ │ ├── BarLineScatterCandleChartDataSet.swift
│ │ │ ├── BubbleChartData.swift
│ │ │ ├── BubbleChartDataEntry.swift
│ │ │ ├── BubbleChartDataSet.swift
│ │ │ ├── CandleChartData.swift
│ │ │ ├── CandleChartDataEntry.swift
│ │ │ ├── CandleChartDataSet.swift
│ │ │ ├── ChartData.swift
│ │ │ ├── ChartDataEntry.swift
│ │ │ ├── ChartDataSet.swift
│ │ │ ├── CombinedChartData.swift
│ │ │ ├── LineChartData.swift
│ │ │ ├── LineChartDataSet.swift
│ │ │ ├── LineRadarChartDataSet.swift
│ │ │ ├── PieChartData.swift
│ │ │ ├── PieChartDataSet.swift
│ │ │ ├── RadarChartData.swift
│ │ │ ├── RadarChartDataSet.swift
│ │ │ ├── ScatterChartData.swift
│ │ │ └── ScatterChartDataSet.swift
│ │ ├── Filters
│ │ │ ├── ChartDataApproximatorFilter.swift
│ │ │ └── ChartDataBaseFilter.swift
│ │ ├── Renderers
│ │ │ ├── BarChartRenderer.swift
│ │ │ ├── BubbleChartRenderer.swift
│ │ │ ├── CandleStickChartRenderer.swift
│ │ │ ├── ChartAxisRendererBase.swift
│ │ │ ├── ChartDataRendererBase.swift
│ │ │ ├── ChartLegendRenderer.swift
│ │ │ ├── ChartRendererBase.swift
│ │ │ ├── ChartXAxisRenderer.swift
│ │ │ ├── ChartXAxisRendererBarChart.swift
│ │ │ ├── ChartXAxisRendererHorizontalBarChart.swift
│ │ │ ├── ChartXAxisRendererRadarChart.swift
│ │ │ ├── ChartYAxisRenderer.swift
│ │ │ ├── ChartYAxisRendererHorizontalBarChart.swift
│ │ │ ├── ChartYAxisRendererRadarChart.swift
│ │ │ ├── CombinedChartRenderer.swift
│ │ │ ├── HorizontalBarChartRenderer.swift
│ │ │ ├── LineChartRenderer.swift
│ │ │ ├── PieChartRenderer.swift
│ │ │ ├── RadarChartRenderer.swift
│ │ │ └── ScatterChartRenderer.swift
│ │ └── Utils
│ │ │ ├── ChartColorTemplates.swift
│ │ │ ├── ChartFillFormatter.swift
│ │ │ ├── ChartHighlight.swift
│ │ │ ├── ChartSelInfo.swift
│ │ │ ├── ChartTransformer.swift
│ │ │ ├── ChartTransformerHorizontalBarChart.swift
│ │ │ ├── ChartUtils.swift
│ │ │ └── ChartViewPortHandler.swift
│ └── Supporting Files
│ │ ├── Charts.h
│ │ └── Info.plist
├── ColorControls.swift
├── Histogram.swift
├── Images.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Info.plist
├── LabelledSlider.swift
├── RotateAndScale.swift
├── SLControls.swift
├── SLGroup.swift
├── ShinpuruImage_Chaining.swift
├── ShinpuruImage_CoreImage.swift
├── ShinpuruImage_vImage.swift
├── ViewController.swift
├── assets
│ ├── HistogramScreenShot.jpg
│ ├── glass.jpg
│ ├── oculista.jpg
│ ├── tram.jpg
│ └── vegas.jpg
├── image.jpg
└── shinpuruImageScreenShot.PNG
└── ShinpuruImageTests
├── Info.plist
└── ShinpuruImageTests.swift
/README.md:
--------------------------------------------------------------------------------
1 | # ShinpuruImage
2 |
3 | ## Syntactic Sugar for Accelerate/vImage and Core Image Filters
4 |
5 | 
6 |
7 | *ShinpuruImage* offers developers a consistent and strongly typed interface to Apple's Core Image and vImage/Accelerate image filters without the need for boilerplate code.
8 |
9 | *ShinpuruImage* filters are implemented as extensions to `UIImage` and can be chained together with a super easy syntax:
10 |
11 | ```
12 | let image = UIImage(named: "vegas.jpg")!
13 | .SIFastBlur(width: 10, height: 10, backgroundColor: UIColor.redColor())
14 | .SIMonochrome(color: UIColor.yellowColor(), intensity: 1)
15 | .SIRotate(angle: 0.3, backgroundColor: UIColor.purpleColor())
16 | ```
17 |
18 | ## Installation
19 |
20 | *ShinpuruImage* consists of three Swift files and to use *ShinpuruImage* in your own project, you simply need to copy:
21 |
22 | * [ShinpuruImage_vImage.swift](https://github.com/FlexMonkey/ShinpuruImage/blob/master/ShinpuruImage/ShinpuruImage_vImage.swift)
23 | * [ShinpuruImage_CoreImage.swift](https://github.com/FlexMonkey/ShinpuruImage/blob/master/ShinpuruImage/ShinpuruImage_CoreImage.swift)
24 | * [ShinpuruImage_Chaining](https://github.com/FlexMonkey/ShinpuruImage/blob/master/ShinpuruImage/ShinpuruImage_Chaining.swift)
25 |
26 | ## Filters
27 |
28 | ### Photo Effects
29 |
30 | * `func SIPhotoEffectNoir() -> UIImage` Applies a preconfigured set of effects that imitate black-and-white photography film with exaggerated contrast.
31 | * `func SIPhotoEffectChrome() -> UIImage` Applies a preconfigured set of effects that imitate vintage photography film with exaggerated color.
32 | * `func SIPhotoEffectFade() -> UIImage` Applies a preconfigured set of effects that imitate vintage photography film with diminished color.
33 | * `func SIPhotoEffectInstant() -> UIImage` Applies a preconfigured set of effects that imitate vintage photography film with distorted colors.
34 | * `func SIPhotoEffectMono() -> UIImage` Applies a preconfigured set of effects that imitate black-and-white photography film with low contrast.
35 | * `func SIPhotoEffectProcess() -> UIImage` Applies a preconfigured set of effects that imitate vintage photography film with emphasized cool colors.
36 | * `func SIPhotoEffectTonal() -> UIImage` Applies a preconfigured set of effects that imitate black-and-white photography film without significantly altering contrast.
37 | * `func SIPhotoEffectTransfer() -> UIImage` Applies a preconfigured set of effects that imitate vintage photography film with emphasized warm colors.
38 |
39 | ### Color Effects
40 |
41 | * `func SIFalseColor(#color0: UIColor, color1: UIColor) -> UIImage` Maps luminance to a color ramp of two colors.
42 | * `func SIPosterize(#levels: Int) -> UIImage` Remaps red, green, and blue color components to the number of brightness values you specify for each color component.
43 | * `func SIMonochrome(#color: UIColor, intensity: Float) -> UIImage` Remaps colors so they fall within shades of a single color.
44 |
45 | ### Stylize
46 |
47 | * `func SIBloom(#radius: Float, intensity: Float) -> UIImage` Softens edges and applies a pleasant glow to an image.
48 | * `func SIGloom(#radius: Float, intensity: Float) -> UIImage` Dulls the highlights of an image.
49 | * `func SIPixellate(#scale: Float) -> UIImage` Makes an image blocky by mapping the image to colored squares whose color is defined by the replaced pixels.
50 |
51 | ### Blur
52 |
53 | * `func SIGaussianBlur(#radius: Float) -> UIImage` Spreads source pixels by an amount specified by a Gaussian distribution.
54 |
55 | ### Color Adjustment
56 |
57 | * `func SIColorControls(#saturation: Float, brightness: Float, contrast: Float) -> UIImage` Adjusts saturation, brightness, and contrast values.
58 | * `func SIExposureAdjust(#ev: Float) -> UIImage` Adjusts the exposure setting for an image similar to the way you control exposure for a camera when you change the F-stop.
59 | * `func SIGammaAdjust(#power: Float) -> UIImage` Adjusts midtone brightness.
60 | * `func SIHueAdjust(#power: Float) -> UIImage` Changes the overall hue, or tint, of the source pixels.
61 | * `func SIVibrance(#amount: Float) -> UIImage` Adjusts the saturation of an image while keeping pleasing skin tones.
62 | * `func SIWhitePointAdjust(#color: UIColor) -> UIImage` Adjusts the reference white point for an image and maps all colors in the source using the new reference.
63 |
64 | ### Morphology functions
65 |
66 | * `func SIDilateFilter(#kernel: [UInt8]) -> UIImage` [Dilates an object](https://developer.apple.com/library/mac/documentation/Performance/Reference/vImage_morphological/#//apple_ref/doc/uid/TP40005492-CH210-DontLinkElementID_1)
67 | * `func SIErodeFilter(#kernel: [UInt8]) -> UIImage` [Erodes an object](https://developer.apple.com/library/mac/documentation/Performance/Reference/vImage_morphological/#//apple_ref/doc/uid/TP40005492-CH210-DontLinkElementID_2)
68 | * `func SIMaxFilter(#width: Int, height: Int) -> UIImage` The morphological operation Max is a special case of the dilation operation whereby all the elements of the kernel have the same value.
69 | * `func SIMinFilter(#width: Int, height: Int) -> UIImage` The morphological operation Min is a special case of the erosion operation whereby all the elements of the kernel have the same value.
70 |
71 | ### High Level Geometry Functions
72 |
73 | * `func SIScale(#scaleX: Float, scaleY: Float) -> UIImage` Resize the input image
74 | * `func SIRotate(#angle: Float, backgroundColor: UIColor = UIColor.blackColor()) -> UIImage` Rotate the input image around a center point by any amount
75 | * `func SIRotateNinety(rotation: RotateNinety, backgroundColor: UIColor = UIColor.blackColor()) -> UIImage` Rotate an image by 0, 90, 180 or 270 degrees
76 | * `func SIHorizontalReflect() -> UIImage` Reflect an image across a mirror plane at the center of the image
77 | * `func SIVerticalReflect() -> UIImage` Reflect an image across a mirror plane at the center of the image
78 |
79 | ### Convolution
80 |
81 | * `func SIBoxBlur(#width: Int, height: Int, backgroundColor: UIColor = UIColor.blackColor()) -> UIImage` Apply a mean filter to the image.
82 | * `func SIFastBlur(#width: Int, height: Int, backgroundColor: UIColor = UIColor.blackColor()) -> UIImage` Apply a tent filter to the image.
83 | * `func SIConvolutionFilter(#kernel: [Int16], divisor: Int, backgroundColor: UIColor = UIColor.blackColor()) -> UIImage` All four channel convolution function
84 |
85 | ### Histogram
86 |
87 |
88 |
89 | * `func SIHistogramCalculation() -> (alpha: [UInt], red: [UInt], green: [UInt], blue: [UInt])` Returns a tuple containing four arrays of 256 `UInt` representing the histogram of the supplied image
90 |
91 | ## Demo Application
92 |
93 | The demo app contains three components:
94 |
95 | * *[RotateAndScale](https://github.com/FlexMonkey/ShinpuruImage/blob/master/ShinpuruImage/RotateAndScale.swift)* - demonstrates chained `SIScale()` and `SIRotate()` controlled by three numeric sliders
96 | * *[ColorControls](https://github.com/FlexMonkey/ShinpuruImage/blob/master/ShinpuruImage/ColorControls.swift)* - demonstrates `SIColorControls` controlled by three numeric sliders
97 | * *[Histogram](https://github.com/FlexMonkey/ShinpuruImage/blob/master/ShinpuruImage/Histogram.swift)* - uses [ios-charts](https://github.com/danielgindi/ios-charts) to demonstrate the use of `SIHistogramCalculation` and the performance benefits of using fast filter chaining.
98 |
99 | ## Filter Chaining
100 |
101 | For the best perfomance when chaining image filters together, *Shinpuru Image* includes a `SIFastChainableImage` type that prevents the chain from converting to `UIImage` between individual chained filters. The syntax is slightly different and requires the source `UIImage` to be cast to a `SIFastChainableImage` and the final output to be converted back to a `UIImage`:
102 |
103 | ```
104 | let image = UIImage(named: "oculista.jpg")!
105 |
106 | let chained = SIFastChainableImage(image: image)
107 | .SIPhotoEffectFade()
108 | .SIGaussianBlur(radius: 5)
109 | .SIFalseColor(color0: UIColor.blueColor(), color1: UIColor.redColor())
110 | .SIPixellate(scale: 5)
111 | .toUIImage()
112 | ```
113 |
114 | For complex chains of filters, using `SIFastChainableImage` can be four or fives times faster. However, in this mode, color management is turned off.
115 |
116 | ## Blurring Images
117 |
118 | To blur an image you have three options: a true Gaussian blur (`SIGaussianBlur`), a box blur (`SIBoxBlur`) and *ShinpuruImage* fast blur (`SIFastBlur`) which is based on `vImageTentConvolve`. Of the three, I've found `SIBoxBlur` to be the fastest and `SIGaussianBlur` to be the slowest. It's worth using `measureBlock()` to do your own performance testing.
119 |
--------------------------------------------------------------------------------
/ShinpuruImage.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ShinpuruImage/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ShinpuruImage
4 | //
5 | // Created by Simon Gladman on 21/05/2015.
6 | // Copyright (c) 2015 Simon Gladman. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(application: UIApplication) {
33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/ShinpuruImage/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/ShinpuruImage/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Charts.xcodeproj/xcshareddata/xcschemes/Charts.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 |
53 |
54 |
55 |
56 |
57 |
58 |
68 |
69 |
75 |
76 |
77 |
78 |
79 |
80 |
86 |
87 |
93 |
94 |
95 |
96 |
98 |
99 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Charts.xcodeproj/xcuserdata/sgladman.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Charts.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 5BA8EC3F1A9D14DC00CE82E1
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Charts/BubbleChartView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BubbleChartView.swift
3 | // Charts
4 | //
5 | // Bubble chart implementation:
6 | // Copyright 2015 Pierre-Marc Airoldi
7 | // Licensed under Apache License 2.0
8 | //
9 | // https://github.com/danielgindi/ios-charts
10 | //
11 |
12 | import Foundation
13 |
14 | public class BubbleChartView: BarLineChartViewBase, BubbleChartRendererDelegate
15 | {
16 | public override func initialize()
17 | {
18 | super.initialize();
19 |
20 | renderer = BubbleChartRenderer(delegate: self, animator: _animator, viewPortHandler: _viewPortHandler);
21 | }
22 |
23 | public override func calcMinMax()
24 | {
25 | super.calcMinMax();
26 |
27 | if (_deltaX == 0.0 && _data.yValCount > 0)
28 | {
29 | _deltaX = 1.0;
30 | }
31 |
32 | _chartXMin = -0.5
33 | _chartXMax = Float(_data.xVals.count) - 0.5
34 |
35 | if let _ = renderer as? BubbleChartRenderer, sets = _data.dataSets as? [BubbleChartDataSet]
36 | {
37 | for set in sets {
38 |
39 | let xmin = set.xMin
40 | let xmax = set.xMax
41 |
42 | if (xmin < _chartXMin)
43 | {
44 | _chartXMin = xmin;
45 | }
46 |
47 | if (xmax > _chartXMax)
48 | {
49 | _chartXMax = xmax;
50 | }
51 | }
52 | }
53 |
54 | _deltaX = CGFloat(abs(_chartXMax - _chartXMin));
55 | }
56 |
57 | // MARK: - BubbleChartRendererDelegate
58 |
59 | public func bubbleChartRendererData(renderer: BubbleChartRenderer) -> BubbleChartData!
60 | {
61 | return _data as! BubbleChartData!;
62 | }
63 |
64 | public func bubbleChartRenderer(renderer: BubbleChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
65 | {
66 | return getTransformer(which);
67 | }
68 |
69 | public func bubbleChartDefaultRendererValueFormatter(renderer: BubbleChartRenderer) -> NSNumberFormatter!
70 | {
71 | return self._defaultValueFormatter;
72 | }
73 |
74 | public func bubbleChartRendererChartYMax(renderer: BubbleChartRenderer) -> Float
75 | {
76 | return self.chartYMax;
77 | }
78 |
79 | public func bubbleChartRendererChartYMin(renderer: BubbleChartRenderer) -> Float
80 | {
81 | return self.chartYMin;
82 | }
83 |
84 | public func bubbleChartRendererChartXMax(renderer: BubbleChartRenderer) -> Float
85 | {
86 | return self.chartXMax;
87 | }
88 |
89 | public func bubbleChartRendererChartXMin(renderer: BubbleChartRenderer) -> Float
90 | {
91 | return self.chartXMin;
92 | }
93 |
94 | public func bubbleChartRendererMaxVisibleValueCount(renderer: BubbleChartRenderer) -> Int
95 | {
96 | return self.maxVisibleValueCount;
97 | }
98 |
99 | public func bubbleChartRendererXValCount(renderer: BubbleChartRenderer) -> Int
100 | {
101 | return _data.xValCount;
102 | }
103 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Charts/CandleStickChartView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CandleStickChartView.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 4/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 |
17 | /// Financial chart type that draws candle-sticks.
18 | public class CandleStickChartView: BarLineChartViewBase, CandleStickChartRendererDelegate
19 | {
20 | internal override func initialize()
21 | {
22 | super.initialize();
23 |
24 | renderer = CandleStickChartRenderer(delegate: self, animator: _animator, viewPortHandler: _viewPortHandler);
25 | _chartXMin = -0.5;
26 | }
27 |
28 | internal override func calcMinMax()
29 | {
30 | super.calcMinMax();
31 |
32 | _chartXMax += 0.5;
33 | _deltaX = CGFloat(abs(_chartXMax - _chartXMin));
34 | }
35 |
36 | // MARK: - CandleStickChartRendererDelegate
37 |
38 | public func candleStickChartRendererCandleData(renderer: CandleStickChartRenderer) -> CandleChartData!
39 | {
40 | return _data as! CandleChartData!;
41 | }
42 |
43 | public func candleStickChartRenderer(renderer: CandleStickChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
44 | {
45 | return self.getTransformer(which);
46 | }
47 |
48 | public func candleStickChartDefaultRendererValueFormatter(renderer: CandleStickChartRenderer) -> NSNumberFormatter!
49 | {
50 | return self.valueFormatter;
51 | }
52 |
53 | public func candleStickChartRendererChartYMax(renderer: CandleStickChartRenderer) -> Float
54 | {
55 | return self.chartYMax;
56 | }
57 |
58 | public func candleStickChartRendererChartYMin(renderer: CandleStickChartRenderer) -> Float
59 | {
60 | return self.chartYMin;
61 | }
62 |
63 | public func candleStickChartRendererChartXMax(renderer: CandleStickChartRenderer) -> Float
64 | {
65 | return self.chartXMax;
66 | }
67 |
68 | public func candleStickChartRendererChartXMin(renderer: CandleStickChartRenderer) -> Float
69 | {
70 | return self.chartXMin;
71 | }
72 |
73 | public func candleStickChartRendererMaxVisibleValueCount(renderer: CandleStickChartRenderer) -> Int
74 | {
75 | return self.maxVisibleValueCount;
76 | }
77 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Charts/CombinedChartView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CombinedChartView.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 4/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 |
17 | /// This chart class allows the combination of lines, bars, scatter and candle data all displayed in one chart area.
18 | public class CombinedChartView: BarLineChartViewBase
19 | {
20 | /// the fill-formatter used for determining the position of the fill-line
21 | internal var _fillFormatter: ChartFillFormatter!
22 |
23 | /// enum that allows to specify the order in which the different data objects for the combined-chart are drawn
24 | @objc
25 | public enum CombinedChartDrawOrder: Int
26 | {
27 | case Bar
28 | case Bubble
29 | case Line
30 | case Candle
31 | case Scatter
32 | }
33 |
34 | public override func initialize()
35 | {
36 | super.initialize();
37 |
38 | _fillFormatter = BarLineChartFillFormatter(chart: self);
39 |
40 | renderer = CombinedChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler);
41 | }
42 |
43 | override func calcMinMax()
44 | {
45 | super.calcMinMax();
46 |
47 | if (self.barData !== nil || self.candleData !== nil || self.bubbleData !== nil)
48 | {
49 | _chartXMin = -0.5;
50 | _chartXMax = Float(_data.xVals.count) - 0.5;
51 |
52 | if (self.bubbleData !== nil)
53 | {
54 | for set in self.bubbleData.dataSets as! [BubbleChartDataSet]
55 | {
56 | let xmin = set.xMin;
57 | let xmax = set.xMax;
58 |
59 | if (xmin < chartXMin)
60 | {
61 | _chartXMin = xmin;
62 | }
63 |
64 | if (xmax > chartXMax)
65 | {
66 | _chartXMax = xmax;
67 | }
68 | }
69 | }
70 |
71 | _deltaX = CGFloat(abs(_chartXMax - _chartXMin));
72 | }
73 | }
74 |
75 | public override var data: ChartData?
76 | {
77 | get
78 | {
79 | return super.data;
80 | }
81 | set
82 | {
83 | super.data = newValue;
84 | (renderer as! CombinedChartRenderer?)!.createRenderers();
85 | }
86 | }
87 |
88 | public var fillFormatter: ChartFillFormatter
89 | {
90 | get
91 | {
92 | return _fillFormatter;
93 | }
94 | set
95 | {
96 | _fillFormatter = newValue;
97 | if (_fillFormatter === nil)
98 | {
99 | _fillFormatter = BarLineChartFillFormatter(chart: self);
100 | }
101 | }
102 | }
103 |
104 | public var lineData: LineChartData!
105 | {
106 | get
107 | {
108 | if (_data === nil)
109 | {
110 | return nil;
111 | }
112 | return (_data as! CombinedChartData!).lineData;
113 | }
114 | }
115 |
116 | public var barData: BarChartData!
117 | {
118 | get
119 | {
120 | if (_data === nil)
121 | {
122 | return nil;
123 | }
124 | return (_data as! CombinedChartData!).barData;
125 | }
126 | }
127 |
128 | public var scatterData: ScatterChartData!
129 | {
130 | get
131 | {
132 | if (_data === nil)
133 | {
134 | return nil;
135 | }
136 | return (_data as! CombinedChartData!).scatterData;
137 | }
138 | }
139 |
140 | public var candleData: CandleChartData!
141 | {
142 | get
143 | {
144 | if (_data === nil)
145 | {
146 | return nil;
147 | }
148 | return (_data as! CombinedChartData!).candleData;
149 | }
150 | }
151 |
152 | public var bubbleData: BubbleChartData!
153 | {
154 | get
155 | {
156 | if (_data === nil)
157 | {
158 | return nil;
159 | }
160 | return (_data as! CombinedChartData!).bubbleData;
161 | }
162 | }
163 |
164 | // MARK: Accessors
165 |
166 | /// flag that enables or disables the highlighting arrow
167 | public var drawHighlightArrowEnabled: Bool
168 | {
169 | get { return (renderer as! CombinedChartRenderer!).drawHighlightArrowEnabled; }
170 | set { (renderer as! CombinedChartRenderer!).drawHighlightArrowEnabled = newValue; }
171 | }
172 |
173 | /// if set to true, all values are drawn above their bars, instead of below their top
174 | public var drawValueAboveBarEnabled: Bool
175 | {
176 | get { return (renderer as! CombinedChartRenderer!).drawValueAboveBarEnabled; }
177 | set { (renderer as! CombinedChartRenderer!).drawValueAboveBarEnabled = newValue; }
178 | }
179 |
180 | /// if set to true, all values of a stack are drawn individually, and not just their sum
181 | public var drawValuesForWholeStackEnabled: Bool
182 | {
183 | get { return (renderer as! CombinedChartRenderer!).drawValuesForWholeStackEnabled; }
184 | set { (renderer as! CombinedChartRenderer!).drawValuesForWholeStackEnabled = newValue; }
185 | }
186 |
187 | /// if set to true, a grey area is darawn behind each bar that indicates the maximum value
188 | public var drawBarShadowEnabled: Bool
189 | {
190 | get { return (renderer as! CombinedChartRenderer!).drawBarShadowEnabled; }
191 | set { (renderer as! CombinedChartRenderer!).drawBarShadowEnabled = newValue; }
192 | }
193 |
194 | /// returns true if drawing the highlighting arrow is enabled, false if not
195 | public var isDrawHighlightArrowEnabled: Bool { return (renderer as! CombinedChartRenderer!).drawHighlightArrowEnabled; }
196 |
197 | /// returns true if drawing values above bars is enabled, false if not
198 | public var isDrawValueAboveBarEnabled: Bool { return (renderer as! CombinedChartRenderer!).drawValueAboveBarEnabled; }
199 |
200 | /// returns true if all values of a stack are drawn, and not just their sum
201 | public var isDrawValuesForWholeStackEnabled: Bool { return (renderer as! CombinedChartRenderer!).drawValuesForWholeStackEnabled; }
202 |
203 | /// returns true if drawing shadows (maxvalue) for each bar is enabled, false if not
204 | public var isDrawBarShadowEnabled: Bool { return (renderer as! CombinedChartRenderer!).drawBarShadowEnabled; }
205 |
206 | /// the order in which the provided data objects should be drawn.
207 | /// The earlier you place them in the provided array, the further they will be in the background.
208 | /// e.g. if you provide [DrawOrder.Bar, DrawOrder.Line], the bars will be drawn behind the lines.
209 | public var drawOrder: [Int]
210 | {
211 | get
212 | {
213 | return (renderer as! CombinedChartRenderer!).drawOrder.map { $0.rawValue };
214 | }
215 | set
216 | {
217 | (renderer as! CombinedChartRenderer!).drawOrder = newValue.map { CombinedChartDrawOrder(rawValue: $0)! };
218 | }
219 | }
220 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Charts/HorizontalBarChartView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HorizontalBarChartView.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 4/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import UIKit
16 |
17 | /// BarChart with horizontal bar orientation. In this implementation, x- and y-axis are switched.
18 | public class HorizontalBarChartView: BarChartView
19 | {
20 | internal override func initialize()
21 | {
22 | super.initialize();
23 |
24 | _leftAxisTransformer = ChartTransformerHorizontalBarChart(viewPortHandler: _viewPortHandler);
25 | _rightAxisTransformer = ChartTransformerHorizontalBarChart(viewPortHandler: _viewPortHandler);
26 |
27 | renderer = HorizontalBarChartRenderer(delegate: self, animator: _animator, viewPortHandler: _viewPortHandler);
28 | _leftYAxisRenderer = ChartYAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: _leftAxis, transformer: _leftAxisTransformer);
29 | _rightYAxisRenderer = ChartYAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, yAxis: _rightAxis, transformer: _rightAxisTransformer);
30 | _xAxisRenderer = ChartXAxisRendererHorizontalBarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, transformer: _leftAxisTransformer, chart: self);
31 | }
32 |
33 | internal override func calculateOffsets()
34 | {
35 | var offsetLeft: CGFloat = 0.0,
36 | offsetRight: CGFloat = 0.0,
37 | offsetTop: CGFloat = 0.0,
38 | offsetBottom: CGFloat = 0.0;
39 |
40 | // setup offsets for legend
41 | if (_legend !== nil && _legend.isEnabled)
42 | {
43 | if (_legend.position == .RightOfChart
44 | || _legend.position == .RightOfChartCenter)
45 | {
46 | offsetRight += _legend.textWidthMax + _legend.xOffset * 2.0;
47 | }
48 | else if (_legend.position == .LeftOfChart
49 | || _legend.position == .LeftOfChartCenter)
50 | {
51 | offsetLeft += _legend.textWidthMax + _legend.xOffset * 2.0;
52 | }
53 | else if (_legend.position == .BelowChartLeft
54 | || _legend.position == .BelowChartRight
55 | || _legend.position == .BelowChartCenter)
56 | {
57 |
58 | offsetBottom += _legend.textHeightMax * 3.0;
59 | }
60 | }
61 |
62 | // offsets for y-labels
63 | if (_leftAxis.needsOffset)
64 | {
65 | offsetTop += _leftAxis.requiredSize().height;
66 | }
67 |
68 | if (_rightAxis.needsOffset)
69 | {
70 | offsetBottom += _rightAxis.requiredSize().height;
71 | }
72 |
73 | let xlabelwidth = _xAxis.labelWidth;
74 |
75 | if (_xAxis.isEnabled)
76 | {
77 | // offsets for x-labels
78 | if (_xAxis.labelPosition == .Bottom)
79 | {
80 | offsetLeft += xlabelwidth;
81 | }
82 | else if (_xAxis.labelPosition == .Top)
83 | {
84 | offsetRight += xlabelwidth;
85 | }
86 | else if (_xAxis.labelPosition == .BothSided)
87 | {
88 | offsetLeft += xlabelwidth;
89 | offsetRight += xlabelwidth;
90 | }
91 | }
92 |
93 | let min: CGFloat = 10.0;
94 |
95 | _viewPortHandler.restrainViewPort(
96 | offsetLeft: max(min, offsetLeft),
97 | offsetTop: max(min, offsetTop),
98 | offsetRight: max(min, offsetRight),
99 | offsetBottom: max(min, offsetBottom));
100 |
101 | prepareOffsetMatrix();
102 | prepareValuePxMatrix();
103 | }
104 |
105 | internal override func prepareValuePxMatrix()
106 | {
107 | _rightAxisTransformer.prepareMatrixValuePx(chartXMin: _rightAxis.axisMinimum, deltaX: CGFloat(_rightAxis.axisRange), deltaY: _deltaX, chartYMin: _chartXMin);
108 | _leftAxisTransformer.prepareMatrixValuePx(chartXMin: _leftAxis.axisMinimum, deltaX: CGFloat(_leftAxis.axisRange), deltaY: _deltaX, chartYMin: _chartXMin);
109 | }
110 |
111 | internal override func calcModulus()
112 | {
113 | _xAxis.axisLabelModulus = Int(ceil((CGFloat(_data.xValCount) * _xAxis.labelHeight) / (_viewPortHandler.contentHeight * viewPortHandler.touchMatrix.d)));
114 |
115 | if (_xAxis.axisLabelModulus < 1)
116 | {
117 | _xAxis.axisLabelModulus = 1;
118 | }
119 | }
120 |
121 | public override func getBarBounds(e: BarChartDataEntry) -> CGRect!
122 | {
123 | let set = _data.getDataSetForEntry(e) as! BarChartDataSet!;
124 |
125 | if (set === nil)
126 | {
127 | return nil;
128 | }
129 |
130 | let barspace = set.barSpace;
131 | let y = CGFloat(e.value);
132 | let x = CGFloat(e.xIndex);
133 |
134 | let spaceHalf = barspace / 2.0;
135 | let top = x - 0.5 + spaceHalf;
136 | let bottom = x + 0.5 - spaceHalf;
137 | let left = y >= 0.0 ? y : 0.0;
138 | let right = y <= 0.0 ? y : 0.0;
139 |
140 | var bounds = CGRect(x: left, y: top, width: right - left, height: bottom - top);
141 |
142 | getTransformer(set.axisDependency).rectValueToPixel(&bounds);
143 |
144 | return bounds;
145 | }
146 |
147 | public override func getPosition(e: ChartDataEntry, axis: ChartYAxis.AxisDependency) -> CGPoint
148 | {
149 | var vals = CGPoint(x: CGFloat(e.value), y: CGFloat(e.xIndex));
150 |
151 | getTransformer(axis).pointValueToPixel(&vals);
152 |
153 | return vals;
154 | }
155 |
156 | public override func getHighlightByTouchPoint(var pt: CGPoint) -> ChartHighlight!
157 | {
158 | if (_dataNotSet || _data === nil)
159 | {
160 | print("Can't select by touch. No data set.");
161 | return nil;
162 | }
163 |
164 | _leftAxisTransformer.pixelToValue(&pt);
165 |
166 | if (pt.y < CGFloat(_chartXMin) || pt.y > CGFloat(_chartXMax))
167 | {
168 | return nil;
169 | }
170 |
171 | return getHighlight(xPosition: pt.y, yPosition: pt.x);
172 | }
173 |
174 | public override var lowestVisibleXIndex: Int
175 | {
176 | let step = CGFloat(_data.dataSetCount);
177 | let div = (step <= 1.0) ? 1.0 : step + (_data as! BarChartData).groupSpace;
178 |
179 | var pt = CGPoint(x: _viewPortHandler.contentLeft, y: _viewPortHandler.contentBottom);
180 | getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt);
181 |
182 | return Int(((pt.y <= 0.0) ? 0.0 : pt.y / div) + 1.0);
183 | }
184 |
185 | public override var highestVisibleXIndex: Int
186 | {
187 | let step = CGFloat(_data.dataSetCount);
188 | let div = (step <= 1.0) ? 1.0 : step + (_data as! BarChartData).groupSpace;
189 |
190 | var pt = CGPoint(x: _viewPortHandler.contentLeft, y: _viewPortHandler.contentTop);
191 | getTransformer(ChartYAxis.AxisDependency.Left).pixelToValue(&pt);
192 |
193 | return Int((pt.y >= CGFloat(chartXMax)) ? CGFloat(chartXMax) / div : (pt.y / div));
194 | }
195 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Charts/LineChartView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LineChartView.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 4/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 |
17 | /// Chart that draws lines, surfaces, circles, ...
18 | public class LineChartView: BarLineChartViewBase, LineChartRendererDelegate
19 | {
20 | /// the width of the highlighning line
21 | /// :default: 3.0
22 | internal var highlightWidth: CGFloat = 3.0
23 |
24 | private var _fillFormatter: ChartFillFormatter!
25 |
26 | internal override func initialize()
27 | {
28 | super.initialize();
29 |
30 | renderer = LineChartRenderer(delegate: self, animator: _animator, viewPortHandler: _viewPortHandler);
31 |
32 | _fillFormatter = BarLineChartFillFormatter(chart: self);
33 | }
34 |
35 | internal override func calcMinMax()
36 | {
37 | super.calcMinMax();
38 |
39 | if (_deltaX == 0.0 && _data.yValCount > 0)
40 | {
41 | _deltaX = 1.0;
42 | }
43 | }
44 |
45 | public var fillFormatter: ChartFillFormatter!
46 | {
47 | get
48 | {
49 | return _fillFormatter;
50 | }
51 | set
52 | {
53 | if (newValue === nil)
54 | {
55 | _fillFormatter = BarLineChartFillFormatter(chart: self);
56 | }
57 | else
58 | {
59 | _fillFormatter = newValue;
60 | }
61 | }
62 | }
63 |
64 | // MARK: - LineChartRendererDelegate
65 |
66 | public func lineChartRendererData(renderer: LineChartRenderer) -> LineChartData!
67 | {
68 | return _data as! LineChartData!;
69 | }
70 |
71 | public func lineChartRenderer(renderer: LineChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
72 | {
73 | return self.getTransformer(which);
74 | }
75 |
76 | public func lineChartRendererFillFormatter(renderer: LineChartRenderer) -> ChartFillFormatter
77 | {
78 | return self.fillFormatter;
79 | }
80 |
81 | public func lineChartDefaultRendererValueFormatter(renderer: LineChartRenderer) -> NSNumberFormatter!
82 | {
83 | return self._defaultValueFormatter;
84 | }
85 |
86 | public func lineChartRendererChartYMax(renderer: LineChartRenderer) -> Float
87 | {
88 | return self.chartYMax;
89 | }
90 |
91 | public func lineChartRendererChartYMin(renderer: LineChartRenderer) -> Float
92 | {
93 | return self.chartYMin;
94 | }
95 |
96 | public func lineChartRendererChartXMax(renderer: LineChartRenderer) -> Float
97 | {
98 | return self.chartXMax;
99 | }
100 |
101 | public func lineChartRendererChartXMin(renderer: LineChartRenderer) -> Float
102 | {
103 | return self.chartXMin;
104 | }
105 |
106 | public func lineChartRendererMaxVisibleValueCount(renderer: LineChartRenderer) -> Int
107 | {
108 | return self.maxVisibleValueCount;
109 | }
110 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Charts/RadarChartView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RadarChartView.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 4/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 | import UIKit.UIColor
17 |
18 | /// Implementation of the RadarChart, a "spidernet"-like chart. It works best
19 | /// when displaying 5-10 entries per DataSet.
20 | public class RadarChartView: PieRadarChartViewBase
21 | {
22 | /// width of the web lines that come from the center.
23 | public var webLineWidth = CGFloat(1.5)
24 |
25 | /// width of the web lines that are in between the lines coming from the center
26 | public var innerWebLineWidth = CGFloat(0.75)
27 |
28 | /// color for the web lines that come from the center
29 | public var webColor = UIColor(red: 122/255.0, green: 122/255.0, blue: 122.0/255.0, alpha: 1.0)
30 |
31 | /// color for the web lines in between the lines that come from the center.
32 | public var innerWebColor = UIColor(red: 122/255.0, green: 122/255.0, blue: 122.0/255.0, alpha: 1.0)
33 |
34 | /// transparency the grid is drawn with (0.0 - 1.0)
35 | public var webAlpha: CGFloat = 150.0 / 255.0
36 |
37 | /// flag indicating if the web lines should be drawn or not
38 | public var drawWeb = true
39 |
40 | /// the object reprsenting the y-axis labels
41 | private var _yAxis: ChartYAxis!
42 |
43 | /// the object representing the x-axis labels
44 | private var _xAxis: ChartXAxis!
45 |
46 | internal var _yAxisRenderer: ChartYAxisRendererRadarChart!
47 | internal var _xAxisRenderer: ChartXAxisRendererRadarChart!
48 |
49 | public override init(frame: CGRect)
50 | {
51 | super.init(frame: frame);
52 | }
53 |
54 | public required init(coder aDecoder: NSCoder)
55 | {
56 | super.init(coder: aDecoder);
57 | }
58 |
59 | internal override func initialize()
60 | {
61 | super.initialize();
62 |
63 | _yAxis = ChartYAxis(position: .Left);
64 | _xAxis = ChartXAxis();
65 | _xAxis.spaceBetweenLabels = 0;
66 |
67 | renderer = RadarChartRenderer(chart: self, animator: _animator, viewPortHandler: _viewPortHandler);
68 |
69 | _yAxisRenderer = ChartYAxisRendererRadarChart(viewPortHandler: _viewPortHandler, yAxis: _yAxis, chart: self);
70 | _xAxisRenderer = ChartXAxisRendererRadarChart(viewPortHandler: _viewPortHandler, xAxis: _xAxis, chart: self);
71 | }
72 |
73 | internal override func calcMinMax()
74 | {
75 | super.calcMinMax();
76 |
77 | let minLeft = _data.getYMin(.Left);
78 | let maxLeft = _data.getYMax(.Left);
79 |
80 | _chartXMax = Float(_data.xVals.count) - 1.0;
81 | _deltaX = CGFloat(abs(_chartXMax - _chartXMin));
82 |
83 | let leftRange = CGFloat(abs(maxLeft - (_yAxis.isStartAtZeroEnabled ? 0.0 : minLeft)));
84 |
85 | let topSpaceLeft = leftRange * _yAxis.spaceTop;
86 | let bottomSpaceLeft = leftRange * _yAxis.spaceBottom;
87 |
88 | _chartXMax = Float(_data.xVals.count) - 1.0;
89 | _deltaX = CGFloat(abs(_chartXMax - _chartXMin));
90 |
91 | _yAxis.axisMaximum = !isnan(_yAxis.customAxisMax) ? _yAxis.customAxisMax : maxLeft + Float(topSpaceLeft);
92 | _yAxis.axisMinimum = !isnan(_yAxis.customAxisMin) ? _yAxis.customAxisMin : minLeft - Float(bottomSpaceLeft);
93 |
94 | // consider starting at zero (0)
95 | if (_yAxis.isStartAtZeroEnabled)
96 | {
97 | _yAxis.axisMinimum = 0.0;
98 | }
99 |
100 | _yAxis.axisRange = abs(_yAxis.axisMaximum - _yAxis.axisMinimum);
101 | }
102 |
103 | public override func getMarkerPosition(entry entry: ChartDataEntry, dataSetIndex: Int) -> CGPoint
104 | {
105 | let angle = self.sliceAngle * CGFloat(entry.xIndex) + self.rotationAngle;
106 | let val = CGFloat(entry.value) * self.factor;
107 | let c = self.centerOffsets;
108 |
109 | let p = CGPoint(x: c.x + val * cos(angle * ChartUtils.Math.FDEG2RAD),
110 | y: c.y + val * sin(angle * ChartUtils.Math.FDEG2RAD));
111 |
112 | return p;
113 | }
114 |
115 | public override func notifyDataSetChanged()
116 | {
117 | if (_dataNotSet)
118 | {
119 | return;
120 | }
121 |
122 | calcMinMax();
123 |
124 | _yAxis?._defaultValueFormatter = _defaultValueFormatter;
125 |
126 | _yAxisRenderer?.computeAxis(yMin: _yAxis.axisMinimum, yMax: _yAxis.axisMaximum);
127 | _xAxisRenderer?.computeAxis(xValAverageLength: _data.xValAverageLength, xValues: _data.xVals);
128 |
129 | if (_legend !== nil && !_legend.isLegendCustom)
130 | {
131 | _legendRenderer?.computeLegend(_data);
132 | }
133 |
134 | calculateOffsets();
135 |
136 | setNeedsDisplay();
137 | }
138 |
139 | public override func drawRect(rect: CGRect)
140 | {
141 | super.drawRect(rect);
142 |
143 | if (_dataNotSet)
144 | {
145 | return;
146 | }
147 |
148 | let context = UIGraphicsGetCurrentContext();
149 |
150 | _xAxisRenderer?.renderAxisLabels(context: context!);
151 |
152 | if (drawWeb)
153 | {
154 | renderer!.drawExtras(context: context!);
155 | }
156 |
157 | _yAxisRenderer.renderLimitLines(context: context!);
158 |
159 | renderer!.drawData(context: context!);
160 |
161 | if (self.highlightEnabled && valuesToHighlight())
162 | {
163 | renderer!.drawHighlighted(context: context!, indices: _indicesToHightlight);
164 | }
165 |
166 | _yAxisRenderer.renderAxisLabels(context: context!);
167 |
168 | renderer!.drawValues(context: context!);
169 |
170 | _legendRenderer.renderLegend(context: context!);
171 |
172 | drawDescription(context: context!);
173 |
174 | drawMarkers(context: context!);
175 | }
176 |
177 | /// Returns the factor that is needed to transform values into pixels.
178 | public var factor: CGFloat
179 | {
180 | let content = _viewPortHandler.contentRect;
181 | return min(content.width / 2.0, content.height / 2.0)
182 | / CGFloat(_yAxis.axisRange);
183 | }
184 |
185 | /// Returns the angle that each slice in the radar chart occupies.
186 | public var sliceAngle: CGFloat
187 | {
188 | return 360.0 / CGFloat(_data.xValCount);
189 | }
190 |
191 | public override func indexForAngle(angle: CGFloat) -> Int
192 | {
193 | // take the current angle of the chart into consideration
194 | let a = ChartUtils.normalizedAngleFromAngle(angle - self.rotationAngle);
195 |
196 | let sliceAngle = self.sliceAngle;
197 |
198 | for (var i = 0; i < _data.xValCount; i++)
199 | {
200 | if (sliceAngle * CGFloat(i + 1) - sliceAngle / 2.0 > a)
201 | {
202 | return i;
203 | }
204 | }
205 |
206 | return 0;
207 | }
208 |
209 | /// Returns the object that represents all y-labels of the RadarChart.
210 | public var yAxis: ChartYAxis
211 | {
212 | return _yAxis;
213 | }
214 |
215 | /// Returns the object that represents all x-labels that are placed around the RadarChart.
216 | public var xAxis: ChartXAxis
217 | {
218 | return _xAxis;
219 | }
220 |
221 | internal override var requiredBottomOffset: CGFloat
222 | {
223 | return _legend.font.pointSize * 6.5;
224 | }
225 |
226 | internal override var requiredBaseOffset: CGFloat
227 | {
228 | return _xAxis.labelWidth;
229 | }
230 |
231 | public override var radius: CGFloat
232 | {
233 | let content = _viewPortHandler.contentRect;
234 | return min(content.width / 2.0, content.height / 2.0);
235 | }
236 |
237 | /// Returns the maximum value this chart can display on it's y-axis.
238 | public override var chartYMax: Float { return _yAxis.axisMaximum; }
239 |
240 | /// Returns the minimum value this chart can display on it's y-axis.
241 | public override var chartYMin: Float { return _yAxis.axisMinimum; }
242 |
243 | /// Returns the range of y-values this chart can display.
244 | public var yRange: Float { return _yAxis.axisRange}
245 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Charts/ScatterChartView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScatterChartView.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 4/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 |
17 | /// The ScatterChart. Draws dots, triangles, squares and custom shapes into the chartview.
18 | public class ScatterChartView: BarLineChartViewBase, ScatterChartRendererDelegate
19 | {
20 | public override func initialize()
21 | {
22 | super.initialize();
23 |
24 | renderer = ScatterChartRenderer(delegate: self, animator: _animator, viewPortHandler: _viewPortHandler);
25 | _chartXMin = -0.5;
26 | }
27 |
28 | public override func calcMinMax()
29 | {
30 | super.calcMinMax();
31 |
32 | if (_deltaX == 0.0 && _data.yValCount > 0)
33 | {
34 | _deltaX = 1.0;
35 | }
36 |
37 | _chartXMax += 0.5;
38 | _deltaX = CGFloat(abs(_chartXMax - _chartXMin));
39 | }
40 |
41 | // MARK: - ScatterChartRendererDelegate
42 |
43 | public func scatterChartRendererData(renderer: ScatterChartRenderer) -> ScatterChartData!
44 | {
45 | return _data as! ScatterChartData!;
46 | }
47 |
48 | public func scatterChartRenderer(renderer: ScatterChartRenderer, transformerForAxis which: ChartYAxis.AxisDependency) -> ChartTransformer!
49 | {
50 | return getTransformer(which);
51 | }
52 |
53 | public func scatterChartDefaultRendererValueFormatter(renderer: ScatterChartRenderer) -> NSNumberFormatter!
54 | {
55 | return self._defaultValueFormatter;
56 | }
57 |
58 | public func scatterChartRendererChartYMax(renderer: ScatterChartRenderer) -> Float
59 | {
60 | return self.chartYMax;
61 | }
62 |
63 | public func scatterChartRendererChartYMin(renderer: ScatterChartRenderer) -> Float
64 | {
65 | return self.chartYMin;
66 | }
67 |
68 | public func scatterChartRendererChartXMax(renderer: ScatterChartRenderer) -> Float
69 | {
70 | return self.chartXMax;
71 | }
72 |
73 | public func scatterChartRendererChartXMin(renderer: ScatterChartRenderer) -> Float
74 | {
75 | return self.chartXMin;
76 | }
77 |
78 | public func scatterChartRendererMaxVisibleValueCount(renderer: ScatterChartRenderer) -> Int
79 | {
80 | return self.maxVisibleValueCount;
81 | }
82 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Components/ChartAxisBase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartAxisBase.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 | import UIKit
17 |
18 | public class ChartAxisBase: ChartComponentBase
19 | {
20 | public var labelFont = UIFont.systemFontOfSize(10.0)
21 | public var labelTextColor = UIColor.blackColor()
22 |
23 | public var axisLineColor = UIColor.grayColor()
24 | public var axisLineWidth = CGFloat(0.5)
25 | public var axisLineDashPhase = CGFloat(0.0)
26 | public var axisLineDashLengths: [CGFloat]!
27 |
28 | public var gridColor = UIColor.grayColor().colorWithAlphaComponent(0.9)
29 | public var gridLineWidth = CGFloat(0.5)
30 | public var gridLineDashPhase = CGFloat(0.0)
31 | public var gridLineDashLengths: [CGFloat]!
32 |
33 | public var drawGridLinesEnabled = true
34 | public var drawAxisLineEnabled = true
35 |
36 | /// flag that indicates of the labels of this axis should be drawn or not
37 | public var drawLabelsEnabled = true
38 |
39 | public var xOffset = CGFloat(5.0)
40 | public var yOffset = CGFloat(5.0)
41 |
42 | /// array of limitlines that can be set for the axis
43 | private var _limitLines = [ChartLimitLine]()
44 |
45 | /// Are the LimitLines drawn behind the data or in front of the data?
46 | /// :default: false
47 | public var drawLimitLinesBehindDataEnabled = false
48 |
49 | public override init()
50 | {
51 | super.init();
52 | }
53 |
54 | public func getLongestLabel() -> String
55 | {
56 | fatalError("getLongestLabel() cannot be called on ChartAxisBase");
57 | }
58 |
59 | public var isDrawGridLinesEnabled: Bool { return drawGridLinesEnabled; }
60 |
61 | public var isDrawAxisLineEnabled: Bool { return drawAxisLineEnabled; }
62 |
63 | public var isDrawLabelsEnabled: Bool { return drawLabelsEnabled; }
64 |
65 | /// Are the LimitLines drawn behind the data or in front of the data?
66 | /// :default: false
67 | public var isDrawLimitLinesBehindDataEnabled: Bool { return drawLimitLinesBehindDataEnabled; }
68 |
69 | /// Adds a new ChartLimitLine to this axis.
70 | public func addLimitLine(line: ChartLimitLine)
71 | {
72 | _limitLines.append(line);
73 | }
74 |
75 | /// Removes the specified ChartLimitLine from the axis.
76 | public func removeLimitLine(line: ChartLimitLine)
77 | {
78 | for (var i = 0; i < _limitLines.count; i++)
79 | {
80 | if (_limitLines[i] === line)
81 | {
82 | _limitLines.removeAtIndex(i);
83 | return;
84 | }
85 | }
86 | }
87 |
88 | /// Removes all LimitLines from the axis.
89 | public func removeAllLimitLines()
90 | {
91 | _limitLines.removeAll(keepCapacity: false);
92 | }
93 |
94 | /// Returns the LimitLines of this axis.
95 | public var limitLines : [ChartLimitLine]
96 | {
97 | return _limitLines;
98 | }
99 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Components/ChartComponentBase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartComponentBase.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 16/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import UIKit
16 |
17 | /// This class encapsulates everything both Axis and Legend have in common.
18 | public class ChartComponentBase: NSObject
19 | {
20 | /// flag that indicates if this component is enabled or not
21 | public var enabled = true
22 |
23 | public override init()
24 | {
25 | super.init();
26 | }
27 |
28 | public var isEnabled: Bool { return enabled; }
29 | }
30 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Components/ChartLimitLine.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartLimitLine.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 | import UIKit
17 |
18 | /// The limit line is an additional feature for all Line, Bar and ScatterCharts.
19 | /// It allows the displaying of an additional line in the chart that marks a certain maximum / limit on the specified axis (x- or y-axis).
20 | public class ChartLimitLine: ChartComponentBase
21 | {
22 | @objc
23 | public enum ChartLimitLabelPosition: Int
24 | {
25 | case Left
26 | case Right
27 | }
28 |
29 | /// limit / maximum (the y-value or xIndex)
30 | public var limit = Float(0.0)
31 |
32 | private var _lineWidth = CGFloat(2.0)
33 | public var lineColor = UIColor(red: 237.0/255.0, green: 91.0/255.0, blue: 91.0/255.0, alpha: 1.0)
34 | public var lineDashPhase = CGFloat(0.0)
35 | public var lineDashLengths: [CGFloat]?
36 | public var valueTextColor = UIColor.blackColor()
37 | public var valueFont = UIFont.systemFontOfSize(13.0)
38 | public var label = ""
39 | public var labelPosition = ChartLimitLabelPosition.Right
40 |
41 | public override init()
42 | {
43 | super.init();
44 | }
45 |
46 | public init(limit: Float)
47 | {
48 | super.init();
49 | self.limit = limit;
50 | }
51 |
52 | public init(limit: Float, label: String)
53 | {
54 | super.init();
55 | self.limit = limit;
56 | self.label = label;
57 | }
58 |
59 | /// set the line width of the chart (min = 0.2f, max = 12f); default 2f
60 | public var lineWidth: CGFloat
61 | {
62 | get
63 | {
64 | return _lineWidth;
65 | }
66 | set
67 | {
68 | _lineWidth = newValue;
69 |
70 | if (_lineWidth < 0.2)
71 | {
72 | _lineWidth = 0.2;
73 | }
74 | if (_lineWidth > 12.0)
75 | {
76 | _lineWidth = 12.0;
77 | }
78 | }
79 | }
80 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Components/ChartMarker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartMarker.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 3/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import UIKit;
16 |
17 | public class ChartMarker: ChartComponentBase
18 | {
19 | /// The marker image to render
20 | public var image: UIImage?
21 |
22 | /// Use this to return the desired offset you wish the MarkerView to have on the x-axis.
23 | public var offset: CGPoint = CGPoint()
24 |
25 | /// The marker's size
26 | public var size: CGSize
27 | {
28 | get
29 | {
30 | return image!.size;
31 | }
32 | }
33 |
34 | public override init()
35 | {
36 | super.init();
37 | }
38 |
39 | /// Draws the ChartMarker on the given position on the given context
40 | public func draw(context context: CGContext, point: CGPoint)
41 | {
42 | let offset = self.offset;
43 | let size = self.size;
44 |
45 | let rect = CGRect(x: point.x + offset.x, y: point.y + offset.y, width: size.width, height: size.height);
46 |
47 | UIGraphicsPushContext(context);
48 | image!.drawInRect(rect);
49 | UIGraphicsPopContext();
50 | }
51 |
52 | /// This method enables a custom ChartMarker to update it's content everytime the MarkerView is redrawn according to the data entry it points to.
53 | public func refreshContent(entry entry: ChartDataEntry, dataSetIndex: Int)
54 | {
55 | // Do nothing here...
56 | }
57 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Components/ChartXAxis.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartXAxis.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 | import UIKit
17 |
18 | public class ChartXAxis: ChartAxisBase
19 | {
20 | @objc
21 | public enum XAxisLabelPosition: Int
22 | {
23 | case Top
24 | case Bottom
25 | case BothSided
26 | case TopInside
27 | case BottomInside
28 | }
29 |
30 | public var values = [String]()
31 | public var labelWidth = CGFloat(1.0)
32 | public var labelHeight = CGFloat(1.0)
33 |
34 | /// the space that should be left out (in characters) between the x-axis labels
35 | /// This only applies if the number of labels that will be skipped in between drawn axis labels is not custom set.
36 | /// :default: 4
37 | public var spaceBetweenLabels = Int(4)
38 |
39 | /// the modulus that indicates if a value at a specified index in an array(list) for the x-axis-labels is drawn or not. Draw when (index % modulus) == 0.
40 | public var axisLabelModulus = Int(1)
41 |
42 | /// Is axisLabelModulus a custom value or auto calculated? If false, then it's auto, if true, then custom.
43 | /// :default: false (automatic modulus)
44 | private var _isAxisModulusCustom = false
45 |
46 | /// the modulus that indicates if a value at a specified index in an array(list) for the y-axis-labels is drawn or not. Draw when (index % modulus) == 0.
47 | /// Used only for Horizontal BarChart
48 | public var yAxisLabelModulus = Int(1)
49 |
50 | /// if set to true, the chart will avoid that the first and last label entry in the chart "clip" off the edge of the chart
51 | public var avoidFirstLastClippingEnabled = false
52 |
53 | /// the position of the x-labels relative to the chart
54 | public var labelPosition = XAxisLabelPosition.Top;
55 |
56 | public override init()
57 | {
58 | super.init();
59 | }
60 |
61 | public override func getLongestLabel() -> String
62 | {
63 | var longest = "";
64 |
65 | for (var i = 0; i < values.count; i++)
66 | {
67 | let text = values[i];
68 |
69 | if (longest.lengthOfBytesUsingEncoding(NSUTF16StringEncoding) < text.lengthOfBytesUsingEncoding(NSUTF16StringEncoding))
70 | {
71 | longest = text;
72 | }
73 | }
74 |
75 | return longest;
76 | }
77 |
78 | public var isAvoidFirstLastClippingEnabled: Bool
79 | {
80 | return avoidFirstLastClippingEnabled;
81 | }
82 |
83 | /// Sets the number of labels that should be skipped on the axis before the next label is drawn.
84 | /// This will disable the feature that automatically calculates an adequate space between the axis labels and set the number of labels to be skipped to the fixed number provided by this method.
85 | /// Call resetLabelsToSkip(...) to re-enable automatic calculation.
86 | public func setLabelsToSkip(count: Int)
87 | {
88 | _isAxisModulusCustom = true;
89 |
90 | if (count < 0)
91 | {
92 | axisLabelModulus = 1;
93 | }
94 | else
95 | {
96 | axisLabelModulus = count + 1;
97 | }
98 | }
99 |
100 | /// Calling this will disable a custom number of labels to be skipped (set by setLabelsToSkip(...)) while drawing the x-axis. Instead, the number of values to skip will again be calculated automatically.
101 | public func resetLabelsToSkip()
102 | {
103 | _isAxisModulusCustom = false;
104 | }
105 |
106 | /// Returns true if a custom axis-modulus has been set that determines the number of labels to skip when drawing.
107 | public var isAxisModulusCustom: Bool
108 | {
109 | return _isAxisModulusCustom;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Components/ChartYAxis.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartYAxis.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 | import UIKit
17 |
18 | /// Class representing the y-axis labels settings and its entries.
19 | /// Be aware that not all features the YLabels class provides are suitable for the RadarChart.
20 | /// Customizations that affect the value range of the axis need to be applied before setting data for the chart.
21 | public class ChartYAxis: ChartAxisBase
22 | {
23 | @objc
24 | public enum YAxisLabelPosition: Int
25 | {
26 | case OutsideChart
27 | case InsideChart
28 | }
29 |
30 | /// Enum that specifies the axis a DataSet should be plotted against, either Left or Right.
31 | @objc
32 | public enum AxisDependency: Int
33 | {
34 | case Left
35 | case Right
36 | }
37 |
38 | public var entries = [Float]()
39 | public var entryCount: Int { return entries.count; }
40 |
41 | /// the number of y-label entries the y-labels should have, default 6
42 | private var _labelCount = Int(6)
43 |
44 | /// indicates if the top y-label entry is drawn or not
45 | public var drawTopYLabelEntryEnabled = true
46 |
47 | /// if true, the y-labels show only the minimum and maximum value
48 | public var showOnlyMinMaxEnabled = false
49 |
50 | /// flag that indicates if the axis is inverted or not
51 | public var inverted = false
52 |
53 | /// if true, the y-label entries will always start at zero
54 | public var startAtZeroEnabled = true
55 |
56 | /// the formatter used to customly format the y-labels
57 | public var valueFormatter: NSNumberFormatter?
58 |
59 | /// the formatter used to customly format the y-labels
60 | internal var _defaultValueFormatter = NSNumberFormatter()
61 |
62 | /// A custom minimum value for this axis.
63 | /// If set, this value will not be calculated automatically depending on the provided data.
64 | /// Use resetcustomAxisMin() to undo this.
65 | /// Do not forget to set startAtZeroEnabled = false if you use this method.
66 | /// Otherwise, the axis-minimum value will still be forced to 0.
67 | public var customAxisMin = Float.NaN
68 |
69 | /// Set a custom maximum value for this axis.
70 | /// If set, this value will not be calculated automatically depending on the provided data.
71 | /// Use resetcustomAxisMax() to undo this.
72 | public var customAxisMax = Float.NaN
73 |
74 | /// axis space from the largest value to the top in percent of the total axis range
75 | public var spaceTop = CGFloat(0.1)
76 |
77 | /// axis space from the smallest value to the bottom in percent of the total axis range
78 | public var spaceBottom = CGFloat(0.1)
79 |
80 | public var axisMaximum = Float(0)
81 | public var axisMinimum = Float(0)
82 |
83 | /// the total range of values this axis covers
84 | public var axisRange = Float(0)
85 |
86 | /// the position of the y-labels relative to the chart
87 | public var labelPosition = YAxisLabelPosition.OutsideChart
88 |
89 | /// the side this axis object represents
90 | private var _axisDependency = AxisDependency.Left
91 |
92 | public override init()
93 | {
94 | super.init();
95 |
96 | _defaultValueFormatter.maximumFractionDigits = 1;
97 | _defaultValueFormatter.minimumFractionDigits = 1;
98 | _defaultValueFormatter.usesGroupingSeparator = true;
99 | }
100 |
101 | public init(position: AxisDependency)
102 | {
103 | super.init();
104 |
105 | _axisDependency = position;
106 |
107 | _defaultValueFormatter.maximumFractionDigits = 1;
108 | _defaultValueFormatter.minimumFractionDigits = 1;
109 | _defaultValueFormatter.usesGroupingSeparator = true;
110 | }
111 |
112 | public var axisDependency: AxisDependency
113 | {
114 | return _axisDependency;
115 | }
116 |
117 | /// the number of label entries the y-axis should have
118 | /// max = 25,
119 | /// min = 2,
120 | /// default = 6,
121 | /// be aware that this number is not fixed and can only be approximated
122 | public var labelCount: Int
123 | {
124 | get
125 | {
126 | return _labelCount;
127 | }
128 | set
129 | {
130 | _labelCount = newValue;
131 |
132 | if (_labelCount > 25)
133 | {
134 | _labelCount = 25;
135 | }
136 | if (_labelCount < 2)
137 | {
138 | _labelCount = 2;
139 | }
140 | }
141 | }
142 |
143 | /// By calling this method, any custom minimum value that has been previously set is reseted, and the calculation is done automatically.
144 | public func resetcustomAxisMin()
145 | {
146 | customAxisMin = Float.NaN;
147 | }
148 |
149 | /// By calling this method, any custom maximum value that has been previously set is reseted, and the calculation is done automatically.
150 | public func resetcustomAxisMax()
151 | {
152 | customAxisMax = Float.NaN;
153 | }
154 |
155 | public func requiredSize() -> CGSize
156 | {
157 | let label = getLongestLabel() as NSString;
158 | var size = label.sizeWithAttributes([NSFontAttributeName: labelFont]);
159 | size.width += xOffset * 2.0;
160 | size.height += yOffset * 2.0;
161 | return size;
162 | }
163 |
164 | public override func getLongestLabel() -> String
165 | {
166 | var longest = "";
167 |
168 | for (var i = 0; i < entries.count; i++)
169 | {
170 | let text = getFormattedLabel(i);
171 |
172 | if (longest.lengthOfBytesUsingEncoding(NSUTF16StringEncoding) < text.lengthOfBytesUsingEncoding(NSUTF16StringEncoding))
173 | {
174 | longest = text;
175 | }
176 | }
177 |
178 | return longest;
179 | }
180 |
181 | /// Returns the formatted y-label at the specified index. This will either use the auto-formatter or the custom formatter (if one is set).
182 | public func getFormattedLabel(index: Int) -> String
183 | {
184 | if (index < 0 || index >= entries.count)
185 | {
186 | return "";
187 | }
188 |
189 | return (valueFormatter ?? _defaultValueFormatter).stringFromNumber(entries[index])!;
190 | }
191 |
192 | /// Returns true if this axis needs horizontal offset, false if no offset is needed.
193 | public var needsOffset: Bool
194 | {
195 | if (isEnabled && isDrawLabelsEnabled && labelPosition == .OutsideChart)
196 | {
197 | return true;
198 | }
199 | else
200 | {
201 | return false;
202 | }
203 | }
204 |
205 | public var isInverted: Bool { return inverted; }
206 |
207 | public var isStartAtZeroEnabled: Bool { return startAtZeroEnabled; }
208 |
209 | public var isShowOnlyMinMaxEnabled: Bool { return showOnlyMinMaxEnabled; }
210 |
211 | public var isDrawTopYLabelEntryEnabled: Bool { return drawTopYLabelEntryEnabled; }
212 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/BarChartData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarChartData.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 26/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 |
17 | public class BarChartData: BarLineScatterCandleChartData
18 | {
19 | private var _groupSpace = CGFloat(0.8)
20 |
21 | /// The spacing is relative to a full bar width
22 | public var groupSpace: CGFloat
23 | {
24 | get
25 | {
26 | if (_dataSets.count <= 1)
27 | {
28 | return 0.0;
29 | }
30 | return _groupSpace;
31 | }
32 | set
33 | {
34 | _groupSpace = newValue;
35 | }
36 | }
37 |
38 | /// Returns true if this BarData object contains grouped DataSets (more than 1 DataSet).
39 | public var isGrouped: Bool
40 | {
41 | return _dataSets.count > 1 ? true : false;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/BarChartDataEntry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarChartDataEntry.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 4/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 |
16 | public class BarChartDataEntry: ChartDataEntry
17 | {
18 | /// the values the stacked barchart holds
19 | public var values: [Float]!
20 |
21 | /// Constructor for stacked bar entries.
22 | public init(values: [Float], xIndex: Int)
23 | {
24 | super.init(value: BarChartDataEntry.calcSum(values), xIndex: xIndex);
25 | self.values = values;
26 | }
27 |
28 | /// Constructor for normal bars (not stacked).
29 | public override init(value: Float, xIndex: Int)
30 | {
31 | super.init(value: value, xIndex: xIndex);
32 | }
33 |
34 | /// Constructor for stacked bar entries.
35 | public init(values: [Float], xIndex: Int, label: String)
36 | {
37 | super.init(value: BarChartDataEntry.calcSum(values), xIndex: xIndex, data: label);
38 | self.values = values;
39 | }
40 |
41 | /// Constructor for normal bars (not stacked).
42 | public override init(value: Float, xIndex: Int, data: AnyObject?)
43 | {
44 | super.init(value: value, xIndex: xIndex, data: data)
45 | }
46 |
47 | /// Returns the closest value inside the values array (for stacked barchart)
48 | /// to the value given as a parameter. The closest value must be higher
49 | /// (above) the provided value.
50 | public func getClosestIndexAbove(value: Float) -> Int
51 | {
52 | if (values == nil)
53 | {
54 | return 0;
55 | }
56 |
57 | var index = values.count - 1;
58 | var remainder: Float = 0.0;
59 |
60 | while (index > 0 && value > values[index] + remainder)
61 | {
62 | remainder += values[index];
63 | index--;
64 | }
65 |
66 | return index;
67 | }
68 |
69 | public func getBelowSum(stackIndex :Int) -> Float
70 | {
71 | if (values == nil)
72 | {
73 | return 0;
74 | }
75 |
76 | var remainder: Float = 0.0;
77 | var index = values.count - 1;
78 |
79 | while (index > stackIndex && index >= 0)
80 | {
81 | remainder += values[index];
82 | index--;
83 | }
84 |
85 | return remainder;
86 | }
87 |
88 | /// Calculates the sum across all values.
89 | private class func calcSum(values: [Float]) -> Float
90 | {
91 | var sum = Float(0.0);
92 |
93 | for f in values
94 | {
95 | sum += f;
96 | }
97 |
98 | return sum;
99 | }
100 |
101 | // MARK: NSCopying
102 |
103 | public override func copyWithZone(zone: NSZone) -> AnyObject
104 | {
105 | let copy = super.copyWithZone(zone) as! BarChartDataEntry;
106 | copy.values = values;
107 | return copy;
108 | }
109 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/BarChartDataSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarChartDataSet.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 4/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 | import UIKit.UIColor
17 |
18 | public class BarChartDataSet: BarLineScatterCandleChartDataSet
19 | {
20 | /// space indicator between the bars in percentage of the whole width of one value (0.15 == 15% of bar width)
21 | public var barSpace: CGFloat = 0.15
22 |
23 | /// the maximum number of bars that are stacked upon each other, this value
24 | /// is calculated from the Entries that are added to the DataSet
25 | private var _stackSize = 1
26 |
27 | /// the color used for drawing the bar-shadows. The bar shadows is a surface behind the bar that indicates the maximum value
28 | public var barShadowColor = UIColor(red: 215.0/255.0, green: 215.0/255.0, blue: 215.0/255.0, alpha: 1.0)
29 |
30 | /// the alpha value (transparency) that is used for drawing the highlight indicator bar. min = 0.0 (fully transparent), max = 1.0 (fully opaque)
31 | public var highLightAlpha = CGFloat(120.0 / 255.0)
32 |
33 | /// the overall entry count, including counting each stack-value individually
34 | private var _entryCountStacks = 0
35 |
36 | /// array of labels used to describe the different values of the stacked bars
37 | public var stackLabels: [String] = ["Stack"]
38 |
39 | public override init(yVals: [ChartDataEntry]?, label: String?)
40 | {
41 | super.init(yVals: yVals, label: label);
42 |
43 | self.highlightColor = UIColor.blackColor();
44 |
45 | self.calcStackSize(yVals as! [BarChartDataEntry]?);
46 | self.calcEntryCountIncludingStacks(yVals as! [BarChartDataEntry]?);
47 | }
48 |
49 | // MARK: NSCopying
50 |
51 | public override func copyWithZone(zone: NSZone) -> AnyObject
52 | {
53 | let copy = super.copyWithZone(zone) as! BarChartDataSet;
54 | copy.barSpace = barSpace;
55 | copy._stackSize = _stackSize;
56 | copy.barShadowColor = barShadowColor;
57 | copy.highLightAlpha = highLightAlpha;
58 | copy._entryCountStacks = _entryCountStacks;
59 | copy.stackLabels = stackLabels;
60 | return copy;
61 | }
62 |
63 | /// Calculates the total number of entries this DataSet represents, including
64 | /// stacks. All values belonging to a stack are calculated separately.
65 | private func calcEntryCountIncludingStacks(yVals: [BarChartDataEntry]!)
66 | {
67 | _entryCountStacks = 0;
68 |
69 | for (var i = 0; i < yVals.count; i++)
70 | {
71 | let vals = yVals[i].values;
72 |
73 | if (vals == nil)
74 | {
75 | _entryCountStacks++;
76 | }
77 | else
78 | {
79 | _entryCountStacks += vals.count;
80 | }
81 | }
82 | }
83 |
84 | /// calculates the maximum stacksize that occurs in the Entries array of this DataSet
85 | private func calcStackSize(yVals: [BarChartDataEntry]!)
86 | {
87 | for (var i = 0; i < yVals.count; i++)
88 | {
89 | let vals = yVals[i].values;
90 |
91 | if (vals != nil && vals.count > _stackSize)
92 | {
93 | _stackSize = vals.count;
94 | }
95 | }
96 | }
97 |
98 | /// Returns the maximum number of bars that can be stacked upon another in this DataSet.
99 | public var stackSize: Int
100 | {
101 | return _stackSize;
102 | }
103 |
104 | /// Returns true if this DataSet is stacked (stacksize > 1) or not.
105 | public var isStacked: Bool
106 | {
107 | return _stackSize > 1 ? true : false;
108 | }
109 |
110 | /// returns the overall entry count, including counting each stack-value individually
111 | public var entryCountStacks: Int
112 | {
113 | return _entryCountStacks;
114 | }
115 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/BarLineScatterCandleChartData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarLineScatterCandleChartData.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 26/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 |
16 | public class BarLineScatterCandleChartData: ChartData
17 | {
18 | public override init()
19 | {
20 | super.init();
21 | }
22 |
23 | public override init(xVals: [String]?)
24 | {
25 | super.init(xVals: xVals);
26 | }
27 |
28 | public override init(xVals: [String]?, dataSets: [ChartDataSet]?)
29 | {
30 | super.init(xVals: xVals, dataSets: dataSets);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/BarLineScatterCandleChartDataSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BarLineScatterCandleChartDataSet.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 26/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import UIKit;
16 |
17 | public class BarLineScatterCandleChartDataSet: ChartDataSet
18 | {
19 | public var highlightColor = UIColor(red: 255.0/255.0, green: 187.0/255.0, blue: 115.0/255.0, alpha: 1.0)
20 | public var highlightLineWidth = CGFloat(1.0)
21 | public var highlightLineDashPhase = CGFloat(0.0)
22 | public var highlightLineDashLengths: [CGFloat]?
23 |
24 | // MARK: NSCopying
25 |
26 | public override func copyWithZone(zone: NSZone) -> AnyObject
27 | {
28 | let copy = super.copyWithZone(zone) as! BarLineScatterCandleChartDataSet;
29 | copy.highlightColor = highlightColor;
30 | copy.highlightLineWidth = highlightLineWidth;
31 | copy.highlightLineDashPhase = highlightLineDashPhase;
32 | copy.highlightLineDashLengths = highlightLineDashLengths;
33 | return copy;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/BubbleChartData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BubbleChartData.swift
3 | // Charts
4 | //
5 | // Bubble chart implementation:
6 | // Copyright 2015 Pierre-Marc Airoldi
7 | // Licensed under Apache License 2.0
8 | //
9 | // https://github.com/danielgindi/ios-charts
10 | //
11 |
12 | public class BubbleChartData: BarLineScatterCandleChartData
13 | {
14 | /// Sets the width of the circle that surrounds the bubble when highlighted for all DataSet objects this data object contains
15 | public func setHighlightCircleWidth(width: CGFloat)
16 | {
17 | for set in _dataSets as! [BubbleChartDataSet]!
18 | {
19 | set.highlightCircleWidth = width;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/BubbleChartDataEntry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BubbleDataEntry.swift
3 | // Charts
4 | //
5 | // Bubble chart implementation:
6 | // Copyright 2015 Pierre-Marc Airoldi
7 | // Licensed under Apache License 2.0
8 | //
9 | // https://github.com/danielgindi/ios-charts
10 | //
11 |
12 | import Foundation
13 |
14 | public class BubbleChartDataEntry: ChartDataEntry
15 | {
16 | /// The size of the bubble.
17 | public var size = CGFloat(0.0)
18 |
19 | /// :xIndex: The index on the x-axis.
20 | /// :val: The value on the y-axis.
21 | /// :size: The size of the bubble.
22 | public init(xIndex: Int, value: Float, size: CGFloat)
23 | {
24 | super.init(value: value, xIndex: xIndex)
25 |
26 | self.size = size
27 | }
28 |
29 | /// :xIndex: The index on the x-axis.
30 | /// :val: The value on the y-axis.
31 | /// :size: The size of the bubble.
32 | /// :data: Spot for additional data this Entry represents.
33 | public init(xIndex: Int, value: Float, size: CGFloat, data: AnyObject?)
34 | {
35 | super.init(value: value, xIndex: xIndex, data: data)
36 |
37 | self.size = size
38 | }
39 |
40 | // MARK: NSCopying
41 |
42 | public override func copyWithZone(zone: NSZone) -> AnyObject
43 | {
44 | let copy = super.copyWithZone(zone) as! BubbleChartDataEntry;
45 | copy.size = size;
46 | return copy;
47 | }
48 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/BubbleChartDataSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BubbleChartDataSet.swift
3 | // Charts
4 | //
5 | // Bubble chart implementation:
6 | // Copyright 2015 Pierre-Marc Airoldi
7 | // Licensed under Apache License 2.0
8 | //
9 | // https://github.com/danielgindi/ios-charts
10 | //
11 |
12 | import Foundation
13 | import CoreGraphics;
14 |
15 | public class BubbleChartDataSet: BarLineScatterCandleChartDataSet
16 | {
17 | internal var _xMax = Float(0.0)
18 | internal var _xMin = Float(0.0)
19 | internal var _maxSize = CGFloat(0.0)
20 |
21 | public var xMin: Float { return _xMin }
22 | public var xMax: Float { return _xMax }
23 | public var maxSize: CGFloat { return _maxSize }
24 |
25 | public func setColor(color: UIColor, alpha: CGFloat)
26 | {
27 | super.setColor(color.colorWithAlphaComponent(alpha))
28 | }
29 |
30 | internal override func calcMinMax()
31 | {
32 | let entries = yVals as! [BubbleChartDataEntry];
33 |
34 | // need chart width to guess this properly
35 |
36 | for entry in entries
37 | {
38 | let ymin = yMin(entry)
39 | let ymax = yMax(entry)
40 |
41 | if (ymin < _yMin)
42 | {
43 | _yMin = ymin
44 | }
45 |
46 | if (ymax > _yMax)
47 | {
48 | _yMax = ymax;
49 | }
50 |
51 | let xmin = xMin(entry)
52 | let xmax = xMax(entry)
53 |
54 | if (xmin < _xMin)
55 | {
56 | _xMin = xmin;
57 | }
58 |
59 | if (xmax > _xMax)
60 | {
61 | _xMax = xmax;
62 | }
63 |
64 | let size = largestSize(entry)
65 |
66 | if (size > _maxSize)
67 | {
68 | _maxSize = size
69 | }
70 | }
71 | }
72 |
73 | /// Sets/gets the width of the circle that surrounds the bubble when highlighted
74 | public var highlightCircleWidth: CGFloat = 2.5;
75 |
76 | private func yMin(entry: BubbleChartDataEntry) -> Float
77 | {
78 | return entry.value
79 | }
80 |
81 | private func yMax(entry: BubbleChartDataEntry) -> Float
82 | {
83 | return entry.value
84 | }
85 |
86 | private func xMin(entry: BubbleChartDataEntry) -> Float
87 | {
88 | return Float(entry.xIndex)
89 | }
90 |
91 | private func xMax(entry: BubbleChartDataEntry) -> Float
92 | {
93 | return Float(entry.xIndex)
94 | }
95 |
96 | private func largestSize(entry: BubbleChartDataEntry) -> CGFloat
97 | {
98 | return entry.size
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/CandleChartData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CandleChartData.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 26/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 |
16 | public class CandleChartData: BarLineScatterCandleChartData
17 | {
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/CandleChartDataEntry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CandleChartDataEntry.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 4/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 |
16 | public class CandleChartDataEntry: ChartDataEntry
17 | {
18 | /// shadow-high value
19 | public var high = Float(0.0)
20 |
21 | /// shadow-low value
22 | public var low = Float(0.0)
23 |
24 | /// close value
25 | public var close = Float(0.0)
26 |
27 | /// open value
28 | public var open = Float(0.0)
29 |
30 | public init(xIndex: Int, shadowH: Float, shadowL: Float, open: Float, close: Float)
31 | {
32 | super.init(value: (shadowH + shadowL) / 2.0, xIndex: xIndex);
33 |
34 | self.high = shadowH;
35 | self.low = shadowL;
36 | self.open = open;
37 | self.close = close;
38 | }
39 |
40 | public init(xIndex: Int, shadowH: Float, shadowL: Float, open: Float, close: Float, data: AnyObject?)
41 | {
42 | super.init(value: (shadowH + shadowL) / 2.0, xIndex: xIndex, data: data);
43 |
44 | self.high = shadowH;
45 | self.low = shadowL;
46 | self.open = open;
47 | self.close = close;
48 | }
49 |
50 | /// Returns the overall range (difference) between shadow-high and shadow-low.
51 | public var shadowRange: Float
52 | {
53 | return abs(high - low);
54 | }
55 |
56 | /// Returns the body size (difference between open and close).
57 | public var bodyRange: Float
58 | {
59 | return abs(open - close);
60 | }
61 |
62 | /// the center value of the candle. (Middle value between high and low)
63 | public override var value: Float
64 | {
65 | get
66 | {
67 | return super.value;
68 | }
69 | set
70 | {
71 | super.value = (high + low) / 2.0;
72 | }
73 | }
74 |
75 | // MARK: NSCopying
76 |
77 | public override func copyWithZone(zone: NSZone) -> AnyObject
78 | {
79 | let copy = super.copyWithZone(zone) as! CandleChartDataEntry;
80 | copy.high = high;
81 | copy.high = low;
82 | copy.high = open;
83 | copy.high = close;
84 | return copy;
85 | }
86 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/CandleChartDataSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CandleChartDataSet.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 4/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 | import UIKit.UIColor
17 |
18 | public class CandleChartDataSet: BarLineScatterCandleChartDataSet
19 | {
20 | /// the width of the candle-shadow-line in pixels.
21 | /// :default: 3.0
22 | public var shadowWidth = CGFloat(1.5)
23 |
24 | /// the space between the candle entries
25 | /// :default: 0.1 (10%)
26 | private var _bodySpace = CGFloat(0.1)
27 |
28 | /// the color of the shadow line
29 | public var shadowColor: UIColor?
30 |
31 | /// color for open <= close
32 | public var decreasingColor: UIColor?
33 |
34 | /// color for open > close
35 | public var increasingColor: UIColor?
36 |
37 | /// Are decreasing values drawn as filled?
38 | public var decreasingFilled = false
39 |
40 | /// Are increasing values drawn as filled?
41 | public var increasingFilled = true
42 |
43 | public override init(yVals: [ChartDataEntry]?, label: String?)
44 | {
45 | super.init(yVals: yVals, label: label);
46 | }
47 |
48 | internal override func calcMinMax()
49 | {
50 | if (yVals.count == 0)
51 | {
52 | return;
53 | }
54 |
55 | var entries = yVals as! [CandleChartDataEntry];
56 |
57 | _yMin = entries[0].low;
58 | _yMax = entries[0].high;
59 |
60 | for (var i = 0; i < entries.count; i++)
61 | {
62 | let e = entries[i];
63 |
64 | if (e.low < _yMin)
65 | {
66 | _yMin = e.low;
67 | }
68 |
69 | if (e.high > _yMax)
70 | {
71 | _yMax = e.high;
72 | }
73 | }
74 | }
75 |
76 | /// the space that is left out on the left and right side of each candle,
77 | /// :default: 0.1 (10%), max 0.45, min 0.0
78 | public var bodySpace: CGFloat
79 | {
80 | set
81 | {
82 | _bodySpace = newValue;
83 |
84 | if (_bodySpace < 0.0)
85 | {
86 | _bodySpace = 0.0;
87 | }
88 | if (_bodySpace > 0.45)
89 | {
90 | _bodySpace = 0.45;
91 | }
92 | }
93 | get
94 | {
95 | return _bodySpace;
96 | }
97 | }
98 |
99 | /// Are increasing values drawn as filled?
100 | public var isIncreasingFilled: Bool { return increasingFilled; }
101 |
102 | /// Are decreasing values drawn as filled?
103 | public var isDecreasingFilled: Bool { return decreasingFilled; }
104 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/ChartDataEntry.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartDataEntry.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 |
17 | public class ChartDataEntry: NSObject //, Equatable
18 | {
19 | /// the actual value (y axis)
20 | public var value = Float(0.0)
21 |
22 | /// the index on the x-axis
23 | public var xIndex = Int(0)
24 |
25 | /// optional spot for additional data this Entry represents
26 | public var data: AnyObject?
27 |
28 | public override init()
29 | {
30 | super.init();
31 | }
32 |
33 | public init(value: Float, xIndex: Int)
34 | {
35 | super.init();
36 |
37 | self.value = value;
38 | self.xIndex = xIndex;
39 | }
40 |
41 | public init(value: Float, xIndex: Int, data: AnyObject?)
42 | {
43 | super.init();
44 |
45 | self.value = value;
46 | self.xIndex = xIndex;
47 | self.data = data;
48 | }
49 |
50 | // MARK: NSObject
51 |
52 | public override func isEqual(object: AnyObject?) -> Bool
53 | {
54 | if (object === nil)
55 | {
56 | return false;
57 | }
58 |
59 | if (!object!.isKindOfClass(self.dynamicType))
60 | {
61 | return false;
62 | }
63 |
64 | if (object!.data !== data && !object!.data.isEqual(self.data))
65 | {
66 | return false;
67 | }
68 |
69 | if (object!.xIndex != xIndex)
70 | {
71 | return false;
72 | }
73 |
74 | if (fabsf(object!.value - value) > 0.00001)
75 | {
76 | return false;
77 | }
78 |
79 | return true;
80 | }
81 |
82 | // MARK: NSObject
83 |
84 | public override var description: String
85 | {
86 | return "ChartDataEntry, xIndex: \(xIndex), value \(value)";
87 | }
88 |
89 | // MARK: NSCopying
90 |
91 | public func copyWithZone(zone: NSZone) -> AnyObject
92 | {
93 | //let copy = self.dynamicType.allocWithZone(zone) as ChartDataEntry;
94 | //TODO:CHECK IT
95 | let copy = self.dynamicType.initialize() as! ChartDataEntry;
96 |
97 | copy.value = value;
98 | copy.xIndex = xIndex;
99 | copy.data = data;
100 | return copy;
101 | }
102 | }
103 |
104 | public func ==(lhs: ChartDataEntry, rhs: ChartDataEntry) -> Bool
105 | {
106 | if (lhs === rhs)
107 | {
108 | return true;
109 | }
110 |
111 | if (!lhs.isKindOfClass(rhs.dynamicType))
112 | {
113 | return false;
114 | }
115 |
116 | if (lhs.data !== rhs.data && !lhs.data!.isEqual(rhs.data))
117 | {
118 | return false;
119 | }
120 |
121 | if (lhs.xIndex != rhs.xIndex)
122 | {
123 | return false;
124 | }
125 |
126 | if (fabsf(lhs.value - rhs.value) > 0.00001)
127 | {
128 | return false;
129 | }
130 |
131 | return true;
132 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/CombinedChartData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CombinedChartData.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 26/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 |
16 | public class CombinedChartData: BarLineScatterCandleChartData
17 | {
18 | private var _lineData: LineChartData!
19 | private var _barData: BarChartData!
20 | private var _scatterData: ScatterChartData!
21 | private var _candleData: CandleChartData!
22 | private var _bubbleData: BubbleChartData!
23 |
24 | public override init()
25 | {
26 | super.init();
27 | }
28 |
29 | public override init(xVals: [String]?)
30 | {
31 | super.init(xVals: xVals);
32 | }
33 |
34 | public var lineData: LineChartData!
35 | {
36 | get
37 | {
38 | return _lineData;
39 | }
40 | set
41 | {
42 | _lineData = newValue;
43 | for dataSet in newValue.dataSets
44 | {
45 | _dataSets.append(dataSet);
46 | }
47 |
48 | checkIsLegal(newValue.dataSets);
49 |
50 | calcMinMax();
51 | calcYValueSum();
52 | calcYValueCount();
53 |
54 | calcXValAverageLength();
55 | }
56 | }
57 |
58 | public var barData: BarChartData!
59 | {
60 | get
61 | {
62 | return _barData;
63 | }
64 | set
65 | {
66 | _barData = newValue;
67 | for dataSet in newValue.dataSets
68 | {
69 | _dataSets.append(dataSet);
70 | }
71 |
72 | checkIsLegal(newValue.dataSets);
73 |
74 | calcMinMax();
75 | calcYValueSum();
76 | calcYValueCount();
77 |
78 | calcXValAverageLength();
79 | }
80 | }
81 |
82 | public var scatterData: ScatterChartData!
83 | {
84 | get
85 | {
86 | return _scatterData;
87 | }
88 | set
89 | {
90 | _scatterData = newValue;
91 | for dataSet in newValue.dataSets
92 | {
93 | _dataSets.append(dataSet);
94 | }
95 |
96 | checkIsLegal(newValue.dataSets);
97 |
98 | calcMinMax();
99 | calcYValueSum();
100 | calcYValueCount();
101 |
102 | calcXValAverageLength();
103 | }
104 | }
105 |
106 | public var candleData: CandleChartData!
107 | {
108 | get
109 | {
110 | return _candleData;
111 | }
112 | set
113 | {
114 | _candleData = newValue;
115 | for dataSet in newValue.dataSets
116 | {
117 | _dataSets.append(dataSet);
118 | }
119 |
120 | checkIsLegal(newValue.dataSets);
121 |
122 | calcMinMax();
123 | calcYValueSum();
124 | calcYValueCount();
125 |
126 | calcXValAverageLength();
127 | }
128 | }
129 |
130 | public var bubbleData: BubbleChartData!
131 | {
132 | get
133 | {
134 | return _bubbleData;
135 | }
136 | set
137 | {
138 | _bubbleData = newValue;
139 | for dataSet in newValue.dataSets
140 | {
141 | _dataSets.append(dataSet);
142 | }
143 |
144 | checkIsLegal(newValue.dataSets);
145 |
146 | calcMinMax();
147 | calcYValueSum();
148 | calcYValueCount();
149 |
150 | calcXValAverageLength();
151 | }
152 | }
153 |
154 | public override func notifyDataChanged()
155 | {
156 | if (_lineData !== nil)
157 | {
158 | _lineData.notifyDataChanged();
159 | }
160 | if (_barData !== nil)
161 | {
162 | _barData.notifyDataChanged();
163 | }
164 | if (_scatterData !== nil)
165 | {
166 | _scatterData.notifyDataChanged();
167 | }
168 | if (_candleData !== nil)
169 | {
170 | _candleData.notifyDataChanged();
171 | }
172 | if (_bubbleData !== nil)
173 | {
174 | _bubbleData.notifyDataChanged();
175 | }
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/LineChartData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LineChartData.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 26/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 |
16 | /// Data object that encapsulates all data associated with a LineChart.
17 | public class LineChartData: ChartData
18 | {
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/LineChartDataSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LineChartDataSet.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 26/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 | import UIKit.UIColor
17 |
18 | public class LineChartDataSet: LineRadarChartDataSet
19 | {
20 | public var circleColors = [UIColor]()
21 | public var circleHoleColor = UIColor.whiteColor()
22 | public var circleRadius = CGFloat(8.0)
23 |
24 | private var _cubicIntensity = CGFloat(0.2)
25 |
26 | public var lineDashPhase = CGFloat(0.0)
27 | public var lineDashLengths: [CGFloat]!
28 |
29 | /// if true, drawing circles is enabled
30 | public var drawCirclesEnabled = true
31 |
32 | /// if true, cubic lines are drawn instead of linear
33 | public var drawCubicEnabled = false
34 |
35 | public var drawCircleHoleEnabled = true;
36 |
37 | public override init()
38 | {
39 | super.init();
40 | circleColors.append(UIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0));
41 | }
42 |
43 | public override init(yVals: [ChartDataEntry]?, label: String?)
44 | {
45 | super.init(yVals: yVals, label: label);
46 | circleColors.append(UIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0));
47 | }
48 |
49 | /// intensity for cubic lines (min = 0.05f, max = 1f)
50 | /// :default: 0.2
51 | public var cubicIntensity: CGFloat
52 | {
53 | get
54 | {
55 | return _cubicIntensity;
56 | }
57 | set
58 | {
59 | _cubicIntensity = newValue;
60 | if (_cubicIntensity > 1.0)
61 | {
62 | _cubicIntensity = 1.0;
63 | }
64 | if (_cubicIntensity < 0.05)
65 | {
66 | _cubicIntensity = 0.05;
67 | }
68 | }
69 | }
70 |
71 | /// Returns the color at the given index of the DataSet's circle-color array.
72 | /// Performs a IndexOutOfBounds check by modulus.
73 | public func getCircleColor(var index: Int) -> UIColor?
74 | {
75 | let size = circleColors.count;
76 | index = index % size;
77 | if (index >= size)
78 | {
79 | return nil;
80 | }
81 | return circleColors[index];
82 | }
83 |
84 | /// Sets the one and ONLY color that should be used for this DataSet.
85 | /// Internally, this recreates the colors array and adds the specified color.
86 | public func setCircleColor(color: UIColor)
87 | {
88 | circleColors.removeAll(keepCapacity: false);
89 | circleColors.append(color);
90 | }
91 |
92 | /// resets the circle-colors array and creates a new one
93 | public func resetCircleColors( index: Int)
94 | {
95 | circleColors.removeAll(keepCapacity: false);
96 | }
97 |
98 | public var isDrawCirclesEnabled: Bool { return drawCirclesEnabled; }
99 |
100 | public var isDrawCubicEnabled: Bool { return drawCubicEnabled; }
101 |
102 | public var isDrawCircleHoleEnabled: Bool { return drawCircleHoleEnabled; }
103 |
104 | // MARK: NSCopying
105 |
106 | public override func copyWithZone(zone: NSZone) -> AnyObject
107 | {
108 | let copy = super.copyWithZone(zone) as! LineChartDataSet;
109 | copy.circleColors = circleColors;
110 | copy.circleRadius = circleRadius;
111 | copy.cubicIntensity = cubicIntensity;
112 | copy.lineDashPhase = lineDashPhase;
113 | copy.lineDashLengths = lineDashLengths;
114 | copy.drawCirclesEnabled = drawCirclesEnabled;
115 | copy.drawCubicEnabled = drawCubicEnabled;
116 | return copy;
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/LineRadarChartDataSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LineRadarChartDataSet.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 26/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 | import UIKit.UIColor
17 |
18 | public class LineRadarChartDataSet: BarLineScatterCandleChartDataSet
19 | {
20 | public var fillColor = UIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0)
21 | public var fillAlpha = CGFloat(0.33)
22 | private var _lineWidth = CGFloat(1.0)
23 | public var drawFilledEnabled = false
24 |
25 | /// line width of the chart (min = 0.2f, max = 10f)
26 | /// :default: 1
27 | public var lineWidth: CGFloat
28 | {
29 | get
30 | {
31 | return _lineWidth;
32 | }
33 | set
34 | {
35 | _lineWidth = newValue;
36 | if (_lineWidth < 0.2)
37 | {
38 | _lineWidth = 0.5;
39 | }
40 | if (_lineWidth > 10.0)
41 | {
42 | _lineWidth = 10.0;
43 | }
44 | }
45 | }
46 |
47 | public var isDrawFilledEnabled: Bool
48 | {
49 | return drawFilledEnabled;
50 | }
51 |
52 | // MARK: NSCopying
53 |
54 | public override func copyWithZone(zone: NSZone) -> AnyObject
55 | {
56 | let copy = super.copyWithZone(zone) as! LineRadarChartDataSet;
57 | copy.fillColor = fillColor;
58 | copy._lineWidth = _lineWidth;
59 | copy.drawFilledEnabled = drawFilledEnabled;
60 | return copy;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/PieChartData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PieData.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 24/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 |
16 | public class PieChartData: ChartData
17 | {
18 | public override init()
19 | {
20 | super.init();
21 |
22 | }
23 |
24 | public override init(xVals: [String]?, dataSets: [ChartDataSet]?)
25 | {
26 | super.init(xVals: xVals, dataSets: dataSets)
27 | }
28 |
29 | public convenience init(xVals: [String]?, dataSet: ChartDataSet?)
30 | {
31 | self.init(xVals: xVals, dataSets: dataSet === nil ? nil : [dataSet!]);
32 | }
33 |
34 | var dataSet: PieChartDataSet?
35 | {
36 | get
37 | {
38 | return dataSets.count > 0 ? dataSets[0] as? PieChartDataSet : nil;
39 | }
40 | set
41 | {
42 | if (newValue != nil)
43 | {
44 | dataSets = [newValue!];
45 | }
46 | else
47 | {
48 | dataSets = [];
49 | }
50 | }
51 | }
52 |
53 | public override func getDataSetByIndex(index: Int) -> ChartDataSet?
54 | {
55 | if (index != 0)
56 | {
57 | return nil;
58 | }
59 | return super.getDataSetByIndex(index);
60 | }
61 |
62 | public override func getDataSetByLabel(label: String, ignorecase: Bool) -> ChartDataSet?
63 | {
64 | if (dataSets.count == 0 || dataSets[0].label == nil)
65 | {
66 | return nil;
67 | }
68 |
69 | if (ignorecase)
70 | {
71 | if (label.caseInsensitiveCompare(dataSets[0].label!) == NSComparisonResult.OrderedSame)
72 | {
73 | return dataSets[0];
74 | }
75 | }
76 | else
77 | {
78 | if (label == dataSets[0].label)
79 | {
80 | return dataSets[0];
81 | }
82 | }
83 | return nil;
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/PieChartDataSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PieChartDataSet.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 24/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 | import CoreGraphics.CGBase
17 | import UIKit.UIColor
18 | import UIKit.UIFont
19 |
20 | public class PieChartDataSet: ChartDataSet
21 | {
22 | private var _sliceSpace = CGFloat(0.0)
23 |
24 | /// indicates the selection distance of a pie slice
25 | public var selectionShift = CGFloat(18.0)
26 |
27 | public override init()
28 | {
29 | super.init();
30 |
31 | self.valueTextColor = UIColor.whiteColor();
32 | self.valueFont = UIFont.systemFontOfSize(13.0);
33 | }
34 |
35 | public override init(yVals: [ChartDataEntry]?, label: String?)
36 | {
37 | super.init(yVals: yVals, label: label);
38 |
39 | self.valueTextColor = UIColor.whiteColor();
40 | self.valueFont = UIFont.systemFontOfSize(13.0);
41 | }
42 |
43 | /// the space that is left out between the piechart-slices, default: 0°
44 | /// --> no space, maximum 45, minimum 0 (no space)
45 | public var sliceSpace: CGFloat
46 | {
47 | get
48 | {
49 | return _sliceSpace;
50 | }
51 | set
52 | {
53 | _sliceSpace = newValue;
54 | if (_sliceSpace > 45.0)
55 | {
56 | _sliceSpace = 45.0;
57 | }
58 | if (_sliceSpace < 0.0)
59 | {
60 | _sliceSpace = 0.0;
61 | }
62 | }
63 | }
64 |
65 | // MARK: NSCopying
66 |
67 | public override func copyWithZone(zone: NSZone) -> AnyObject
68 | {
69 | let copy = super.copyWithZone(zone) as! PieChartDataSet;
70 | copy._sliceSpace = _sliceSpace;
71 | copy.selectionShift = selectionShift;
72 | return copy;
73 | }
74 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/RadarChartData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RadarChartData.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 26/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 | import UIKit.UIColor
17 |
18 | public class RadarChartData: ChartData
19 | {
20 | public var highlightColor = UIColor(red: 255.0/255.0, green: 187.0/255.0, blue: 115.0/255.0, alpha: 1.0)
21 | public var highlightLineWidth = CGFloat(1.0)
22 | public var highlightLineDashPhase = CGFloat(0.0)
23 | public var highlightLineDashLengths: [CGFloat]?
24 |
25 | internal override func initialize(dataSets: [ChartDataSet])
26 | {
27 | super.initialize(dataSets);
28 |
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/RadarChartDataSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RadarChartDataSet.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 24/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 | import UIKit.UIFont
17 |
18 | public class RadarChartDataSet: LineRadarChartDataSet
19 | {
20 | public override init()
21 | {
22 | super.init();
23 |
24 | self.valueFont = UIFont.systemFontOfSize(13.0);
25 | }
26 |
27 | public override init(yVals: [ChartDataEntry]?, label: String?)
28 | {
29 | super.init(yVals: yVals, label: label);
30 |
31 | self.valueFont = UIFont.systemFontOfSize(13.0);
32 | }
33 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/ScatterChartData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScatterChartData.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 26/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import UIKit
15 |
16 | public class ScatterChartData: BarLineScatterCandleChartData
17 | {
18 | /// Returns the maximum shape-size across all DataSets.
19 | public func getGreatestShapeSize() -> CGFloat
20 | {
21 | var max = CGFloat(0.0);
22 |
23 | for set in _dataSets
24 | {
25 | let scatterDataSet = set as? ScatterChartDataSet;
26 |
27 | if (scatterDataSet == nil)
28 | {
29 | print("ScatterChartData: Found a DataSet which is not a ScatterChartDataSet");
30 | }
31 | else
32 | {
33 | let size = scatterDataSet!.scatterShapeSize;
34 |
35 | if (size > max)
36 | {
37 | max = size;
38 | }
39 | }
40 | }
41 |
42 | return max;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Data/ScatterChartDataSet.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ScatterChartDataSet.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 26/2/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics;
16 |
17 | public class ScatterChartDataSet: BarLineScatterCandleChartDataSet
18 | {
19 | @objc
20 | public enum ScatterShape: Int
21 | {
22 | case Cross
23 | case Triangle
24 | case Circle
25 | case Square
26 | case Custom
27 | }
28 |
29 | public var scatterShapeSize = CGFloat(15.0)
30 | public var scatterShape = ScatterShape.Square
31 | public var customScatterShape: CGPath?
32 |
33 | // MARK: NSCopying
34 |
35 | public override func copyWithZone(zone: NSZone) -> AnyObject
36 | {
37 | let copy = super.copyWithZone(zone) as! ScatterChartDataSet;
38 | copy.scatterShapeSize = scatterShapeSize;
39 | copy.scatterShape = scatterShape;
40 | copy.customScatterShape = customScatterShape;
41 | return copy;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Filters/ChartDataApproximatorFilter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartDataApproximator.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 |
17 | public class ChartDataApproximatorFilter: ChartDataBaseFilter
18 | {
19 | @objc
20 | public enum ApproximatorType: Int
21 | {
22 | case None
23 | case RamerDouglasPeucker
24 | }
25 |
26 | /// the type of filtering algorithm to use
27 | public var type = ApproximatorType.None
28 |
29 | /// the tolerance to be filtered with
30 | /// When using the Douglas-Peucker-Algorithm, the tolerance is an angle in degrees, that will trigger the filtering
31 | public var tolerance = Double(0.0)
32 |
33 | public var scaleRatio = Float(1.0)
34 | public var deltaRatio = Float(1.0)
35 |
36 | public override init()
37 | {
38 | super.init();
39 | }
40 |
41 | /// Initializes the approximator with the given type and tolerance.
42 | /// If toleranec <= 0, no filtering will be done.
43 | public init(type: ApproximatorType, tolerance: Double)
44 | {
45 | super.init();
46 |
47 | setup(type, tolerance: tolerance);
48 | }
49 |
50 | /// Sets type and tolerance.
51 | /// If tolerance <= 0, no filtering will be done.
52 | public func setup(type: ApproximatorType, tolerance: Double)
53 | {
54 | self.type = type;
55 | self.tolerance = tolerance;
56 | }
57 |
58 | /// Sets the ratios for x- and y-axis, as well as the ratio of the scale levels
59 | public func setRatios(deltaRatio: Float, scaleRatio: Float)
60 | {
61 | self.deltaRatio = deltaRatio;
62 | self.scaleRatio = scaleRatio;
63 | }
64 |
65 | /// Filters according to type. Uses the pre set set tolerance
66 | ///
67 | /// :param: points the points to filter
68 | public override func filter(points: [ChartDataEntry]) -> [ChartDataEntry]
69 | {
70 | return filter(points, tolerance: tolerance);
71 | }
72 |
73 | /// Filters according to type.
74 | ///
75 | /// :param: points the points to filter
76 | /// :param: tolerance the angle in degrees that will trigger the filtering
77 | public func filter(points: [ChartDataEntry], tolerance: Double) -> [ChartDataEntry]
78 | {
79 | if (tolerance <= 0)
80 | {
81 | return points;
82 | }
83 |
84 | switch (type)
85 | {
86 | case .RamerDouglasPeucker:
87 | return reduceWithDouglasPeuker(points, epsilon: tolerance);
88 | case .None:
89 | return points;
90 | //default:
91 | // return points;
92 | }
93 | }
94 |
95 | /// uses the douglas peuker algorithm to reduce the given arraylist of entries
96 | private func reduceWithDouglasPeuker(entries: [ChartDataEntry], epsilon: Double) -> [ChartDataEntry]
97 | {
98 | // if a shape has 2 or less points it cannot be reduced
99 | if (epsilon <= 0 || entries.count < 3)
100 | {
101 | return entries;
102 | }
103 |
104 | var keep = [Bool](count: entries.count, repeatedValue: false);
105 |
106 | // first and last always stay
107 | keep[0] = true;
108 | keep[entries.count - 1] = true;
109 |
110 | // first and last entry are entry point to recursion
111 | algorithmDouglasPeucker(entries, epsilon: epsilon, start: 0, end: entries.count - 1, keep: &keep);
112 |
113 | // create a new array with series, only take the kept ones
114 | var reducedEntries = [ChartDataEntry]();
115 | for (var i = 0; i < entries.count; i++)
116 | {
117 | if (keep[i])
118 | {
119 | let curEntry = entries[i];
120 | reducedEntries.append(ChartDataEntry(value: curEntry.value, xIndex: curEntry.xIndex));
121 | }
122 | }
123 |
124 | return reducedEntries;
125 | }
126 |
127 | /// apply the Douglas-Peucker-Reduction to an ArrayList of Entry with a given epsilon (tolerance)
128 | ///
129 | /// :param: entries
130 | /// :param: epsilon as y-value
131 | /// :param: start
132 | /// :param: end
133 | private func algorithmDouglasPeucker(entries: [ChartDataEntry], epsilon: Double, start: Int, end: Int, inout keep: [Bool])
134 | {
135 | if (end <= start + 1)
136 | {
137 | // recursion finished
138 | return;
139 | }
140 |
141 | // find the greatest distance between start and endpoint
142 | var maxDistIndex = Int(0);
143 | var distMax = Double(0.0);
144 |
145 | let firstEntry = entries[start];
146 | let lastEntry = entries[end];
147 |
148 | for (var i = start + 1; i < end; i++)
149 | {
150 | let dist = calcAngleBetweenLines(firstEntry, end1: lastEntry, start2: firstEntry, end2: entries[i]);
151 |
152 | // keep the point with the greatest distance
153 | if (dist > distMax)
154 | {
155 | distMax = dist;
156 | maxDistIndex = i;
157 | }
158 | }
159 |
160 | if (distMax > epsilon)
161 | {
162 | // keep max dist point
163 | keep[maxDistIndex] = true;
164 |
165 | // recursive call
166 | algorithmDouglasPeucker(entries, epsilon: epsilon, start: start, end: maxDistIndex, keep: &keep);
167 | algorithmDouglasPeucker(entries, epsilon: epsilon, start: maxDistIndex, end: end, keep: &keep);
168 | } // else don't keep the point...
169 | }
170 |
171 | /// calculate the distance between a line between two entries and an entry (point)
172 | ///
173 | /// :param: startEntry line startpoint
174 | /// :param: endEntry line endpoint
175 | /// :param: entryPoint the point to which the distance is measured from the line
176 | private func calcPointToLineDistance(startEntry: ChartDataEntry, endEntry: ChartDataEntry, entryPoint: ChartDataEntry) -> Double
177 | {
178 | let xDiffEndStart = Float(endEntry.xIndex) - Float(startEntry.xIndex);
179 | let xDiffEntryStart = Float(entryPoint.xIndex) - Float(startEntry.xIndex);
180 |
181 | let normalLength = sqrt((xDiffEndStart)
182 | * (xDiffEndStart)
183 | + (endEntry.value - startEntry.value)
184 | * (endEntry.value - startEntry.value));
185 |
186 | return Double(fabs((xDiffEntryStart)
187 | * (endEntry.value - startEntry.value)
188 | - (entryPoint.value - startEntry.value)
189 | * (xDiffEndStart))) / Double(normalLength);
190 | }
191 |
192 | /// Calculates the angle between two given lines. The provided entries mark the starting and end points of the lines.
193 | private func calcAngleBetweenLines(start1: ChartDataEntry, end1: ChartDataEntry, start2: ChartDataEntry, end2: ChartDataEntry) -> Double
194 | {
195 | let angle1 = calcAngleWithRatios(start1, p2: end1);
196 | let angle2 = calcAngleWithRatios(start2, p2: end2);
197 |
198 | return fabs(angle1 - angle2);
199 | }
200 |
201 | /// calculates the angle between two entries (points) in the chart taking ratios into consideration
202 | private func calcAngleWithRatios(p1: ChartDataEntry, p2: ChartDataEntry) -> Double
203 | {
204 | let dx = Double(p2.xIndex) * Double(deltaRatio) - Double(p1.xIndex) * Double(deltaRatio);
205 | let dy = p2.value * scaleRatio - p1.value * scaleRatio;
206 | return atan2(Double(dy), dx) * ChartUtils.Math.RAD2DEG;
207 | }
208 |
209 | // calculates the angle between two entries (points) in the chart
210 | private func calcAngle(p1: ChartDataEntry, p2: ChartDataEntry) -> Double
211 | {
212 | let dx = p2.xIndex - p1.xIndex;
213 | let dy = p2.value - p1.value;
214 | return atan2(Double(dy), Double(dx)) * ChartUtils.Math.RAD2DEG;
215 | }
216 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Filters/ChartDataBaseFilter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartDataFilter.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 |
17 | public class ChartDataBaseFilter: NSObject
18 | {
19 | public override init()
20 | {
21 | super.init();
22 | }
23 |
24 | public func filter(points: [ChartDataEntry]) -> [ChartDataEntry]
25 | {
26 | fatalError("filter() cannot be called on ChartDataBaseFilter");
27 | }
28 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Renderers/ChartAxisRendererBase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartAxisRendererBase.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 3/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import UIKit
16 |
17 | public class ChartAxisRendererBase: ChartRendererBase
18 | {
19 | internal var transformer: ChartTransformer!;
20 |
21 | public override init()
22 | {
23 | super.init();
24 | }
25 |
26 | public init(viewPortHandler: ChartViewPortHandler, transformer: ChartTransformer!)
27 | {
28 | super.init(viewPortHandler: viewPortHandler);
29 |
30 | self.transformer = transformer;
31 | }
32 |
33 | /// Draws the axis labels on the specified context
34 | public func renderAxisLabels(context context: CGContext)
35 | {
36 | fatalError("renderAxisLabels() cannot be called on ChartAxisRendererBase");
37 | }
38 |
39 | /// Draws the grid lines belonging to the axis.
40 | public func renderGridLines(context context: CGContext)
41 | {
42 | fatalError("renderGridLines() cannot be called on ChartAxisRendererBase");
43 | }
44 |
45 | /// Draws the line that goes alongside the axis.
46 | public func renderAxisLine(context context: CGContext)
47 | {
48 | fatalError("renderAxisLine() cannot be called on ChartAxisRendererBase");
49 | }
50 |
51 | /// Draws the LimitLines associated with this axis to the screen.
52 | public func renderLimitLines(context context: CGContext)
53 | {
54 | fatalError("renderLimitLines() cannot be called on ChartAxisRendererBase");
55 | }
56 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Renderers/ChartDataRendererBase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartDataRendererBase.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 4/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 |
17 | public class ChartDataRendererBase: ChartRendererBase
18 | {
19 | internal var _animator: ChartAnimator!;
20 |
21 | public init(animator: ChartAnimator?, viewPortHandler: ChartViewPortHandler)
22 | {
23 | super.init(viewPortHandler: viewPortHandler);
24 | _animator = animator;
25 | }
26 |
27 | public func drawData(context context: CGContext)
28 | {
29 | fatalError("drawData() cannot be called on ChartDataRendererBase");
30 | }
31 |
32 | public func drawValues(context context: CGContext)
33 | {
34 | fatalError("drawValues() cannot be called on ChartDataRendererBase");
35 | }
36 |
37 | public func drawExtras(context context: CGContext)
38 | {
39 | fatalError("drawExtras() cannot be called on ChartDataRendererBase");
40 | }
41 |
42 | public func drawHighlighted(context context: CGContext, indices: [ChartHighlight])
43 | {
44 | fatalError("drawHighlighted() cannot be called on ChartDataRendererBase");
45 | }
46 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Renderers/ChartRendererBase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartRendererBase.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 3/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 |
17 | public class ChartRendererBase: NSObject
18 | {
19 | /// the component that handles the drawing area of the chart and it's offsets
20 | public var viewPortHandler: ChartViewPortHandler!;
21 |
22 | /// the minimum value on the x-axis that should be plotted
23 | internal var _minX: Int = 0;
24 |
25 | /// the maximum value on the x-axis that should be plotted
26 | internal var _maxX: Int = 0;
27 |
28 | public override init()
29 | {
30 | super.init();
31 | }
32 |
33 | public init(viewPortHandler: ChartViewPortHandler)
34 | {
35 | super.init();
36 | self.viewPortHandler = viewPortHandler;
37 | }
38 |
39 | /// Returns true if the specified value fits in between the provided min and max bounds, false if not.
40 | internal func fitsBounds(val: Float, min: Float, max: Float) -> Bool
41 | {
42 | if (val < min || val > max)
43 | {
44 | return false;
45 | }
46 | else
47 | {
48 | return true;
49 | }
50 | }
51 |
52 | /// Calculates the minimum and maximum x-value the chart can currently display (with the given zoom level).
53 | public func calcXBounds(chart chart: BarLineChartViewBase, xAxisModulus: Int)
54 | {
55 | let low = chart.lowestVisibleXIndex;
56 | let high = chart.highestVisibleXIndex;
57 |
58 | let subLow = (low % xAxisModulus == 0) ? xAxisModulus : 0;
59 |
60 | _minX = max((low / xAxisModulus) * (xAxisModulus) - subLow, 0);
61 | _maxX = min((high / xAxisModulus) * (xAxisModulus) + xAxisModulus, Int(chart.chartXMax));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Renderers/ChartXAxisRendererBarChart.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartXAxisRendererBarChart.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 3/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 | import UIKit.UIFont
17 |
18 | public class ChartXAxisRendererBarChart: ChartXAxisRenderer
19 | {
20 | internal weak var _chart: BarChartView!;
21 |
22 | public init(viewPortHandler: ChartViewPortHandler, xAxis: ChartXAxis, transformer: ChartTransformer!, chart: BarChartView)
23 | {
24 | super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: transformer);
25 |
26 | self._chart = chart;
27 | }
28 |
29 | /// draws the x-labels on the specified y-position
30 | internal override func drawLabels(context context: CGContext, pos: CGFloat)
31 | {
32 | if (_chart.data === nil)
33 | {
34 | return;
35 | }
36 |
37 | let labelFont = _xAxis.labelFont;
38 | let labelTextColor = _xAxis.labelTextColor;
39 |
40 | let barData = _chart.data as! BarChartData;
41 | let step = barData.dataSetCount;
42 |
43 | let trans = transformer.valueToPixelMatrix;
44 |
45 | var position = CGPoint(x: 0.0, y: 0.0);
46 |
47 | for (var i = _minX; i <= _maxX; i += _xAxis.axisLabelModulus)
48 | {
49 | position.x = CGFloat(i * step) + CGFloat(i) * barData.groupSpace + barData.groupSpace / 2.0;
50 | position.y = 0.0;
51 |
52 | // consider groups (center label for each group)
53 | if (step > 1)
54 | {
55 | position.x += (CGFloat(step) - 1.0) / 2.0;
56 | }
57 |
58 | position = CGPointApplyAffineTransform(position, trans);
59 |
60 | if (viewPortHandler.isInBoundsX(position.x) && i >= 0 && i < _xAxis.values.count)
61 | {
62 | let label = _xAxis.values[i];
63 | var labelns = label as NSString;
64 |
65 | if (_xAxis.isAvoidFirstLastClippingEnabled)
66 | {
67 | // avoid clipping of the last
68 | if (i == _xAxis.values.count - 1)
69 | {
70 | let width = label.sizeWithAttributes([NSFontAttributeName: _xAxis.labelFont]).width;
71 |
72 | if (width > viewPortHandler.offsetRight * 2.0
73 | && position.x + width > viewPortHandler.chartWidth)
74 | {
75 | position.x -= width / 2.0;
76 | }
77 | }
78 | else if (i == 0)
79 | { // avoid clipping of the first
80 | let width = label.sizeWithAttributes([NSFontAttributeName: _xAxis.labelFont]).width;
81 | position.x += width / 2.0;
82 | }
83 | }
84 |
85 | ChartUtils.drawText(context: context, text: label, point: CGPoint(x: position.x, y: pos), align: .Center, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor]);
86 | }
87 | }
88 | }
89 |
90 | private var _gridLineSegmentsBuffer = [CGPoint](count: 2, repeatedValue: CGPoint());
91 |
92 | public override func renderGridLines(context context: CGContext)
93 | {
94 | if (!_xAxis.isDrawGridLinesEnabled || !_xAxis.isEnabled)
95 | {
96 | return;
97 | }
98 |
99 | let barData = _chart.data as! BarChartData;
100 | let step = barData.dataSetCount;
101 |
102 | CGContextSaveGState(context);
103 |
104 | CGContextSetStrokeColorWithColor(context, _xAxis.gridColor.CGColor);
105 | CGContextSetLineWidth(context, _xAxis.gridLineWidth);
106 | if (_xAxis.gridLineDashLengths != nil)
107 | {
108 | CGContextSetLineDash(context, _xAxis.gridLineDashPhase, _xAxis.gridLineDashLengths, _xAxis.gridLineDashLengths.count);
109 | }
110 | else
111 | {
112 | CGContextSetLineDash(context, 0.0, nil, 0);
113 | }
114 |
115 | let trans = transformer.valueToPixelMatrix;
116 |
117 | var position = CGPoint(x: 0.0, y: 0.0);
118 |
119 | for (var i = _minX; i < _maxX; i += _xAxis.axisLabelModulus)
120 | {
121 | position.x = CGFloat(i * step) + CGFloat(i) * barData.groupSpace - 0.5;
122 | position.y = 0.0;
123 | position = CGPointApplyAffineTransform(position, trans);
124 |
125 | if (viewPortHandler.isInBoundsX(position.x))
126 | {
127 | _gridLineSegmentsBuffer[0].x = position.x;
128 | _gridLineSegmentsBuffer[0].y = viewPortHandler.contentTop;
129 | _gridLineSegmentsBuffer[1].x = position.x;
130 | _gridLineSegmentsBuffer[1].y = viewPortHandler.contentBottom;
131 | CGContextStrokeLineSegments(context, _gridLineSegmentsBuffer, 2);
132 | }
133 | }
134 |
135 | CGContextRestoreGState(context);
136 | }
137 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Renderers/ChartXAxisRendererRadarChart.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartXAxisRendererRadarChart.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 3/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 | import UIKit.UIFont
17 |
18 | public class ChartXAxisRendererRadarChart: ChartXAxisRenderer
19 | {
20 | private weak var _chart: RadarChartView!;
21 |
22 | public init(viewPortHandler: ChartViewPortHandler, xAxis: ChartXAxis, chart: RadarChartView)
23 | {
24 | super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: nil);
25 |
26 | _chart = chart;
27 | }
28 |
29 | public override func renderAxisLabels(context context: CGContext)
30 | {
31 | if (!_xAxis.isEnabled || !_xAxis.isDrawLabelsEnabled)
32 | {
33 | return;
34 | }
35 |
36 | let labelFont = _xAxis.labelFont;
37 | let labelTextColor = _xAxis.labelTextColor;
38 |
39 | let sliceangle = _chart.sliceAngle;
40 |
41 | // calculate the factor that is needed for transforming the value to pixels
42 | let factor = _chart.factor;
43 |
44 | let center = _chart.centerOffsets;
45 |
46 | for (var i = 0, count = _xAxis.values.count; i < count; i++)
47 | {
48 | let text = _xAxis.values[i];
49 |
50 | let angle = (sliceangle * CGFloat(i) + _chart.rotationAngle) % 360.0;
51 |
52 | let p = ChartUtils.getPosition(center: center, dist: CGFloat(_chart.yRange) * factor + _xAxis.labelWidth / 2.0, angle: angle);
53 |
54 | ChartUtils.drawText(context: context, text: text, point: CGPoint(x: p.x, y: p.y - _xAxis.labelHeight / 2.0), align: .Center, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor]);
55 | }
56 | }
57 |
58 | public override func renderLimitLines(context context: CGContext)
59 | {
60 | /// XAxis LimitLines on RadarChart not yet supported.
61 | }
62 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Renderers/ChartYAxisRendererRadarChart.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartYAxisRendererRadarChart.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 3/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 | import UIKit.UIFont
17 |
18 | public class ChartYAxisRendererRadarChart: ChartYAxisRenderer
19 | {
20 | private weak var _chart: RadarChartView!;
21 |
22 | public init(viewPortHandler: ChartViewPortHandler, yAxis: ChartYAxis, chart: RadarChartView)
23 | {
24 | super.init(viewPortHandler: viewPortHandler, yAxis: yAxis, transformer: nil);
25 |
26 | _chart = chart;
27 | }
28 |
29 | public override func computeAxis(yMin yMin: Float, yMax: Float)
30 | {
31 | computeAxisValues(min: yMin, max: yMax);
32 | }
33 |
34 | internal override func computeAxisValues(min yMin: Float, max yMax: Float)
35 | {
36 | let labelCount = _yAxis.labelCount;
37 | let range = abs(yMax - yMin);
38 |
39 | if (labelCount == 0 || range <= 0)
40 | {
41 | _yAxis.entries = [Float]();
42 | return;
43 | }
44 |
45 | let rawInterval = range / Float(labelCount);
46 | var interval = ChartUtils.roundToNextSignificant(number: Double(rawInterval));
47 | let intervalMagnitude = pow(10.0, round(log10(interval)));
48 | let intervalSigDigit = Int(interval / intervalMagnitude);
49 |
50 | if (intervalSigDigit > 5)
51 | {
52 | // Use one order of magnitude higher, to avoid intervals like 0.9 or
53 | // 90
54 | interval = floor(10 * intervalMagnitude);
55 | }
56 |
57 | // if the labels should only show min and max
58 | if (_yAxis.isShowOnlyMinMaxEnabled)
59 | {
60 | _yAxis.entries = [Float]();
61 | _yAxis.entries.append(yMin);
62 | _yAxis.entries.append(yMax);
63 | }
64 | else
65 | {
66 | let first = ceil(Double(yMin) / interval) * interval;
67 | let last = ChartUtils.nextUp(floor(Double(yMax) / interval) * interval);
68 |
69 | var f: Double;
70 | var i: Int;
71 | var n = 0;
72 | for (f = first; f <= last; f += interval)
73 | {
74 | ++n;
75 | }
76 |
77 | if (isnan(_yAxis.customAxisMax))
78 | {
79 | n += 1;
80 | }
81 |
82 | if (_yAxis.entries.count < n)
83 | {
84 | // Ensure stops contains at least numStops elements.
85 | _yAxis.entries = [Float](count: n, repeatedValue: 0.0);
86 | }
87 |
88 | for (f = first, i = 0; i < n; f += interval, ++i)
89 | {
90 | _yAxis.entries[i] = Float(f);
91 | }
92 | }
93 |
94 | _yAxis.axisMaximum = _yAxis.entries[_yAxis.entryCount - 1];
95 | _yAxis.axisRange = abs(_yAxis.axisMaximum - _yAxis.axisMinimum);
96 | }
97 |
98 | public override func renderAxisLabels(context context: CGContext)
99 | {
100 | if (!_yAxis.isEnabled || !_yAxis.isDrawLabelsEnabled)
101 | {
102 | return;
103 | }
104 |
105 | let labelFont = _yAxis.labelFont;
106 | let labelTextColor = _yAxis.labelTextColor;
107 |
108 | let center = _chart.centerOffsets;
109 | let factor = _chart.factor;
110 |
111 | let labelCount = _yAxis.entryCount;
112 |
113 | let labelLineHeight = _yAxis.labelFont.lineHeight;
114 |
115 | for (var j = 0; j < labelCount; j++)
116 | {
117 | if (j == labelCount - 1 && _yAxis.isDrawTopYLabelEntryEnabled == false)
118 | {
119 | break;
120 | }
121 |
122 | let r = CGFloat(_yAxis.entries[j] - _yAxis.axisMinimum) * factor;
123 |
124 | let p = ChartUtils.getPosition(center: center, dist: r, angle: _chart.rotationAngle);
125 |
126 | let label = _yAxis.getFormattedLabel(j);
127 |
128 | ChartUtils.drawText(context: context, text: label, point: CGPoint(x: p.x + 10.0, y: p.y - labelLineHeight), align: .Left, attributes: [NSFontAttributeName: labelFont, NSForegroundColorAttributeName: labelTextColor]);
129 | }
130 | }
131 |
132 | public override func renderLimitLines(context context: CGContext)
133 | {
134 | var limitLines = _yAxis.limitLines;
135 |
136 | if (limitLines.count == 0)
137 | {
138 | return;
139 | }
140 |
141 | let sliceangle = _chart.sliceAngle;
142 |
143 | // calculate the factor that is needed for transforming the value to pixels
144 | let factor = _chart.factor;
145 |
146 | let center = _chart.centerOffsets;
147 |
148 | for (var i = 0; i < limitLines.count; i++)
149 | {
150 | let l = limitLines[i];
151 |
152 | CGContextSetStrokeColorWithColor(context, l.lineColor.CGColor);
153 | CGContextSetLineWidth(context, l.lineWidth);
154 | if (l.lineDashLengths != nil)
155 | {
156 | CGContextSetLineDash(context, l.lineDashPhase, l.lineDashLengths!, l.lineDashLengths!.count);
157 | }
158 | else
159 | {
160 | CGContextSetLineDash(context, 0.0, nil, 0);
161 | }
162 |
163 | let r = CGFloat(l.limit - _chart.chartYMin) * factor;
164 |
165 | CGContextBeginPath(context);
166 |
167 | for (var j = 0, count = _chart.data!.xValCount; j < count; j++)
168 | {
169 | let p = ChartUtils.getPosition(center: center, dist: r, angle: sliceangle * CGFloat(j) + _chart.rotationAngle);
170 |
171 | if (j == 0)
172 | {
173 | CGContextMoveToPoint(context, p.x, p.y);
174 | }
175 | else
176 | {
177 | CGContextAddLineToPoint(context, p.x, p.y);
178 | }
179 | }
180 |
181 | CGContextClosePath(context);
182 |
183 | CGContextStrokePath(context);
184 | }
185 | }
186 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Utils/ChartColorTemplates.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartColorTemplates.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 | import UIKit
17 |
18 | public class ChartColorTemplates: NSObject
19 | {
20 | public class func liberty () -> [UIColor]
21 | {
22 | return [
23 | UIColor(red: 207/255.0, green: 248/255.0, blue: 246/255.0, alpha: 1.0),
24 | UIColor(red: 148/255.0, green: 212/255.0, blue: 212/255.0, alpha: 1.0),
25 | UIColor(red: 136/255.0, green: 180/255.0, blue: 187/255.0, alpha: 1.0),
26 | UIColor(red: 118/255.0, green: 174/255.0, blue: 175/255.0, alpha: 1.0),
27 | UIColor(red: 42/255.0, green: 109/255.0, blue: 130/255.0, alpha: 1.0)
28 | ];
29 | }
30 |
31 | public class func joyful () -> [UIColor]
32 | {
33 | return [
34 | UIColor(red: 217/255.0, green: 80/255.0, blue: 138/255.0, alpha: 1.0),
35 | UIColor(red: 254/255.0, green: 149/255.0, blue: 7/255.0, alpha: 1.0),
36 | UIColor(red: 254/255.0, green: 247/255.0, blue: 120/255.0, alpha: 1.0),
37 | UIColor(red: 106/255.0, green: 167/255.0, blue: 134/255.0, alpha: 1.0),
38 | UIColor(red: 53/255.0, green: 194/255.0, blue: 209/255.0, alpha: 1.0)
39 | ];
40 | }
41 |
42 | public class func pastel () -> [UIColor]
43 | {
44 | return [
45 | UIColor(red: 64/255.0, green: 89/255.0, blue: 128/255.0, alpha: 1.0),
46 | UIColor(red: 149/255.0, green: 165/255.0, blue: 124/255.0, alpha: 1.0),
47 | UIColor(red: 217/255.0, green: 184/255.0, blue: 162/255.0, alpha: 1.0),
48 | UIColor(red: 191/255.0, green: 134/255.0, blue: 134/255.0, alpha: 1.0),
49 | UIColor(red: 179/255.0, green: 48/255.0, blue: 80/255.0, alpha: 1.0)
50 | ];
51 | }
52 |
53 | public class func colorful () -> [UIColor]
54 | {
55 | return [
56 | UIColor(red: 193/255.0, green: 37/255.0, blue: 82/255.0, alpha: 1.0),
57 | UIColor(red: 255/255.0, green: 102/255.0, blue: 0/255.0, alpha: 1.0),
58 | UIColor(red: 245/255.0, green: 199/255.0, blue: 0/255.0, alpha: 1.0),
59 | UIColor(red: 106/255.0, green: 150/255.0, blue: 31/255.0, alpha: 1.0),
60 | UIColor(red: 179/255.0, green: 100/255.0, blue: 53/255.0, alpha: 1.0)
61 | ];
62 | }
63 |
64 | public class func vordiplom () -> [UIColor]
65 | {
66 | return [
67 | UIColor(red: 192/255.0, green: 255/255.0, blue: 140/255.0, alpha: 1.0),
68 | UIColor(red: 255/255.0, green: 247/255.0, blue: 140/255.0, alpha: 1.0),
69 | UIColor(red: 255/255.0, green: 208/255.0, blue: 140/255.0, alpha: 1.0),
70 | UIColor(red: 140/255.0, green: 234/255.0, blue: 255/255.0, alpha: 1.0),
71 | UIColor(red: 255/255.0, green: 140/255.0, blue: 157/255.0, alpha: 1.0)
72 | ];
73 | }
74 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Utils/ChartFillFormatter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartFillFormatter.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 6/3/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 |
17 | /// Protocol for providing a custom logic to where the filling line of a DataSet should end. If setFillEnabled(...) is set to true.
18 | @objc
19 | public protocol ChartFillFormatter
20 | {
21 | /// Returns the vertical (y-axis) position where the filled-line of the DataSet should end.
22 | func getFillLinePosition(dataSet dataSet: LineChartDataSet, data: LineChartData, chartMaxY: Float, chartMinY: Float) -> CGFloat;
23 | }
24 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Utils/ChartHighlight.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartHighlight.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 |
17 | public class ChartHighlight: NSObject
18 | {
19 | /// the x-index of the highlighted value
20 | private var _xIndex = Int(0)
21 |
22 | /// the index of the dataset the highlighted value is in
23 | private var _dataSetIndex = Int(0)
24 |
25 | /// index which value of a stacked bar entry is highlighted
26 | /// :default: -1
27 | private var _stackIndex = Int(-1)
28 |
29 | public override init()
30 | {
31 | super.init();
32 | }
33 |
34 | public init(xIndex x: Int, dataSetIndex: Int)
35 | {
36 | super.init();
37 |
38 | _xIndex = x;
39 | _dataSetIndex = dataSetIndex;
40 | }
41 |
42 | public init(xIndex x: Int, dataSetIndex: Int, stackIndex: Int)
43 | {
44 | super.init();
45 |
46 | _xIndex = x;
47 | _dataSetIndex = dataSetIndex;
48 | _stackIndex = stackIndex;
49 | }
50 |
51 | public var dataSetIndex: Int { return _dataSetIndex; }
52 | public var xIndex: Int { return _xIndex; }
53 | public var stackIndex: Int { return _stackIndex; }
54 |
55 | // MARK: NSObject
56 |
57 | public override var description: String
58 | {
59 | return "Highlight, xIndex: \(_xIndex), dataSetIndex: \(_dataSetIndex), stackIndex (only stacked barentry): \(_stackIndex)";
60 | }
61 |
62 | public override func isEqual(object: AnyObject?) -> Bool
63 | {
64 | if (object === nil)
65 | {
66 | return false;
67 | }
68 |
69 | if (!object!.isKindOfClass(self.dynamicType))
70 | {
71 | return false;
72 | }
73 |
74 | if (object!.xIndex != _xIndex)
75 | {
76 | return false;
77 | }
78 |
79 | if (object!.dataSetIndex != _dataSetIndex)
80 | {
81 | return false;
82 | }
83 |
84 | if (object!.stackIndex != _stackIndex)
85 | {
86 | return false;
87 | }
88 |
89 | return true;
90 | }
91 | }
92 |
93 | func ==(lhs: ChartHighlight, rhs: ChartHighlight) -> Bool
94 | {
95 | if (lhs === rhs)
96 | {
97 | return true;
98 | }
99 |
100 | if (!lhs.isKindOfClass(rhs.dynamicType))
101 | {
102 | return false;
103 | }
104 |
105 | if (lhs._xIndex != rhs._xIndex)
106 | {
107 | return false;
108 | }
109 |
110 | if (lhs._dataSetIndex != rhs._dataSetIndex)
111 | {
112 | return false;
113 | }
114 |
115 | if (lhs._stackIndex != rhs._stackIndex)
116 | {
117 | return false;
118 | }
119 |
120 | return true;
121 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Utils/ChartSelInfo.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartselInfo.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 |
17 | public class ChartSelInfo: NSObject
18 | {
19 | private var _value = Float(0)
20 | private var _dataSetIndex = Int(0)
21 | private var _dataSet: ChartDataSet!
22 |
23 | public override init()
24 | {
25 | super.init();
26 | }
27 |
28 | public init(value: Float, dataSetIndex: Int, dataSet: ChartDataSet)
29 | {
30 | super.init();
31 |
32 | _value = value;
33 | _dataSetIndex = dataSetIndex;
34 | _dataSet = dataSet;
35 | }
36 |
37 | public var value: Float
38 | {
39 | return _value;
40 | }
41 |
42 | public var dataSetIndex: Int
43 | {
44 | return _dataSetIndex;
45 | }
46 |
47 | public var dataSet: ChartDataSet?
48 | {
49 | return _dataSet;
50 | }
51 |
52 | // MARK: NSObject
53 |
54 | public override func isEqual(object: AnyObject?) -> Bool
55 | {
56 | if (object === nil)
57 | {
58 | return false;
59 | }
60 |
61 | if (!object!.isKindOfClass(self.dynamicType))
62 | {
63 | return false;
64 | }
65 |
66 | if (object!.value != _value)
67 | {
68 | return false;
69 | }
70 |
71 | if (object!.dataSetIndex != _dataSetIndex)
72 | {
73 | return false;
74 | }
75 |
76 | if (object!.dataSet !== _dataSet)
77 | {
78 | return false;
79 | }
80 |
81 | return true;
82 | }
83 | }
84 |
85 | public func ==(lhs: ChartSelInfo, rhs: ChartSelInfo) -> Bool
86 | {
87 | if (lhs === rhs)
88 | {
89 | return true;
90 | }
91 |
92 | if (!lhs.isKindOfClass(rhs.dynamicType))
93 | {
94 | return false;
95 | }
96 |
97 | if (lhs.value != rhs.value)
98 | {
99 | return false;
100 | }
101 |
102 | if (lhs.dataSetIndex != rhs.dataSetIndex)
103 | {
104 | return false;
105 | }
106 |
107 | if (lhs.dataSet !== rhs.dataSet)
108 | {
109 | return false;
110 | }
111 |
112 | return true;
113 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Utils/ChartTransformerHorizontalBarChart.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChartTransformerHorizontalBarChart.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 1/4/15.
6 | //
7 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
8 | // A port of MPAndroidChart for iOS
9 | // Licensed under Apache License 2.0
10 | //
11 | // https://github.com/danielgindi/ios-charts
12 | //
13 |
14 | import Foundation
15 | import CoreGraphics.CGBase
16 |
17 | public class ChartTransformerHorizontalBarChart: ChartTransformer
18 | {
19 | /// Prepares the matrix that contains all offsets.
20 | public override func prepareMatrixOffset(inverted: Bool)
21 | {
22 | if (!inverted)
23 | {
24 | _matrixOffset = CGAffineTransformMakeTranslation(_viewPortHandler.offsetLeft, _viewPortHandler.chartHeight - _viewPortHandler.offsetBottom);
25 | }
26 | else
27 | {
28 | _matrixOffset = CGAffineTransformMakeScale(-1.0, 1.0);
29 | _matrixOffset = CGAffineTransformTranslate(_matrixOffset,
30 | -(_viewPortHandler.chartWidth - _viewPortHandler.offsetRight),
31 | _viewPortHandler.chartHeight - _viewPortHandler.offsetBottom);
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Classes/Utils/ChartUtils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.swift
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | import Foundation
16 | import UIKit
17 | import Darwin;
18 |
19 | internal class ChartUtils
20 | {
21 | internal struct Math
22 | {
23 | internal static let FDEG2RAD = CGFloat(M_PI / 180.0);
24 | internal static let FRAD2DEG = CGFloat(180.0 / M_PI);
25 | internal static let DEG2RAD = M_PI / 180.0;
26 | internal static let RAD2DEG = 180.0 / M_PI;
27 | };
28 |
29 | internal class func roundToNextSignificant(number number: Double) -> Double
30 | {
31 | if (isinf(number) || isnan(number) || number == 0)
32 | {
33 | return number;
34 | }
35 |
36 | let d = ceil(log10(number < 0.0 ? -number : number));
37 | let pw = 1 - Int(d);
38 | let magnitude = pow(Double(10.0), Double(pw));
39 | let shifted = round(number * magnitude);
40 | return shifted / magnitude;
41 | }
42 |
43 | internal class func decimals(number: Float) -> Int
44 | {
45 | if (number == 0.0)
46 | {
47 | return 0;
48 | }
49 |
50 | let i = roundToNextSignificant(number: Double(number));
51 | return Int(ceil(-log10(i))) + 2;
52 | }
53 |
54 | internal class func nextUp(number: Double) -> Double
55 | {
56 | if (isinf(number) || isnan(number))
57 | {
58 | return number;
59 | }
60 | else
61 | {
62 | return number + DBL_EPSILON;
63 | }
64 | }
65 |
66 | /// Returns the index of the DataSet that contains the closest value on the y-axis. This is needed for highlighting.
67 | internal class func closestDataSetIndex(valsAtIndex: [ChartSelInfo], value: Float, axis: ChartYAxis.AxisDependency?) -> Int
68 | {
69 | var index = -1;
70 | var distance = FLT_MAX;
71 |
72 | for (var i = 0; i < valsAtIndex.count; i++)
73 | {
74 | let sel = valsAtIndex[i];
75 |
76 | if (axis == nil || sel.dataSet?.axisDependency == axis)
77 | {
78 | let cdistance = abs(sel.value - value);
79 | if (cdistance < distance)
80 | {
81 | index = valsAtIndex[i].dataSetIndex;
82 | distance = cdistance;
83 | }
84 | }
85 | }
86 |
87 | return index;
88 | }
89 |
90 | /// Returns the minimum distance from a touch-y-value (in pixels) to the closest y-value (in pixels) that is displayed in the chart.
91 | internal class func getMinimumDistance(valsAtIndex: [ChartSelInfo], val: Float, axis: ChartYAxis.AxisDependency) -> Float
92 | {
93 | var distance = FLT_MAX;
94 |
95 | for (var i = 0, count = valsAtIndex.count; i < count; i++)
96 | {
97 | let sel = valsAtIndex[i];
98 |
99 | if (sel.dataSet!.axisDependency == axis)
100 | {
101 | let cdistance = abs(sel.value - val);
102 | if (cdistance < distance)
103 | {
104 | distance = cdistance;
105 | }
106 | }
107 | }
108 |
109 | return distance;
110 | }
111 |
112 | /// Calculates the position around a center point, depending on the distance from the center, and the angle of the position around the center.
113 | internal class func getPosition(center center: CGPoint, dist: CGFloat, angle: CGFloat) -> CGPoint
114 | {
115 | return CGPoint(
116 | x: center.x + dist * cos(angle * Math.FDEG2RAD),
117 | y: center.y + dist * sin(angle * Math.FDEG2RAD)
118 | );
119 | }
120 |
121 | internal class func drawText(context context: CGContext, text: String, var point: CGPoint, align: NSTextAlignment, attributes: [String : AnyObject]?)
122 | {
123 | if (align == .Center)
124 | {
125 | point.x -= (text as NSString).sizeWithAttributes(attributes).width / 2.0;
126 | }
127 | else if (align == .Right)
128 | {
129 | point.x -= text.sizeWithAttributes(attributes).width;
130 | }
131 |
132 | UIGraphicsPushContext(context);
133 | (text as NSString).drawAtPoint(point, withAttributes: attributes);
134 | UIGraphicsPopContext();
135 |
136 |
137 |
138 | }
139 |
140 | /// returns an angle between 0.0 < 360.0 (not less than zero, less than 360)
141 | internal class func normalizedAngleFromAngle(var angle: CGFloat) -> CGFloat
142 | {
143 | while (angle < 0.0)
144 | {
145 | angle += 360.0;
146 | }
147 |
148 | return angle % 360.0;
149 | }
150 |
151 |
152 | /// MARK: - Bridging functions
153 |
154 | internal class func bridgedObjCGetUIColorArray (swift array: [UIColor?]) -> [NSObject]
155 | {
156 | var newArray = [NSObject]();
157 | for val in array
158 | {
159 | if (val == nil)
160 | {
161 | newArray.append(NSNull());
162 | }
163 | else
164 | {
165 | newArray.append(val!);
166 | }
167 | }
168 | return newArray;
169 | }
170 |
171 | internal class func bridgedObjCGetUIColorArray (objc array: [NSObject]) -> [UIColor?]
172 | {
173 | var newArray = [UIColor?]();
174 | for object in array
175 | {
176 | newArray.append(object as? UIColor)
177 | }
178 | return newArray;
179 | }
180 |
181 | internal class func bridgedObjCGetStringArray (swift array: [String?]) -> [NSObject]
182 | {
183 | var newArray = [NSObject]();
184 | for val in array
185 | {
186 | if (val == nil)
187 | {
188 | newArray.append(NSNull());
189 | }
190 | else
191 | {
192 | newArray.append(val!);
193 | }
194 | }
195 | return newArray;
196 | }
197 |
198 | internal class func bridgedObjCGetStringArray (objc array: [NSObject]) -> [String?]
199 | {
200 | var newArray = [String?]();
201 | for object in array
202 | {
203 | newArray.append(object as? String)
204 | }
205 | return newArray;
206 | }
207 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Supporting Files/Charts.h:
--------------------------------------------------------------------------------
1 | //
2 | // Charts.h
3 | // Charts
4 | //
5 | // Created by Daniel Cohen Gindi on 23/2/15.
6 |
7 | //
8 | // Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
9 | // A port of MPAndroidChart for iOS
10 | // Licensed under Apache License 2.0
11 | //
12 | // https://github.com/danielgindi/ios-charts
13 | //
14 |
15 | #import
16 |
17 | //! Project version number for Charts.
18 | FOUNDATION_EXPORT double ChartsVersionNumber;
19 |
20 | //! Project version string for Charts.
21 | FOUNDATION_EXPORT const unsigned char ChartsVersionString[];
22 |
23 | // In this header, you should import all the public headers of your framework using statements like #import
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ShinpuruImage/Charts/Supporting Files/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 2.0.9
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 14
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ShinpuruImage/ColorControls.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ColorControls.swift
3 | // ShinpuruImage
4 | //
5 | // Created by Simon Gladman on 23/05/2015.
6 | // Copyright (c) 2015 Simon Gladman. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ColorControls: SLHGroup
12 | {
13 | let slidersGroup = SLVGroup()
14 |
15 | let saturationSlider = LabelledSlider(title: "Saturation", minimumValue: 0, maximumValue: 2)
16 | let brightnessSlider = LabelledSlider(title: "Brightness", minimumValue: -1, maximumValue: 1)
17 | let contrastSlider = LabelledSlider(title: "Contrast", minimumValue: 0, maximumValue: 2)
18 |
19 | let imageView = UIImageView()
20 |
21 | let image = UIImage(named: "oculista.jpg")!
22 |
23 | required init()
24 | {
25 | super.init()
26 |
27 | margin = 5
28 | slidersGroup.margin = 5
29 |
30 | saturationSlider.value = 2
31 | brightnessSlider.value = 0
32 | contrastSlider.value = 1
33 | imageView.contentMode = UIViewContentMode.ScaleAspectFit
34 |
35 | saturationSlider.addTarget(self, action: "colorControlsChange", forControlEvents: UIControlEvents.ValueChanged)
36 | brightnessSlider.addTarget(self, action: "colorControlsChange", forControlEvents: UIControlEvents.ValueChanged)
37 | contrastSlider.addTarget(self, action: "colorControlsChange", forControlEvents: UIControlEvents.ValueChanged)
38 |
39 | slidersGroup.children = [saturationSlider, brightnessSlider, contrastSlider]
40 |
41 | children = [slidersGroup, imageView]
42 |
43 | colorControlsChange()
44 | }
45 |
46 | func colorControlsChange()
47 | {
48 | imageView.image = image
49 | .SIColorControls(saturation: saturationSlider.value, brightness: brightnessSlider.value, contrast: contrastSlider.value)
50 | }
51 |
52 | required init(coder aDecoder: NSCoder) {
53 | fatalError("init(coder:) has not been implemented")
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/ShinpuruImage/Histogram.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Histogram.swift
3 | // ShinpuruImage
4 | //
5 | // Created by Simon Gladman on 25/05/2015.
6 | // Copyright (c) 2015 Simon Gladman. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Charts
11 |
12 | class Histogram: SLHGroup
13 | {
14 | let leftGroup = SLVGroup()
15 | let rightGroup = SLVGroup()
16 |
17 | let imageView = UIImageView()
18 |
19 | let foo = [String](count: 256, repeatedValue: "")
20 | var redChartData = [ChartDataEntry](count: 256, repeatedValue: ChartDataEntry())
21 | var greenChartData = [ChartDataEntry](count: 256, repeatedValue: ChartDataEntry())
22 | var blueChartData = [ChartDataEntry](count: 256, repeatedValue: ChartDataEntry())
23 |
24 | let redSlider = LabelledSlider(title: "White Point Red")
25 | let greenSlider = LabelledSlider(title: "White Point Green")
26 | let blueSlider = LabelledSlider(title: "White Point Blue")
27 |
28 | let saturationSlider = LabelledSlider(title: "Saturation", minimumValue: 0, maximumValue: 4)
29 | let brightnessSlider = LabelledSlider(title: "Brightness", minimumValue: -1, maximumValue: 1)
30 | let contrastSlider = LabelledSlider(title: "Contrast", minimumValue: 0, maximumValue: 2)
31 |
32 | let gammaSlider = LabelledSlider(title: "Gamma", minimumValue: 0, maximumValue: 4)
33 |
34 | let hueSlider = LabelledSlider(title: "Hue", minimumValue: 0, maximumValue: Float(M_PI * 2))
35 | let exposureSlider = LabelledSlider(title: "Exposure", minimumValue: 0, maximumValue: 4)
36 |
37 | let fastChainHGroup = SLHGroup()
38 | let fastChainSwitch = UISwitch()
39 | let fastChainLabel = UILabel()
40 |
41 | let chart = LineChartView()
42 |
43 | required init()
44 | {
45 | super.init()
46 |
47 | let left = chart.getAxis(ChartYAxis.AxisDependency.Left)
48 | left.customAxisMax = 20_000
49 | left.drawLabelsEnabled = false
50 |
51 | let right = chart.getAxis(ChartYAxis.AxisDependency.Right)
52 | right.customAxisMax = 20_000
53 | right.drawLabelsEnabled = false
54 |
55 | chart.descriptionText = ""
56 |
57 | margin = 20
58 | leftGroup.margin = 10
59 |
60 | imageView.contentMode = UIViewContentMode.ScaleAspectFit
61 |
62 | chart.backgroundColor = UIColor.lightGrayColor()
63 |
64 | redSlider.value = 1
65 | greenSlider.value = 1
66 | blueSlider.value = 1
67 |
68 | saturationSlider.value = 2
69 | contrastSlider.value = 1
70 |
71 | gammaSlider.value = 1
72 | exposureSlider.value = 0.5
73 |
74 | redSlider.addTarget(self, action: "updateImage", forControlEvents: UIControlEvents.ValueChanged)
75 | greenSlider.addTarget(self, action: "updateImage", forControlEvents: UIControlEvents.ValueChanged)
76 | blueSlider.addTarget(self, action: "updateImage", forControlEvents: UIControlEvents.ValueChanged)
77 |
78 | saturationSlider.addTarget(self, action: "updateImage", forControlEvents: UIControlEvents.ValueChanged)
79 | brightnessSlider.addTarget(self, action: "updateImage", forControlEvents: UIControlEvents.ValueChanged)
80 | contrastSlider.addTarget(self, action: "updateImage", forControlEvents: UIControlEvents.ValueChanged)
81 |
82 | gammaSlider.addTarget(self, action: "updateImage", forControlEvents: UIControlEvents.ValueChanged)
83 |
84 | hueSlider.addTarget(self, action: "updateImage", forControlEvents: UIControlEvents.ValueChanged)
85 | exposureSlider.addTarget(self, action: "updateImage", forControlEvents: UIControlEvents.ValueChanged)
86 |
87 | fastChainLabel.text = "Use Fast Chaining"
88 | fastChainLabel.textAlignment = NSTextAlignment.Right
89 | fastChainLabel.frame = CGRect(x: 0, y: 0, width: 1, height: fastChainSwitch.intrinsicContentSize().height)
90 | fastChainHGroup.children = [fastChainLabel, fastChainSwitch]
91 | fastChainHGroup.explicitSize = fastChainSwitch.intrinsicContentSize().height
92 |
93 | rightGroup.children = [imageView, chart]
94 | leftGroup.children = [redSlider, greenSlider, blueSlider, saturationSlider, brightnessSlider, contrastSlider, gammaSlider, hueSlider, exposureSlider, fastChainHGroup]
95 |
96 | children = [leftGroup, rightGroup]
97 |
98 | updateImage()
99 | }
100 |
101 | func updateImage()
102 | {
103 | let targetColor = UIColor(red: CGFloat(redSlider.value),
104 | green: CGFloat(greenSlider.value),
105 | blue: CGFloat(blueSlider.value),
106 | alpha: CGFloat(1.0))
107 |
108 | let startTime = CFAbsoluteTimeGetCurrent()
109 |
110 | let image: UIImage!
111 |
112 | if !fastChainSwitch.on
113 | {
114 | image = UIImage(named: "tram.jpg")?
115 | .SIWhitePointAdjust(color: targetColor)
116 | .SIColorControls(saturation: saturationSlider.value, brightness: brightnessSlider.value, contrast: contrastSlider.value)
117 | .SIGammaAdjust(power: gammaSlider.value)
118 | .SIExposureAdjust(ev: exposureSlider.value)
119 | .SIHueAdjust(power: hueSlider.value)
120 | }
121 | else
122 | {
123 | image = SIFastChainableImage(image: UIImage(named: "tram.jpg")!)!
124 | .SIWhitePointAdjust(color: targetColor)
125 | .SIColorControls(saturation: saturationSlider.value, brightness: brightnessSlider.value, contrast: contrastSlider.value)
126 | .SIGammaAdjust(power: gammaSlider.value)
127 | .SIExposureAdjust(ev: exposureSlider.value)
128 | .SIHueAdjust(power: hueSlider.value)
129 | .toUIImage()
130 | }
131 |
132 | let duration = CFAbsoluteTimeGetCurrent() - startTime
133 |
134 | print("duration = \(duration) fast chain = \(fastChainSwitch.on)")
135 |
136 | let histogram = image?.SIHistogramCalculation()
137 |
138 | imageView.image = image
139 |
140 | for i: Int in 0 ... 255
141 | {
142 | redChartData[i] = ( ChartDataEntry(value: Float(histogram!.red[i]), xIndex: i) )
143 | greenChartData[i] = ( ChartDataEntry(value: Float(histogram!.green[i]), xIndex: i) )
144 | blueChartData[i] = ( ChartDataEntry(value: Float(histogram!.blue[i]), xIndex: i) )
145 | }
146 |
147 | let redChartDataSet = LineChartDataSet(yVals: redChartData, label: "red")
148 | let greenChartDataSet = LineChartDataSet(yVals: greenChartData, label: "green")
149 | let blueChartDataSet = LineChartDataSet(yVals: blueChartData, label: "blue")
150 |
151 | redChartDataSet.setColor(UIColor.redColor())
152 | redChartDataSet.lineWidth = 2
153 | redChartDataSet.drawCirclesEnabled = false
154 |
155 | greenChartDataSet.setColor(UIColor.greenColor())
156 | greenChartDataSet.lineWidth = 2
157 | greenChartDataSet.drawCirclesEnabled = false
158 |
159 | blueChartDataSet.setColor(UIColor.blueColor())
160 | blueChartDataSet.lineWidth = 2
161 | blueChartDataSet.drawCirclesEnabled = false
162 |
163 | let lineChartData = LineChartData(xVals: foo, dataSets: [redChartDataSet, greenChartDataSet, blueChartDataSet])
164 |
165 | chart.data = lineChartData
166 | }
167 |
168 | required init(coder aDecoder: NSCoder) {
169 | fatalError("init(coder:) has not been implemented")
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/ShinpuruImage/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "ipad",
5 | "size" : "29x29",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "ipad",
10 | "size" : "29x29",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "ipad",
15 | "size" : "40x40",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "ipad",
20 | "size" : "40x40",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "ipad",
25 | "size" : "76x76",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "ipad",
30 | "size" : "76x76",
31 | "scale" : "2x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/ShinpuruImage/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations~ipad
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationPortraitUpsideDown
37 | UIInterfaceOrientationLandscapeLeft
38 | UIInterfaceOrientationLandscapeRight
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/ShinpuruImage/LabelledSlider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LabelledSlider.swift
3 | // ShinpuruImage
4 | //
5 | // Created by Simon Gladman on 23/05/2015.
6 | // Copyright (c) 2015 Simon Gladman. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class LabelledSlider: UIControl
12 | {
13 | let slider = UISlider(frame: CGRectZero)
14 | let label = UILabel(frame: CGRectZero)
15 |
16 | required init(title: String, minimumValue: Float = 0, maximumValue: Float = 1)
17 | {
18 | super.init(frame: CGRectZero)
19 |
20 | slider.minimumValue = minimumValue
21 | slider.maximumValue = maximumValue
22 |
23 | self.title = title
24 | updateLabel()
25 | }
26 |
27 | required init(coder aDecoder: NSCoder) {
28 | fatalError("init(coder:) has not been implemented")
29 | }
30 |
31 | var title: String = ""
32 | {
33 | didSet
34 | {
35 | updateLabel()
36 | }
37 | }
38 |
39 | var value: Float = 0
40 | {
41 | didSet
42 | {
43 | slider.value = Float(value)
44 | updateLabel()
45 | }
46 | }
47 |
48 | override func didMoveToSuperview()
49 | {
50 | slider.addTarget(self, action: "sliderChangeHandler", forControlEvents: .ValueChanged)
51 |
52 | layer.cornerRadius = 5
53 | layer.borderColor = UIColor.lightGrayColor().CGColor
54 | layer.borderWidth = 1
55 |
56 | addSubview(slider)
57 | addSubview(label)
58 | }
59 |
60 | func sliderChangeHandler()
61 | {
62 | value = slider.value
63 |
64 | sendActionsForControlEvents(.ValueChanged)
65 | }
66 |
67 | func updateLabel()
68 | {
69 | label.text = title + ": " + (NSString(format: "%.3f", Float(value)) as String)
70 | }
71 |
72 | override func layoutSubviews()
73 | {
74 | label.frame = CGRect(x: 0, y: 0, width: frame.width, height: frame.height / 2).insetBy(dx: 5, dy: 5)
75 | slider.frame = CGRect(x: 0, y: frame.height / 2, width: frame.width, height: frame.height / 2).insetBy(dx: 5, dy: 5)
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/ShinpuruImage/RotateAndScale.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RotateAndScale.swift
3 | // ShinpuruImage
4 | //
5 | // Created by Simon Gladman on 23/05/2015.
6 | // Copyright (c) 2015 Simon Gladman. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class RotateAndScale: SLHGroup
12 | {
13 | let slidersGroup = SLVGroup()
14 |
15 | let scaleXslider = LabelledSlider(title: "Scale X", minimumValue: 0.001, maximumValue: 1)
16 | let scaleYslider = LabelledSlider(title: "Scale Y", minimumValue: 0.001, maximumValue: 1)
17 | let rotateslider = LabelledSlider(title: "Rotation", minimumValue: 0, maximumValue: Float(2 * M_PI))
18 |
19 | let imageView = UIImageView()
20 |
21 | let image = UIImage(named: "vegas.jpg")!
22 |
23 | required init()
24 | {
25 | super.init()
26 |
27 | margin = 5
28 | slidersGroup.margin = 5
29 |
30 | scaleXslider.value = 1
31 | scaleYslider.value = 1
32 | imageView.contentMode = UIViewContentMode.ScaleAspectFit
33 |
34 | scaleXslider.addTarget(self, action: "scaleRotateChange", forControlEvents: UIControlEvents.ValueChanged)
35 | scaleYslider.addTarget(self, action: "scaleRotateChange", forControlEvents: UIControlEvents.ValueChanged)
36 | rotateslider.addTarget(self, action: "scaleRotateChange", forControlEvents: UIControlEvents.ValueChanged)
37 |
38 | slidersGroup.children = [scaleXslider, scaleYslider, rotateslider]
39 |
40 | children = [slidersGroup, imageView]
41 |
42 | scaleRotateChange()
43 | }
44 |
45 | func scaleRotateChange()
46 | {
47 | imageView.image = image
48 | .SIScale(scaleX: scaleXslider.value, scaleY: scaleYslider.value)
49 | .SIRotate(angle: rotateslider.value, backgroundColor: UIColor.lightGrayColor())
50 | }
51 |
52 | required init(coder aDecoder: NSCoder) {
53 | fatalError("init(coder:) has not been implemented")
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/ShinpuruImage/SLControls.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SLControls.swift
3 | // ShinpuruLayout
4 | //
5 | // Created by Simon Gladman on 03/05/2015.
6 | // Copyright (c) 2015 Simon Gladman. All rights reserved.
7 | //
8 | // This program is free software: you can redistribute it and/or modify
9 | // it under the terms of the GNU General Public License as published by
10 | // the Free Software Foundation, either version 3 of the License, or
11 | // (at your option) any later version.
12 | //
13 | // This program is distributed in the hope that it will be useful,
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | // GNU General Public License for more details.
17 |
18 | // You should have received a copy of the GNU General Public License
19 | // along with this program. If not, see
20 |
21 | import UIKit
22 |
23 | public class SLLabel: UILabel, SLLayoutItem
24 | {
25 | public var percentageSize: CGFloat?
26 | public var explicitSize: CGFloat?
27 | }
28 |
29 | public class SLSegmentedControl: UISegmentedControl, SLLayoutItem
30 | {
31 | public var percentageSize: CGFloat?
32 | public var explicitSize: CGFloat?
33 | }
34 |
35 | public class SLButton: UIButton, SLLayoutItem
36 | {
37 | public var percentageSize: CGFloat?
38 | public var explicitSize: CGFloat?
39 | }
40 |
41 | public class SLImageView: UIImageView, SLLayoutItem
42 | {
43 | public var percentageSize: CGFloat?
44 | public var explicitSize: CGFloat?
45 | }
46 |
47 | public class SLSpacer: UIView, SLLayoutItem
48 | {
49 | public var percentageSize: CGFloat?
50 | public var explicitSize: CGFloat?
51 |
52 | required public init(percentageSize: CGFloat?, explicitSize: CGFloat?)
53 | {
54 | super.init(frame: CGRectZero)
55 |
56 | self.percentageSize = percentageSize
57 | self.explicitSize = explicitSize
58 | }
59 |
60 | required public init(coder aDecoder: NSCoder)
61 | {
62 | super.init(coder: aDecoder)!
63 | }
64 | }
65 |
66 | /// SLLayoutItem
67 | public protocol SLLayoutItem
68 | {
69 | /// For items in an HGroup, the width as a percentage of the parent's width, for items in a VGroup, the height as a percentage of the parent's height
70 | /// If set to nil, Shinpuru Layout treats this like a standard UIView and automatically sets percentage itself
71 | var percentageSize: CGFloat? {get set}
72 |
73 | /// If percentage is nil, optional explicit size allows the item's width or height to be set in points
74 | var explicitSize: CGFloat? {get set}
75 | }
--------------------------------------------------------------------------------
/ShinpuruImage/ShinpuruImage_Chaining.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShinpuruImage_Chaining.swift
3 | // ShinpuruImage
4 | //
5 | // Created by Simon Gladman on 21/05/2015.
6 | // Copyright (c) 2015 Simon Gladman. All rights reserved.
7 | //
8 | // This program is free software: you can redistribute it and/or modify
9 | // it under the terms of the GNU General Public License as published by
10 | // the Free Software Foundation, either version 3 of the License, or
11 | // (at your option) any later version.
12 | //
13 | // This program is distributed in the hope that it will be useful,
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | // GNU General Public License for more details.
17 |
18 | // You should have received a copy of the GNU General Public License
19 | // along with this program. If not, see
20 | //
21 | // Requires ShinpuruImage_CoreImage.swift
22 |
23 | import UIKit
24 |
25 | // MARK: Photo Effects
26 |
27 | extension CIImage
28 | {
29 | func SIPhotoEffectNoir() -> CIImage
30 | {
31 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectNoir", keyValuePairs: [])
32 | }
33 |
34 | func SIPhotoEffectChrome() -> CIImage
35 | {
36 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectChrome", keyValuePairs: [])
37 | }
38 |
39 | func SIPhotoEffectFade() -> CIImage
40 | {
41 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectFade", keyValuePairs: [])
42 | }
43 |
44 | func SIPhotoEffectInstant() -> CIImage
45 | {
46 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectInstant", keyValuePairs: [])
47 | }
48 |
49 | func SIPhotoEffectMono() -> CIImage
50 | {
51 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectMono", keyValuePairs: [])
52 | }
53 |
54 | func SIPhotoEffectProcess() -> CIImage
55 | {
56 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectProcess", keyValuePairs: [])
57 | }
58 |
59 | func SIPhotoEffectTonal() -> CIImage
60 | {
61 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectTonal", keyValuePairs: [])
62 | }
63 |
64 | func SIPhotoEffectTransfer() -> CIImage
65 | {
66 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectTransfer", keyValuePairs: [])
67 | }
68 |
69 | // MARK: CICategoryColorEffect
70 |
71 | func SIFalseColor(color0 color0: UIColor, color1: UIColor) -> CIImage
72 | {
73 | let inputColor0 = KeyValuePair(key: "inputColor0", value: CIColor(color: color0))
74 | let inputColor1 = KeyValuePair(key: "inputColor1", value: CIColor(color: color1))
75 |
76 | let filterName = "CIFalseColor"
77 |
78 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputColor0, inputColor1])
79 | }
80 |
81 | func SIPosterize(levels levels: Int) -> CIImage
82 | {
83 | let inputLevels = KeyValuePair(key: "inputLevels", value: levels)
84 |
85 | let filterName = "CIColorPosterize"
86 |
87 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputLevels])
88 | }
89 |
90 | func SIMonochrome(color color: UIColor, intensity: Float) -> CIImage
91 | {
92 | let inputColor = KeyValuePair(key: "inputColor", value: CIColor(color: color))
93 | let inputIntensity = KeyValuePair(key: "inputIntensity", value: intensity)
94 |
95 | let filterName = "CIColorMonochrome"
96 |
97 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputColor, inputIntensity])
98 | }
99 |
100 | // MARK: CICategoryStylize
101 |
102 | func SIBloom(radius radius: Float, intensity: Float) -> CIImage
103 | {
104 | let inputRadius = KeyValuePair(key: "inputRadius", value: radius)
105 | let inputIntensity = KeyValuePair(key: "inputIntensity", value: intensity)
106 |
107 | let filterName = "CIBloom"
108 |
109 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputRadius, inputIntensity])
110 | }
111 |
112 | func SIGloom(radius radius: Float, intensity: Float) -> CIImage
113 | {
114 | let inputRadius = KeyValuePair(key: "inputRadius", value: radius)
115 | let inputIntensity = KeyValuePair(key: "inputIntensity", value: intensity)
116 |
117 | let filterName = "CIGloom"
118 |
119 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputRadius, inputIntensity])
120 | }
121 |
122 | func SIPixellate(scale scale: Float) -> CIImage
123 | {
124 | let inputScale = KeyValuePair(key: "inputScale", value: scale)
125 |
126 | let filterName = "CIPixellate"
127 |
128 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputScale])
129 | }
130 |
131 | // MARK: CICategoryBlur
132 |
133 | func SIGaussianBlur(radius radius: Float) -> CIImage
134 | {
135 | let inputRadius = KeyValuePair(key: "inputRadius", value: radius)
136 |
137 | let filterName = "CIGaussianBlur"
138 |
139 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputRadius])
140 | }
141 |
142 | // MARK: CICategoryColorAdjustment
143 |
144 | func SIColorControls(saturation saturation: Float, brightness: Float, contrast: Float) -> CIImage
145 | {
146 | let inputSaturation = KeyValuePair(key: "inputSaturation", value: saturation)
147 | let inputBrightness = KeyValuePair(key: "inputBrightness", value: brightness)
148 | let inputContrast = KeyValuePair(key: "inputContrast", value: contrast)
149 |
150 | let filterName = "CIColorControls"
151 |
152 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputSaturation, inputBrightness, inputContrast])
153 | }
154 |
155 | func SIExposureAdjust(ev ev: Float) -> CIImage
156 | {
157 | let inputEV = KeyValuePair(key: "inputEV", value: ev)
158 |
159 | let filterName = "CIExposureAdjust"
160 |
161 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputEV])
162 | }
163 |
164 | func SIGammaAdjust(power power: Float) -> CIImage
165 | {
166 | let inputPower = KeyValuePair(key: "inputPower", value: power)
167 |
168 | let filterName = "CIGammaAdjust"
169 |
170 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputPower])
171 | }
172 |
173 | func SIHueAdjust(power power: Float) -> CIImage
174 | {
175 | let inputAngle = KeyValuePair(key: "inputAngle", value: power)
176 |
177 | let filterName = "CIHueAdjust"
178 |
179 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputAngle])
180 | }
181 |
182 | func SIVibrance(amount amount: Float) -> CIImage
183 | {
184 | let inputAmount = KeyValuePair(key: "inputAmount", value: amount)
185 |
186 | let filterName = "CIVibrance"
187 |
188 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputAmount])
189 | }
190 |
191 | func SIWhitePointAdjust(color color: UIColor) -> CIImage
192 | {
193 | let inputColor = KeyValuePair(key: "inputColor", value: CIColor(color: color))
194 |
195 | let filterName = "CIWhitePointAdjust"
196 |
197 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputColor])
198 | }
199 |
200 | // MARK: To UIImage
201 |
202 | func toUIImage() -> UIImage
203 | {
204 | let filteredImageRef = ShinpuruCoreImageHelper.ciContextFast.createCGImage(self, fromRect: self.extent)
205 | let filteredImage = UIImage(CGImage: filteredImageRef)
206 |
207 | return filteredImage
208 | }
209 | }
210 |
211 | // MARK: Utilities
212 |
213 | extension ShinpuruCoreImageHelper
214 | {
215 | static func applyFilter(image: CIImage, filterName: String, keyValuePairs: [KeyValuePair]) -> CIImage
216 | {
217 | let ciFilter = CIFilter(name: filterName)
218 |
219 | let inputImage = KeyValuePair(key: kCIInputImageKey, value: image)
220 | ciFilter!.setValue(inputImage.value, forKey: inputImage.key)
221 |
222 | keyValuePairs.map({ ciFilter!.setValue($0.value, forKey: $0.key) })
223 |
224 | return ciFilter!.valueForKey(kCIOutputImageKey) as! CIImage
225 | }
226 | }
227 |
228 |
--------------------------------------------------------------------------------
/ShinpuruImage/ShinpuruImage_CoreImage.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShinpuruImage_CoreImage.swift
3 | // ShinpuruImage
4 | //
5 | // Created by Simon Gladman on 21/05/2015.
6 | // Copyright (c) 2015 Simon Gladman. All rights reserved.
7 | //
8 | // This program is free software: you can redistribute it and/or modify
9 | // it under the terms of the GNU General Public License as published by
10 | // the Free Software Foundation, either version 3 of the License, or
11 | // (at your option) any later version.
12 | //
13 | // This program is distributed in the hope that it will be useful,
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 | // GNU General Public License for more details.
17 |
18 | // You should have received a copy of the GNU General Public License
19 | // along with this program. If not, see
20 |
21 | import UIKit
22 |
23 | // MARK: Photo Effects
24 |
25 | extension UIImage
26 | {
27 | func SIPhotoEffectNoir() -> UIImage
28 | {
29 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectNoir", keyValuePairs: [])
30 | }
31 |
32 | func SIPhotoEffectChrome() -> UIImage
33 | {
34 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectChrome", keyValuePairs: [])
35 | }
36 |
37 | func SIPhotoEffectFade() -> UIImage
38 | {
39 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectFade", keyValuePairs: [])
40 | }
41 |
42 | func SIPhotoEffectInstant() -> UIImage
43 | {
44 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectInstant", keyValuePairs: [])
45 | }
46 |
47 | func SIPhotoEffectMono() -> UIImage
48 | {
49 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectMono", keyValuePairs: [])
50 | }
51 |
52 | func SIPhotoEffectProcess() -> UIImage
53 | {
54 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectProcess", keyValuePairs: [])
55 | }
56 |
57 | func SIPhotoEffectTonal() -> UIImage
58 | {
59 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectTonal", keyValuePairs: [])
60 | }
61 |
62 | func SIPhotoEffectTransfer() -> UIImage
63 | {
64 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: "CIPhotoEffectTransfer", keyValuePairs: [])
65 | }
66 |
67 | // MARK: CICategoryColorEffect
68 |
69 | func SIFalseColor(color0 color0: UIColor, color1: UIColor) -> UIImage
70 | {
71 | let inputColor0 = KeyValuePair(key: "inputColor0", value: CIColor(color: color0))
72 | let inputColor1 = KeyValuePair(key: "inputColor1", value: CIColor(color: color1))
73 |
74 | let filterName = "CIFalseColor"
75 |
76 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputColor0, inputColor1])
77 | }
78 |
79 | func SIPosterize(levels levels: Int) -> UIImage
80 | {
81 | let inputLevels = KeyValuePair(key: "inputLevels", value: levels)
82 |
83 | let filterName = "CIColorPosterize"
84 |
85 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputLevels])
86 | }
87 |
88 | func SIMonochrome(color color: UIColor, intensity: Float) -> UIImage
89 | {
90 | let inputColor = KeyValuePair(key: "inputColor", value: CIColor(color: color))
91 | let inputIntensity = KeyValuePair(key: "inputIntensity", value: intensity)
92 |
93 | let filterName = "CIColorMonochrome"
94 |
95 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputColor, inputIntensity])
96 | }
97 |
98 | // MARK: CICategoryStylize
99 |
100 | func SIBloom(radius radius: Float, intensity: Float) -> UIImage
101 | {
102 | let inputRadius = KeyValuePair(key: "inputRadius", value: radius)
103 | let inputIntensity = KeyValuePair(key: "inputIntensity", value: intensity)
104 |
105 | let filterName = "CIBloom"
106 |
107 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputRadius, inputIntensity])
108 | }
109 |
110 | func SIGloom(radius radius: Float, intensity: Float) -> UIImage
111 | {
112 | let inputRadius = KeyValuePair(key: "inputRadius", value: radius)
113 | let inputIntensity = KeyValuePair(key: "inputIntensity", value: intensity)
114 |
115 | let filterName = "CIGloom"
116 |
117 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputRadius, inputIntensity])
118 | }
119 |
120 | func SIPixellate(scale scale: Float) -> UIImage
121 | {
122 | let inputScale = KeyValuePair(key: "inputScale", value: scale)
123 |
124 | let filterName = "CIPixellate"
125 |
126 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputScale])
127 | }
128 |
129 | // MARK: CICategoryBlur
130 |
131 | func SIGaussianBlur(radius radius: Float) -> UIImage
132 | {
133 | let inputRadius = KeyValuePair(key: "inputRadius", value: radius)
134 |
135 | let filterName = "CIGaussianBlur"
136 |
137 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputRadius])
138 | }
139 |
140 | // MARK: CICategoryColorAdjustment
141 |
142 | func SIColorControls(saturation saturation: Float, brightness: Float, contrast: Float) -> UIImage
143 | {
144 | let inputSaturation = KeyValuePair(key: "inputSaturation", value: saturation)
145 | let inputBrightness = KeyValuePair(key: "inputBrightness", value: brightness)
146 | let inputContrast = KeyValuePair(key: "inputContrast", value: contrast)
147 |
148 | let filterName = "CIColorControls"
149 |
150 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputSaturation, inputBrightness, inputContrast])
151 | }
152 |
153 | func SIExposureAdjust(ev ev: Float) -> UIImage
154 | {
155 | let inputEV = KeyValuePair(key: "inputEV", value: ev)
156 |
157 | let filterName = "CIExposureAdjust"
158 |
159 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputEV])
160 | }
161 |
162 | func SIGammaAdjust(power power: Float) -> UIImage
163 | {
164 | let inputPower = KeyValuePair(key: "inputPower", value: power)
165 |
166 | let filterName = "CIGammaAdjust"
167 |
168 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputPower])
169 | }
170 |
171 | func SIHueAdjust(power power: Float) -> UIImage
172 | {
173 | let inputAngle = KeyValuePair(key: "inputAngle", value: power)
174 |
175 | let filterName = "CIHueAdjust"
176 |
177 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputAngle])
178 | }
179 |
180 | func SIVibrance(amount amount: Float) -> UIImage
181 | {
182 | let inputAmount = KeyValuePair(key: "inputAmount", value: amount)
183 |
184 | let filterName = "CIVibrance"
185 |
186 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputAmount])
187 | }
188 |
189 | func SIWhitePointAdjust(color color: UIColor) -> UIImage
190 | {
191 | let inputColor = KeyValuePair(key: "inputColor", value: CIColor(color: color))
192 |
193 | let filterName = "CIWhitePointAdjust"
194 |
195 | return ShinpuruCoreImageHelper.applyFilter(self, filterName: filterName, keyValuePairs: [inputColor])
196 | }
197 | }
198 |
199 | // MARK: Utilities
200 |
201 | import CoreImage
202 | import Foundation
203 |
204 | class ShinpuruCoreImageHelper
205 | {
206 |
207 | static let ciContext = CIContext(options: nil)
208 | static let ciContextFast = CIContext(EAGLContext: EAGLContext(API: EAGLRenderingAPI.OpenGLES2), options: [kCIContextWorkingColorSpace: NSNull()])
209 |
210 | static func applyFilter(image: UIImage, filterName: String, keyValuePairs: [KeyValuePair]) -> UIImage
211 | {
212 | let ciFilter = CIFilter(name: filterName)
213 |
214 | let inputImage = KeyValuePair(key: kCIInputImageKey, value: CIImage(image: image)!)
215 | ciFilter!.setValue(inputImage.value, forKey: inputImage.key)
216 |
217 | keyValuePairs.map({ ciFilter!.setValue($0.value, forKey: $0.key) })
218 |
219 | let filteredImageData = ciFilter!.valueForKey(kCIOutputImageKey) as! CIImage!
220 | let filteredImageRef = ShinpuruCoreImageHelper.ciContext.createCGImage(filteredImageData, fromRect: filteredImageData.extent)
221 |
222 | let filteredImage = UIImage(CGImage: filteredImageRef)
223 |
224 | return filteredImage
225 | }
226 | }
227 |
228 | typealias SIFastChainableImage = CIImage
229 | typealias KeyValuePair = (key:String, value: AnyObject)
230 |
--------------------------------------------------------------------------------
/ShinpuruImage/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // ShinpuruImage
4 | //
5 | // Created by Simon Gladman on 21/05/2015.
6 | // Copyright (c) 2015 Simon Gladman. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import Charts
11 |
12 | class ViewController: UIViewController {
13 |
14 | let histogram = Histogram()
15 | let simpleDemo = SimpleDemo()
16 |
17 | let mainGroup = SLVGroup()
18 |
19 | let segmentedControl = SLSegmentedControl(items: ["Simple Demo", "Histogram / Fast Chaining Demo"])
20 |
21 | override func viewDidLoad()
22 | {
23 | segmentedControl.selectedSegmentIndex = 1
24 | segmentedControl.explicitSize = 60
25 | segmentedControl.addTarget(self, action: "selectionChange", forControlEvents: UIControlEvents.ValueChanged)
26 |
27 | mainGroup.margin = 20
28 | mainGroup.children = [segmentedControl, histogram]
29 |
30 | view.addSubview(mainGroup)
31 | }
32 |
33 | func selectionChange()
34 | {
35 | mainGroup.removeChild(atIndex: 1)
36 |
37 | let newChild = segmentedControl.selectedSegmentIndex == 0 ? simpleDemo : histogram
38 |
39 | mainGroup.addChild(newChild, atIndex: 1)
40 | }
41 |
42 | override func viewDidLayoutSubviews()
43 | {
44 | let top = topLayoutGuide.length
45 | let bottom = bottomLayoutGuide.length
46 |
47 | mainGroup.frame = CGRect(x: 0, y: top, width: view.frame.width, height: view.frame.height - top - bottom).insetBy(dx: 20, dy: 20)
48 | }
49 |
50 | }
51 |
52 |
53 | class SimpleDemo: SLVGroup
54 | {
55 | required init()
56 | {
57 | super.init()
58 |
59 | children = [RotateAndScale(), ColorControls()]
60 | }
61 |
62 | required init(coder aDecoder: NSCoder) {
63 | fatalError("init(coder:) has not been implemented")
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/ShinpuruImage/assets/HistogramScreenShot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FlexMonkey/ShinpuruImage/8632c4eaa3be836acf7e923d81eccfce4907afdc/ShinpuruImage/assets/HistogramScreenShot.jpg
--------------------------------------------------------------------------------
/ShinpuruImage/assets/glass.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FlexMonkey/ShinpuruImage/8632c4eaa3be836acf7e923d81eccfce4907afdc/ShinpuruImage/assets/glass.jpg
--------------------------------------------------------------------------------
/ShinpuruImage/assets/oculista.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FlexMonkey/ShinpuruImage/8632c4eaa3be836acf7e923d81eccfce4907afdc/ShinpuruImage/assets/oculista.jpg
--------------------------------------------------------------------------------
/ShinpuruImage/assets/tram.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FlexMonkey/ShinpuruImage/8632c4eaa3be836acf7e923d81eccfce4907afdc/ShinpuruImage/assets/tram.jpg
--------------------------------------------------------------------------------
/ShinpuruImage/assets/vegas.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FlexMonkey/ShinpuruImage/8632c4eaa3be836acf7e923d81eccfce4907afdc/ShinpuruImage/assets/vegas.jpg
--------------------------------------------------------------------------------
/ShinpuruImage/image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FlexMonkey/ShinpuruImage/8632c4eaa3be836acf7e923d81eccfce4907afdc/ShinpuruImage/image.jpg
--------------------------------------------------------------------------------
/ShinpuruImage/shinpuruImageScreenShot.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FlexMonkey/ShinpuruImage/8632c4eaa3be836acf7e923d81eccfce4907afdc/ShinpuruImage/shinpuruImageScreenShot.PNG
--------------------------------------------------------------------------------
/ShinpuruImageTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ShinpuruImageTests/ShinpuruImageTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ShinpuruImageTests.swift
3 | // ShinpuruImageTests
4 | //
5 | // Created by Simon Gladman on 21/05/2015.
6 | // Copyright (c) 2015 Simon Gladman. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import XCTest
11 |
12 | class ShinpuruImageTests: XCTestCase
13 | {
14 | var image: UIImage!
15 | var imageView: UIImageView!
16 |
17 | override func setUp()
18 | {
19 | super.setUp()
20 |
21 | image = UIImage(named: "oculista.jpg")!
22 | imageView = UIImageView()
23 | }
24 |
25 | override func tearDown()
26 | {
27 | super.tearDown()
28 |
29 | image = nil
30 | imageView = nil
31 | }
32 |
33 | func testUIImageChaining()
34 | {
35 | self.measureBlock()
36 | {
37 | let chained = self.image
38 | .SIPhotoEffectFade()
39 | .SIGaussianBlur(radius: 5)
40 | .SIPhotoEffectInstant()
41 | .SIPhotoEffectNoir()
42 | .SIGaussianBlur(radius: 5)
43 | .SIPhotoEffectProcess()
44 | .SIPhotoEffectTonal()
45 | .SIPhotoEffectProcess()
46 | .SIPhotoEffectTonal()
47 | .SIGaussianBlur(radius: 6)
48 | .SIBloom(radius: 20, intensity: 20)
49 | .SIColorControls(saturation: 0.5, brightness: 1, contrast: 2)
50 | .SIWhitePointAdjust(color: UIColor.yellowColor())
51 | .SIFalseColor(color0: UIColor.blueColor(), color1: UIColor.redColor())
52 | .SIPixellate(scale: 5)
53 |
54 | self.imageView.image = chained
55 | }
56 | }
57 |
58 | func testCIImageChaining()
59 | {
60 | self.measureBlock()
61 | {
62 | let chained = SIFastChainableImage(image: self.image)
63 | .SIPhotoEffectFade()
64 | .SIGaussianBlur(radius: 5)
65 | .SIPhotoEffectInstant()
66 | .SIPhotoEffectNoir()
67 | .SIGaussianBlur(radius: 5)
68 | .SIPhotoEffectProcess()
69 | .SIPhotoEffectTonal()
70 | .SIPhotoEffectProcess()
71 | .SIPhotoEffectTonal()
72 | .SIGaussianBlur(radius: 6)
73 | .SIBloom(radius: 20, intensity: 20)
74 | .SIColorControls(saturation: 0.5, brightness: 1, contrast: 2)
75 | .SIWhitePointAdjust(color: UIColor.yellowColor())
76 | .SIFalseColor(color0: UIColor.blueColor(), color1: UIColor.redColor())
77 | .SIPixellate(scale: 5)
78 | .toUIImage()
79 |
80 | self.imageView.image = chained
81 | }
82 | }
83 |
84 | // 0.311 sec on iPad Air 2
85 | // 0.348 sec on iPhone 6
86 | func testPerformanceSIFastBlur()
87 | {
88 | self.measureBlock()
89 | {
90 | for i in 0 ... 10
91 | {
92 | let blurred = self.image.SIFastBlur(width: i * 5, height: i * 5)
93 | }
94 | }
95 | }
96 |
97 | // 0.330 sec on iPad Air 2
98 | // 0.417 sec on iPhone 6
99 | func testPerformanceSIGaussianBlur()
100 | {
101 | self.measureBlock()
102 | {
103 | for i in 0 ... 10
104 | {
105 | let blurred = self.image.SIGaussianBlur(radius: Float(i) * 2.5)
106 | }
107 | }
108 | }
109 |
110 | // 0.271 sec on iPad Air 2
111 | // 0.294 on iPhone 6
112 | func testPerformanceSIBoxBlur()
113 | {
114 | self.measureBlock()
115 | {
116 | for i in 0 ... 10
117 | {
118 | let blurred = self.image.SIBoxBlur(width: i * 5, height: i * 5)
119 | }
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------