ProMotion-map 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 730e656d5fad2888c9705a25a3344e086c3db6ff
4
+ data.tar.gz: d6d4d53d49f436970603a88d2c78110699900119
5
+ SHA512:
6
+ metadata.gz: 6fed3989bcade0436a2ee3d5f72f695de72ba733bf846917ab9c4a76cab8b12805eab9c8754cacd353e4b2596f6f86f988b4446f0a0ec1221b72c3399be820a3
7
+ data.tar.gz: e583ef3a2a88df469cbc54c8df5a507508698fd6c15151f9023590120c0b890a6d8e29755eda88a57ce8fb2cd4932ca0d82a527af728f7615ad5a6453797b8a5
data/README.md ADDED
@@ -0,0 +1,224 @@
1
+ # ProMotion-map
2
+
3
+ ProMotion-map is push notification support, extracted from the
4
+ popular RubyMotion gem [ProMotion](https://github.com/clearsightstudio/ProMotion).
5
+
6
+ ## Installation
7
+
8
+ ```ruby
9
+ gem 'ProMotion-map'
10
+ ```
11
+
12
+ ## Usage
13
+
14
+ Easily create a map screen, complete with annotations.
15
+
16
+ *Has all the methods of PM::Screen*
17
+
18
+ ```ruby
19
+ class MyMapScreen < PM::MapScreen
20
+ title "My Map"
21
+ start_position latitude: 35.090648651123, longitude: -82.965972900391, radius: 4
22
+
23
+ def on_appear
24
+ update_annotation_data
25
+ end
26
+
27
+ def annotation_data
28
+ [{
29
+ longitude: -82.965972900391,
30
+ latitude: 35.090648651123,
31
+ title: "Rainbow Falls",
32
+ subtitle: "Nantahala National Forest"
33
+ },{
34
+ longitude: -82.966093558105,
35
+ latitude: 35.092520895652,
36
+ title: "Turtleback Falls",
37
+ subtitle: "Nantahala National Forest"
38
+ },{
39
+ longitude: -82.95916,
40
+ latitude: 35.07496,
41
+ title: "Windy Falls"
42
+ },{
43
+ longitude: -82.943031505056,
44
+ latitude: 35.102516828489,
45
+ title: "Upper Bearwallow Falls",
46
+ subtitle: "Gorges State Park"
47
+ },{
48
+ longitude: -82.956244328014,
49
+ latitude: 35.085548421623,
50
+ title: "Stairway Falls",
51
+ subtitle: "Gorges State Park",
52
+ your_param: "CustomWhatever"
53
+ }, {
54
+ longitude: -82.965972900391,
55
+ latitude: 35.090648651123,
56
+ title: "Rainbow Falls",
57
+ subtitle: "Nantahala National Forest",
58
+ image: UIImage.imageNamed("custom-pin")
59
+ }]
60
+ end
61
+
62
+
63
+ end
64
+ ```
65
+
66
+ Here's a neat way to zoom into a specific marker in an animated fashion and then select the marker:
67
+
68
+ ```ruby
69
+ def zoom_to_marker(marker)
70
+ set_region region(coordinate: marker.coordinate, span: [0.05, 0.05])
71
+ select_annotation marker
72
+ end
73
+ ```
74
+
75
+ ---
76
+
77
+ ### Methods
78
+
79
+ #### annotation_data
80
+
81
+ Method that is called to get the map's annotation data and build the map. If you do not want any annotations, simply return an empty array.
82
+
83
+ ```ruby
84
+ def annotation_data
85
+ [{
86
+ longitude: -82.965972900391,
87
+ latitude: 35.090648651123,
88
+ title: "Rainbow Falls",
89
+ subtitle: "Nantahala National Forest"
90
+ },{
91
+ longitude: -82.965972900391,
92
+ latitude: 35.090648651123,
93
+ title: "Rainbow Falls",
94
+ subtitle: "Nantahala National Forest",
95
+ image: "custom-pin" # Use your own custom image. It will be converted to a UIImage automatically.
96
+ },{
97
+ longitude: -82.966093558105,
98
+ latitude: 35.092520895652,
99
+ title: "Turtleback Falls",
100
+ subtitle: "Nantahala National Forest"
101
+ },{
102
+ longitude: -82.95916,
103
+ latitude: 35.07496,
104
+ title: "Windy Falls"
105
+ },{
106
+ longitude: -82.943031505056,
107
+ latitude: 35.102516828489,
108
+ title: "Upper Bearwallow Falls",
109
+ subtitle: "Gorges State Park"
110
+ },{
111
+ longitude: -82.956244328014,
112
+ latitude: 35.085548421623,
113
+ title: "Stairway Falls",
114
+ subtitle: "Gorges State Park",
115
+ your_param: "CustomWahtever"
116
+ }]
117
+ end
118
+ ```
119
+
120
+ You may pass whatever properties you want in the annotation hash, but `:longitude`, `:latitude`, and `:title` are required.
121
+
122
+ Use `:image` to specify a custom image. Pass in a string to conserve memory and it will be converted using `UIImage.imageNamed(your_string)`. If you pass in a `UIImage`, we'll use that, but keep in mind that there will be another unnecessary copy of the UIImage in memory.
123
+
124
+ You can access annotation data you've arbitrarily stored in the hash by calling `annotation_instance.annotation_params[:your_param]`.
125
+
126
+ #### update_annotation_data
127
+
128
+ Forces a reload of all the annotations
129
+
130
+ #### center
131
+
132
+ Returns a `CLLocation2D` instance with the center coordinates of the map.
133
+
134
+ #### center=({latitude: Float, longitude: Float, animated: Boolean})
135
+
136
+ Sets the center of the map. `animated` property defaults to `true`.
137
+
138
+ #### annotations
139
+
140
+ Returns an array of all the annotations.
141
+
142
+ #### select_annotation(annotation, animated=true)
143
+
144
+ Selects a single annotation.
145
+
146
+ #### select_annotation_at(annotation_index, animated=true)
147
+
148
+ Selects a single annotation using the annotation at the index of your `annotation_data` array.
149
+
150
+ #### selected_annotations
151
+
152
+ Returns an array of annotations that are selected. If no annotations are selected, returns `nil`.
153
+
154
+ #### deselect_annotations(animated=false)
155
+
156
+ Deselects all selected annotations.
157
+
158
+ #### add_annotation(annotation)
159
+
160
+ Adds a new annotation to the map. Refer to `annotation_data` (above) for hash properties.
161
+
162
+ #### add_annotations(annotations)
163
+
164
+ Adds more than one annotation at a time to the map.
165
+
166
+ #### clear_annotations
167
+
168
+ Removes all annotations from the `MapScreen`.
169
+
170
+ #### zoom_to_fit_annotations(animated=true)
171
+
172
+ Changes the zoom and center point of the `MapScreen` to fit all the annotations.
173
+
174
+ #### set_region(region, animated=true)
175
+
176
+ Sets the region of the `MapScreen`. `region` should be an instance of `MKCoordinateRegion`.
177
+
178
+ #### region(params)
179
+
180
+ Helper method to create an `MKCoordinateRegion`. Expects a hash in the form of:
181
+
182
+ ```ruby
183
+ my_region = region({
184
+ coordinate:{
185
+ latitude: 35.0906,
186
+ longitude: -82.965
187
+ },
188
+ # span is the latitude and longitude delta
189
+ span: [0.5, 0.5]
190
+ })
191
+ ```
192
+
193
+ ---
194
+
195
+ ### Class Methods
196
+
197
+ #### start_position(latitude: Float, longitude: Float, radius: Float)
198
+
199
+ Class method to set the initial starting position of the `MapScreen`.
200
+
201
+ ```ruby
202
+ class MyMapScreen < PM::MapScreen
203
+ start_position latitude: 36.10, longitude: -80.26, radius: 4
204
+ end
205
+ ```
206
+
207
+ `radius` is the zoom level of the map in miles (default: 10).
208
+
209
+ ---
210
+
211
+ ### Accessors
212
+
213
+ #### mapview
214
+
215
+ Reference to the created UIMapView.
216
+
217
+ ## Contributing
218
+
219
+ 1. Fork it
220
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
221
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
222
+ 4. Make some specs pass
223
+ 5. Push to the branch (`git push origin my-new-feature`)
224
+ 6. Create new Pull Request
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ unless defined?(Motion::Project::Config)
4
+ raise "ProMotion-map must be required within a RubyMotion project."
5
+ end
6
+
7
+ Motion::Project::App.setup do |app|
8
+ lib_dir_path = File.dirname(File.expand_path(__FILE__))
9
+ app.files << File.join(lib_dir_path, "ProMotion/map/map_screen_annotation.rb")
10
+ app.files << File.join(lib_dir_path, "ProMotion/map/map_screen_module.rb")
11
+ app.files << File.join(lib_dir_path, "ProMotion/map/map_screen.rb")
12
+
13
+ app.frameworks += %w(CoreLocation MapKit)
14
+ end
@@ -0,0 +1,6 @@
1
+ module ProMotion
2
+ class MapScreen < ViewController
3
+ include ProMotion::ScreenModule
4
+ include ProMotion::MapScreenModule
5
+ end
6
+ end
@@ -0,0 +1,65 @@
1
+ module ProMotion
2
+ class MapScreenAnnotation
3
+
4
+ # Creates the new annotation object
5
+ def initialize(params = {})
6
+ @params = params
7
+ set_defaults
8
+
9
+ unless @params[:latitude] && @params[:longitude]
10
+ PM.logger.error("You are required to specify :latitude and :longitude for annotations.")
11
+ return nil
12
+ end
13
+ @coordinate = CLLocationCoordinate2D.new(@params[:latitude], @params[:longitude])
14
+ end
15
+
16
+ def set_defaults
17
+ @params = {
18
+ title: "Title",
19
+ pin_color: MKPinAnnotationColorRed,
20
+ identifier: "Annotation-#{@params[:pin_color] || @params[:image]}",
21
+ show_callout: true,
22
+ animates_drop: false
23
+ }.merge(@params)
24
+ end
25
+
26
+ def title
27
+ @params[:title]
28
+ end
29
+
30
+ def subtitle
31
+ @params[:subtitle] ||= nil
32
+ end
33
+
34
+ def coordinate
35
+ @coordinate
36
+ end
37
+
38
+ def cllocation
39
+ CLLocation.alloc.initWithLatitude(@params[:latitude], longitude:@params[:longitude])
40
+ end
41
+
42
+ def setCoordinate(new_coordinate);
43
+ if new_coordinate.is_a? Hash
44
+ @coordinate = CLLocationCoordinate2D.new(new_coordinate[:latitude], new_coordinate[:longitude])
45
+ else
46
+ @coordinate = new_coordinate
47
+ end
48
+ end
49
+
50
+ # Allows for retrieving your own custom values on the annotation
51
+ def annotation_params
52
+ @params
53
+ end
54
+
55
+ def method_missing(meth, *args)
56
+ if @params[meth.to_sym]
57
+ @params[meth.to_sym]
58
+ else
59
+ PM.logger.warn "The annotation parameter \"#{meth}\" does not exist on this pin."
60
+ nil
61
+ end
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,248 @@
1
+ module ProMotion
2
+ module MapScreenModule
3
+ attr_accessor :mapview
4
+
5
+ def screen_setup
6
+ check_mapkit_included
7
+ self.mapview ||= add MKMapView.new, {
8
+ frame: CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height),
9
+ resize: [ :width, :height ],
10
+ delegate: self
11
+ }
12
+
13
+ check_annotation_data
14
+ @promotion_annotation_data = []
15
+ set_up_start_position
16
+ end
17
+
18
+ def view_will_appear(animated)
19
+ super
20
+ update_annotation_data
21
+ end
22
+
23
+ def check_mapkit_included
24
+ PM.logger.error "You must add MapKit and CoreLocation to your project's frameworks in the Rakefile." unless defined?(CLLocationCoordinate2D)
25
+ end
26
+
27
+ def check_annotation_data
28
+ PM.logger.error "Missing #annotation_data method in MapScreen #{self.class.to_s}." unless self.respond_to?(:annotation_data)
29
+ end
30
+
31
+ def update_annotation_data
32
+ clear_annotations
33
+ add_annotations annotation_data
34
+ end
35
+
36
+ def map
37
+ self.mapview
38
+ end
39
+
40
+ def center
41
+ self.mapview.centerCoordinate
42
+ end
43
+
44
+ def center=(params={})
45
+ PM.logger.error "Missing #:latitude property in call to #center=." unless params[:latitude]
46
+ PM.logger.error "Missing #:longitude property in call to #center=." unless params[:longitude]
47
+ params[:animated] = true
48
+
49
+ # Set the new region
50
+ self.mapview.setCenterCoordinate(
51
+ CLLocationCoordinate2D.new(params[:latitude], params[:longitude]),
52
+ animated:params[:animated]
53
+ )
54
+ end
55
+
56
+ def show_user_location
57
+ set_show_user_location true
58
+ end
59
+
60
+ def hide_user_location
61
+ set_show_user_location false
62
+ end
63
+
64
+ def set_show_user_location(show)
65
+ self.mapview.showsUserLocation = show
66
+ end
67
+
68
+ def showing_user_location?
69
+ self.mapview.showsUserLocation
70
+ end
71
+
72
+ def user_location
73
+ self.mapview.userLocation.location.nil? ? nil : self.mapview.userLocation.location.coordinate
74
+ end
75
+
76
+ def zoom_to_user(radius = 0.05, animated=true)
77
+ show_user_location unless showing_user_location?
78
+ set_region(MKCoordinateRegionMake(user_location, [radius, radius]), animated)
79
+ end
80
+
81
+ def annotations
82
+ @promotion_annotation_data
83
+ end
84
+
85
+ def select_annotation(annotation, animated=true)
86
+ self.mapview.selectAnnotation(annotation, animated:animated)
87
+ end
88
+
89
+ def select_annotation_at(annotation_index, animated=true)
90
+ select_annotation(annotations[annotation_index], animated:animated)
91
+ end
92
+
93
+ def selected_annotations
94
+ self.mapview.selectedAnnotations
95
+ end
96
+
97
+ def deselect_annotations(animated=false)
98
+ unless selected_annotations.nil?
99
+ selected_annotations.each do |annotation|
100
+ self.mapview.deselectAnnotation(annotation, animated:animated)
101
+ end
102
+ end
103
+ end
104
+
105
+ def add_annotation(annotation)
106
+ @promotion_annotation_data << MapScreenAnnotation.new(annotation)
107
+ self.mapview.addAnnotation @promotion_annotation_data.last
108
+ end
109
+
110
+ def add_annotations(annotations)
111
+ @promotion_annotation_data = Array(annotations).map{|a| MapScreenAnnotation.new(a)}
112
+ self.mapview.addAnnotations @promotion_annotation_data
113
+ end
114
+
115
+ def clear_annotations
116
+ @promotion_annotation_data.each do |a|
117
+ self.mapview.removeAnnotation(a)
118
+ end
119
+ @promotion_annotation_data = []
120
+ end
121
+
122
+ def mapView(mapView, viewForAnnotation:annotation)
123
+ return if annotation.is_a? MKUserLocation
124
+
125
+ identifier = annotation.annotation_params[:identifier]
126
+ if view = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
127
+ view.annotation = annotation
128
+ else
129
+ #Set the pin properties
130
+ if annotation.annotation_params[:image]
131
+ view = MKAnnotationView.alloc.initWithAnnotation(annotation, reuseIdentifier:identifier)
132
+ view.image = annotation.annotation_params[:image]
133
+ else
134
+ view = MKPinAnnotationView.alloc.initWithAnnotation(annotation, reuseIdentifier:identifier)
135
+ view.animatesDrop = annotation.annotation_params[:animates_drop]
136
+ view.pinColor = annotation.annotation_params[:pin_color]
137
+ end
138
+ view.canShowCallout = annotation.annotation_params[:show_callout]
139
+ end
140
+ view
141
+ end
142
+
143
+ def set_start_position(params={})
144
+ params[:latitude] ||= 37.331789
145
+ params[:longitude] ||= -122.029620
146
+ params[:radius] ||= 10
147
+
148
+ meters_per_mile = 1609.344
149
+
150
+ initialLocation = CLLocationCoordinate2D.new(params[:latitude], params[:longitude])
151
+ region = MKCoordinateRegionMakeWithDistance(initialLocation, params[:radius] * meters_per_mile, params[:radius] * meters_per_mile)
152
+ set_region(region, animated:false)
153
+ end
154
+
155
+ def set_up_start_position
156
+ if self.class.respond_to?(:get_start_position) && self.class.get_start_position
157
+ self.set_start_position self.class.get_start_position_params
158
+ end
159
+ end
160
+
161
+ # TODO: Why is this so complex?
162
+ def zoom_to_fit_annotations(animated=true)
163
+ #Don't attempt the rezoom of there are no pins
164
+ return if annotations.count == 0
165
+
166
+ #Set some crazy boundaries
167
+ topLeft = CLLocationCoordinate2D.new(-90, 180)
168
+ bottomRight = CLLocationCoordinate2D.new(90, -180)
169
+
170
+ #Find the bounds of the pins
171
+ annotations.each do |a|
172
+ topLeft.longitude = [topLeft.longitude, a.coordinate.longitude].min
173
+ topLeft.latitude = [topLeft.latitude, a.coordinate.latitude].max
174
+ bottomRight.longitude = [bottomRight.longitude, a.coordinate.longitude].max
175
+ bottomRight.latitude = [bottomRight.latitude, a.coordinate.latitude].min
176
+ end
177
+
178
+ #Find the bounds of all the pins and set the mapView
179
+ coord = CLLocationCoordinate2D.new(
180
+ topLeft.latitude - (topLeft.latitude - bottomRight.latitude) * 0.5,
181
+ topLeft.longitude + (bottomRight.longitude - topLeft.longitude) * 0.5
182
+ )
183
+
184
+ # Add some padding to the edges
185
+ span = MKCoordinateSpanMake(
186
+ ((topLeft.latitude - bottomRight.latitude) * 1.075).abs,
187
+ ((bottomRight.longitude - topLeft.longitude) * 1.075).abs
188
+ )
189
+
190
+ region = MKCoordinateRegionMake(coord, span)
191
+ fits = self.mapview.regionThatFits(region);
192
+
193
+ set_region(fits, animated:animated)
194
+ end
195
+
196
+ def set_region(region, animated=true)
197
+ self.mapview.setRegion(region, animated:animated)
198
+ end
199
+
200
+ def region(params)
201
+ return nil unless params.is_a? Hash
202
+
203
+ params[:coordinate] = CLLocationCoordinate2D.new(params[:coordinate][:latitude], params[:coordinate][:longitude]) if params[:coordinate].is_a? Hash
204
+ params[:span] = MKCoordinateSpanMake(params[:span][0], params[:span][1]) if params[:span].is_a? Array
205
+
206
+ if params[:coordinate] && params[:span]
207
+ MKCoordinateRegionMake( params[:coordinate], params[:span] )
208
+ end
209
+ end
210
+
211
+ def look_up_address(args={}, &callback)
212
+ args[:address] = args if args.is_a? String # Assume if a string is passed that they want an address
213
+
214
+ geocoder = CLGeocoder.new
215
+ return geocoder.geocodeAddressDictionary(args[:address], completionHandler: callback) if args[:address].is_a?(Hash)
216
+ return geocoder.geocodeAddressString(args[:address].to_s, completionHandler: callback) unless args[:region]
217
+ return geocoder.geocodeAddressString(args[:address].to_s, inRegion:args[:region].to_s, completionHandler: callback) if args[:region]
218
+ end
219
+
220
+ ########## Cocoa touch methods #################
221
+ def mapView(mapView, didUpdateUserLocation:userLocation)
222
+ if self.respond_to?(:on_user_location)
223
+ on_user_location(userLocation)
224
+ else
225
+ PM.logger.info "You're tracking the user's location but have not implemented the #on_user_location(location) method in MapScreen #{self.class.to_s}."
226
+ end
227
+ end
228
+
229
+ module MapClassMethods
230
+ def start_position(params={})
231
+ @start_position_params = params
232
+ @start_position = true
233
+ end
234
+
235
+ def get_start_position_params
236
+ @start_position_params ||= nil
237
+ end
238
+
239
+ def get_start_position
240
+ @start_position ||= false
241
+ end
242
+ end
243
+ def self.included(base)
244
+ base.extend(MapClassMethods)
245
+ end
246
+
247
+ end
248
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ProMotion-map
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mark Rickert
8
+ - Jamon Holmgren
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-05-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ProMotion
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 2.0.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 2.0.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: motion-stump
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '0.3'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '0.3'
42
+ - !ruby/object:Gem::Dependency
43
+ name: motion-redgreen
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '0.1'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '0.1'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ description: Adds PM::MapScreen support to ProMotion.
71
+ email:
72
+ - mark@mohawkapps.com
73
+ - jamon@clearsightstudio.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - README.md
79
+ - lib/ProMotion-map.rb
80
+ - lib/ProMotion/map/map_screen.rb
81
+ - lib/ProMotion/map/map_screen_annotation.rb
82
+ - lib/ProMotion/map/map_screen_module.rb
83
+ homepage: https://github.com/clearsightstudio/ProMotion-map
84
+ licenses:
85
+ - MIT
86
+ metadata: {}
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 2.2.2
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: Adds PM::MapScreen support to ProMotion. Extracted from ProMotion.
107
+ test_files: []