@furkot/export-kml
Version:
Generate KML file from Furkot trip data.
180 lines (149 loc) • 4.33 kB
JavaScript
const { generator } = require('gexode');
const colors = require('./colors');
exports = module.exports = writeKml;
exports.contentType = 'application/vnd.google-earth.kml+xml';
exports.extension = 'kml';
exports.encoding = 'utf8';
const stepProperty2kmlProperty = {
'visit_duration': 'duration',
'pin': 'icon',
'url': 'url'
};
function* each(array, fn, thisArg) {
if (!array) { return; }
for (let i = 0; i < array.length; i++) {
yield* fn.call(thisArg, array[i], i, array);
}
}
function toFixed(c) {
return c.toFixed(6);
}
function* writeKml(options) {
const gen = generator({ pretty: true });
function* nd(name, description, address) {
yield* gen.elIfText('name', name);
yield* gen.elIfText('address', address);
yield* gen.elIfText('description', description);
}
function* lineStyle(color) {
yield* gen.start('Style');
yield* gen.start('LineStyle');
yield* gen.el('color', null, colors[color]);
yield* gen.el('width', null, 4);
yield* gen.end();
yield* gen.end();
}
function* lineString(feature, coordinates) {
yield* gen.start('Placemark');
yield* nd(feature.name, feature.desc);
if (feature.color) {
yield* lineStyle(feature.color);
}
yield* gen.start('LineString');
if (coordinates) {
yield* gen.el('coordinates', null, coordinates.join(' '));
}
yield* gen.end();
yield* gen.end();
}
function* extendedData(step) {
const items = Object.keys(stepProperty2kmlProperty)
.map(key => {
return {
name: stepProperty2kmlProperty[key],
value: step[key]
};
})
.filter(item => item.value);
if (!items.length) {
return;
}
yield* gen.start('ExtendedData');
for(const item of items) {
yield* gen.start('Data', { name: item.name });
yield* gen.el('value', null, item.value);
yield* gen.end();
}
yield* gen.end();
}
function* point(coordinates) {
const coordText = toFixed(coordinates.lon) + ',' + toFixed(coordinates.lat);
yield* gen.start('Point');
yield* gen.el('coordinates', null, coordText);
yield* gen.end();
}
function* addPoints(points) {
yield* each(points, function* (step) {
if (!step.coordinates) {
return;
}
yield* gen.start('Placemark');
yield* nd(step.name, step.notes, step.address);
yield* extendedData(step);
yield* point(step.coordinates);
yield* gen.end();
});
}
function points2coordinates(points) {
if (!points) {
return [];
}
return points.reduce(function (coords, p) {
if (p.coordinates) {
coords.push(toFixed(p.coordinates.lon) + ',' + toFixed(p.coordinates.lat));
} else if (Array.isArray(p)) {
coords.push(toFixed(p[0]) + ',' + toFixed(p[1]));
}
return coords;
}, []);
}
function* addTrack(track) {
let coordinates;
if (track.points) {
coordinates = track.points.reduce(function (coords, step) {
coords.push.apply(coords, points2coordinates(step.track));
return coords;
}, []);
}
yield* lineString(track, coordinates);
}
function* addTracks(tracks) {
yield* gen.start('Folder');
yield* nd('tracks');
yield* each(tracks, addTrack);
yield* gen.end();
}
function* addRoute(route) {
const coordinates = points2coordinates(route.points);
yield* lineString(route, coordinates);
}
function* addRoutes(routes) {
yield* gen.start('Folder');
yield* nd('routes');
yield* each(routes, addRoute);
yield* gen.end();
}
function* generate() {
// HACK: we seem to use options.routes[0].points in some modules
if (!options.waypoints) {
options.waypoints = options.routes && options.routes[0] && options.routes[0].points;
delete options.routes;
}
yield* gen.header();
yield* gen.start('kml', {
xmlns: 'http://www.opengis.net/kml/2.2'
});
yield* gen.start('Document');
yield* nd(options.metadata.name, options.metadata.desc);
yield* addPoints(options.waypoints);
if (options.routes) {
yield* addRoutes(options.routes);
}
if (options.tracks) {
yield* addTracks(options.tracks);
}
yield* gen.end();
yield* gen.end();
}
yield* generate();
}