make 'cancel' function in FileSource optional
update README
This commit is contained in:
103
README.md
103
README.md
@@ -27,7 +27,7 @@ Other platforms will fall back to a source compile with `npm run build`. To comp
|
||||
## Rendering a map tile
|
||||
|
||||
```js
|
||||
var map = new mbgl.Map(fileSource);
|
||||
var map = new mbgl.Map({ request: function() {} });
|
||||
map.load(require('./test/fixtures/style.json'));
|
||||
map.render({}, function(err, image) {
|
||||
if (err) throw err;
|
||||
@@ -61,22 +61,20 @@ npm test
|
||||
|
||||
## Implementing a file source
|
||||
|
||||
When creating a `Map` object, you need to pass a `FileSource` object as the first parameter
|
||||
When creating a `Map`, you must pass an options object (with a required `request` and optional `cancel` method) as the first parameter.
|
||||
|
||||
```js
|
||||
var request = require('request');
|
||||
|
||||
var fileSource = new mbgl.FileSource();
|
||||
fileSource.request = function(req) {
|
||||
// TODO
|
||||
};
|
||||
|
||||
fileSource.cancel = function(req) {
|
||||
// TODO
|
||||
};
|
||||
var map = new mbgl.Map({
|
||||
request: function(req) {
|
||||
// TODO
|
||||
},
|
||||
cancel: function(req) {
|
||||
// TODO
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The `request()` method starts a new request to a file, while `cancel()` tells your FileSource implementation to cancel the request (if possible). The `req` parameter has two properties:
|
||||
The `request()` method starts a new request to a file, while `cancel()` tells the FileSource to cancel the request (if possible). The `req` parameter has two properties:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -104,12 +102,13 @@ It has no significance for anything but serves as a hint to your implemention as
|
||||
A sample implementation that reads files from disk would look like the following:
|
||||
|
||||
```js
|
||||
fileSource.request = function(req) {
|
||||
fs.readFile(path.join('base/path', req.url), function(err, data) {
|
||||
req.respond(err, { data: data });
|
||||
});
|
||||
};
|
||||
fileSource.cancel = function() {};
|
||||
var map = new mbgl.Map({
|
||||
request: function(req) {
|
||||
fs.readFile(path.join('base/path', req.url), function(err, data) {
|
||||
req.respond(err, { data: data });
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
This is a very barebones implementation and you'll probably want a better implementation. E.g. it passes the url verbatim to the file system, but you'd want add some logic that normalizes `http` URLs. You'll notice that once your implementation has obtained the requested file, you have to deliver it to the requestee by calling `req.respond()`, which takes either an error object or `null` and an object with several settings:
|
||||
@@ -129,51 +128,51 @@ A sample implementation that uses [`request`](https://github.com/request/request
|
||||
var mbgl = require('mapbox-gl-native');
|
||||
var request = require('request');
|
||||
|
||||
var fileSource = new mbgl.FileSource();
|
||||
fileSource.request = function(req) {
|
||||
request({
|
||||
url: req.url,
|
||||
encoding: null,
|
||||
gzip: true
|
||||
}, function (err, res, body) {
|
||||
if (req.canceled) {
|
||||
return;
|
||||
}
|
||||
var map = new mbgl.Map({
|
||||
request: function(req) {
|
||||
request({
|
||||
url: req.url,
|
||||
encoding: null,
|
||||
gzip: true
|
||||
}, function (err, res, body) {
|
||||
if (req.canceled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
req.respond(err);
|
||||
} else if (res.statusCode == 200) {
|
||||
var response = {};
|
||||
if (err) {
|
||||
req.respond(err);
|
||||
} else if (res.statusCode == 200) {
|
||||
var response = {};
|
||||
|
||||
if (res.headers.modified) { response.modified = new Date(res.headers.modified); }
|
||||
if (res.headers.expires) { response.expires = new Date(res.headers.expires); }
|
||||
if (res.headers.etag) { response.etag = res.headers.etag; }
|
||||
response.data = body;
|
||||
req.respond(null, response);
|
||||
} else {
|
||||
req.respond(new Error(JSON.parse(body).message));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
fileSource.cancel = function(req) {
|
||||
req.canceled = true;
|
||||
};
|
||||
if (res.headers.modified) { response.modified = new Date(res.headers.modified); }
|
||||
if (res.headers.expires) { response.expires = new Date(res.headers.expires); }
|
||||
if (res.headers.etag) { response.etag = res.headers.etag; }
|
||||
response.data = body;
|
||||
req.respond(null, response);
|
||||
} else {
|
||||
req.respond(new Error(JSON.parse(body).message));
|
||||
}
|
||||
});
|
||||
},
|
||||
cancel: function(req) {
|
||||
req.canceled = true;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Note that in reality, Mapbox GL uses two types of protocols: `asset://` for files that should be loaded from some local static system, and `http://` (and `https://`), which should be loaded from the internet. However, stylesheets are free to use other protocols too, if your implementation of FileSource supports these; e.g. you could use `s3://` to indicate that files are supposed to be loaded from S3.
|
||||
Note that in reality, Mapbox GL uses two types of protocols: `asset://` for files that should be loaded from some local static system, and `http://` (and `https://`), which should be loaded from the internet. However, stylesheets are free to use other protocols too, if your implementation of `request` supports these; e.g. you could use `s3://` to indicate that files are supposed to be loaded from S3.
|
||||
|
||||
## Mapbox API Access tokens
|
||||
|
||||
To use styles that rely on Mapbox vector tiles, you must pass an [API access token](https://www.mapbox.com/developers/api/#access-tokens) in your `FileSource` implementation with requests to `mapbox://` protocols.
|
||||
To use styles that rely on Mapbox vector tiles, you must pass an [API access token](https://www.mapbox.com/developers/api/#access-tokens) in your `request` implementation with requests to `mapbox://` protocols.
|
||||
|
||||
```js
|
||||
var mbgl = require('mapbox-gl-native');
|
||||
var request = require('request');
|
||||
var url = require('url');
|
||||
|
||||
var fileSource = new mbgl.FileSource();
|
||||
fileSource.request = function(req) {
|
||||
var options = {};
|
||||
options.request = function(req) {
|
||||
var opts = {
|
||||
url: req.url,
|
||||
encoding: null,
|
||||
@@ -201,7 +200,7 @@ fileSource.request = function(req) {
|
||||
});
|
||||
}
|
||||
|
||||
var map = mbgl.Map(fileSource);
|
||||
var map = new mbgl.Map(options);
|
||||
var style = mapboxStyle; // includes a datasource with a reference to something like `mapbox://mapbox.mapbox-streets-v6`
|
||||
|
||||
map.load(style);
|
||||
|
||||
@@ -9,18 +9,16 @@ var PNG = require('pngjs').PNG;
|
||||
|
||||
var base = path.join(path.dirname(process.mainModule.filename), '../test');
|
||||
|
||||
var fileSource = new mbgl.FileSource();
|
||||
fileSource.request = function(req) {
|
||||
fs.readFile(path.join(base, req.url), function(err, data) {
|
||||
req.respond(err, { data: data });
|
||||
});
|
||||
};
|
||||
var map = new mbgl.Map({
|
||||
request: function(req) {
|
||||
fs.readFile(path.join(base, req.url), function(err, data) {
|
||||
req.respond(err, { data: data });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
fileSource.cancel = function(req) {
|
||||
};
|
||||
|
||||
var map = new mbgl.Map(fileSource);
|
||||
map.load(require('../test/fixtures/style.json'));
|
||||
|
||||
map.render({}, function(err, data) {
|
||||
if (err) throw err;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"nan": "^1.8.4",
|
||||
"nan": "^1.9.0",
|
||||
"node-pre-gyp": "^0.6.7"
|
||||
},
|
||||
"bundledDependencies": [
|
||||
|
||||
@@ -61,17 +61,17 @@ NAN_METHOD(NodeMap::New) {
|
||||
}
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsObject()) {
|
||||
return NanThrowTypeError("Requires FileSource options as first argument");
|
||||
return NanThrowTypeError("Requires an options object as first argument");
|
||||
}
|
||||
|
||||
auto options = args[0]->ToObject();
|
||||
|
||||
// Check that request() and cancel() are defined.
|
||||
if (!options->Has(NanNew("request")) || !options->Get(NanNew("request"))->IsFunction()) {
|
||||
return NanThrowError("FileSource options must have a request member function");
|
||||
return NanThrowError("Options object must have a 'request' method");
|
||||
}
|
||||
if (!options->Has(NanNew("cancel")) || !options->Get(NanNew("cancel"))->IsFunction()) {
|
||||
return NanThrowError("FileSource options must have a cancel member function");
|
||||
if (options->Has(NanNew("cancel")) && !options->Get(NanNew("cancel"))->IsFunction()) {
|
||||
return NanThrowError("Options object 'cancel' property must be a function");
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -44,13 +44,10 @@ public:
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Instance
|
||||
private:
|
||||
NodeMap(v8::Handle<v8::Object> source);
|
||||
NodeMap(v8::Handle<v8::Object>);
|
||||
~NodeMap();
|
||||
|
||||
private:
|
||||
// For retaining the FileSource object.
|
||||
v8::Persistent<v8::Object> source;
|
||||
|
||||
mbgl::HeadlessView view;
|
||||
NodeFileSource fs;
|
||||
std::unique_ptr<mbgl::Map> map;
|
||||
|
||||
@@ -31,31 +31,27 @@ function setup(options, callback) {
|
||||
callback(new mbgl.Map(options));
|
||||
}
|
||||
|
||||
function getFileSourceOptions(gzip, t) {
|
||||
var options = {};
|
||||
function getOptions(gzip, t) {
|
||||
return {
|
||||
request: function(req) {
|
||||
var parts = req.url.split('.');
|
||||
var filetype = parts[parts.length - 1];
|
||||
|
||||
options.request = function(req) {
|
||||
var parts = req.url.split('.');
|
||||
var filetype = parts[parts.length - 1];
|
||||
|
||||
request({
|
||||
url: 'http://localhost:' + server.address().port + path.join('/', req.url),
|
||||
encoding: null,
|
||||
gzip: filetype === 'pbf' ? gzip : true,
|
||||
headers: {
|
||||
'Accept-Encoding': 'gzip'
|
||||
}
|
||||
}, function (err, res, body) {
|
||||
t.error(err);
|
||||
var response = {};
|
||||
response.data = res.body;
|
||||
req.respond(null, response);
|
||||
});
|
||||
request({
|
||||
url: 'http://localhost:' + server.address().port + path.join('/', req.url),
|
||||
encoding: null,
|
||||
gzip: filetype === 'pbf' ? gzip : true,
|
||||
headers: {
|
||||
'Accept-Encoding': 'gzip'
|
||||
}
|
||||
}, function (err, res, body) {
|
||||
t.error(err);
|
||||
var response = {};
|
||||
response.data = res.body;
|
||||
req.respond(null, response);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
options.cancel = function(req) {};
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
test('gzip', function(t) {
|
||||
@@ -64,7 +60,7 @@ test('gzip', function(t) {
|
||||
if (msg.severity == 'ERROR') t.error(msg);
|
||||
});
|
||||
|
||||
setup(getFileSourceOptions(true, t), function(map) {
|
||||
setup(getOptions(true, t), function(map) {
|
||||
map.load(style);
|
||||
map.render({}, function(err, data) {
|
||||
mbgl.removeAllListeners('message');
|
||||
@@ -110,7 +106,7 @@ test('gzip', function(t) {
|
||||
}
|
||||
});
|
||||
|
||||
setup(getFileSourceOptions(false, t), function(map) {
|
||||
setup(getOptions(false, t), function(map) {
|
||||
map.load(style);
|
||||
map.render({}, function(err, data) {
|
||||
map.release();
|
||||
|
||||
@@ -34,39 +34,35 @@ test('Map', function(t) {
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test('should require a FileSource options object as first parameter', function(t) {
|
||||
t.test('should require an options object as first parameter', function(t) {
|
||||
t.throws(function() {
|
||||
new mbgl.Map();
|
||||
}, /Requires FileSource options as first argument/);
|
||||
}, /Requires an options object as first argument/);
|
||||
|
||||
t.throws(function() {
|
||||
new mbgl.Map('options');
|
||||
}, /Requires FileSource options as first argument/);
|
||||
}, /Requires an options object as first argument/);
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test('should require the FileSource options object to have request and cancel methods', function(t) {
|
||||
t.test('should require then options object to have request and cancel methods', function(t) {
|
||||
var options = {};
|
||||
|
||||
t.throws(function() {
|
||||
new mbgl.Map(options);
|
||||
}, /FileSource options must have a request member function/);
|
||||
}, /Options object must have a 'request' method/);
|
||||
|
||||
options.request = 'test';
|
||||
t.throws(function() {
|
||||
new mbgl.Map(options);
|
||||
}, /FileSource options must have a request member function/);
|
||||
}, /Options object must have a 'request' method/);
|
||||
|
||||
options.request = function() {};
|
||||
t.throws(function() {
|
||||
new mbgl.Map(options);
|
||||
}, /FileSource options must have a cancel member function/);
|
||||
|
||||
options.cancel = 'test';
|
||||
t.throws(function() {
|
||||
new mbgl.Map(options);
|
||||
}, /FileSource options must have a cancel member function/);
|
||||
}, /Options object 'cancel' property must be a function/);
|
||||
|
||||
options.cancel = function() {};
|
||||
t.doesNotThrow(function() {
|
||||
|
||||
Reference in New Issue
Block a user