motion-plot 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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