Commit 796d7ba2 authored by Mohsen Taleb's avatar Mohsen Taleb

Updated SDK to comply with mapbox v2.2.3. Improved README and demos.

parent d773d470
This diff is collapsed.
# cedarmaps.js # cedarmaps.js
This is CedarMaps Javascript API. It's simply a wrapper for [Mapbox Javascript API](https://github.com/mapbox/mapbox.js/), which is itself built as a [Leaflet](http://leafletjs.com/) plugin. You can [read about its launch](http://mapbox.com/blog/mapbox-js-with-leaflet/). This is CedarMaps Javascript API. It's simply a wrapper for [Mapbox Javascript API](https://github.com/mapbox/mapbox.js/), (Currently `v2.2.3`) which is itself built as a [Leaflet](http://leafletjs.com/) plugin. You can [read about its launch](http://mapbox.com/blog/mapbox-js-with-leaflet/).
# Table of Contents
- [Basic Usage](#usage)
- [API](#api)
- [Forward/Reverse Geocoding](#forwardreverse-geocoding)
- [Geocoding](#lcedarmapsgeocoderid-options)
- [Geocoding Sample Codes](#geocoding-examples)
- [Reverse Geocoding](#geocoderreversequerylocation-callback)
- [Reverse Geocoding Sample Code](#reverse-geocoding-examples)
- [Building SDK](#building-sdk)
- [Updating SDK](#updating-sdk)
- [Updating mapbox.js submodule](#updating-mapboxjs-submodule)
- [Updating Cedarmaps.js](#updating-cedarmapsjs)
## Usage ## Usage
Recommended usage is via the CedarMaps CDN: Recommended usage is via the CedarMaps CDN:
```html ```html
<script src='http://api.cedarmaps.com/cedarmaps.js/v1.0.1/cedarmaps.js'></script> <script src='http://api.cedarmaps.com/cedarmaps.js/v1.1.0/cedarmaps.js'></script>
<link href='http://api.cedarmaps.com/cedarmaps.js/v1.0.1/cedarmaps.css' rel='stylesheet' /> <link href='http://api.cedarmaps.com/cedarmaps.js/v1.1.0/cedarmaps.css' rel='stylesheet' />
``` ```
The `cedarmaps.js` file includes the Leaflet library. Alternatively, you can use `cedarmaps.standalone.js`, which does not include Leaflet (you will have to provide it yourself). The `cedarmaps.js` file includes the Leaflet library. Alternatively, you can use `cedarmaps.standalone.js`, which does not include Leaflet (you will have to provide it yourself).
...@@ -33,10 +46,90 @@ You can also see the [API documentation](http://mapbox.com/mapbox.js/api/) and [ ...@@ -33,10 +46,90 @@ You can also see the [API documentation](http://mapbox.com/mapbox.js/api/) and [
## API ## API
Managed as Markdown in `API.md`, following the standards in `DOCUMENTING.md` API is almost the same as mapbox's API. [Check it out](http://mapbox.com/mapbox.js/api/).
API is almost the same as mapbox's API. [Check it out](http://mapbox.com/mapbox.js/api/). However two mostly used methods: forward and reverse geocoding APIs are described below for easy access:
## Building ## Forward/Reverse Geocoding
### L.cedarmaps.geocoder(id, options)
A low-level interface to geocoding, useful for more complex uses and reverse-geocoding.
| Options | Value | Description |
| ---- | ---- | ---- |
| id | string | currently `cedarmaps.streets` |
| options | Object | The second argument is optional. If provided, it may include: <ul><li>`accessToken`: Mapbox API access token. Overrides `L.cedarmaps.accessToken` for this geocoder.</li></ul> |
_Returns_ a `L.cedarmaps.geocoder` object.
example:
```
var geocoder = L.cedarmaps.geocoder('cedarmaps.streets');
```
### geocoder.query(queryString|options, callback)
Queries the geocoder with a query string, and returns its result, if any.
| Options | Value | Description |
| ---- | ---- | ---- |
| queryString (_required_) | string | a query, expressed as a string, like 'Arkansas' |
| options | object | an object containing the query and options parameters like `{ query: 'ونک', limit: 5 }`. <br><br>Other available parameteres: <br><br> <ul><li>`limit` *integer* - Max is 30</li><li>`distance` *float* - Unit is km, 0.1 means 100 meters</li><li>`location` *lat,lon* - For searching near a location. should be accompanied with distance param</li><li>`type` *enum* - Possible values: `locality`, `roundabout`, `street`, `freeway`, `expressway`, `boulevard` <br>(You can mix types by separating them with comma)</li><li>`ne` *lat,lon* - Specifies north east of the bounding box - should be accompanied with `sw` param</li><li>`sw` lat,lon - Specifies south west of the bounding box - should be accompanied with `ne` param</li></ul> |
| callback (_required_) | function | a callback |
The callback is called with arguments
1. An error, if any
2. The result. This is an object with the following members:
{
status: // OK
results: // raw results
}
_Example_: [Live example of geocoder.query centering a map.](http://www.cedarmaps.com/websdk/demos/geocoder-control.html)
_Returns_: the geocoder object. The return value of this function is not useful - you must use a callback to get results.
#### Geocoding Examples:
using a single query parameter:
```
geocoder.query('ونک', function(){});
```
using query string along with an option (Limiting the results):
```
geocoder.query({query:'ونک', limit: 5}, function(){});
```
limiting results based on one or more feature types:
```
geocoder.query({query:'ونک', type: 'locality'}, function(){});
geocoder.query({query:'ونک', type: 'locality,roundabout'}, function(){});
geocoder.query({query:'ونک', type: 'street', limit:2}, function(){});
```
searching within in a specific bounding box:
```
geocoder.query({query:'لادن', ne: '35.76817388431271,51.41721725463867', sw: '35.75316460798604,51.39232635498047'}, function(){});
```
### geocoder.reverseQuery(location, callback)
Queries the geocoder with a location, and returns its result, if any.
| Options | Value | Description |
| ---- | ---- | ---- |
| location (_required_) | object | A query, expressed as an object:<ul><li>`[lon, lat] // an array of lon, lat`</li><li>`{ lat: 0, lon: 0 } // a lon, lat object`</li><li>`{ lat: 0, lng: 0 } // a lng, lat object`</li></ul> The first argument can also be an array of objects in that form to geocode more than one item. |
| callback (_required_) | function | The callback is called with arguments <ul><li>An error, if any</li><li>The result. This is an object of the raw result from Mapbox.</li></ul>
_Returns_: the geocoder object. The return value of this function is not useful - you must use a callback to get results.
#### Reverse Geocoding Examples
```
var geocoder = L.cedarmaps.geocoder('cedarmaps.streets');
geocoder.reverseQuery({lat: 35.754592526442465, lng: 51.401896476745605}, function(){});
```
# Building SDK
Requires [node.js](http://nodejs.org/) installed on your system. Requires [node.js](http://nodejs.org/) installed on your system.
Grunt makes use of [Browserify](http://browserify.org/) under the hood to build the project while resolving dependencies. Grunt makes use of [Browserify](http://browserify.org/) under the hood to build the project while resolving dependencies.
...@@ -52,7 +145,7 @@ grunt build ...@@ -52,7 +145,7 @@ grunt build
Built files are copied into `dist/` folder according to current SDK `version`. (See `package.json`) Built files are copied into `dist/` folder according to current SDK `version`. (See `package.json`)
Note that every time you pull new changes from repository, you should run `grunt build`. Note that every time you pull new changes from repository, you should run `grunt build`.
# Updating # Updating SDK
## Updating mapbox.js submodule ## Updating mapbox.js submodule
The mapbox.js SDK is updated from time to time and obviously cedarmaps.js also needs to be synced. The submodule is residing in `/mapbox.js` folder and points to a specific mapbox.js tag (not the HEAD, of course). The mapbox.js SDK is updated from time to time and obviously cedarmaps.js also needs to be synced. The submodule is residing in `/mapbox.js` folder and points to a specific mapbox.js tag (not the HEAD, of course).
......
.leaflet-control-mapbox-geocoder.active .leaflet-control-mapbox-geocoder-wrap {
width: 250px;
}
.leaflet-control-mapbox-geocoder .leaflet-control-mapbox-geocoder-form input {
width: 250px;
}
.leaflet-control-mapbox-geocoder-results {
width: 250px;
}
\ No newline at end of file
...@@ -3,11 +3,14 @@ ...@@ -3,11 +3,14 @@
<head> <head>
<meta charset=utf-8 /> <meta charset=utf-8 />
<title>Reverse Geocoding Testing Environment</title> <title>CedarMaps - Sample Geocoder Control</title>
<script src='../dist/v1.0.1/cedarmaps.js'></script> <script src='../dist/v1.1.0/cedarmaps.js'></script>
<script src='../access-token.js'></script> <script src='../access-token.js'></script>
<link href='../dist/v1.0.1/cedarmaps.css' rel='stylesheet' /> <link href='../dist/v1.1.0/cedarmaps.css' rel='stylesheet' />
<link href='css/styles.css' rel='stylesheet' />
<style> <style>
body { body {
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
<head> <head>
<meta charset=utf-8 /> <meta charset=utf-8 />
<title>CedarMaps Web SDK Demos</title> <title>CedarMaps - Simple Map Load</title>
<script src='../dist/v1.0.1/cedarmaps.js'></script> <script src='../dist/v1.1.0/cedarmaps.js'></script>
<script src='../access-token.js'></script> <script src='../access-token.js'></script>
<link href='../dist/v1.0.1/cedarmaps.css' rel='stylesheet' /> <link href='../dist/v1.1.0/cedarmaps.css' rel='stylesheet' />
<style> <style>
body { body {
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
<head> <head>
<meta charset=utf-8 /> <meta charset=utf-8 />
<title>Reverse Geocoding Testing Environment</title> <title>CedarMaps - Reverse Geocoding Sample</title>
<script src='../dist/v1.0.1/cedarmaps.js'></script> <script src='../dist/v1.1.0/cedarmaps.js'></script>
<script src='../access-token.js'></script> <script src='../access-token.js'></script>
<link href='../dist/v1.0.1/cedarmaps.css' rel='stylesheet' /> <link href='../dist/v1.1.0/cedarmaps.css' rel='stylesheet' />
<style> <style>
body { body {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"author": "CedarStudios", "author": "CedarStudios",
"name": "cedarmaps.js", "name": "cedarmaps.js",
"description": "CedarMaps javascript API built on top of mapbox.js", "description": "CedarMaps javascript API built on top of mapbox.js",
"version": "1.0.1", "version": "1.1.0",
"homepage": "http://www.cedarmaps.com/", "homepage": "http://www.cedarmaps.com/",
"repository": { "repository": {
"type": "git", "type": "git",
...@@ -10,10 +10,11 @@ ...@@ -10,10 +10,11 @@
}, },
"main": "src/index.js", "main": "src/index.js",
"dependencies": { "dependencies": {
"leaflet": "0.7.3",
"mustache": "0.7.3",
"corslite": "0.0.6", "corslite": "0.0.6",
"sanitize-caja": "0.1.2" "isarray": "0.0.1",
"leaflet": "0.7.7",
"mustache": "0.7.3",
"sanitize-caja": "0.1.3"
}, },
"devDependencies": { "devDependencies": {
"browserify": "^6.3.2", "browserify": "^6.3.2",
......
...@@ -7,18 +7,17 @@ module.exports = function(path, accessToken) { ...@@ -7,18 +7,17 @@ module.exports = function(path, accessToken) {
accessToken = accessToken || L.cedarmaps.accessToken; accessToken = accessToken || L.cedarmaps.accessToken;
if (!accessToken && config.REQUIRE_ACCESS_TOKEN) { if (!accessToken && config.REQUIRE_ACCESS_TOKEN) {
// TODO: Change the urls for getting access token
throw new Error('An API access token is required to use cedarmaps.js. ' + throw new Error('An API access token is required to use cedarmaps.js. ' +
'See https://www.mapbox.com/mapbox.js/api/v' + version + '/api-access-tokens/'); 'See https://www.mapbox.com/mapbox.js/api/v' + version + '/api-access-tokens/');
} }
var url = ('https:' === document.location.protocol || config.FORCE_HTTPS) ? config.HTTPS_URL : config.HTTP_URL; var url = (document.location.protocol === 'https:' || config.FORCE_HTTPS) ? config.HTTPS_URL : config.HTTP_URL;
url = url.replace(/\/v4$/, '');
url += path; url += path;
url += url.indexOf('?') !== -1 ? '&access_token=' : '?access_token='; url += url.indexOf('?') !== -1 ? '&access_token=' : '?access_token=';
if (config.REQUIRE_ACCESS_TOKEN) { if (config.REQUIRE_ACCESS_TOKEN) {
if (accessToken[0] === 's') { if (accessToken[0] === 's') {
// TODO: Change the urls for getting access token
throw new Error('Use a public access token (pk.*) with Mapbox.js, not a secret access token (sk.*). ' + throw new Error('Use a public access token (pk.*) with Mapbox.js, not a secret access token (sk.*). ' +
'See https://www.mapbox.com/mapbox.js/api/v' + version + '/api-access-tokens/'); 'See https://www.mapbox.com/mapbox.js/api/v' + version + '/api-access-tokens/');
} }
......
'use strict'; 'use strict';
var util = require('../mapbox.js/src/util'), var isArray = require('isarray'),
urlhelper = require('./url'), util = require('../mapbox.js/src/util'),
format_url = require('./format_url'),
//feedback = require('./feedback'), //feedback = require('./feedback'),
request = require('./request'); request = require('./request');
// Low-level geocoding interface - wraps specific API calls and their // Low-level geocoding interface - wraps specific API calls and their
// return values. // return values.
module.exports = function(url, options) { module.exports = function(url, options) {
if (!options) options = {};
var geocoder = {}; var geocoder = {};
util.strict(url, 'string'); util.strict(url, 'string');
if (url.indexOf('/') === -1) { if (url.indexOf('/') === -1) {
url = urlhelper('/geocode/' + url + '/{query}.json', options && options.accessToken); url = format_url('/geocode/' + url + '/{query}.json', options.accessToken, 5);
}
function roundTo(latLng, precision) {
var mult = Math.pow(10, precision);
latLng.lat = Math.round(latLng.lat * mult) / mult;
latLng.lng = Math.round(latLng.lng * mult) / mult;
return latLng;
} }
geocoder.getURL = function() { geocoder.getURL = function() {
...@@ -22,24 +30,58 @@ module.exports = function(url, options) { ...@@ -22,24 +30,58 @@ module.exports = function(url, options) {
}; };
geocoder.queryURL = function(_) { geocoder.queryURL = function(_) {
var query; var isObject = !(isArray(_) || typeof _ === 'string'),
query = isObject ? _.query : _;
if (typeof _ !== 'string') { if (isArray(query)) {
var parts = []; var parts = [];
for (var i = 0; i < _.length; i++) { for (var i = 0; i < query.length; i++) {
parts[i] = encodeURIComponent(_[i]); parts[i] = encodeURIComponent(query[i]);
} }
query = parts.join(';'); query = parts.join(';');
} else { } else {
query = encodeURIComponent(_); query = encodeURIComponent(query);
}
//feedback.record({ geocoding: query });
var url = L.Util.template(geocoder.getURL(), {query: query});
/*
* Handling cedarmaps' API options for geocoding
*/
if (isObject && _.limit) {
url += '&limit=' + _.limit;
} }
//feedback.record({geocoding: query}); if (isObject && _.distance) {
return L.Util.template(geocoder.getURL(), {query: query}); url += '&distance=' + _.distance;
}
if (isObject && _.ne && _.sw) {
url += '&ne=' + _.ne + '&sw=' + _.sw;
}
if (isObject && _.type) {
if (isArray(_.type)) {
url += '&type=' + _.type.join(',');
} else {
url += '&type=' + _.type;
}
}
if (isObject && _.proximity) {
var proximity = roundTo(L.latLng(_.proximity), 3);
url += '&proximity=' + proximity.lng + ',' + proximity.lat;
}
return url;
}; };
geocoder.query = function(_, callback) { geocoder.query = function(_, callback) {
util.strict(callback, 'function'); util.strict(callback, 'function');
request(geocoder.queryURL(_), function(err, json) { request(geocoder.queryURL(_), function(err, json) {
if (json && (json.length || json.results)) { if (json && (json.length || json.results)) {
callback(null, json); callback(null, json);
......
...@@ -22,7 +22,9 @@ var GeocoderControl = L.Control.extend({ ...@@ -22,7 +22,9 @@ var GeocoderControl = L.Control.extend({
}, },
setURL: function(_) { setURL: function(_) {
this.geocoder = geocoder(_, {accessToken: this.options.accessToken}); this.geocoder = geocoder(_, {
accessToken: this.options.accessToken
});
return this; return this;
}, },
...@@ -51,7 +53,7 @@ var GeocoderControl = L.Control.extend({ ...@@ -51,7 +53,7 @@ var GeocoderControl = L.Control.extend({
} }
}, },
_closeIfOpen: function(e) { _closeIfOpen: function() {
if (L.DomUtil.hasClass(this._container, 'active') && if (L.DomUtil.hasClass(this._container, 'active') &&
!this.options.keepOpen) { !this.options.keepOpen) {
L.DomUtil.removeClass(this._container, 'active'); L.DomUtil.removeClass(this._container, 'active');
...@@ -138,7 +140,14 @@ var GeocoderControl = L.Control.extend({ ...@@ -138,7 +140,14 @@ var GeocoderControl = L.Control.extend({
for (var i = 0, l = Math.min(features.length, 10); i < l; i++) { for (var i = 0, l = Math.min(features.length, 10); i < l; i++) {
var feature = features[i]; var feature = features[i];
var name = feature.name; var name = feature.name;
var address = feature.address; var addressComponents = [];
//if (feature.components.country) addressComponents.push(feature.components.country);
if (feature.components.city) addressComponents.push(feature.components.city);
if (feature.components.districts[0]) addressComponents.push(feature.components.districts[0]);
if (feature.components.localities[0]) addressComponents.push(feature.components.localities[0]);
var address = addressComponents.join('، ');
if (!name.length) continue; if (!name.length) continue;
var r = L.DomUtil.create('a', '', this._results); var r = L.DomUtil.create('a', '', this._results);
...@@ -184,13 +193,19 @@ var GeocoderControl = L.Control.extend({ ...@@ -184,13 +193,19 @@ var GeocoderControl = L.Control.extend({
L.DomEvent.preventDefault(e); L.DomEvent.preventDefault(e);
if (this._input.value === '') return this._updateSubmit(); if (this._input.value === '') return this._updateSubmit();
L.DomUtil.addClass(this._container, 'searching'); L.DomUtil.addClass(this._container, 'searching');
this.geocoder.query(this._input.value, this._updateSubmit); this.geocoder.query({
query: this._input.value,
proximity: this.options.proximity ? this._map.getCenter() : false
}, this._updateSubmit);
}, },
_autocomplete: function(e) { _autocomplete: function() {
if (!this.options.autocomplete) return; if (!this.options.autocomplete) return;
if (this._input.value === '') return this._updateAutocomplete(); if (this._input.value === '') return this._updateAutocomplete();
this.geocoder.query(this._input.value, this._updateAutocomplete); this.geocoder.query({
query: this._input.value,
proximity: this.options.proximity ? this._map.getCenter() : false
}, this._updateAutocomplete);
} }
}); });
......
'use strict';
require('../mapbox.js/src/index'); require('../mapbox.js/src/index');
require('./cedarmaps'); require('./cedarmaps');
...@@ -13,18 +13,19 @@ module.exports = function(url, callback) { ...@@ -13,18 +13,19 @@ module.exports = function(url, callback) {
if (!('withCredentials' in new window.XMLHttpRequest())) { if (!('withCredentials' in new window.XMLHttpRequest())) {
// XDomainRequest in use; doesn't support cross-protocol requests // XDomainRequest in use; doesn't support cross-protocol requests
return document.location.protocol; return document.location.protocol;
} else if ('https:' === protocol || 'https:' === document.location.protocol || config.FORCE_HTTPS) { } else if (protocol === 'https:' || document.location.protocol === 'https:' || config.FORCE_HTTPS) {
return 'https:'; return 'https:';
} else { } else {
return 'http:'; return 'http:';
} }
}); });
return corslite(url, onload);
function onload(err, resp) { function onload(err, resp) {
if (!err && resp) { if (!err && resp) {
resp = JSON.parse(resp.responseText); resp = JSON.parse(resp.responseText);
} }
callback(err, resp); callback(err, resp);
} }
return corslite(url, onload);
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment