motion-plot 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ gem_rebuild
File without changes
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rake', '0.9.6'
4
+ gem 'bubble-wrap'
5
+ gem 'cocoapods'
6
+ gem 'motion-cocoapods'
7
+
8
+ # Specify your gem's dependencies in motion-plot.gemspec
9
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Amit Kumar
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Motion::Plot
2
+
3
+ Build native charts as you are used with Highcharts/D3. This library is a wrapper on top of CorePlot
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'motion-plot'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install motion-plot
18
+
19
+ ## Usage
20
+
21
+ Look at examples directory for usage options.
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+ $:.unshift("/Library/RubyMotion/lib")
3
+ require 'motion/project'
4
+ require "bundler/gem_tasks"
5
+ require "bundler/setup"
6
+ Bundler.require :default
7
+
8
+ $:.unshift("./lib/")
9
+ require './lib/motion-plot'
10
+
11
+ Motion::Project::App.setup do |app|
12
+ # Use `rake config' to see complete project settings.
13
+ app.name = 'MotionPlot'
14
+
15
+
16
+ app.frameworks << "QuartzCore"
17
+
18
+ app.pods do
19
+ pod "CorePlot"
20
+ end
21
+
22
+ end
@@ -0,0 +1,14 @@
1
+ class AppDelegate
2
+
3
+ def application(application, didFinishLaunchingWithOptions:launchOptions)
4
+
5
+ @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
6
+
7
+ @chart_view = GraphHostingView.alloc.initWithFrame [[10, 10], [App.frame.size.width-10, App.frame.size.height]]
8
+
9
+
10
+
11
+ true
12
+ end
13
+
14
+ end
@@ -0,0 +1,20 @@
1
+ require "motion-plot/version"
2
+ require 'bubble-wrap'
3
+ require 'motion-cocoapods'
4
+ require 'cocoapods'
5
+
6
+
7
+ Motion::Project::App.setup do |app|
8
+
9
+ Dir.glob(File.join(File.dirname(__FILE__), 'motion-plot/**/*.rb')).each do |file|
10
+ app.files.unshift(file)
11
+ end
12
+
13
+ app.files.unshift(File.join(File.dirname(__FILE__), 'motion-plot/chart/base.rb'))
14
+
15
+ app.frameworks << "QuartzCore"
16
+
17
+ app.pods do
18
+ pod "CorePlot"
19
+ end
20
+ end
@@ -0,0 +1,27 @@
1
+ module MotionPlot
2
+ class Area < Line
3
+
4
+ def plot_type
5
+ "area"
6
+ end
7
+
8
+ def add_series
9
+ super
10
+ @plots.each do |line|
11
+ add_area_gradient(line)
12
+ end
13
+ end
14
+
15
+ def add_area_gradient(line)
16
+ line.areaFill = AreaGradient.new(@orientation).fill_with(line.dataLineStyle.lineColor)
17
+ line.areaBaseValue = CPTDecimalFromString("0.0")
18
+ end
19
+
20
+ protected
21
+
22
+ def plot_type
23
+ "area"
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,74 @@
1
+ module MotionPlot
2
+ class Bar < Base
3
+
4
+ attr_reader :data_hash
5
+
6
+ CPDBarInitialX = 0.0
7
+
8
+ def add_series
9
+ @stacking = @plot_options ? @plot_options.bar[:stacking] : nil
10
+
11
+ bar_x = CPDBarInitialX
12
+ @data_hash = {}
13
+ horizontal_bar = (@orientation == "vertical") ? true : false
14
+ @delegate_object = case @stacking
15
+ when "normal"
16
+ StackBarDelegate.new(self)
17
+ when "percent"
18
+ PercentBarDelegate.new(self)
19
+ else
20
+ BarDelegate.new(self)
21
+ end
22
+
23
+ @series.keys.each_with_index do |name, index|
24
+ bar = CPTBarPlot.tubularBarPlotWithColor(@series[name].color, horizontalBars: horizontal_bar)
25
+ bar.barWidth = CPTDecimalFromDouble(@series[name].width)
26
+ bar.barOffset = CPTDecimalFromDouble(bar_x) unless(@stacking)
27
+
28
+ bar.identifier = name
29
+
30
+ _style = CPTMutableLineStyle.alloc.init
31
+ _style.lineWidth = 0.5
32
+ _style.lineColor = CPTColor.lightGrayColor
33
+
34
+ bar.lineStyle = _style
35
+ bar.dataSource = @delegate_object
36
+ bar.delegate = @delegate_object
37
+ bar.barBasesVary = @stacking ? true : false
38
+
39
+ @graph.addPlot(bar)
40
+ @plots << bar
41
+
42
+ animate(bar)
43
+
44
+ bar_x += @series[name].width
45
+ @data_hash[index] = @series[name].data
46
+ end
47
+ end
48
+
49
+ def animate(bar)
50
+ bar.anchorPoint = [0.0, 0.0]
51
+ scale_direction = (@orientation == "vertical") ? "transform.scale.x" : "transform.scale.y"
52
+ scaling = CABasicAnimation.animationWithKeyPath(scale_direction)
53
+ scaling.fromValue = 0.0
54
+ scaling.toValue = 1.0
55
+ scaling.duration = 1.0
56
+ scaling.removedOnCompletion = false
57
+ scaling.fillMode = KCAFillModeBackwards
58
+
59
+ bar.addAnimation(scaling, forKey:"scaling")
60
+ end
61
+
62
+ protected
63
+ def default_style
64
+ {
65
+ width: 0.25
66
+ }
67
+ end
68
+
69
+ def plot_type
70
+ "bar"
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,194 @@
1
+ module MotionPlot
2
+ class Base
3
+
4
+ attr_reader :layer_hosting_view, :graph, :series, :plot_space, :major_grid_line_style, :plots, :xaxis, :yaxis, :title
5
+
6
+ attr_accessor :legend, :plot_symbol, :axes, :theme, :data_label, :orientation, :plot_options
7
+
8
+ def bootstrap(options)
9
+ options.each_pair {|key, value|
10
+ send("#{key}=", value) if(respond_to?("#{key}="))
11
+ }
12
+
13
+ if(options[:title])
14
+ @title = Title.new(options[:title])
15
+ end
16
+
17
+ @axes = {}
18
+ if(options[:xAxis])
19
+ @axes[:x] = Axis.new(options[:xAxis].merge(type: 'xaxis'))
20
+ else
21
+ @axes[:x] = Axis.new(type: 'xaxis', enabled: false)
22
+ end
23
+
24
+ if(options[:yAxis])
25
+ @axes[:y] = Axis.new(options[:yAxis].merge(type: 'yaxis'))
26
+ else
27
+ @axes[:y] = Axis.new(type: 'yaxis', enabled: false)
28
+ end
29
+
30
+ if(@plot_options)
31
+ @plot_options = PlotOptions.new(@plot_options)
32
+ end
33
+
34
+ @series = {}
35
+ series = options[:series]
36
+ series && series.each_with_index {|hash, index|
37
+ hash.merge!({index: index, defaults: default_style, plot_options: @plot_options, type: self.plot_type})
38
+ @series[hash[:name]] = Series.new(hash)
39
+ }
40
+
41
+ if(options[:legend])
42
+ @legend = Legend.new(options[:legend])
43
+ end
44
+
45
+ if(options[:data_label])
46
+ @data_label = DataLabel.new(options[:data_label])
47
+ end
48
+
49
+ if(@plot_symbol)
50
+ @plot_symbol = PlotSymbol.new(options[:plot_symbol])
51
+ end
52
+
53
+ @plots = []
54
+ end
55
+
56
+ def initWithOptions(options, containerView:container)
57
+ bootstrap(options)
58
+
59
+ @layer_hosting_view = CPTGraphHostingView.alloc.initWithFrame([[0, 0], [container.frame.size.width, container.frame.size.height]])
60
+
61
+ bounds = @layer_hosting_view.bounds
62
+
63
+ # create and assign chart to the hosting view.
64
+ @graph = CPTXYGraph.alloc.initWithFrame(bounds)
65
+ @layer_hosting_view.hostedGraph = @graph
66
+
67
+ add_chart_title(@title) if(@title)
68
+
69
+ @graph.applyTheme(@theme || Theme.default)
70
+
71
+ default_padding
72
+
73
+ @chart_layers = [NSNumber.numberWithInt(CPTGraphLayerTypePlots), NSNumber.numberWithInt(CPTGraphLayerTypeMajorGridLines), NSNumber.numberWithInt(CPTGraphLayerTypeMinorGridLines), NSNumber.numberWithInt(CPTGraphLayerTypeAxisLines), NSNumber.numberWithInt(CPTGraphLayerTypeAxisLabels), NSNumber.numberWithInt(CPTGraphLayerTypeAxisTitles)]
74
+ @graph.topDownLayerOrder = @chart_layers
75
+
76
+
77
+ # add plot space
78
+ add_plot_space
79
+
80
+ @major_grid_line_style = CPTMutableLineStyle.lineStyle
81
+ @major_grid_line_style.lineWidth = 0.75
82
+ @major_grid_line_style.lineColor = CPTColor.grayColor.colorWithAlphaComponent(0.25)
83
+
84
+ axisSet = @graph.axisSet
85
+
86
+ # Setting up x-axis
87
+ if(@axes[:x].enabled?)
88
+ axis = @axes[:x]
89
+ @xaxis = axisSet.xAxis
90
+ @xaxis.majorGridLineStyle = @major_grid_line_style
91
+ @xaxis.minorTicksPerInterval = 1
92
+
93
+ add_axis_title(@xaxis, axis.title)
94
+
95
+ if(axis.labels)
96
+ labels = axis.labels.each_with_index.map do |l, i|
97
+ @xaxis.labelingPolicy = CPTAxisLabelingPolicyNone
98
+ label = CPTAxisLabel.alloc.initWithText(l, textStyle: axis.text_style)
99
+ label.tickLocation = CPTDecimalFromInt(i)
100
+ label.offset = 3.0
101
+ label
102
+ end
103
+
104
+ @xaxis.axisLabels = NSSet.setWithArray(labels)
105
+ end
106
+ end
107
+
108
+ # Setting up y-axis
109
+ if(@axes[:y].enabled?)
110
+ @yaxis = axisSet.yAxis
111
+ @yaxis.majorGridLineStyle = @major_grid_line_style
112
+ @yaxis.minorTicksPerInterval = 1
113
+ @yaxis.labelingPolicy = CPTAxisLabelingPolicyAutomatic
114
+
115
+ axis = @axes[:y]
116
+ add_axis_title(@yaxis, axis.title)
117
+ @yaxis.setLabelTextStyle(axis.text_style)
118
+ end
119
+
120
+ @graph.axisSet = nil if(not @axes[:x].enabled? and not @axes[:y].enabled?)
121
+
122
+ add_series
123
+
124
+ add_legend if(@legend.enabled?)
125
+
126
+ add_xy_range
127
+
128
+ @layer_hosting_view
129
+ end
130
+
131
+ def add_plot_space
132
+ @plot_space = @graph.defaultPlotSpace
133
+ @plot_space.delegate = self
134
+ @plot_space.allowsUserInteraction = true
135
+ end
136
+
137
+ def add_plot_symbol(plot, index)
138
+ plot.plotSymbol = @plot_symbol.symbol_for(plot, atIndex: index)
139
+ plot.plotSymbolMarginForHitDetection = 5.0
140
+ end
141
+
142
+ def add_xy_range
143
+ return if(not @axes[:x].enabled? and not @axes[:y].enabled?)
144
+ @plot_space.scaleToFitPlots(@plots)
145
+ x_range = @plot_space.xRange.mutableCopy
146
+ y_range = @plot_space.yRange.mutableCopy
147
+
148
+ x_range.expandRangeByFactor(CPTDecimalFromDouble(1.03))
149
+ y_range.expandRangeByFactor(CPTDecimalFromDouble(1.03))
150
+
151
+ @plot_space.xRange = x_range
152
+ @plot_space.yRange = y_range
153
+ end
154
+
155
+ def add_chart_title(title)
156
+ @graph.title = title.text
157
+ @graph.titleTextStyle = title.text_style
158
+ @graph.titlePlotAreaFrameAnchor = title.position
159
+ end
160
+
161
+ def add_axis_title(axis, title)
162
+ axis.title = title.text
163
+ axis.titleTextStyle = title.text_style
164
+ axis.titleOffset = title.style.offset
165
+ end
166
+
167
+ def add_legend
168
+ @graph.legend = @legend.cpt_legend(@graph)
169
+ @graph.legendAnchor = @legend.position
170
+ @graph.legendDisplacement = @legend.displacement
171
+ end
172
+
173
+ def default_padding
174
+ @graph.plotAreaFrame.masksToBorder = false
175
+ @graph.plotAreaFrame.borderLineStyle = nil
176
+ @graph.plotAreaFrame.paddingLeft = 50.0
177
+ @graph.plotAreaFrame.paddingTop = 10.0
178
+ @graph.plotAreaFrame.paddingRight = 20.0
179
+ @graph.plotAreaFrame.paddingBottom = 20.0
180
+
181
+
182
+ @graph.paddingLeft = 5.0
183
+ @graph.paddingRight = 0.0
184
+ @graph.paddingTop = 10.0
185
+ @graph.paddingBottom = 10.0
186
+ end
187
+
188
+ protected
189
+ def default_style
190
+ # inheriting classes should implement this
191
+ {}
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,31 @@
1
+ module MotionPlot
2
+ class BarDelegate
3
+
4
+ # delegate :series, :to => :delegated_to
5
+
6
+ def initialize(source)
7
+ @delegated_to = source
8
+ end
9
+
10
+ def numberOfRecordsForPlot(plot)
11
+ @delegated_to.series[plot.identifier].data.size
12
+ end
13
+
14
+ def numberForPlot(plot, field:field_enum, recordIndex:index)
15
+ data = @delegated_to.series[plot.identifier].data
16
+
17
+ (field_enum == CPTBarPlotFieldBarTip) ? data[index] : index
18
+ end
19
+
20
+ def barPlot(plot, barWasSelectedAtRecordIndex:index)
21
+ if(@delegated_to.data_label and @delegated_to.data_label.annotation)
22
+ @delegated_to.graph.plotAreaFrame.plotArea.removeAnnotation(@delegated_to.data_label.annotation)
23
+ @delegated_to.data_label.annotation = nil
24
+ end
25
+
26
+ y_value = @delegated_to.series[plot.identifier].data[index].round(2)
27
+ @delegated_to.graph.plotAreaFrame.plotArea.addAnnotation(@delegated_to.data_label.annotation_for(y_value, atCoordinate: [index+CPTDecimalFloatValue(plot.barOffset), y_value], plotSpace: @delegated_to.graph.defaultPlotSpace))
28
+ end
29
+
30
+ end
31
+ end