├── .gitignore
├── .npmignore
├── README.md
├── demo
└── index.html
├── package.json
├── plugin.xml
├── screenshots
├── android
│ └── android-marker-amsterdam.png
└── ios
│ ├── ios-location-benelux.png
│ ├── ios-location-europe-dark-boxed.png
│ └── ios-marker-amsterdam.png
├── src
├── android
│ ├── Mapbox.java
│ ├── mapbox.gradle
│ └── res
│ │ └── values
│ │ └── mapboxstrings.xml
└── ios
│ ├── CDVMapbox.h
│ ├── CDVMapbox.m
│ ├── Headers
│ ├── MGLAccountManager.h
│ ├── MGLAnnotation.h
│ ├── MGLAnnotationImage.h
│ ├── MGLGeometry.h
│ ├── MGLMapCamera.h
│ ├── MGLMapView+IBAdditions.h
│ ├── MGLMapView.h
│ ├── MGLMultiPoint.h
│ ├── MGLOverlay.h
│ ├── MGLPointAnnotation.h
│ ├── MGLPolygon.h
│ ├── MGLPolyline.h
│ ├── MGLShape.h
│ ├── MGLStyle.h
│ ├── MGLTypes.h
│ ├── MGLUserLocation.h
│ └── Mapbox.h
│ └── libs
│ ├── Mapbox.bundle
│ ├── Compass.png
│ ├── Compass@2x.png
│ ├── Compass@3x.png
│ ├── README
│ ├── api_mapbox_com-digicert.der
│ ├── api_mapbox_com-geotrust.der
│ ├── default_marker.png
│ ├── default_marker@2x.png
│ ├── default_marker@3x.png
│ ├── mapbox.png
│ ├── mapbox@2x.png
│ ├── mapbox@3x.png
│ └── star_tilestream_net.der
│ ├── Settings.bundle
│ ├── Root.plist
│ └── en.lproj
│ │ └── Root.strings
│ ├── libMapbox.a
│ └── version.txt
├── typescript
└── mapbox.d.ts
└── www
└── Mapbox.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | demo/
2 | screenshots/
3 | .*
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Mapbox Cordova Plugin
2 | by [Telerik](https://www.telerik.com) / [Eddy Verbruggen](http://twitter.com/eddyverbruggen)
3 |
4 | ## 0. Index
5 |
6 | 1. [Description](#1-description)
7 | 2. [Screenshots](#2-screenshots)
8 | 3. [Installation](#3-installation)
9 | 4. [Usage](#4-usage)
10 | 5. [License](#5-license)
11 |
12 | ## 1. Description
13 |
14 | Use Mapbox - an OpenGL powered vector-based native mapping solution - in your Cordova / PhoneGap app.
15 |
16 | iOS and Android are fully supported.
17 |
18 | ## 2. Screenshots
19 |
20 | ### iOS
21 |
22 |
23 |
24 |
25 |
26 | ### Android
27 |
28 |
29 |
30 |
31 | ## 3. Installation
32 |
33 | npm (latest stable)
34 | ```
35 | $ cordova plugin add cordova-plugin-mapbox --variable ACCESS_TOKEN=your.access.token
36 | ```
37 |
38 | Github master (lastest develop)
39 | ```
40 | $ cordova plugin add https://github.com/Telerik-Verified-Plugins/Mapbox --variable ACCESS_TOKEN=your.access.token
41 | ```
42 |
43 | Mapbox.js is brought in automatically. There is no need to change or add anything in your html.
44 |
45 | ## 4. Usage
46 |
47 | [We've documented the Mapbox plugin API here.](http://plugins.telerik.com/cordova/plugin/mapbox)
48 |
49 | For a quick demo, check the [demo code](demo/index.html) which shows all the tricks in the book.
50 |
51 | ## 5. License
52 |
53 | [The MIT License (MIT)](http://www.opensource.org/licenses/mit-license.html)
54 |
55 | Permission is hereby granted, free of charge, to any person obtaining a copy
56 | of this software and associated documentation files (the "Software"), to deal
57 | in the Software without restriction, including without limitation the rights
58 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
59 | copies of the Software, and to permit persons to whom the Software is
60 | furnished to do so, subject to the following conditions:
61 |
62 | The above copyright notice and this permission notice shall be included in
63 | all copies or substantial portions of the Software.
64 |
65 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
66 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
67 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
68 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
69 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
70 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
71 | THE SOFTWARE.
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Mapbox test
10 |
11 |
12 |
13 |
Mapbox test
14 |
15 |
16 |
Connecting to Device
17 |
Device is Ready
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
282 |
283 |
284 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.2.3",
3 | "name": "cordova-plugin-mapbox",
4 | "cordova_name": "Mapbox",
5 | "description": "Need native maps? Look no further!",
6 | "license": "MIT",
7 | "repo": "https://github.com/Telerik-Verified-Plugins/Mapbox.git",
8 | "issue": "https://github.com/Telerik-Verified-Plugins/Mapbox/issues",
9 | "keywords": [
10 | "Mapbox",
11 | "Maps",
12 | "Mapping",
13 | "Native maps",
14 | "ecosystem:cordova",
15 | "cordova-android",
16 | "cordova-ios"
17 | ],
18 | "platforms": [
19 | "android",
20 | "ios"
21 | ],
22 | "engines": [
23 | {
24 | "name": "cordova",
25 | "version": ">=3.5.0"
26 | }
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | Mapbox
8 |
9 | Need native maps? Look no further!
10 |
11 | Telerik / Eddy Verbruggen
12 |
13 | MIT
14 |
15 | Mapbox, Maps, Mapping, Native maps
16 |
17 | https://github.com/Telerik-Verified-Plugins/Mapbox
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
57 |
58 |
59 | $ACCESS_TOKEN
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | $ACCESS_TOKEN
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/screenshots/android/android-marker-amsterdam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Telerik-Verified-Plugins/Mapbox/717930e83e915bb1cb442beb53b23a66cf7388d6/screenshots/android/android-marker-amsterdam.png
--------------------------------------------------------------------------------
/screenshots/ios/ios-location-benelux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Telerik-Verified-Plugins/Mapbox/717930e83e915bb1cb442beb53b23a66cf7388d6/screenshots/ios/ios-location-benelux.png
--------------------------------------------------------------------------------
/screenshots/ios/ios-location-europe-dark-boxed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Telerik-Verified-Plugins/Mapbox/717930e83e915bb1cb442beb53b23a66cf7388d6/screenshots/ios/ios-location-europe-dark-boxed.png
--------------------------------------------------------------------------------
/screenshots/ios/ios-marker-amsterdam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Telerik-Verified-Plugins/Mapbox/717930e83e915bb1cb442beb53b23a66cf7388d6/screenshots/ios/ios-marker-amsterdam.png
--------------------------------------------------------------------------------
/src/android/Mapbox.java:
--------------------------------------------------------------------------------
1 | package com.telerik.plugins.mapbox;
2 |
3 | import android.Manifest;
4 | import android.content.pm.PackageManager;
5 | import android.content.res.Resources;
6 | import android.os.Build;
7 | import android.support.annotation.NonNull;
8 | import android.support.v4.app.ActivityCompat;
9 | import android.util.DisplayMetrics;
10 | import android.view.ViewGroup;
11 | import android.widget.FrameLayout;
12 | import android.graphics.PointF;
13 |
14 | import com.mapbox.mapboxsdk.camera.CameraPosition;
15 | import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
16 | import com.mapbox.mapboxsdk.constants.Style;
17 | import com.mapbox.mapboxsdk.annotations.Marker;
18 | import com.mapbox.mapboxsdk.annotations.MarkerOptions;
19 | import com.mapbox.mapboxsdk.annotations.PolygonOptions;
20 | import com.mapbox.mapboxsdk.geometry.LatLng;
21 | import com.mapbox.mapboxsdk.geometry.LatLngZoom;
22 | import com.mapbox.mapboxsdk.geometry.CoordinateBounds;
23 | import com.mapbox.mapboxsdk.views.MapView;
24 |
25 | import org.apache.cordova.CallbackContext;
26 | import org.apache.cordova.CordovaArgs;
27 | import org.apache.cordova.CordovaInterface;
28 | import org.apache.cordova.CordovaPlugin;
29 | import org.apache.cordova.CordovaWebView;
30 | import org.apache.cordova.PluginResult;
31 | import org.json.JSONArray;
32 | import org.json.JSONException;
33 | import org.json.JSONObject;
34 |
35 | import java.util.HashMap;
36 | import java.util.Map;
37 |
38 |
39 | // TODO for screen rotation, see https://www.mapbox.com/mapbox-android-sdk/#screen-rotation
40 | // TODO fox Xwalk compat, see nativepagetransitions plugin
41 | // TODO look at demo app: https://github.com/mapbox/mapbox-gl-native/blob/master/android/java/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxgl/testapp/MainActivity.java
42 | public class Mapbox extends CordovaPlugin {
43 |
44 | public static final String FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
45 | public static final String COARSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
46 | public static final int LOCATION_REQ_CODE = 0;
47 |
48 | public static final int PERMISSION_DENIED_ERROR = 20;
49 |
50 | private static final String MAPBOX_ACCESSTOKEN_RESOURCE_KEY = "mapbox_accesstoken";
51 |
52 | private static final String ACTION_SHOW = "show";
53 | private static final String ACTION_HIDE = "hide";
54 | private static final String ACTION_ADD_MARKERS = "addMarkers";
55 | private static final String ACTION_REMOVE_ALL_MARKERS = "removeAllMarkers";
56 | private static final String ACTION_ADD_MARKER_CALLBACK = "addMarkerCallback";
57 | // TODO:
58 | // private static final String ACTION_REMOVE_MARKER_CALLBACK = "removeMarkerCallback";
59 | private static final String ACTION_ADD_POLYGON = "addPolygon";
60 | private static final String ACTION_ADD_GEOJSON = "addGeoJSON";
61 | private static final String ACTION_GET_CENTER = "getCenter";
62 | private static final String ACTION_SET_CENTER = "setCenter";
63 | private static final String ACTION_GET_ZOOMLEVEL = "getZoomLevel";
64 | private static final String ACTION_SET_ZOOMLEVEL = "setZoomLevel";
65 | private static final String ACTION_GET_BOUNDS = "getBounds";
66 | private static final String ACTION_SET_BOUNDS = "setBounds";
67 | private static final String ACTION_GET_TILT = "getTilt";
68 | private static final String ACTION_SET_TILT = "setTilt";
69 | private static final String ACTION_ANIMATE_CAMERA = "animateCamera";
70 | private static final String ACTION_ON_REGION_WILL_CHANGE = "onRegionWillChange";
71 | private static final String ACTION_ON_REGION_IS_CHANGING = "onRegionIsChanging";
72 | private static final String ACTION_ON_REGION_DID_CHANGE = "onRegionDidChange";
73 | // TODO:
74 | // private static final String ACTION_OFF_REGION_WILL_CHANGE = "offRegionWillChange";
75 | // private static final String ACTION_OFF_REGION_IS_CHANGING = "offRegionIsChanging";
76 | // private static final String ACTION_OFF_REGION_DID_CHANGE = "offRegionDidChange";
77 |
78 | public static MapView mapView;
79 | private static float retinaFactor;
80 | private String accessToken;
81 | private CallbackContext callback;
82 | private CallbackContext markerCallbackContext;
83 |
84 | private boolean showUserLocation;
85 |
86 | @Override
87 | public void initialize(CordovaInterface cordova, CordovaWebView webView) {
88 | super.initialize(cordova, webView);
89 |
90 | DisplayMetrics metrics = new DisplayMetrics();
91 | cordova.getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
92 | retinaFactor = metrics.density;
93 |
94 | try {
95 | int mapboxAccesstokenResourceId = cordova.getActivity().getResources().getIdentifier(MAPBOX_ACCESSTOKEN_RESOURCE_KEY, "string", cordova.getActivity().getPackageName());
96 | accessToken = cordova.getActivity().getString(mapboxAccesstokenResourceId);
97 | } catch (Resources.NotFoundException e) {
98 | // we'll deal with this when the accessToken property is read, but for now let's dump the error:
99 | e.printStackTrace();
100 | }
101 | }
102 |
103 | @Override
104 | public boolean execute(final String action, final CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
105 |
106 | this.callback = callbackContext;
107 |
108 | try {
109 | if (ACTION_SHOW.equals(action)) {
110 | final JSONObject options = args.getJSONObject(0);
111 | final String style = getStyle(options.optString("style"));
112 |
113 | final JSONObject margins = options.isNull("margins") ? null : options.getJSONObject("margins");
114 | final int left = applyRetinaFactor(margins == null || margins.isNull("left") ? 0 : margins.getInt("left"));
115 | final int right = applyRetinaFactor(margins == null || margins.isNull("right") ? 0 : margins.getInt("right"));
116 | final int top = applyRetinaFactor(margins == null || margins.isNull("top") ? 0 : margins.getInt("top"));
117 | final int bottom = applyRetinaFactor(margins == null || margins.isNull("bottom") ? 0 : margins.getInt("bottom"));
118 |
119 | final JSONObject center = options.isNull("center") ? null : options.getJSONObject("center");
120 |
121 | this.showUserLocation = !options.isNull("showUserLocation") && options.getBoolean("showUserLocation");
122 |
123 | cordova.getActivity().runOnUiThread(new Runnable() {
124 | @Override
125 | public void run() {
126 | if (accessToken == null) {
127 | callbackContext.error(MAPBOX_ACCESSTOKEN_RESOURCE_KEY + " not set in strings.xml");
128 | return;
129 | }
130 | mapView = new MapView(webView.getContext(), accessToken);
131 |
132 | // need to do this to register a receiver which onPause later needs
133 | mapView.onResume();
134 | mapView.onCreate(null);
135 |
136 | try {
137 | mapView.setCompassEnabled(options.isNull("hideCompass") || !options.getBoolean("hideCompass"));
138 | mapView.setRotateEnabled(options.isNull("disableRotation") || !options.getBoolean("disableRotation"));
139 | mapView.setScrollEnabled(options.isNull("disableScroll") || !options.getBoolean("disableScroll"));
140 | mapView.setZoomEnabled(options.isNull("disableZoom") || !options.getBoolean("disableZoom"));
141 | mapView.setTiltEnabled(options.isNull("disableTilt") || !options.getBoolean("disableTilt"));
142 |
143 | // placing these offscreen in case the user wants to hide them
144 | if (!options.isNull("hideAttribution") && options.getBoolean("hideAttribution")) {
145 | mapView.setAttributionMargins(-300, 0, 0, 0);
146 | }
147 | if (!options.isNull("hideLogo") && options.getBoolean("hideLogo")) {
148 | mapView.setLogoMargins(-300, 0, 0, 0);
149 | }
150 |
151 | if (showUserLocation) {
152 | showUserLocation();
153 | }
154 |
155 | Double zoom = options.isNull("zoomLevel") ? 10 : options.getDouble("zoomLevel");
156 | float zoomLevel = zoom.floatValue();
157 | if (center != null) {
158 | final double lat = center.getDouble("lat");
159 | final double lng = center.getDouble("lng");
160 | mapView.setLatLng(new LatLngZoom(lat, lng, zoomLevel));
161 | } else {
162 | if (zoomLevel > 18.0) {
163 | zoomLevel = 18.0f;
164 | }
165 | mapView.setZoom(zoomLevel);
166 | }
167 |
168 | if (options.has("markers")) {
169 | addMarkers(options.getJSONArray("markers"));
170 | }
171 | } catch (JSONException e) {
172 | callbackContext.error(e.getMessage());
173 | return;
174 | }
175 |
176 | mapView.setStyleUrl(style);
177 |
178 | // position the mapView overlay
179 | int webViewWidth = webView.getView().getWidth();
180 | int webViewHeight = webView.getView().getHeight();
181 | final FrameLayout layout = (FrameLayout) webView.getView().getParent();
182 | FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(webViewWidth - left - right, webViewHeight - top - bottom);
183 | params.setMargins(left, top, right, bottom);
184 | mapView.setLayoutParams(params);
185 |
186 | layout.addView(mapView);
187 | callbackContext.success();
188 | }
189 | });
190 |
191 | } else if (ACTION_HIDE.equals(action)) {
192 | if (mapView != null) {
193 |
194 | // Remove marker callback handler
195 | this.markerCallbackContext = null;
196 |
197 | cordova.getActivity().runOnUiThread(new Runnable() {
198 | @Override
199 | public void run() {
200 | ViewGroup vg = (ViewGroup) mapView.getParent();
201 |
202 | if (vg != null) {
203 | vg.removeView(mapView);
204 | }
205 |
206 | callbackContext.success();
207 | }
208 | });
209 | }
210 |
211 | } else if (ACTION_GET_CENTER.equals(action)) {
212 | if (mapView != null) {
213 | cordova.getActivity().runOnUiThread(new Runnable() {
214 | @Override
215 | public void run() {
216 | final LatLng center = mapView.getLatLng();
217 | Map result = new HashMap();
218 | result.put("lat", center.getLatitude());
219 | result.put("lng", center.getLongitude());
220 | callbackContext.success(new JSONObject(result));
221 | }
222 | });
223 | }
224 |
225 | } else if (ACTION_SET_CENTER.equals(action)) {
226 | if (mapView != null) {
227 | cordova.getActivity().runOnUiThread(new Runnable() {
228 | @Override
229 | public void run() {
230 | try {
231 | final JSONObject options = args.getJSONObject(0);
232 | final boolean animated = !options.isNull("animated") && options.getBoolean("animated");
233 | final double lat = options.getDouble("lat");
234 | final double lng = options.getDouble("lng");
235 | mapView.setLatLng(new LatLng(lat, lng), animated);
236 | callbackContext.success();
237 | } catch (JSONException e) {
238 | callbackContext.error(e.getMessage());
239 | }
240 | }
241 | });
242 | }
243 |
244 | } else if (ACTION_GET_ZOOMLEVEL.equals(action)) {
245 | if (mapView != null) {
246 | cordova.getActivity().runOnUiThread(new Runnable() {
247 | @Override
248 | public void run() {
249 | final double zoomLevel = mapView.getZoom();
250 | callbackContext.success("" + zoomLevel);
251 | }
252 | });
253 | }
254 |
255 | } else if (ACTION_SET_ZOOMLEVEL.equals(action)) {
256 | if (mapView != null) {
257 | cordova.getActivity().runOnUiThread(new Runnable() {
258 | @Override
259 | public void run() {
260 | try {
261 | final JSONObject options = args.getJSONObject(0);
262 | final double zoom = options.getDouble("level");
263 | if (zoom >= 0 && zoom <= 20) {
264 | final boolean animated = !options.isNull("animated") && options.getBoolean("animated");
265 | mapView.setZoom(zoom, animated);
266 | callbackContext.success();
267 | } else {
268 | callbackContext.error("invalid zoomlevel, use any double value from 0 to 20 (like 8.3)");
269 | }
270 | } catch (JSONException e) {
271 | callbackContext.error(e.getMessage());
272 | }
273 | }
274 | });
275 | }
276 |
277 |
278 | } else if (ACTION_GET_BOUNDS.equals(action)) {
279 | if (mapView != null) {
280 | cordova.getActivity().runOnUiThread(new Runnable() {
281 | @Override
282 | public void run() {
283 | // NOTE: need to change to this on a future release
284 | // final CoordinateBounds bounds = mapView.getVisibleCoordinateBounds();
285 | // final LatLng sw = bounds.getSouthWest();
286 | // final LatLng ne = bounds.getNorthEast();
287 |
288 | // NOTE: Workaround, see: https://github.com/mapbox/mapbox-gl-native/issues/3863#issuecomment-181825298
289 | int viewportWidth = mapView.getWidth();
290 | int viewportHeight = mapView.getHeight();
291 | LatLng sw = mapView.fromScreenLocation(new PointF(0, viewportHeight)); // bottom left
292 | LatLng ne = mapView.fromScreenLocation(new PointF(viewportWidth, 0)); // top right
293 |
294 | Map result = new HashMap();
295 | result.put("sw_lat", sw.getLatitude());
296 | result.put("sw_lng", sw.getLongitude());
297 | result.put("ne_lat", ne.getLatitude());
298 | result.put("ne_lng", ne.getLongitude());
299 | callbackContext.success(new JSONObject(result));
300 | }
301 | });
302 | }
303 |
304 | } else if (ACTION_SET_BOUNDS.equals(action)) {
305 | if (mapView != null) {
306 | cordova.getActivity().runOnUiThread(new Runnable() {
307 | @Override
308 | public void run() {
309 | try {
310 | final JSONObject options = args.getJSONObject(0);
311 | final boolean animated = !options.isNull("animated") && options.getBoolean("animated");
312 | final double sw_lat = options.getDouble("sw_lat");
313 | final double sw_lng = options.getDouble("sw_lng");
314 | final double ne_lat = options.getDouble("ne_lat");
315 | final double ne_lng = options.getDouble("ne_lng");
316 | final LatLng sw = new LatLng(sw_lat, sw_lng);
317 | final LatLng ne = new LatLng(ne_lat, ne_lng);
318 | final CoordinateBounds bounds = new CoordinateBounds(sw, ne);
319 | mapView.setVisibleCoordinateBounds(bounds, animated);
320 | callbackContext.success();
321 | } catch (JSONException e) {
322 | callbackContext.error(e.getMessage());
323 | }
324 | }
325 | });
326 | }
327 |
328 | } else if (ACTION_GET_TILT.equals(action)) {
329 | if (mapView != null) {
330 | cordova.getActivity().runOnUiThread(new Runnable() {
331 | @Override
332 | public void run() {
333 | final double tilt = mapView.getTilt();
334 | callbackContext.success("" + tilt);
335 | }
336 | });
337 | }
338 |
339 | } else if (ACTION_SET_TILT.equals(action)) {
340 | if (mapView != null) {
341 | cordova.getActivity().runOnUiThread(new Runnable() {
342 | @Override
343 | public void run() {
344 | try {
345 | final JSONObject options = args.getJSONObject(0);
346 | mapView.setTilt(
347 | options.optDouble("pitch", 20), // default 20
348 | options.optLong("duration", 5000)); // default 5s
349 | callbackContext.success();
350 | } catch (JSONException e) {
351 | callbackContext.error(e.getMessage());
352 | }
353 | }
354 | });
355 | }
356 |
357 | } else if (ACTION_ANIMATE_CAMERA.equals(action)) {
358 | if (mapView != null) {
359 | cordova.getActivity().runOnUiThread(new Runnable() {
360 | @Override
361 | public void run() {
362 | try {
363 | // TODO check mandatory elements
364 | final JSONObject options = args.getJSONObject(0);
365 |
366 | final JSONObject target = options.getJSONObject("target");
367 | final double lat = target.getDouble("lat");
368 | final double lng = target.getDouble("lng");
369 |
370 | final CameraPosition.Builder builder =
371 | new CameraPosition.Builder()
372 | .target(new LatLng(lat, lng));
373 |
374 | if (options.has("bearing")) {
375 | builder.bearing(((Double)options.getDouble("bearing")).floatValue());
376 | }
377 | if (options.has("tilt")) {
378 | builder.tilt(((Double)options.getDouble("tilt")).floatValue());
379 | }
380 | if (options.has("zoomLevel")) {
381 | builder.zoom(((Double)options.getDouble("zoomLevel")).floatValue());
382 | }
383 |
384 | mapView.animateCamera(
385 | CameraUpdateFactory.newCameraPosition(builder.build()),
386 | (options.optInt("duration", 15)) * 1000, // default 15 seconds
387 | null);
388 |
389 | callbackContext.success();
390 | } catch (JSONException e) {
391 | callbackContext.error(e.getMessage());
392 | }
393 | }
394 | });
395 | }
396 |
397 | } else if (ACTION_ADD_POLYGON.equals(action)) {
398 | cordova.getActivity().runOnUiThread(new Runnable() {
399 | @Override
400 | public void run() {
401 | try {
402 | final PolygonOptions polygon = new PolygonOptions();
403 | final JSONObject options = args.getJSONObject(0);
404 | final JSONArray points = options.getJSONArray("points");
405 | for (int i = 0; i < points.length(); i++) {
406 | final JSONObject marker = points.getJSONObject(i);
407 | final double lat = marker.getDouble("lat");
408 | final double lng = marker.getDouble("lng");
409 | polygon.add(new LatLng(lat, lng));
410 | }
411 | mapView.addPolygon(polygon);
412 |
413 | callbackContext.success();
414 | } catch (JSONException e) {
415 | callbackContext.error(e.getMessage());
416 | }
417 | }
418 | });
419 |
420 | } else if (ACTION_ADD_GEOJSON.equals(action)) {
421 | cordova.getActivity().runOnUiThread(new Runnable() {
422 | @Override
423 | public void run() {
424 | // TODO implement
425 | callbackContext.success();
426 | }
427 | });
428 |
429 | } else if (ACTION_ADD_MARKERS.equals(action)) {
430 | cordova.getActivity().runOnUiThread(new Runnable() {
431 | @Override
432 | public void run() {
433 | try {
434 | addMarkers(args.getJSONArray(0));
435 | callbackContext.success();
436 | } catch (JSONException e) {
437 | callbackContext.error(e.getMessage());
438 | }
439 | }
440 | });
441 |
442 | } else if (ACTION_REMOVE_ALL_MARKERS.equals(action)) {
443 | if (mapView != null) {
444 | cordova.getActivity().runOnUiThread(new Runnable() {
445 | @Override
446 | public void run() {
447 | mapView.removeAllAnnotations();
448 | callbackContext.success();
449 | }
450 | });
451 | }
452 |
453 | } else if (ACTION_ADD_MARKER_CALLBACK.equals(action)) {
454 | this.markerCallbackContext = callbackContext;
455 | mapView.setOnInfoWindowClickListener(new MarkerClickListener());
456 |
457 | } else if (ACTION_ON_REGION_WILL_CHANGE.equals(action)) {
458 | if (mapView != null) {
459 | mapView.addOnMapChangedListener(new RegionWillChangeListener(callbackContext));
460 | }
461 |
462 | } else if (ACTION_ON_REGION_IS_CHANGING.equals(action)) {
463 | if (mapView != null) {
464 | mapView.addOnMapChangedListener(new RegionIsChangingListener(callbackContext));
465 | }
466 |
467 | } else if (ACTION_ON_REGION_DID_CHANGE.equals(action)) {
468 | if (mapView != null) {
469 | mapView.addOnMapChangedListener(new RegionDidChangeListener(callbackContext));
470 | }
471 |
472 | } else {
473 | return false;
474 | }
475 | } catch (Throwable t) {
476 | t.printStackTrace();
477 | callbackContext.error(t.getMessage());
478 | }
479 | return true;
480 | }
481 |
482 | private void addMarkers(JSONArray markers) throws JSONException {
483 | for (int i=0; i
2 |
3 |
--------------------------------------------------------------------------------
/src/ios/CDVMapbox.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import "Mapbox.h"
3 |
4 | @interface CDVMapbox : CDVPlugin
5 |
6 | @property (retain) MGLMapView *mapView;
7 | @property (retain) NSString *markerCallbackId;
8 | @property (retain) MGLPointAnnotation *selectedAnnotation;
9 | @property (retain) NSString *regionWillChangeAnimatedCallbackId;
10 | @property (retain) NSString *regionIsChangingCallbackId;
11 | @property (retain) NSString *regionDidChangeAnimatedCallbackId;
12 |
13 | - (void) show:(CDVInvokedUrlCommand*)command;
14 | - (void) hide:(CDVInvokedUrlCommand*)command;
15 |
16 | - (void) addMarkers:(CDVInvokedUrlCommand*)command;
17 | - (void) removeAllMarkers:(CDVInvokedUrlCommand*)command;
18 | - (void) addMarkerCallback:(CDVInvokedUrlCommand*)command;
19 |
20 | - (void) animateCamera:(CDVInvokedUrlCommand*)command;
21 |
22 | - (void) addPolygon:(CDVInvokedUrlCommand*)command;
23 |
24 | - (void) addGeoJSON:(CDVInvokedUrlCommand*)command;
25 |
26 | - (void) getCenter:(CDVInvokedUrlCommand*)command;
27 | - (void) setCenter:(CDVInvokedUrlCommand*)command;
28 |
29 | - (void) getZoomLevel:(CDVInvokedUrlCommand*)command;
30 | - (void) setZoomLevel:(CDVInvokedUrlCommand*)command;
31 |
32 | - (void) getBounds:(CDVInvokedUrlCommand*)command;
33 | - (void) setBounds:(CDVInvokedUrlCommand*)command;
34 |
35 | - (void) getTilt:(CDVInvokedUrlCommand*)command;
36 | - (void) setTilt:(CDVInvokedUrlCommand*)command;
37 |
38 | - (void) convertCoordinate:(CDVInvokedUrlCommand*)command;
39 | - (void) convertPoint:(CDVInvokedUrlCommand*)command;
40 |
41 | - (void) onRegionWillChange:(CDVInvokedUrlCommand*)command;
42 | - (void) onRegionIsChanging:(CDVInvokedUrlCommand*)command;
43 | - (void) onRegionDidChange:(CDVInvokedUrlCommand*)command;
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/src/ios/CDVMapbox.m:
--------------------------------------------------------------------------------
1 | #import "CDVMapbox.h"
2 |
3 | @implementation CDVMapbox
4 |
5 | - (void) show:(CDVInvokedUrlCommand*)command {
6 | NSDictionary *args = [command.arguments objectAtIndex:0];
7 |
8 | NSURL* mapStyle = [self getMapStyle:[args objectForKey:@"style"]];
9 |
10 | // where shall we show the map overlay?
11 | NSDictionary *margins = [args objectForKey:@"margins"];
12 | // note that these will correctly fall back to 0 if not passed in
13 | int left = [[margins objectForKey:@"left"] intValue];
14 | int right = [[margins objectForKey:@"right"] intValue];
15 | int top = [[margins objectForKey:@"top"] intValue];
16 | int bottom = [[margins objectForKey:@"bottom"] intValue];
17 |
18 | CGRect webviewFrame = self.webView.frame;
19 |
20 | CGRect mapFrame = CGRectMake(left, top, webviewFrame.size.width - left - right, webviewFrame.size.height - top - bottom);
21 |
22 | _mapView = [[MGLMapView alloc] initWithFrame:mapFrame
23 | styleURL:mapStyle];
24 |
25 | _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
26 |
27 | NSNumber *zoomLevel = [args valueForKey:@"zoomLevel"];
28 | if (zoomLevel == nil) {
29 | // we need a default
30 | zoomLevel = [NSNumber numberWithDouble:10.0];
31 | }
32 | NSDictionary *center = [args objectForKey:@"center"];
33 | if (center != nil) {
34 | NSNumber *clat = [center valueForKey:@"lat"];
35 | NSNumber *clng = [center valueForKey:@"lng"];
36 | [_mapView setCenterCoordinate:CLLocationCoordinate2DMake(clat.doubleValue, clng.doubleValue)
37 | zoomLevel:zoomLevel.doubleValue
38 | animated:NO];
39 | } else {
40 | [_mapView setZoomLevel:zoomLevel.doubleValue];
41 | }
42 |
43 |
44 | _mapView.delegate = self;
45 |
46 | // default NO, note that this requires adding `NSLocationWhenInUseUsageDescription` or `NSLocationAlwaysUsageDescription` to the plist
47 | _mapView.showsUserLocation = [[args objectForKey:@"showUserLocation"] boolValue];
48 |
49 | // default NO
50 | _mapView.attributionButton.hidden = [[args objectForKey:@"hideAttribution"] boolValue];
51 |
52 | // default NO - required for the 'starter' plan
53 | _mapView.logoView.hidden = [[args objectForKey:@"hideLogo"] boolValue];
54 |
55 | // default NO
56 | _mapView.compassView.hidden = [[args objectForKey:@"hideCompass"] boolValue];
57 |
58 | // default YES
59 | _mapView.rotateEnabled = ![[args objectForKey:@"disableRotation"] boolValue];
60 |
61 | // default YES
62 | _mapView.pitchEnabled = ![[args objectForKey:@"disablePitch"] boolValue];
63 |
64 | // default YES
65 | _mapView.allowsTilting = ![[args objectForKey:@"disableTilt"] boolValue];
66 |
67 | // default YES
68 | _mapView.scrollEnabled = ![[args objectForKey:@"disableScroll"] boolValue];
69 |
70 | // default YES
71 | _mapView.zoomEnabled = ![[args objectForKey:@"disableZoom"] boolValue];
72 |
73 | [self.webView addSubview:_mapView];
74 |
75 | // render markers async as the app will crash if we add it before the map is loaded.. and the delegate events are not sufficiently helpful
76 | NSArray* markers = [args objectForKey:@"markers"];
77 | if (markers != nil) {
78 | // Draw the markers after the map has initialized
79 | [self performSelector:@selector(putMarkersOnTheMap:) withObject:markers afterDelay:1.0];
80 | }
81 |
82 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
83 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
84 | }
85 |
86 | - (void) hide:(CDVInvokedUrlCommand*)command {
87 | [_mapView removeFromSuperview];
88 |
89 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
90 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
91 | }
92 |
93 | - (void) getCenter:(CDVInvokedUrlCommand*)command {
94 | CLLocationCoordinate2D ctr = _mapView.centerCoordinate;
95 | NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:
96 | [NSNumber numberWithDouble:ctr.latitude], @"lat",
97 | [NSNumber numberWithDouble:ctr.longitude], @"lng",
98 | nil];
99 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
100 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
101 | }
102 |
103 | - (void) setCenter:(CDVInvokedUrlCommand*)command {
104 | NSDictionary *args = [command.arguments objectAtIndex:0];
105 | NSNumber *clat = [args valueForKey:@"lat"];
106 | NSNumber *clng = [args valueForKey:@"lng"];
107 | BOOL animated = [[args objectForKey:@"animated"] boolValue];
108 | [_mapView setCenterCoordinate:CLLocationCoordinate2DMake(clat.doubleValue, clng.doubleValue) animated:animated];
109 |
110 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
111 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
112 | }
113 |
114 | - (void) setTilt:(CDVInvokedUrlCommand*)command {
115 | // TODO tilt/pitch seems not to be implemented in Mapbox iOS SDK (yet)
116 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not implemented for iOS (yet)"];
117 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
118 | }
119 |
120 | - (void) getTilt:(CDVInvokedUrlCommand*)command {
121 | // TODO seems not to be implemented in Mapbox iOS SDK (yet)
122 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not implemented for iOS (yet)"];
123 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
124 | }
125 |
126 | - (void) setZoomLevel:(CDVInvokedUrlCommand*)command {
127 | NSDictionary *args = [command.arguments objectAtIndex:0];
128 | NSNumber *level = [args objectForKey:@"level"];
129 | BOOL animated = [[args objectForKey:@"animated"] boolValue];
130 | double zoom = level.doubleValue;
131 | if (zoom >= 0 && zoom <= 20) {
132 | [_mapView setZoomLevel:zoom animated:animated];
133 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
134 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
135 | } else {
136 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"invalid zoomlevel, use any double value from 0 to 20 (like 8.3)"];
137 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
138 | }
139 | }
140 |
141 | - (void) getZoomLevel:(CDVInvokedUrlCommand*)command {
142 | double zoom = _mapView.zoomLevel;
143 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:zoom];
144 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
145 | }
146 |
147 | - (void) getBounds:(CDVInvokedUrlCommand*)command {
148 | MGLCoordinateBounds bounds = _mapView.visibleCoordinateBounds;
149 | NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:
150 | [NSNumber numberWithDouble:bounds.sw.latitude], @"sw_lat",
151 | [NSNumber numberWithDouble:bounds.sw.longitude], @"sw_lng",
152 | [NSNumber numberWithDouble:bounds.ne.latitude], @"ne_lat",
153 | [NSNumber numberWithDouble:bounds.ne.longitude], @"ne_lng",
154 | nil];
155 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dic];
156 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
157 | }
158 |
159 | - (void) setBounds:(CDVInvokedUrlCommand*)command {
160 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"not implemented for iOS (yet)"];
161 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
162 | }
163 |
164 | - (void)animateCamera:(CDVInvokedUrlCommand*)command {
165 | NSDictionary *args = [command.arguments objectAtIndex:0];
166 |
167 | MGLMapCamera * cam = [MGLMapCamera camera];
168 |
169 | NSNumber *altitude = [args valueForKey:@"altitude"];
170 | if (altitude != nil) {
171 | cam.altitude = [altitude doubleValue];
172 | }
173 |
174 | NSNumber *tilt = [args valueForKey:@"tilt"];
175 | if (tilt != nil) {
176 | cam.pitch = [tilt floatValue];
177 | }
178 |
179 | NSNumber *bearing = [args valueForKey:@"bearing"];
180 | if (bearing != nil) {
181 | cam.heading = [bearing floatValue];
182 | }
183 |
184 | NSTimeInterval durInt = 15; // default 15
185 | NSNumber *duration = [args valueForKey:@"duration"];
186 | if (duration != nil) {
187 | durInt = [duration intValue];
188 | }
189 |
190 | NSDictionary *target = [args objectForKey:@"target"];
191 | if (target != nil) {
192 | NSNumber *clat = [target valueForKey:@"lat"];
193 | NSNumber *clng = [target valueForKey:@"lng"];
194 | cam.centerCoordinate = CLLocationCoordinate2DMake(clat.doubleValue, clng.doubleValue);
195 | }
196 |
197 | [_mapView setCamera:cam withDuration:durInt animationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
198 |
199 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
200 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
201 | }
202 |
203 | - (void)addPolygon:(CDVInvokedUrlCommand*)command {
204 | NSDictionary *args = [command.arguments objectAtIndex:0];
205 | NSArray* points = [args objectForKey:@"points"];
206 | if (points != nil) {
207 | [self.commandDelegate runInBackground:^{
208 | CLLocationCoordinate2D *coordinates = malloc(points.count * sizeof(CLLocationCoordinate2D));
209 | for (int i=0; i 90)||(fabs(lng) > 180)){
280 | CDVPluginResult * pluginResult = [CDVPluginResult
281 | resultWithStatus:CDVCommandStatus_ERROR
282 | messageAsString:@"Incorrect Leaflet.LatLng value."];
283 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
284 | }
285 |
286 | CGPoint screenPoint = [_mapView convertCoordinate:CLLocationCoordinate2DMake(lat, lng)
287 | toPointToView:_mapView];
288 |
289 | NSDictionary *point = @{@"x" : @(screenPoint.x), @"y" : @(screenPoint.y)};
290 |
291 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:point];
292 |
293 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
294 | }
295 |
296 | - (void) convertPoint:(CDVInvokedUrlCommand *)command {
297 | NSDictionary *args = command.arguments[0];
298 |
299 | float x = [[args valueForKey:@"x"] floatValue];
300 | float y = [[args valueForKey:@"y"] floatValue];
301 |
302 | if ((x < 0 || y < 0)){
303 | CDVPluginResult * pluginResult = [CDVPluginResult
304 | resultWithStatus:CDVCommandStatus_ERROR
305 | messageAsString:@"Incorrect Leaflet.Point point coordinates."];
306 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
307 | }
308 |
309 | CLLocationCoordinate2D location = [_mapView convertPoint:CGPointMake(x, y)
310 | toCoordinateFromView:_mapView];
311 |
312 | NSDictionary *coordinates = @{@"lat" : @(location.latitude), @"lng" : @(location.longitude)};
313 |
314 | CDVPluginResult * pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:coordinates];
315 |
316 | [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
317 | }
318 |
319 | - (void) onRegionWillChange:(CDVInvokedUrlCommand*)command {
320 | self.regionWillChangeAnimatedCallbackId = command.callbackId;
321 | }
322 |
323 | - (void) onRegionIsChanging:(CDVInvokedUrlCommand*)command {
324 | self.regionIsChangingCallbackId = command.callbackId;
325 | }
326 |
327 | - (void) onRegionDidChange:(CDVInvokedUrlCommand*)command {
328 | self.regionDidChangeAnimatedCallbackId = command.callbackId;
329 | }
330 | #pragma mark - MGLMapViewDelegate
331 |
332 | // this method is invoked every time an annotation is clicked
333 | - (BOOL)mapView:(MGLMapView *)mapView annotationCanShowCallout:(id )annotation {
334 | return YES;
335 | }
336 |
337 | //- (MGLAnnotationImage *)mapView:(MGLMapView *)mapView imageForAnnotation:(id )annotation {
338 | // TODO should be able to use an img from www/
339 | // MGLAnnotationImage *annotationImage = [mapView dequeueReusableAnnotationImageWithIdentifier:@"pisa"];
340 |
341 | // if (!annotationImage) {
342 | // Leaning Tower of Pisa by Stefan Spieler from the Noun Project
343 | // UIImage *image = [UIImage imageNamed:@"pisa"];
344 | // annotationImage = [MGLAnnotationImage annotationImageWithImage:image reuseIdentifier:@"pisa"];
345 | // }
346 |
347 | // return annotationImage;
348 | //}
349 |
350 | - (nullable UIView *)mapView:(MGLMapView *)mapView rightCalloutAccessoryViewForAnnotation:(id )annotation {
351 | if (self.markerCallbackId != nil) {
352 | self.selectedAnnotation = annotation;
353 | UIButton *butt = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
354 | [butt addTarget:self action:@selector(annotationInfoButtonTouched:) forControlEvents:UIControlEventTouchDown];
355 | return butt;
356 | } else {
357 | return nil;
358 | }
359 | }
360 |
361 | - (void) annotationInfoButtonTouched:(UIButton *)sender {
362 | if (self.markerCallbackId != nil && self.selectedAnnotation != nil) {
363 | NSMutableDictionary* returnInfo = [NSMutableDictionary dictionaryWithCapacity:4];
364 | [returnInfo setObject:self.selectedAnnotation.title forKey:@"title"];
365 | if (self.selectedAnnotation.subtitle != nil) {
366 | [returnInfo setObject:self.selectedAnnotation.subtitle forKey:@"subtitle"];
367 | }
368 | [returnInfo setObject:[NSNumber numberWithDouble:self.selectedAnnotation.coordinate.latitude] forKey:@"lat"];
369 | [returnInfo setObject:[NSNumber numberWithDouble:self.selectedAnnotation.coordinate.longitude] forKey:@"lng"];
370 |
371 | CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:returnInfo];
372 | [result setKeepCallbackAsBool:YES];
373 | [self.commandDelegate sendPluginResult:result callbackId:self.markerCallbackId];
374 | }
375 | }
376 |
377 | - (NSURL*) getMapStyle:(NSString*) input {
378 | if ([input isEqualToString:@"light"]) {
379 | return [MGLStyle lightStyleURL];
380 | } else if ([input isEqualToString:@"dark"]) {
381 | return [MGLStyle darkStyleURL];
382 | } else if ([input isEqualToString:@"emerald"]) {
383 | return [MGLStyle emeraldStyleURL];
384 | } else if ([input isEqualToString:@"satellite"]) {
385 | return [MGLStyle satelliteStyleURL];
386 | } else if ([input isEqualToString:@"hybrid"]) {
387 | return [MGLStyle hybridStyleURL];
388 | } else if ( input != nil ) {
389 | NSURL *url = [NSURL URLWithString:input];
390 | return url;
391 | } else {
392 | return [MGLStyle streetsStyleURL];
393 | }
394 | }
395 |
396 | - (NSMutableDictionary*) getResultOnMapChange{
397 |
398 | NSMutableDictionary* returnInfo = [NSMutableDictionary dictionary];
399 | MGLMapCamera* camera = _mapView.camera;
400 |
401 | returnInfo[@"lat"] = @(_mapView.centerCoordinate.latitude);
402 | returnInfo[@"lng"] = @(_mapView.centerCoordinate.longitude);
403 | returnInfo[@"camAltitude"] = @(_mapView.camera.altitude);
404 | returnInfo[@"camPitch"] = @(_mapView.camera.pitch);
405 | returnInfo[@"camHeading"] = @(_mapView.camera.heading);
406 |
407 | return returnInfo;
408 | }
409 |
410 |
411 | - (void)mapView:(nonnull MGLMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
412 | if (self.regionWillChangeAnimatedCallbackId != nil) {
413 |
414 | NSMutableDictionary* returnInfo = [self getResultOnMapChange];
415 |
416 | CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:returnInfo];
417 | [result setKeepCallbackAsBool:YES];
418 | [self.commandDelegate sendPluginResult:result callbackId:self.regionWillChangeAnimatedCallbackId];
419 | }
420 | };
421 |
422 | - (void)mapViewRegionIsChanging:(nonnull MGLMapView *)mapView{
423 | if (self.regionIsChangingCallbackId != nil) {
424 |
425 | NSMutableDictionary* returnInfo = [self getResultOnMapChange];
426 |
427 | CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:returnInfo];
428 | [result setKeepCallbackAsBool:YES];
429 | [self.commandDelegate sendPluginResult:result callbackId:self.regionIsChangingCallbackId];
430 | }
431 | };
432 |
433 | - (void)mapView:(nonnull MGLMapView *)mapView regionDidChangeAnimated:(BOOL)animated{
434 | if (self.regionDidChangeAnimatedCallbackId != nil) {
435 |
436 | NSMutableDictionary* returnInfo = [self getResultOnMapChange];
437 |
438 | CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:returnInfo];
439 | [result setKeepCallbackAsBool:YES];
440 | [self.commandDelegate sendPluginResult:result callbackId:self.regionDidChangeAnimatedCallbackId];
441 | }
442 | };
443 |
444 | @end
445 |
--------------------------------------------------------------------------------
/src/ios/Headers/MGLAccountManager.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #import "MGLTypes.h"
4 |
5 | NS_ASSUME_NONNULL_BEGIN
6 |
7 | /** The MGLAccountManager object provides a global way to set a Mapbox API access token, as well as other settings used framework-wide. */
8 | @interface MGLAccountManager : NSObject
9 |
10 | /** @name Authorizing Access */
11 |
12 | /** Set the Mapbox API access token for the framework.
13 | *
14 | * You can set an access token on MGLAccountManager or on an individual map view. The same token is used throughout the framework.
15 | * @param accessToken The Mapbox API access token. */
16 | + (void)setAccessToken:(nullable NSString *)accessToken;
17 |
18 | /** Retreive the Mapbox API access token for the framework.
19 | *
20 | * You can set an access token on MGLAccountManager or on an individual map view. The same token is used throughout the framework.
21 | * @return accessToken The Mapbox API access token. */
22 | + (nullable NSString *)accessToken;
23 |
24 | /** @name Providing User Metrics Opt-Out */
25 |
26 | /** Whether in-app user metrics opt-out is configured. If set to the default value of `NO`, a user opt-out preference is expected in a `Settings.bundle` that shows in the application's section within the system Settings app. */
27 | + (BOOL)mapboxMetricsEnabledSettingShownInApp;
28 |
29 | @end
30 |
31 | NS_ASSUME_NONNULL_END
32 |
--------------------------------------------------------------------------------
/src/ios/Headers/MGLAnnotation.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | #import "MGLTypes.h"
5 |
6 | NS_ASSUME_NONNULL_BEGIN
7 |
8 | /** The `MGLAnnotation` protocol is used to provide annotation-related information to a map view. To use this protocol, you adopt it in any custom objects that store or represent annotation data. Each object then serves as the source of information about a single map annotation and provides critical information, such as the annotation’s location on the map. Annotation objects do not provide the visual representation of the annotation but typically coordinate (in conjunction with the map view’s delegate) the creation of an appropriate objects to handle the display.
9 | *
10 | * An object that adopts this protocol must implement the `coordinate` property. The other methods of this protocol are optional. */
11 | @protocol MGLAnnotation
12 |
13 | /** @name Position Attributes */
14 |
15 | /** The center point (specified as a map coordinate) of the annotation. (required) (read-only) */
16 | @property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
17 |
18 | @optional
19 |
20 | /** @name Title Attributes */
21 |
22 | /** The string containing the annotation’s title.
23 | *
24 | * Although this property is optional, if you support the selection of annotations in your map view, you are expected to provide this property. This string is displayed in the callout for the associated annotation. */
25 | @property (nonatomic, readonly, copy, nullable) NSString *title;
26 |
27 | /** The string containing the annotation’s subtitle.
28 | *
29 | * This string is displayed in the callout for the associated annotation. */
30 | @property (nonatomic, readonly, copy, nullable) NSString *subtitle;
31 |
32 | @end
33 |
34 | NS_ASSUME_NONNULL_END
35 |
--------------------------------------------------------------------------------
/src/ios/Headers/MGLAnnotationImage.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #import "MGLTypes.h"
4 |
5 | NS_ASSUME_NONNULL_BEGIN
6 |
7 | /** The MGLAnnotationImage class is responsible for presenting point-based annotations visually on a map view. Annotation image objects wrap `UIImage` objects and may be recycled later and put into a reuse queue that is maintained by the map view. */
8 | @interface MGLAnnotationImage : NSObject
9 |
10 | /** @name Initializing and Preparing the Image Object */
11 |
12 | /** Initializes and returns a new annotation image object.
13 | * @param image The image to be displayed for the annotation.
14 | * @param reuseIdentifier The string that identifies that this annotation image is reusable.
15 | * @return The initialized annotation image object or `nil` if there was a problem initializing the object. */
16 | + (instancetype)annotationImageWithImage:(UIImage *)image reuseIdentifier:(NSString *)reuseIdentifier;
17 |
18 | /** @name Getting and Setting Attributes */
19 |
20 | /** The image to be displayed for the annotation. */
21 | @property (nonatomic, readonly) UIImage *image;
22 |
23 | /** The string that identifies that this annotation image is reusable. (read-only)
24 | *
25 | * You specify the reuse identifier when you create the image object. You use this type later to retrieve an annotation image object that was created previously but which is currently unused because its annotation is not on screen.
26 | *
27 | * If you define distinctly different types of annotations (with distinctly different annotation images to go with them), you can differentiate between the annotation types by specifying different reuse identifiers for each one. */
28 | @property (nonatomic, readonly) NSString *reuseIdentifier;
29 |
30 | /** A Boolean value indicating whether the annotation is enabled.
31 | *
32 | * The default value of this property is `YES`. If the value of this property is `NO`, the annotation image ignores touch events and cannot be selected. */
33 | @property (nonatomic, getter=isEnabled) BOOL enabled;
34 |
35 | @end
36 |
37 | NS_ASSUME_NONNULL_END
38 |
--------------------------------------------------------------------------------
/src/ios/Headers/MGLGeometry.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import
4 |
5 | #import "MGLTypes.h"
6 |
7 | NS_ASSUME_NONNULL_BEGIN
8 |
9 | /** Defines the area spanned by an MGLCoordinateBounds. */
10 | typedef struct {
11 | CLLocationDegrees latitudeDelta;
12 | CLLocationDegrees longitudeDelta;
13 | } MGLCoordinateSpan;
14 |
15 | /** Creates a new MGLCoordinateSpan from the given latitudinal and longitudinal deltas. */
16 | NS_INLINE MGLCoordinateSpan MGLCoordinateSpanMake(CLLocationDegrees latitudeDelta, CLLocationDegrees longitudeDelta) {
17 | MGLCoordinateSpan span;
18 | span.latitudeDelta = latitudeDelta;
19 | span.longitudeDelta = longitudeDelta;
20 | return span;
21 | }
22 |
23 | /** Returns `YES` if the two coordinate spans represent the same latitudinal change and the same longitudinal change. */
24 | NS_INLINE BOOL MGLCoordinateSpanEqualToCoordinateSpan(MGLCoordinateSpan span1, MGLCoordinateSpan span2) {
25 | return (span1.latitudeDelta == span2.latitudeDelta &&
26 | span1.longitudeDelta == span2.longitudeDelta);
27 | }
28 |
29 | /** An area of zero width and zero height. */
30 | extern const MGLCoordinateSpan MGLCoordinateSpanZero;
31 |
32 | /** A rectangular area as measured on a two-dimensional map projection. */
33 | typedef struct {
34 | CLLocationCoordinate2D sw;
35 | CLLocationCoordinate2D ne;
36 | } MGLCoordinateBounds;
37 |
38 | /** Creates a new MGLCoordinateBounds structure from the given southwest and northeast coordinates. */
39 | NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsMake(CLLocationCoordinate2D sw, CLLocationCoordinate2D ne) {
40 | MGLCoordinateBounds bounds;
41 | bounds.sw = sw;
42 | bounds.ne = ne;
43 | return bounds;
44 | }
45 |
46 | /** Returns `YES` if the two coordinate bounds are equal to each other. */
47 | NS_INLINE BOOL MGLCoordinateBoundsEqualToCoordinateBounds(MGLCoordinateBounds bounds1, MGLCoordinateBounds bounds2) {
48 | return (bounds1.sw.latitude == bounds2.sw.latitude &&
49 | bounds1.sw.longitude == bounds2.sw.longitude &&
50 | bounds1.ne.latitude == bounds2.ne.latitude &&
51 | bounds1.ne.longitude == bounds2.ne.longitude);
52 | }
53 |
54 | /** Returns the area spanned by the coordinate bounds. */
55 | NS_INLINE MGLCoordinateSpan MGLCoordinateBoundsGetCoordinateSpan(MGLCoordinateBounds bounds) {
56 | return MGLCoordinateSpanMake(bounds.ne.latitude - bounds.sw.latitude,
57 | bounds.ne.longitude - bounds.sw.longitude);
58 | }
59 |
60 | /** Returns a coordinate bounds with southwest and northeast coordinates that are offset from those of the source bounds. */
61 | NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsOffset(MGLCoordinateBounds bounds, MGLCoordinateSpan offset) {
62 | MGLCoordinateBounds offsetBounds = bounds;
63 | offsetBounds.sw.latitude += offset.latitudeDelta;
64 | offsetBounds.sw.longitude += offset.longitudeDelta;
65 | offsetBounds.ne.latitude += offset.latitudeDelta;
66 | offsetBounds.ne.longitude += offset.longitudeDelta;
67 | return offsetBounds;
68 | }
69 |
70 | /** Returns `YES` if the coordinate bounds covers no area.
71 | *
72 | * Note that a bounds may be empty but have a non-zero coordinate span (e.g., when its northeast point lies due north of its southwest point). */
73 | NS_INLINE BOOL MGLCoordinateBoundsIsEmpty(MGLCoordinateBounds bounds) {
74 | MGLCoordinateSpan span = MGLCoordinateBoundsGetCoordinateSpan(bounds);
75 | return span.latitudeDelta == 0 || span.longitudeDelta == 0;
76 | }
77 |
78 | /** Returns a formatted string for the given coordinate bounds. */
79 | NS_INLINE NSString *MGLStringFromCoordinateBounds(MGLCoordinateBounds bounds) {
80 | return [NSString stringWithFormat:@"{{%.1f, %.1f}, {%.1f, %.1f}}",
81 | bounds.sw.latitude, bounds.sw.longitude,
82 | bounds.ne.latitude, bounds.ne.longitude];
83 | }
84 |
85 | /** Returns radians, converted from degrees. */
86 | NS_INLINE CGFloat MGLRadiansFromDegrees(CLLocationDegrees degrees)
87 | {
88 | return (CGFloat)(degrees * M_PI) / 180;
89 | }
90 |
91 | /** Returns degrees, converted from radians. */
92 | NS_INLINE CLLocationDegrees MGLDegreesFromRadians(CGFloat radians)
93 | {
94 | return radians * 180 / M_PI;
95 | }
96 |
97 | NS_ASSUME_NONNULL_END
98 |
--------------------------------------------------------------------------------
/src/ios/Headers/MGLMapCamera.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import
4 |
5 | #import "MGLTypes.h"
6 |
7 | NS_ASSUME_NONNULL_BEGIN
8 |
9 | /** An `MGLMapCamera` object represents a viewpoint from which the user observes some point on an `MGLMapView`. */
10 | @interface MGLMapCamera : NSObject
11 |
12 | /** Coordinate at the center of the map view. */
13 | @property (nonatomic) CLLocationCoordinate2D centerCoordinate;
14 |
15 | /** Heading measured in degrees clockwise from true north. */
16 | @property (nonatomic) CLLocationDirection heading;
17 |
18 | /** Pitch toward the horizon measured in degrees, with 0 degrees resulting in a two-dimensional map. */
19 | @property (nonatomic) CGFloat pitch;
20 |
21 | /** Meters above ground level. */
22 | @property (nonatomic) CLLocationDistance altitude;
23 |
24 | /** Returns a new camera with all properties set to 0. */
25 | + (instancetype)camera;
26 |
27 | + (instancetype)cameraLookingAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
28 | fromEyeCoordinate:(CLLocationCoordinate2D)eyeCoordinate
29 | eyeAltitude:(CLLocationDistance)eyeAltitude;
30 |
31 | + (instancetype)cameraLookingAtCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
32 | fromDistance:(CLLocationDistance)distance
33 | pitch:(CGFloat)pitch
34 | heading:(CLLocationDirection)heading;
35 |
36 | @end
37 |
38 | NS_ASSUME_NONNULL_END
39 |
--------------------------------------------------------------------------------
/src/ios/Headers/MGLMapView+IBAdditions.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #import "MGLTypes.h"
4 |
5 | @class MGLMapView;
6 |
7 | NS_ASSUME_NONNULL_BEGIN
8 |
9 | @interface MGLMapView (IBAdditions)
10 |
11 | // Core properties that can be manipulated in the Attributes inspector in
12 | // Interface Builder. These redeclarations merely add the IBInspectable keyword.
13 | // They appear here to ensure that they appear above the convenience properties;
14 | // inspectables declared in MGLMapView.h are always sorted before those in
15 | // MGLMapView+IBAdditions.h, due to ASCII sort order.
16 |
17 | #if TARGET_INTERFACE_BUILDER
18 |
19 | // HACK: We want this property to look like a URL bar in the Attributes
20 | // inspector, but just calling it styleURL would violate Cocoa naming
21 | // conventions and conflict with the existing NSURL property. Fortunately, IB
22 | // strips out the two underscores for display.
23 | @property (nonatomic, nullable) IBInspectable NSString *styleURL__;
24 |
25 | #endif // TARGET_INTERFACE_BUILDER
26 |
27 | // Convenience properties related to the initial viewport. These properties
28 | // are not meant to be used outside of Interface Builder. latitude and longitude
29 | // are backed by properties of type CLLocationDegrees, but these declarations
30 | // must use the type double because Interface Builder is unaware that
31 | // CLLocationDegrees is a typedef for double.
32 |
33 | @property (nonatomic) IBInspectable double latitude;
34 | @property (nonatomic) IBInspectable double longitude;
35 | @property (nonatomic) IBInspectable double zoomLevel;
36 |
37 | // Renamed properties. Interface Builder derives the display name of each
38 | // inspectable from the runtime name, but runtime names don’t always make sense
39 | // in UI.
40 |
41 | @property (nonatomic) IBInspectable BOOL allowsZooming;
42 | @property (nonatomic) IBInspectable BOOL allowsScrolling;
43 | @property (nonatomic) IBInspectable BOOL allowsRotating;
44 | @property (nonatomic) IBInspectable BOOL allowsTilting;
45 | @property (nonatomic) IBInspectable BOOL showsUserLocation;
46 |
47 | @end
48 |
49 | NS_ASSUME_NONNULL_END
50 |
--------------------------------------------------------------------------------
/src/ios/Headers/MGLMapView.h:
--------------------------------------------------------------------------------
1 | #import "MGLGeometry.h"
2 | #import "MGLMapCamera.h"
3 |
4 | #import
5 | #import
6 |
7 | #import "MGLTypes.h"
8 |
9 | NS_ASSUME_NONNULL_BEGIN
10 |
11 | @class MGLAnnotationImage;
12 | @class MGLUserLocation;
13 | @class MGLPolyline;
14 | @class MGLPolygon;
15 | @class MGLShape;
16 |
17 | @protocol MGLMapViewDelegate;
18 | @protocol MGLAnnotation;
19 | @protocol MGLOverlay;
20 |
21 | /** An MGLMapView object provides an embeddable map interface, similar to the one provided by Apple's MapKit. You use this class to display map information and to manipulate the map contents from your application. You can center the map on a given coordinate, specify the size of the area you want to display, and style the features of the map to fit your application's use case.
22 | *
23 | * Use of MGLMapView requires a Mapbox API access token. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/account/apps/). If you instantiate an MGLMapView from Interface Builder, rendering of the map won't begin until the accessToken property has been set.
24 | *
25 | * @warning Please note that you are responsible for getting permission to use the map data, and for ensuring your use adheres to the relevant terms of use. */
26 | IB_DESIGNABLE
27 | @interface MGLMapView : UIView
28 |
29 | #pragma mark - Initializing a Map View
30 |
31 | /** @name Initializing a Map View */
32 |
33 | /** Initializes and returns a newly allocated map view with the specified frame and the default style.
34 | * @param frame The frame for the view, measured in points.
35 | * @return An initialized map view. */
36 | - (instancetype)initWithFrame:(CGRect)frame;
37 |
38 | /** Initializes and returns a newly allocated map view with the specified frame and style URL.
39 | * @param frame The frame for the view, measured in points.
40 | * @param styleURL The map style URL to use. Can be either an HTTP/HTTPS URL or a Mapbox map ID style URL (`mapbox://styles//