arcgis-parser
Version:
Parser for ArcGIS REST Services to human friendly JSON.
287 lines (263 loc) • 7.16 kB
JavaScript
;
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var proj4 = _interopDefault(require('proj4'));
var URL = require('url');
/**
* @typedef {Object} Service
* @property {string} type
* @property {string} version
* @property {string} title
*/
/**
* Parse Service
*
* @param {Object} json
* @returns {Service} Parsed Service
*/
function parseService (json) {
const documentInfo = json.documentInfo || {};
const title = documentInfo.Title || null;
const version = json.currentVersion || null;
return {
type: (title && version) ? 'ArcGIS REST Service' : null,
version: version,
title: title
}
}
/**
* Clean URL
*
* @param {string} url Url
* @returns {string} Cleaned URL
*/
function clean (url) {
return url
.replace(/%3A/g, ':')
.replace(/%7B/g, '{')
.replace(/%7D/g, '}')
.replace(/%2C/g, ',')
}
/**
* Map Zoom
*
* @param {number} scale
* @returns {number} zoom level
*/
function mapZoom (scale) {
if (scale === null || scale === undefined) throw new Error('scale is required')
if (typeof scale !== 'number') throw new Error('scale should be a number')
const lookup = {
0: 591657527.591555,
1: 295828763.795777,
2: 147914381.897889,
3: 73957190.948944,
4: 36978595.474472,
5: 18489297.737236,
6: 9244648.868618,
7: 4622324.434309,
8: 2311162.217155,
9: 1155581.108577,
10: 577790.554289,
11: 288895.277144,
12: 144447.638572,
13: 72223.819286,
14: 36111.909643,
15: 18055.954822,
16: 9027.977411,
17: 4513.988705,
18: 2256.994353,
19: 1128.497176,
20: 564.248588,
21: 282.124294,
22: 141.062147,
23: 70.5310735,
24: 35,
25: 20,
26: 10,
27: 5,
28: 2.5,
29: 1,
30: 1
};
for (var zoom = 0; zoom < Object.keys(lookup).length; zoom++) {
if (Math.floor(scale) === Math.floor(lookup[zoom])) return zoom
if (Math.floor(scale) > Math.floor(lookup[zoom])) {
if (zoom === 0) return 0
return zoom - 1
}
}
return null
}
/**
* @typedef {Object} Layer
* @property {string} title
* @property {string} identifier
* @property {string} author
* @property {string} abstract
* @property {string} attribution
* @property {string} category
* @property {string} keywords
* @property {string} format
* @property {string} formats
* @property {number} minzoom
* @property {number} maxzoom
* @property {Array<number>} bbox
*/
/**
* Parse Layer
*
* @param {string} url
* @param {Object} json
* @returns {Layer} Parsed Layer
*/
function parseLayer (url, json) {
const documentInfo = json.documentInfo || {};
const title = documentInfo.Title || null;
var identifier;
const identifierMatch = url.match(/services\/(.+)\//);
if (identifierMatch.length > 0) identifier = identifierMatch[1];
// Formats
var format$$1 = 'jpg';
const formats = json.supportedImageFormatTypes || '';
if (formats.match(/png/i)) format$$1 = 'png';
else if (formats.match(/jpg/i)) format$$1 = 'jpg';
// BBox
var bbox = null;
if (json.fullExtent) {
const west = json.fullExtent.xmin;
const south = json.fullExtent.ymin;
const east = json.fullExtent.xmax;
const north = json.fullExtent.ymax;
const wkid = json.fullExtent.spatialReference.latestWkid;
switch (wkid) {
case 4326:
bbox = [west, south, east, north];
break
default:
let proj;
try {
proj = proj4('EPSG:' + wkid);
} catch (e) {
proj = null;
}
if (proj) {
const westsouth = proj.inverse([west, south]);
const eastnorth = proj.inverse([east, north]);
bbox = [westsouth[0], westsouth[1], eastnorth[0], eastnorth[1]];
} else bbox = null;
}
}
var minzoom;
var maxzoom;
if (json.minScale && json.maxScale) {
minzoom = (json.minScale !== 0) ? mapZoom(json.minScale) : 0;
maxzoom = (json.maxScale !== 0) ? mapZoom(json.maxScale) : 18;
}
minzoom = minzoom || 0;
maxzoom = maxzoom || 18;
bbox = bbox || [-180, -85, 180, 85];
return {
title: title,
identifier: identifier,
author: documentInfo.Author || null,
abstract: json.description || json.serviceDescription || null,
attribution: json.copyrightText || null,
category: documentInfo.Category || null,
keywords: documentInfo.Keywords || null,
format: format$$1,
formats: formats,
minzoom: minzoom,
maxzoom: maxzoom,
bbox: bbox
}
}
/**
* Parse URL
*
* @param {string} url
* @param {Object} json
* @returns {URL} Parsed URL
*/
function parseUrl (url, json) {
const parse$$1 = URL.parse(url);
// getCapabilities
parse$$1.search = null;
parse$$1.query = {f: 'pjson'};
const getCapabilities = clean(URL.format(parse$$1));
// Slippy
var slippy = null;
// Map Server
if (json.capabilities && json.capabilities.includes('Map')) {
const formats = json.supportedImageFormatTypes || '';
const format$$1 = (formats.match(/png/i)) ? 'png' : 'jpg';
parse$$1.query = {
bbox: '{bbox4326}',
bboxSR: '4326',
imageSR: '3857',
size: '256,256',
format: format$$1,
transparent: 'false',
f: 'image'
};
parse$$1.path = null;
parse$$1.pathname = parse$$1.pathname + '/export';
slippy = clean(URL.format(parse$$1));
}
// Image Server
if (json.capabilities && json.capabilities.includes('Image')) {
const formats = json.supportedImageFormatTypes || '';
const format$$1 = (formats.match(/png/i)) ? 'png' : 'jpg';
parse$$1.query = {
bbox: '{bbox4326}',
bboxSR: '4326',
imageSR: '3857',
size: '256,256',
format: format$$1,
transparent: 'false',
f: 'image'
};
parse$$1.path = null;
parse$$1.pathname = parse$$1.pathname + '/exportImage';
slippy = clean(URL.format(parse$$1));
}
var world = null;
if (slippy) {
let bbox = parseLayer(url, json).bbox;
// EPSG:3857 doesn't support latitudes higher than 84 degrees
if (bbox[0] < -179) bbox[0] = -179;
if (bbox[1] < -84) bbox[1] = -84;
if (bbox[2] > 179) bbox[2] = 179;
if (bbox[3] > 84) bbox[3] = 84;
world = slippy.replace(/{bbox4326}/, bbox.join(','));
}
return {
getCapabilities: getCapabilities,
slippy: slippy,
world: world,
host: parse$$1.host
}
}
/**
* ArcGIS Parser
*
* @param {string} url ArcGIS REST service url
* @param {Object} json MapServer or ImageServer JSON
* @returns {Metadata} Metadata
* @example
* const url = 'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer?f=pjson'
* const response = await fetch(url)
* const json = await response.json()
* const metadata = arcgisParser(url, json)
* //=metadata
*/
function arcgisParser (url, json) {
if (!url) throw new Error('url is required')
if (!json) throw new Error('json is required')
return {
service: parseService(json),
layer: parseLayer(url, json),
url: parseUrl(url, json)
}
}
module.exports = arcgisParser;
module.exports.default = arcgisParser;