Skip to content

Commit

Permalink
support for contour_meters Isochrone API param mapbox/playground#193
Browse files Browse the repository at this point in the history
  • Loading branch information
GrigoryDobrov committed Jul 1, 2022
1 parent 1eab68b commit 21372d7
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 12 deletions.
5 changes: 3 additions & 2 deletions docs/services.md
Expand Up @@ -2134,8 +2134,9 @@ Given a location and a routing profile, retrieve up to four isochrone contours
- `config` **[Object][200]**
- `config.profile` **(`"driving"` \| `"walking"` \| `"cycling"`)** A Mapbox Directions routing profile ID. (optional, default `"driving"`)
- `config.coordinates` **[Coordinates][232]** A {longitude,latitude} coordinate pair around which to center the isochrone lines.
- `config.minutes` **[Array][210]<[number][205]>** The times in minutes to use for each isochrone contour. You can specify up to four contours. Times must be in increasing order. The maximum time that can be specified is 60 minutes.
- `config.colors` **[Array][210]<[string][201]>?** The colors to use for each isochrone contour, specified as hex values without a leading # (for example, ff0000 for red). If this parameter is used, there must be the same number of colors as there are entries in contours_minutes. If no colors are specified, the Isochrone API will assign a default rainbow color scheme to the output.
- `config.minutes` **[Array][210]<[number][205]>?** The times in minutes to use for each isochrone contour. You can specify up to four contours. Times must be in increasing order. The maximum time that can be specified is 60 minutes. Setting minutes and meters in the same time is an error.
- `config.meters` **[Array][210]<[number][205]>?** The distances in meters to use for each isochrone contour. You can specify up to four contours. Distances must be in increasing order. The maximum distance that can be specified is 100000 meters. Setting minutes and meters in the same time is an error.
- `config.colors` **[Array][210]<[string][201]>?** The colors to use for each isochrone contour, specified as hex values without a leading # (for example, ff0000 for red). If this parameter is used, there must be the same number of colors as there are entries in contours_minutes or contours_meters. If no colors are specified, the Isochrone API will assign a default rainbow color scheme to the output.
- `config.polygons` **[boolean][202]?** Specify whether to return the contours as GeoJSON polygons (true) or linestrings (false, default). When polygons=true, any contour that forms a ring is returned as a polygon.
- `config.denoise` **[number][205]?** A floating point value from 0.0 to 1.0 that can be used to remove smaller contours. The default is 1.0. A value of 1.0 will only return the largest contour for a given time value. A value of 0.5 drops any contours that are less than half the area of the largest contour in the set of contours for that same time value.
- `config.generalize` **[number][205]?** A positive floating point value in meters used as the tolerance for Douglas-Peucker generalization. There is no upper bound. If no value is specified in the request, the Isochrone API will choose the most optimized generalization to use for the request. Note that the generalization of contours can lead to self-intersections, as well as intersections of adjacent contours.
Expand Down
70 changes: 69 additions & 1 deletion services/__tests__/isochrone.test.js
Expand Up @@ -51,7 +51,7 @@ describe('getContours', () => {
});
});

test('with all config options', () => {
test('with all config options (minutes)', () => {
isochrone.getContours({
coordinates: [-118.22258, 33.99038],
minutes: [5, 10, 15, 20],
Expand Down Expand Up @@ -79,6 +79,34 @@ describe('getContours', () => {
});
});

test('with all config options (meters)', () => {
isochrone.getContours({
coordinates: [-118.22258, 33.99038],
meters: [5000, 10000, 15000, 20000],
profile: 'walking',
polygons: true,
colors: ['6706ce', '04e813', '4286f4', '555555'],
denoise: 0,
generalize: 0
});

expect(tu.requestConfig(isochrone)).toEqual({
path: '/isochrone/v1/mapbox/:profile/:coordinates',
method: 'GET',
params: {
coordinates: '-118.22258,33.99038',
profile: 'walking'
},
query: {
contours_meters: '5000,10000,15000,20000',
polygons: 'true',
contours_colors: '6706ce,04e813,4286f4,555555',
denoise: 0,
generalize: 0
}
});
});

test('hex colors with # are removed', () => {
isochrone.getContours({
coordinates: [-118.22258, 33.99038],
Expand Down Expand Up @@ -109,6 +137,15 @@ describe('getContours', () => {
).toThrow('minutes must contain between 1 and 4 contour values');
});

test('errors if more than 4 contours_meters requested', () => {
expect(() =>
isochrone.getContours({
coordinates: [-118.22258, 33.99038],
meters: [5000, 10000, 15000, 20000, 30000]
})
).toThrow('meters must contain between 1 and 4 contour values');
});

test('errors if minute value is greater than 60', () => {
expect(() =>
isochrone.getContours({
Expand All @@ -118,6 +155,15 @@ describe('getContours', () => {
).toThrow('minutes must be less than 60');
});

test('errors if meter value is greater than 100000', () => {
expect(() =>
isochrone.getContours({
coordinates: [-118.22258, 33.99038],
meters: [10000, 50000, 100000, 100001]
})
).toThrow('meters must be less than 100000');
});

test('errors if generalize is less than 0', () => {
expect(() =>
isochrone.getContours({
Expand All @@ -138,4 +184,26 @@ describe('getContours', () => {
})
).toThrow('colors should have the same number of entries as minutes');
});

test('colors should have the same number of entries as meters', () => {
expect(() =>
isochrone.getContours({
coordinates: [-118.22258, 33.99038],
meters: [5000, 10000, 15000, 20000],
profile: 'walking',
colors: ['6706ce', '04e813']
})
).toThrow('colors should have the same number of entries as meters');
});

test('either meters or minutes should be specified', () => {
expect(() =>
isochrone.getContours({
coordinates: [-118.22258, 33.99038],
minutes: [5, 10, 15, 20],
meters: [5000, 10000, 15000, 20000],
profile: 'walking'
})
).toThrow("minutes and meters can't be specified at the same time");
});
});
40 changes: 31 additions & 9 deletions services/isochrone.js
Expand Up @@ -18,8 +18,9 @@ var Isochrone = {};
* @param {Object} config
* @param {'driving'|'walking'|'cycling'} [config.profile="driving"] - A Mapbox Directions routing profile ID.
* @param {Coordinates} config.coordinates - A {longitude,latitude} coordinate pair around which to center the isochrone lines.
* @param {Array<number>} config.minutes - The times in minutes to use for each isochrone contour. You can specify up to four contours. Times must be in increasing order. The maximum time that can be specified is 60 minutes.
* @param {Array<string>} [config.colors] - The colors to use for each isochrone contour, specified as hex values without a leading # (for example, ff0000 for red). If this parameter is used, there must be the same number of colors as there are entries in contours_minutes. If no colors are specified, the Isochrone API will assign a default rainbow color scheme to the output.
* @param {Array<number>} [config.minutes] - The times in minutes to use for each isochrone contour. You can specify up to four contours. Times must be in increasing order. The maximum time that can be specified is 60 minutes. Setting minutes and meters in the same time is an error.
* @param {Array<number>} [config.meters] - The distances in meters to use for each isochrone contour. You can specify up to four contours. Distances must be in increasing order. The maximum distance that can be specified is 100000 meters. Setting minutes and meters in the same time is an error.
* @param {Array<string>} [config.colors] - The colors to use for each isochrone contour, specified as hex values without a leading # (for example, ff0000 for red). If this parameter is used, there must be the same number of colors as there are entries in contours_minutes or contours_meters. If no colors are specified, the Isochrone API will assign a default rainbow color scheme to the output.
* @param {boolean} [config.polygons] - Specify whether to return the contours as GeoJSON polygons (true) or linestrings (false, default). When polygons=true, any contour that forms a ring is returned as a polygon.
* @param {number} [config.denoise] - A floating point value from 0.0 to 1.0 that can be used to remove smaller contours. The default is 1.0. A value of 1.0 will only return the largest contour for a given time value. A value of 0.5 drops any contours that are less than half the area of the largest contour in the set of contours for that same time value.
* @param {number} [config.generalize] - A positive floating point value in meters used as the tolerance for Douglas-Peucker generalization. There is no upper bound. If no value is specified in the request, the Isochrone API will choose the most optimized generalization to use for the request. Note that the generalization of contours can lead to self-intersections, as well as intersections of adjacent contours.
Expand All @@ -31,6 +32,7 @@ Isochrone.getContours = function(config) {
profile: v.oneOf('driving', 'walking', 'cycling'),
coordinates: v.coordinates,
minutes: v.arrayOf(v.number),
meters: v.arrayOf(v.number),
colors: v.arrayOf(v.string),
polygons: v.boolean,
denoise: v.number,
Expand All @@ -39,28 +41,47 @@ Isochrone.getContours = function(config) {

config.profile = config.profile || 'driving';

var minutesCount = config.minutes.length;
if (config.minutes !== undefined && config.meters !== undefined) {
throw new Error("minutes and meters can't be specified at the same time");
}
var contours = config.minutes ? config.minutes : config.meters;
var contours_name = config.minutes ? 'minutes' : 'meters';
var contoursCount = contours.length;

if (minutesCount < 1 || minutesCount > 4) {
throw new Error('minutes must contain between 1 and 4 contour values');
if (contoursCount < 1 || contoursCount > 4) {
throw new Error(
contours_name + ' must contain between 1 and 4 contour values'
);
}

if (
config.colors !== undefined &&
config.minutes !== undefined &&
config.colors.length !== config.minutes.length
contours !== undefined &&
config.colors.length !== contoursCount
) {
throw new Error('colors should have the same number of entries as minutes');
throw new Error(
'colors should have the same number of entries as ' + contours_name
);
}

if (
config.minutes !== undefined &&
!config.minutes.every(function(minute) {
return minute <= 60;
})
) {
throw new Error('minutes must be less than 60');
}

if (
config.meters !== undefined &&
!config.meters.every(function(meter) {
return meter <= 100000;
})
) {
throw new Error('meters must be less than 100000');
}

if (config.generalize && config.generalize < 0) {
throw new Error('generalize tolerance must be a positive number');
}
Expand All @@ -74,7 +95,8 @@ Isochrone.getContours = function(config) {
}

var query = stringifyBooleans({
contours_minutes: config.minutes.join(','),
contours_minutes: config.minutes ? config.minutes.join(',') : null,
contours_meters: config.meters ? config.meters.join(',') : null,
contours_colors: config.colors ? config.colors.join(',') : null,
polygons: config.polygons,
denoise: config.denoise,
Expand Down

0 comments on commit 21372d7

Please sign in to comment.