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,60 @@
1
+ module MotionPlot
2
+ class PercentBarDelegate
3
+
4
+ def initialize(source)
5
+ @delegated_to = source
6
+ @number_of_plots = @delegated_to.series.keys.size
7
+ end
8
+
9
+ def numberOfRecordsForPlot(plot)
10
+ @delegated_to.series[plot.identifier].data.size
11
+ end
12
+
13
+ def numberForPlot(plot, field:field_enum, recordIndex:index)
14
+ case field_enum
15
+ when CPTBarPlotFieldBarLocation
16
+ index
17
+ when CPTBarPlotFieldBarTip
18
+ plot_index = @delegated_to.series[plot.identifier].index
19
+ record_data = @delegated_to.series[plot.identifier].data[index]
20
+ bar_tip_value(plot_index, recordIndex:index, startValue:record_data)
21
+ when CPTBarPlotFieldBarBase
22
+ plot_index = @delegated_to.series[plot.identifier].index
23
+ bar_base_value(plot_index, recordIndex:index)
24
+ end
25
+ end
26
+
27
+ def barPlot(plot, barWasSelectedAtRecordIndex:index)
28
+ if(@delegated_to.data_label and @delegated_to.data_label.annotation)
29
+ @delegated_to.graph.plotAreaFrame.plotArea.removeAnnotation(@delegated_to.data_label.annotation)
30
+ @delegated_to.data_label.annotation = nil
31
+ end
32
+
33
+ y_value = (@delegated_to.series[plot.identifier].data[index].round(2) / total_sum_at_index(index)) * 100
34
+ plot_index = @delegated_to.series[plot.identifier].index
35
+ y_pos = (0..plot_index).inject(0) {|base, i| base + (@delegated_to.data_hash[i][index] / total_sum_at_index(index)) * 100 }
36
+
37
+ @delegated_to.graph.plotAreaFrame.plotArea.addAnnotation(@delegated_to.data_label.annotation_for("#{y_value} %", atCoordinate: [index+CPTDecimalFloatValue(plot.barOffset), y_pos], plotSpace: @delegated_to.graph.defaultPlotSpace))
38
+ end
39
+
40
+ protected
41
+ def bar_base_value(plot_index, recordIndex:index)
42
+ return 0 if(plot_index == 0)
43
+
44
+ (0..plot_index-1).inject(0) {|base, i| base + (@delegated_to.data_hash[i][index] / total_sum_at_index(index))*100 }
45
+ end
46
+
47
+ def bar_tip_value(plot_index, recordIndex:index, startValue:value)
48
+ return (value / total_sum_at_index(index))*100 if(plot_index == 0)
49
+
50
+ (0..plot_index).inject(0) {|base, i| base + (@delegated_to.data_hash[i][index] / total_sum_at_index(index))*100 }
51
+ end
52
+
53
+ def total_sum_at_index(index)
54
+ total ||= (0..@number_of_plots-1).inject(0) {|total, i| total + @delegated_to.data_hash[i][index]}
55
+
56
+ total
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,55 @@
1
+ module MotionPlot
2
+ class StackBarDelegate
3
+
4
+ # consign :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
+ case field_enum
16
+ when CPTBarPlotFieldBarLocation
17
+ index
18
+ when CPTBarPlotFieldBarTip
19
+ plot_index = @delegated_to.series[plot.identifier].index
20
+ record_data = @delegated_to.series[plot.identifier].data[index]
21
+ bar_tip_value(plot_index, recordIndex:index, startValue:record_data)
22
+ when CPTBarPlotFieldBarBase
23
+ plot_index = @delegated_to.series[plot.identifier].index
24
+ bar_base_value(plot_index, recordIndex:index)
25
+ end
26
+ end
27
+
28
+ def barPlot(plot, barWasSelectedAtRecordIndex:index)
29
+ if(@delegated_to.data_label and @delegated_to.data_label.annotation)
30
+ @delegated_to.graph.plotAreaFrame.plotArea.removeAnnotation(@delegated_to.data_label.annotation)
31
+ @delegated_to.data_label.annotation = nil
32
+ end
33
+
34
+ y_value = @delegated_to.series[plot.identifier].data[index].round(2)
35
+ plot_index = @delegated_to.series[plot.identifier].index
36
+ y_pos = (0..plot_index).inject(0) {|base, i| base + @delegated_to.data_hash[i][index]}
37
+
38
+ @delegated_to.graph.plotAreaFrame.plotArea.addAnnotation(@delegated_to.data_label.annotation_for(y_value, atCoordinate: [index+CPTDecimalFloatValue(plot.barOffset), y_pos], plotSpace: @delegated_to.graph.defaultPlotSpace))
39
+ end
40
+
41
+ protected
42
+ def bar_base_value(plot_index, recordIndex:index)
43
+ return 0 if(plot_index == 0)
44
+
45
+ (0..plot_index-1).inject(0) {|base, i| base + @delegated_to.data_hash[i][index] }
46
+ end
47
+
48
+ def bar_tip_value(plot_index, recordIndex:index, startValue:value)
49
+ return value if(plot_index == 0)
50
+
51
+ (0..plot_index).inject(0) {|base, i| base + @delegated_to.data_hash[i][index] }
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,65 @@
1
+ module MotionPlot
2
+ class Line < Base
3
+
4
+ attr_accessor :curve_inerpolation
5
+
6
+ def add_series
7
+ @series.keys.each_with_index do |name, index|
8
+ line = CPTScatterPlot.alloc.initWithFrame(CGRectNull)
9
+ line.identifier = name
10
+
11
+ line_style = line.dataLineStyle.mutableCopy
12
+ line_style.lineWidth = @series[name].width
13
+
14
+ line_style.lineColor = @series[name].color
15
+
16
+ line.dataLineStyle = line_style
17
+ line.dataSource = self
18
+ line.delegate = self
19
+ line.interpolation = CPTScatterPlotInterpolationCurved if(@curve_inerpolation)
20
+
21
+ add_plot_symbol(line, index) if(@plot_symbol)
22
+
23
+ @graph.addPlot(line)
24
+ @plots << line
25
+ end
26
+ end
27
+
28
+ # This implementation of this method will put the line graph in a fix position so it won't be scrollable.
29
+ def plotSpace(space, willChangePlotRangeTo:new_range, forCoordinate:coordinate)
30
+ (coordinate == CPTCoordinateY) ? space.yRange : space.xRange
31
+ end
32
+
33
+ def scatterPlot(plot, plotSymbolWasSelectedAtRecordIndex:index)
34
+ if(@data_label and @data_label.annotation)
35
+ @graph.plotAreaFrame.plotArea.removeAnnotation(@data_label.annotation)
36
+ @data_label.annotation = nil
37
+ end
38
+
39
+ y_value = @series[plot.identifier].data[index].round(2)
40
+ @graph.plotAreaFrame.plotArea.addAnnotation(@data_label.annotation_for(y_value, atCoordinate: [index, y_value], plotSpace: @graph.defaultPlotSpace))
41
+ end
42
+
43
+ def numberOfRecordsForPlot(plot)
44
+ @series[plot.identifier].data.size
45
+ end
46
+
47
+ def numberForPlot(plot, field:field_enum, recordIndex:index)
48
+ data = @series[plot.identifier].data
49
+
50
+ (field_enum == CPTScatterPlotFieldY) ? data[index] : index
51
+ end
52
+
53
+ protected
54
+ def default_style
55
+ {
56
+ width: 2.0
57
+ }
58
+ end
59
+
60
+ def plot_type
61
+ "line"
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,128 @@
1
+ module MotionPlot
2
+ class Pie < Base
3
+
4
+ attr_accessor :selected_slice
5
+
6
+ def add_series
7
+ pie = CPTPieChart.alloc.init
8
+ pie.dataSource = self
9
+ pie.delegate = self
10
+ pie.pieRadius = pie_radius
11
+ pie.startAngle = Math::PI/4
12
+ pie.sliceDirection = CPTPieDirectionClockwise #CPTPieDirectionCounterClockwise
13
+ pie.identifier = plot_identifier
14
+
15
+ series_data.each_with_index {|obj, i| @selected_slice = i if(obj[:selected]) }
16
+
17
+ add_gradient(pie)
18
+
19
+ animate(pie)
20
+ @graph.addPlot(pie)
21
+ end
22
+
23
+ def default_padding
24
+ pie_series.style.paddings_for(@graph)
25
+ pie_series.style.plot_area.add_style(@graph.plotAreaFrame)
26
+ end
27
+
28
+ def numberOfRecordsForPlot(plot)
29
+ series_data.size
30
+ end
31
+
32
+ def numberForPlot(plot, field: fieldEnum, recordIndex: index)
33
+ fieldEnum == CPTPieChartFieldSliceWidth ? series_data[index][:y] : index
34
+ end
35
+
36
+ def legendTitleForPieChart(pie, recordIndex: index)
37
+ series_data[index][:name]
38
+ end
39
+
40
+ def sliceFillForPieChart(plot, recordIndex: index)
41
+ CPTFill.alloc.initWithColor Series::COLORS[index].to_color.to_cpt_color
42
+ end
43
+
44
+ def radialOffsetForPieChart(plot, recordIndex: index)
45
+ offset = 0.0
46
+
47
+ if(@selected_slice == index)
48
+ offset = pie_radius / 25.0
49
+ end
50
+
51
+ offset
52
+ end
53
+
54
+ def pieChart(plot, sliceWasSelectedAtRecordIndex: index)
55
+ @selected_slice = index
56
+ plot.reloadData
57
+ end
58
+
59
+ def dataLabelForPlot(plot, recordIndex: index)
60
+ @data_label.annotation_text_style(series_data[index][:y].round(2))
61
+ end
62
+
63
+ protected
64
+ def plot_type
65
+ "pie"
66
+ end
67
+
68
+ def add_gradient(pie)
69
+ if(pie_series.style.gradient)
70
+ overlay_gradient = CPTGradient.alloc.init
71
+ overlay_gradient.gradientType = CPTGradientTypeRadial
72
+
73
+ overlay_gradient = overlay_gradient.addColorStop(CPTColor.blackColor.colorWithAlphaComponent(0.0), atPosition:0.0)
74
+ overlay_gradient = overlay_gradient.addColorStop(CPTColor.blackColor.colorWithAlphaComponent(0.3), atPosition:0.9)
75
+ overlay_gradient = overlay_gradient.addColorStop(CPTColor.blackColor.colorWithAlphaComponent(0.7), atPosition:1.0)
76
+ pie.overlayFill = overlay_gradient
77
+ end
78
+ end
79
+
80
+ def pie_radius
81
+ [
82
+ 0.8 * (@layer_hosting_view.frame.size.height - 2 * @graph.paddingLeft) / 2.0,
83
+ 0.8 * (@layer_hosting_view.frame.size.width - 2 * @graph.paddingTop) / 2.0
84
+ ].min
85
+ end
86
+
87
+ def plot_identifier
88
+ @series.keys.select{|k| @series[k].type == plot_type}.first
89
+ end
90
+
91
+ def series_data
92
+ pie_series.data
93
+ end
94
+
95
+ def pie_series
96
+ @series[plot_identifier]
97
+ end
98
+
99
+ def animate(plot)
100
+ CATransaction.begin
101
+ CATransaction.setAnimationDuration 2.0
102
+ CATransaction.setAnimationTimingFunction CAMediaTimingFunction.functionWithName(KCAMediaTimingFunctionEaseIn)
103
+
104
+ radial_animation = CABasicAnimation.animationWithKeyPath("pieRadius")
105
+
106
+ radial_animation.fromValue = 0.0
107
+ radial_animation.toValue = pie_radius
108
+ radial_animation.duration = 1.0
109
+ radial_animation.removedOnCompletion = false
110
+ radial_animation.fillMode = KCAFillModeForwards
111
+
112
+ plot.addAnimation(radial_animation, forKey:"pieRadius")
113
+
114
+
115
+ angle_animation = CABasicAnimation.animationWithKeyPath 'angle'
116
+ angle_animation.fromValue = 0.0
117
+ angle_animation.toValue = Math::PI/4
118
+ angle_animation.duration = 1.0
119
+ angle_animation.removedOnCompletion = false
120
+ angle_animation.fillMode = KCAFillModeForwards
121
+
122
+ plot.addAnimation(angle_animation, forKey:"angle")
123
+
124
+ CATransaction.commit
125
+ end
126
+
127
+ end
128
+ end
@@ -0,0 +1,5 @@
1
+ class UIColor
2
+ def to_cpt_color
3
+ CPTColor.alloc.initWithCGColor(self.CGColor)
4
+ end
5
+ end
@@ -0,0 +1,44 @@
1
+ module MotionPlot
2
+ class Series
3
+
4
+ COLORS = ['4572A7', 'AA4643', '89A54E', '80699B', '3D96AE', 'DB843D', '92A8CD', 'A47D7C', 'B5CA92']
5
+
6
+ attr_accessor :name, :data, :index, :type, :style
7
+
8
+ def initialize(args={})
9
+ args.each_pair {|key, value|
10
+ send("#{key}=", value) if(respond_to?("#{key}="))
11
+ }
12
+
13
+ style_attr = args[:defaults].merge!(color: COLORS[args[:index]])
14
+ merge_plot_options(style_attr, args[:plot_options])
15
+ merge_style(style_attr, args[:style])
16
+
17
+ @style = Style.new(style_attr)
18
+ end
19
+
20
+ def color
21
+ @style.color
22
+ end
23
+
24
+ def width
25
+ @style.width
26
+ end
27
+
28
+ private
29
+ def merge_plot_options(style, plot_options)
30
+ return if(plot_options.nil?)
31
+ return if(plot_options.send(type).nil?)
32
+ return if(plot_options.send(type)[:style].nil?)
33
+
34
+ merge_style(style, plot_options.send(type)[:style])
35
+ end
36
+
37
+ def merge_style(old_style, new_style)
38
+ old_style.merge!(new_style) {|key, old_val, new_val|
39
+ new_val.nil? ? old_val : new_val
40
+ } if(new_style)
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,22 @@
1
+ module MotionPlot
2
+ class Theme
3
+ DEFAULTS = {
4
+ :dark_gradient => KCPTDarkGradientTheme,
5
+ :plain_black => KCPTPlainBlackTheme,
6
+ :plain_white => KCPTPlainWhiteTheme,
7
+ :slate => KCPTSlateTheme,
8
+ :stocks => KCPTStocksTheme
9
+ }
10
+
11
+ class << self
12
+ def method_missing(m, *args, &block)
13
+ method_name = m == :default ? :plain_white : m
14
+
15
+ raise unless(DEFAULTS.keys.include?(method_name))
16
+
17
+ CPTTheme.themeNamed(DEFAULTS[method_name])
18
+ end
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ module MotionPlot
2
+ class AnchorPosition
3
+ DEFAULTS = {
4
+ :top_right => CPTRectAnchorTopRight,
5
+ :bottom_left => CPTRectAnchorBottomLeft,
6
+ :bottom => CPTRectAnchorBottom,
7
+ :bottom_right => CPTRectAnchorBottomRight,
8
+ :left => CPTRectAnchorLeft,
9
+ :right => CPTRectAnchorRight,
10
+ :top_left => CPTRectAnchorTopLeft,
11
+ :top => CPTRectAnchorTop,
12
+ :center => CPTRectAnchorCenter
13
+ }
14
+
15
+ class << self
16
+
17
+ def method_missing(m, *args, &block)
18
+ method_name = m == :default ? :top : m
19
+
20
+ raise unless(DEFAULTS.keys.include?(method_name))
21
+
22
+ DEFAULTS[method_name]
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ module MotionPlot
2
+ class AreaGradient
3
+
4
+ attr_accessor :angle
5
+
6
+ def initialize(orientation)
7
+ @angle = (orientation == "vertical") ? 0.0 : -90.0
8
+ end
9
+
10
+ def fill_with(color)
11
+ gradient = CPTGradient.gradientWithBeginningColor(color, endingColor:CPTColor.clearColor)
12
+ gradient.angle = @angle
13
+
14
+ CPTFill.fillWithGradient(gradient)
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,37 @@
1
+ module MotionPlot
2
+ class Axis
3
+ attr_accessor :title, :enabled, :type, :labels, :style
4
+
5
+ def initialize(args)
6
+ args.each_pair {|key, value|
7
+ send("#{key}=", value) if(respond_to?("#{key}="))
8
+ }
9
+
10
+ if(args[:title])
11
+ @title = Title.new(args[:title])
12
+ end
13
+
14
+ if(args[:style])
15
+ @style = Style.new(args[:style])
16
+ else
17
+ @style = Style.new
18
+ end
19
+ end
20
+
21
+ def text_style
22
+ TextStyle.cpt_text_style(@style)
23
+ end
24
+
25
+ def is_x?
26
+ type == "xaxis"
27
+ end
28
+
29
+ def is_y?
30
+ type == "yaxis"
31
+ end
32
+
33
+ def enabled?
34
+ enabled
35
+ end
36
+ end
37
+ end