344 lines
11 KiB
JavaScript
344 lines
11 KiB
JavaScript
|
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.tokml = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||
|
var strxml = require('strxml'),
|
||
|
tag = strxml.tag,
|
||
|
encode = strxml.encode;
|
||
|
|
||
|
module.exports = function tokml(geojson, options) {
|
||
|
|
||
|
options = options || {
|
||
|
documentName: undefined,
|
||
|
documentDescription: undefined,
|
||
|
name: 'name',
|
||
|
description: 'description',
|
||
|
simplestyle: false,
|
||
|
timestamp: 'timestamp'
|
||
|
};
|
||
|
|
||
|
return '<?xml version="1.0" encoding="UTF-8"?>' +
|
||
|
tag('kml',
|
||
|
tag('Document',
|
||
|
documentName(options) +
|
||
|
documentDescription(options) +
|
||
|
root(geojson, options)
|
||
|
), [['xmlns', 'http://www.opengis.net/kml/2.2']]);
|
||
|
};
|
||
|
|
||
|
function feature(options, styleHashesArray) {
|
||
|
return function(_) {
|
||
|
if (!_.properties || !geometry.valid(_.geometry)) return '';
|
||
|
var geometryString = geometry.any(_.geometry);
|
||
|
if (!geometryString) return '';
|
||
|
|
||
|
var styleDefinition = '',
|
||
|
styleReference = '';
|
||
|
if (options.simplestyle) {
|
||
|
var styleHash = hashStyle(_.properties);
|
||
|
if (styleHash) {
|
||
|
if (geometry.isPoint(_.geometry) && hasMarkerStyle(_.properties)) {
|
||
|
if (styleHashesArray.indexOf(styleHash) === -1) {
|
||
|
styleDefinition = markerStyle(_.properties, styleHash);
|
||
|
styleHashesArray.push(styleHash);
|
||
|
}
|
||
|
styleReference = tag('styleUrl', '#' + styleHash);
|
||
|
} else if ((geometry.isPolygon(_.geometry) || geometry.isLine(_.geometry)) &&
|
||
|
hasPolygonAndLineStyle(_.properties)) {
|
||
|
if (styleHashesArray.indexOf(styleHash) === -1) {
|
||
|
styleDefinition = polygonAndLineStyle(_.properties, styleHash);
|
||
|
styleHashesArray.push(styleHash);
|
||
|
}
|
||
|
styleReference = tag('styleUrl', '#' + styleHash);
|
||
|
}
|
||
|
// Note that style of GeometryCollection / MultiGeometry is not supported
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return styleDefinition + tag('Placemark',
|
||
|
name(_.properties, options) +
|
||
|
description(_.properties, options) +
|
||
|
extendeddata(_.properties) +
|
||
|
timestamp(_.properties, options) +
|
||
|
geometryString +
|
||
|
styleReference);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function root(_, options) {
|
||
|
if (!_.type) return '';
|
||
|
var styleHashesArray = [];
|
||
|
|
||
|
switch (_.type) {
|
||
|
case 'FeatureCollection':
|
||
|
if (!_.features) return '';
|
||
|
return _.features.map(feature(options, styleHashesArray)).join('');
|
||
|
case 'Feature':
|
||
|
return feature(options, styleHashesArray)(_);
|
||
|
default:
|
||
|
return feature(options, styleHashesArray)({
|
||
|
type: 'Feature',
|
||
|
geometry: _,
|
||
|
properties: {}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function documentName(options) {
|
||
|
return (options.documentName !== undefined) ? tag('name', options.documentName) : '';
|
||
|
}
|
||
|
|
||
|
function documentDescription(options) {
|
||
|
return (options.documentDescription !== undefined) ? tag('description', options.documentDescription) : '';
|
||
|
}
|
||
|
|
||
|
function name(_, options) {
|
||
|
return _[options.name] ? tag('name', encode(_[options.name])) : '';
|
||
|
}
|
||
|
|
||
|
function description(_, options) {
|
||
|
return _[options.description] ? tag('description', encode(_[options.description])) : '';
|
||
|
}
|
||
|
|
||
|
function timestamp(_, options) {
|
||
|
return _[options.timestamp] ? tag('TimeStamp', tag('when', encode(_[options.timestamp]))) : '';
|
||
|
}
|
||
|
|
||
|
// ## Geometry Types
|
||
|
//
|
||
|
// https://developers.google.com/kml/documentation/kmlreference#geometry
|
||
|
var geometry = {
|
||
|
Point: function(_) {
|
||
|
return tag('Point', tag('coordinates', _.coordinates.join(',')));
|
||
|
},
|
||
|
LineString: function(_) {
|
||
|
return tag('LineString', tag('coordinates', linearring(_.coordinates)));
|
||
|
},
|
||
|
Polygon: function(_) {
|
||
|
if (!_.coordinates.length) return '';
|
||
|
var outer = _.coordinates[0],
|
||
|
inner = _.coordinates.slice(1),
|
||
|
outerRing = tag('outerBoundaryIs',
|
||
|
tag('LinearRing', tag('coordinates', linearring(outer)))),
|
||
|
innerRings = inner.map(function(i) {
|
||
|
return tag('innerBoundaryIs',
|
||
|
tag('LinearRing', tag('coordinates', linearring(i))));
|
||
|
}).join('');
|
||
|
return tag('Polygon', outerRing + innerRings);
|
||
|
},
|
||
|
MultiPoint: function(_) {
|
||
|
if (!_.coordinates.length) return '';
|
||
|
return tag('MultiGeometry', _.coordinates.map(function(c) {
|
||
|
return geometry.Point({ coordinates: c });
|
||
|
}).join(''));
|
||
|
},
|
||
|
MultiPolygon: function(_) {
|
||
|
if (!_.coordinates.length) return '';
|
||
|
return tag('MultiGeometry', _.coordinates.map(function(c) {
|
||
|
return geometry.Polygon({ coordinates: c });
|
||
|
}).join(''));
|
||
|
},
|
||
|
MultiLineString: function(_) {
|
||
|
if (!_.coordinates.length) return '';
|
||
|
return tag('MultiGeometry', _.coordinates.map(function(c) {
|
||
|
return geometry.LineString({ coordinates: c });
|
||
|
}).join(''));
|
||
|
},
|
||
|
GeometryCollection: function(_) {
|
||
|
return tag('MultiGeometry',
|
||
|
_.geometries.map(geometry.any).join(''));
|
||
|
},
|
||
|
valid: function(_) {
|
||
|
return _ && _.type && (_.coordinates ||
|
||
|
_.type === 'GeometryCollection' && _.geometries && _.geometries.every(geometry.valid));
|
||
|
},
|
||
|
any: function(_) {
|
||
|
if (geometry[_.type]) {
|
||
|
return geometry[_.type](_);
|
||
|
} else {
|
||
|
return '';
|
||
|
}
|
||
|
},
|
||
|
isPoint: function(_) {
|
||
|
return _.type === 'Point' ||
|
||
|
_.type === 'MultiPoint';
|
||
|
},
|
||
|
isPolygon: function(_) {
|
||
|
return _.type === 'Polygon' ||
|
||
|
_.type === 'MultiPolygon';
|
||
|
},
|
||
|
isLine: function(_) {
|
||
|
return _.type === 'LineString' ||
|
||
|
_.type === 'MultiLineString';
|
||
|
}
|
||
|
};
|
||
|
|
||
|
function linearring(_) {
|
||
|
return _.map(function(cds) { return cds.join(','); }).join(' ');
|
||
|
}
|
||
|
|
||
|
// ## Data
|
||
|
function extendeddata(_) {
|
||
|
return tag('ExtendedData', pairs(_).map(data).join(''));
|
||
|
}
|
||
|
|
||
|
function data(_) {
|
||
|
return tag('Data', tag('value', encode(_[1])), [['name', encode(_[0])]]);
|
||
|
}
|
||
|
|
||
|
// ## Marker style
|
||
|
function hasMarkerStyle(_) {
|
||
|
return !!(_['marker-size'] || _['marker-symbol'] || _['marker-color']);
|
||
|
}
|
||
|
|
||
|
function markerStyle(_, styleHash) {
|
||
|
return tag('Style',
|
||
|
tag('IconStyle',
|
||
|
tag('Icon',
|
||
|
tag('href', iconUrl(_)))) +
|
||
|
iconSize(_), [['id', styleHash]]);
|
||
|
}
|
||
|
|
||
|
function iconUrl(_) {
|
||
|
var size = _['marker-size'] || 'medium',
|
||
|
symbol = _['marker-symbol'] ? '-' + _['marker-symbol'] : '',
|
||
|
color = (_['marker-color'] || '7e7e7e').replace('#', '');
|
||
|
|
||
|
return 'https://api.tiles.mapbox.com/v3/marker/' + 'pin-' + size.charAt(0) +
|
||
|
symbol + '+' + color + '.png';
|
||
|
}
|
||
|
|
||
|
function iconSize(_) {
|
||
|
return tag('hotSpot', '', [
|
||
|
['xunits', 'fraction'],
|
||
|
['yunits', 'fraction'],
|
||
|
['x', 0.5],
|
||
|
['y', 0.5]
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
// ## Polygon and Line style
|
||
|
function hasPolygonAndLineStyle(_) {
|
||
|
for (var key in _) {
|
||
|
if ({
|
||
|
"stroke": true,
|
||
|
"stroke-opacity": true,
|
||
|
"stroke-width": true,
|
||
|
"fill": true,
|
||
|
"fill-opacity": true
|
||
|
}[key]) return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function polygonAndLineStyle(_, styleHash) {
|
||
|
var lineStyle = tag('LineStyle', [
|
||
|
tag('color', hexToKmlColor(_['stroke'], _['stroke-opacity']) || 'ff555555') +
|
||
|
tag('width', _['stroke-width'] === undefined ? 2 : _['stroke-width'])
|
||
|
]);
|
||
|
|
||
|
var polyStyle = '';
|
||
|
|
||
|
if (_['fill'] || _['fill-opacity']) {
|
||
|
polyStyle = tag('PolyStyle', [
|
||
|
tag('color', hexToKmlColor(_['fill'], _['fill-opacity']) || '88555555')
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
return tag('Style', lineStyle + polyStyle, [['id', styleHash]]);
|
||
|
}
|
||
|
|
||
|
// ## Style helpers
|
||
|
function hashStyle(_) {
|
||
|
var hash = '';
|
||
|
|
||
|
if (_['marker-symbol']) hash = hash + 'ms' + _['marker-symbol'];
|
||
|
if (_['marker-color']) hash = hash + 'mc' + _['marker-color'].replace('#', '');
|
||
|
if (_['marker-size']) hash = hash + 'ms' + _['marker-size'];
|
||
|
if (_['stroke']) hash = hash + 's' + _['stroke'].replace('#', '');
|
||
|
if (_['stroke-width']) hash = hash + 'sw' + _['stroke-width'].toString().replace('.', '');
|
||
|
if (_['stroke-opacity']) hash = hash + 'mo' + _['stroke-opacity'].toString().replace('.', '');
|
||
|
if (_['fill']) hash = hash + 'f' + _['fill'].replace('#', '');
|
||
|
if (_['fill-opacity']) hash = hash + 'fo' + _['fill-opacity'].toString().replace('.', '');
|
||
|
|
||
|
return hash;
|
||
|
}
|
||
|
|
||
|
function hexToKmlColor(hexColor, opacity) {
|
||
|
if (typeof hexColor !== 'string') return '';
|
||
|
|
||
|
hexColor = hexColor.replace('#', '').toLowerCase();
|
||
|
|
||
|
if (hexColor.length === 3) {
|
||
|
hexColor = hexColor[0] + hexColor[0] +
|
||
|
hexColor[1] + hexColor[1] +
|
||
|
hexColor[2] + hexColor[2];
|
||
|
} else if (hexColor.length !== 6) {
|
||
|
return '';
|
||
|
}
|
||
|
|
||
|
var r = hexColor[0] + hexColor[1];
|
||
|
var g = hexColor[2] + hexColor[3];
|
||
|
var b = hexColor[4] + hexColor[5];
|
||
|
|
||
|
var o = 'ff';
|
||
|
if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) {
|
||
|
o = (opacity * 255).toString(16);
|
||
|
if (o.indexOf('.') > -1) o = o.substr(0, o.indexOf('.'));
|
||
|
if (o.length < 2) o = '0' + o;
|
||
|
}
|
||
|
|
||
|
return o + b + g + r;
|
||
|
}
|
||
|
|
||
|
// ## General helpers
|
||
|
function pairs(_) {
|
||
|
var o = [];
|
||
|
for (var i in _) o.push([i, _[i]]);
|
||
|
return o;
|
||
|
}
|
||
|
},{"strxml":2}],2:[function(require,module,exports){
|
||
|
module.exports.attr = attr;
|
||
|
module.exports.tagClose = tagClose;
|
||
|
module.exports.tag = tag;
|
||
|
module.exports.encode = encode;
|
||
|
|
||
|
/**
|
||
|
* @param {array} _ an array of attributes
|
||
|
* @returns {string}
|
||
|
*/
|
||
|
function attr(_) {
|
||
|
return (_ && _.length) ? (' ' + _.map(function(a) {
|
||
|
return a[0] + '="' + a[1] + '"';
|
||
|
}).join(' ')) : '';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {string} el element name
|
||
|
* @param {array} attributes array of pairs
|
||
|
* @returns {string}
|
||
|
*/
|
||
|
function tagClose(el, attributes) {
|
||
|
return '<' + el + attr(attributes) + '/>';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {string} el element name
|
||
|
* @param {string} contents innerXML
|
||
|
* @param {array} attributes array of pairs
|
||
|
* @returns {string}
|
||
|
*/
|
||
|
function tag(el, contents, attributes) {
|
||
|
return '<' + el + attr(attributes) + '>' + contents + '</' + el + '>';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {string} _ a string of attribute
|
||
|
* @returns {string}
|
||
|
*/
|
||
|
function encode(_) {
|
||
|
if(_==null ||_==undefined)return '';
|
||
|
return (_ === null ? '' : _.toString()).replace(/&/g, '&')
|
||
|
.replace(/</g, '<')
|
||
|
.replace(/>/g, '>')
|
||
|
.replace(/"/g, '"');
|
||
|
}
|
||
|
|
||
|
},{}]},{},[1])(1)
|
||
|
});
|