From 875c9546a6dbf77733c329b6fdaf726f0ba575f5 Mon Sep 17 00:00:00 2001 From: Vinzenz Rosenkranz Date: Thu, 13 Aug 2015 16:30:47 +0200 Subject: [PATCH 1/3] added possibility to load gpx track files --- appinfo/application.php | 5 + appinfo/routes.php | 1 + controller/pagecontroller.php | 28 +- img/mapIcons/disused:butcher.png | Bin 1526 -> 0 bytes .../leaflet/plugins/leaflet-omnivore.js | 1865 +++++++++++++++++ js/script.js | 11 + templates/main.php | 1 + 7 files changed, 1910 insertions(+), 1 deletion(-) delete mode 100644 img/mapIcons/disused:butcher.png create mode 100644 js/3rdparty/leaflet/plugins/leaflet-omnivore.js diff --git a/appinfo/application.php b/appinfo/application.php index 19a5980..35d5077 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -34,6 +34,7 @@ public function __construct (array $urlParams=array()) { return new PageController( $c->query('AppName'), $c->query('Request'), + $c->query('RootFolder'), $c->query('UserId'), $c->query('CacheManager'), $c->query('LocationManager') @@ -58,6 +59,10 @@ public function __construct (array $urlParams=array()) { $c->query('ServerContainer')->getDb() ); }); + + $container->registerService('RootFolder', function($c) { + return $this->getContainer()->getServer()->getRootFolder(); + }); /** * Core diff --git a/appinfo/routes.php b/appinfo/routes.php index 725327a..accb013 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -28,6 +28,7 @@ array('name' => 'page#adresslookup', 'url' => '/adresslookup', 'verb' => 'GET'), array('name' => 'page#geodecode', 'url' => '/geodecode', 'verb' => 'GET'), array('name' => 'page#search', 'url' => '/search', 'verb' => 'GET'), + array('name' => 'page#getgpsfiles', 'url' => '/getgps', 'verb' => 'GET'), array('name' => 'location#update', 'url' => '/api/1.0/location/update', 'verb' => 'GET'), array('name' => 'location#add_device', 'url' => '/api/1.0/location/adddevice', 'verb' => 'POST'), diff --git a/controller/pagecontroller.php b/controller/pagecontroller.php index 41259a9..eaf311a 100644 --- a/controller/pagecontroller.php +++ b/controller/pagecontroller.php @@ -15,17 +15,21 @@ use \OCP\AppFramework\Http\TemplateResponse; use \OCP\AppFramework\Controller; use \OCA\Maps\Db\CacheManager; +use \OCP\Files\Folder; +use \OCP\Files\IRootFolder; class PageController extends Controller { private $userId; private $cacheManager; private $locationManager; - public function __construct($appName, IRequest $request, $userId, $cacheManager,$locationManager) { + private $rootF; + public function __construct($appName, IRequest $request, $rootF, $userId, $cacheManager,$locationManager) { parent::__construct($appName, $request); $this -> userId = $userId; $this -> cacheManager = $cacheManager; $this -> locationManager = $locationManager; + $this -> rootF = $rootF; } /** @@ -229,4 +233,26 @@ private function getURL($url, $userAgent = true) { } + public function getGpsFiles(){ + $path = '/' . $this->userId . '/files/MyTracks'; + if ($this->rootF->nodeExists($path)) { + $folder = $this->rootF->get($path); + } else { + $folder = $this->rootF->newFolder($path); + } + $nodes = $folder->getDirectoryListing(); + $suffix = ".gpx"; + foreach($nodes as $n){ + if($n->getType() == \OCP\Files\FileInfo::TYPE_FILE){ + $name = $n->getName(); + if(substr_compare($name, $suffix, -strlen($suffix)) === 0){ + $arr = array(); + $arr['dir'] = $n->getParent()->getName(); + $arr['file'] = $n->getName(); + $files[] = $arr; + } + } + } + return $files; + } } diff --git a/img/mapIcons/disused:butcher.png b/img/mapIcons/disused:butcher.png deleted file mode 100644 index e1e6378881eb434acde0c2f99404a24edab65445..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1526 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;Eegmrwuz1!qY_K~!i%?V9at97P<*FS*O}1Bn$9hzS?X zyCy_@8Bs!mB@u+?MZg*=CFM-=;%KOFMI}kal$JD?90aO}QcS5tL5pHZ#fMZuix#}* zQtQP&90`{8;tT(TalVtC>Fj1Uw@(-MqyryrZ|65NzwiEjGrM~?fm|gu6FiWLhn81o zONd`tiH9yG&jh9F*Cu=i{JM2vuOu`y zrb*bjAoRS^#&`Y7&i%&v8Zf?p zZCKfvUqRMs(OlM~m=_oVRY!j2-p_|0iPV)xB7MyNLL_yKl$Di{fq?;KeZh+?FE1xO zJw5EWsHli^baZU9DOi!4>8%Lv+4Gq0{Huo!v8XOBEs1jlBl5HJ$4GB)FKKOUCBa~j z6c-nh!NEbLEhsH570137SyxxbqGjZ#rDIBa&fM%Nb`kh@Ux~bN^)x9dDPayGAx#x`fbD+eDwIImNCtcVbdd!EXEC(v$TVL|j~1=k{*nwrSTsY#MuJE?R^ zrn0h|`;u0=u||D-0S4#{;Kw7GMA*0f&6*qV?`QY|>;mqjhu;aIm zdw(Rzx8Gb6-ys~LjpNzH6OjNZTT@fRj=Q?Lbk19)t*uS;C7+kaae`+e0U}scRmF~b z_C2q2)CxRh<#{<4HUF{7DxQi2aImqlksYUgd7rJEw5es#PQKO1eLKZ-kpN3RzyATV zU)_x00>K{XimW*CRz&pShP;RbAI=|PZyWvn5C4(IvDv*4bar+!JG8@h-p(y~6A3oc zlPvWRmEqTpi1XR>+hlQZQKThA;fG_?9gmH%d*}W1oUnIGUPa2_4Fc&1VdLZDN}G|P z7evZ>$*zgy{C4FyX>V^Af@!zx6Erk5DBHNjk;u&(F=c0d#g<5Fl!WnLKfbK&%&*+N z*u_Pj)1;Ue>}-N@`hzEwo%s=D-S6`?TOwzI2Q(?>B{>&Qbw6Zxtuo)ZnbDFEcQm;FpLXc4JKkp4KE-E7*QU8)mpzJ78eD zo1Nr6a&|!kZ3~pk%1rTL8reD8(XvI@g|Q=)FB+P|sy>xq{cyYu)J@UmG+UuDS8~m1 zzFiF9f@ 0) { + var fn = queue.shift(); + fn(); + } + } + }, true); + + return function nextTick(fn) { + queue.push(fn); + window.postMessage('process-tick', '*'); + }; + } + + return function nextTick(fn) { + setTimeout(fn, 0); + }; +})(); + +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +// TODO(shtylman) +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; + +},{}],5:[function(require,module,exports){ +function corslite(url, callback, cors) { + var sent = false; + + if (typeof window.XMLHttpRequest === 'undefined') { + return callback(Error('Browser not supported')); + } + + if (typeof cors === 'undefined') { + var m = url.match(/^\s*https?:\/\/[^\/]*/); + cors = m && (m[0] !== location.protocol + '//' + location.domain + + (location.port ? ':' + location.port : '')); + } + + var x = new window.XMLHttpRequest(); + + function isSuccessful(status) { + return status >= 200 && status < 300 || status === 304; + } + + if (cors && !('withCredentials' in x)) { + // IE8-9 + x = new window.XDomainRequest(); + + // Ensure callback is never called synchronously, i.e., before + // x.send() returns (this has been observed in the wild). + // See https://github.com/mapbox/mapbox.js/issues/472 + var original = callback; + callback = function() { + if (sent) { + original.apply(this, arguments); + } else { + var that = this, args = arguments; + setTimeout(function() { + original.apply(that, args); + }, 0); + } + } + } + + function loaded() { + if ( + // XDomainRequest + x.status === undefined || + // modern browsers + isSuccessful(x.status)) callback.call(x, null, x); + else callback.call(x, x, null); + } + + // Both `onreadystatechange` and `onload` can fire. `onreadystatechange` + // has [been supported for longer](http://stackoverflow.com/a/9181508/229001). + if ('onload' in x) { + x.onload = loaded; + } else { + x.onreadystatechange = function readystate() { + if (x.readyState === 4) { + loaded(); + } + }; + } + + // Call the callback with the XMLHttpRequest object as an error and prevent + // it from ever being called again by reassigning it to `noop` + x.onerror = function error(evt) { + // XDomainRequest provides no evt parameter + callback.call(this, evt || true, null); + callback = function() { }; + }; + + // IE9 must have onprogress be set to a unique function. + x.onprogress = function() { }; + + x.ontimeout = function(evt) { + callback.call(this, evt, null); + callback = function() { }; + }; + + x.onabort = function(evt) { + callback.call(this, evt, null); + callback = function() { }; + }; + + // GET is the only supported HTTP Verb by XDomainRequest and is the + // only one supported here. + x.open('GET', url, true); + + // Send the request. Sending data is not supported. + x.send(null); + sent = true; + + return x; +} + +if (typeof module !== 'undefined') module.exports = corslite; + +},{}],6:[function(require,module,exports){ +var dsv = require('dsv'), + sexagesimal = require('sexagesimal'); + +function isLat(f) { return !!f.match(/(Lat)(itude)?/gi); } +function isLon(f) { return !!f.match(/(L)(on|ng)(gitude)?/i); } + +function keyCount(o) { + return (typeof o == 'object') ? Object.keys(o).length : 0; +} + +function autoDelimiter(x) { + var delimiters = [',', ';', '\t', '|']; + var results = []; + + delimiters.forEach(function(delimiter) { + var res = dsv(delimiter).parse(x); + if (res.length >= 1) { + var count = keyCount(res[0]); + for (var i = 0; i < res.length; i++) { + if (keyCount(res[i]) !== count) return; + } + results.push({ + delimiter: delimiter, + arity: Object.keys(res[0]).length, + }); + } + }); + + if (results.length) { + return results.sort(function(a, b) { + return b.arity - a.arity; + })[0].delimiter; + } else { + return null; + } +} + +function auto(x) { + var delimiter = autoDelimiter(x); + if (!delimiter) return null; + return dsv(delimiter).parse(x); +} + +function csv2geojson(x, options, callback) { + + if (!callback) { + callback = options; + options = {}; + } + + options.delimiter = options.delimiter || ','; + + var latfield = options.latfield || '', + lonfield = options.lonfield || ''; + + var features = [], + featurecollection = { type: 'FeatureCollection', features: features }; + + if (options.delimiter === 'auto' && typeof x == 'string') { + options.delimiter = autoDelimiter(x); + if (!options.delimiter) return callback({ + type: 'Error', + message: 'Could not autodetect delimiter' + }); + } + + var parsed = (typeof x == 'string') ? dsv(options.delimiter).parse(x) : x; + + if (!parsed.length) return callback(null, featurecollection); + + if (!latfield || !lonfield) { + for (var f in parsed[0]) { + if (!latfield && isLat(f)) latfield = f; + if (!lonfield && isLon(f)) lonfield = f; + } + if (!latfield || !lonfield) { + var fields = []; + for (var k in parsed[0]) fields.push(k); + return callback({ + type: 'Error', + message: 'Latitude and longitude fields not present', + data: parsed, + fields: fields + }); + } + } + + var errors = []; + + for (var i = 0; i < parsed.length; i++) { + if (parsed[i][lonfield] !== undefined && + parsed[i][lonfield] !== undefined) { + + var lonk = parsed[i][lonfield], + latk = parsed[i][latfield], + lonf, latf, + a; + + a = sexagesimal(lonk, 'EW'); + if (a) lonk = a; + a = sexagesimal(latk, 'NS'); + if (a) latk = a; + + lonf = parseFloat(lonk); + latf = parseFloat(latk); + + if (isNaN(lonf) || + isNaN(latf)) { + errors.push({ + message: 'A row contained an invalid value for latitude or longitude', + row: parsed[i] + }); + } else { + if (!options.includeLatLon) { + delete parsed[i][lonfield]; + delete parsed[i][latfield]; + } + + features.push({ + type: 'Feature', + properties: parsed[i], + geometry: { + type: 'Point', + coordinates: [ + parseFloat(lonf), + parseFloat(latf) + ] + } + }); + } + } + } + + callback(errors.length ? errors: null, featurecollection); +} + +function toLine(gj) { + var features = gj.features; + var line = { + type: 'Feature', + geometry: { + type: 'LineString', + coordinates: [] + } + }; + for (var i = 0; i < features.length; i++) { + line.geometry.coordinates.push(features[i].geometry.coordinates); + } + line.properties = features[0].properties; + return { + type: 'FeatureCollection', + features: [line] + }; +} + +function toPolygon(gj) { + var features = gj.features; + var poly = { + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [[]] + } + }; + for (var i = 0; i < features.length; i++) { + poly.geometry.coordinates[0].push(features[i].geometry.coordinates); + } + poly.properties = features[0].properties; + return { + type: 'FeatureCollection', + features: [poly] + }; +} + +module.exports = { + isLon: isLon, + isLat: isLat, + csv: dsv.csv.parse, + tsv: dsv.tsv.parse, + dsv: dsv, + auto: auto, + csv2geojson: csv2geojson, + toLine: toLine, + toPolygon: toPolygon +}; + +},{"dsv":7,"sexagesimal":8}],7:[function(require,module,exports){ +var fs = require("fs"); + +module.exports = new Function("dsv.version = \"0.0.3\";\n\ndsv.tsv = dsv(\"\\t\");\ndsv.csv = dsv(\",\");\n\nfunction dsv(delimiter) {\n var dsv = {},\n reFormat = new RegExp(\"[\\\"\" + delimiter + \"\\n]\"),\n delimiterCode = delimiter.charCodeAt(0);\n\n dsv.parse = function(text, f) {\n var o;\n return dsv.parseRows(text, function(row, i) {\n if (o) return o(row, i - 1);\n var a = new Function(\"d\", \"return {\" + row.map(function(name, i) {\n return JSON.stringify(name) + \": d[\" + i + \"]\";\n }).join(\",\") + \"}\");\n o = f ? function(row, i) { return f(a(row), i); } : a;\n });\n };\n\n dsv.parseRows = function(text, f) {\n var EOL = {}, // sentinel value for end-of-line\n EOF = {}, // sentinel value for end-of-file\n rows = [], // output rows\n N = text.length,\n I = 0, // current character index\n n = 0, // the current line number\n t, // the current token\n eol; // is the current token followed by EOL?\n\n function token() {\n if (I >= N) return EOF; // special case: end of file\n if (eol) return eol = false, EOL; // special case: end of line\n\n // special case: quotes\n var j = I;\n if (text.charCodeAt(j) === 34) {\n var i = j;\n while (i++ < N) {\n if (text.charCodeAt(i) === 34) {\n if (text.charCodeAt(i + 1) !== 34) break;\n ++i;\n }\n }\n I = i + 2;\n var c = text.charCodeAt(i + 1);\n if (c === 13) {\n eol = true;\n if (text.charCodeAt(i + 2) === 10) ++I;\n } else if (c === 10) {\n eol = true;\n }\n return text.substring(j + 1, i).replace(/\"\"/g, \"\\\"\");\n }\n\n // common case: find next delimiter or newline\n while (I < N) {\n var c = text.charCodeAt(I++), k = 1;\n if (c === 10) eol = true; // \\n\n else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } // \\r|\\r\\n\n else if (c !== delimiterCode) continue;\n return text.substring(j, I - k);\n }\n\n // special case: last token before EOF\n return text.substring(j);\n }\n\n while ((t = token()) !== EOF) {\n var a = [];\n while (t !== EOL && t !== EOF) {\n a.push(t);\n t = token();\n }\n if (f && !(a = f(a, n++))) continue;\n rows.push(a);\n }\n\n return rows;\n };\n\n dsv.format = function(rows) {\n if (Array.isArray(rows[0])) return dsv.formatRows(rows); // deprecated; use formatRows\n var fieldSet = {}, fields = [];\n\n // Compute unique fields in order of discovery.\n rows.forEach(function(row) {\n for (var field in row) {\n if (!(field in fieldSet)) {\n fields.push(fieldSet[field] = field);\n }\n }\n });\n\n return [fields.map(formatValue).join(delimiter)].concat(rows.map(function(row) {\n return fields.map(function(field) {\n return formatValue(row[field]);\n }).join(delimiter);\n })).join(\"\\n\");\n };\n\n dsv.formatRows = function(rows) {\n return rows.map(formatRow).join(\"\\n\");\n };\n\n function formatRow(row) {\n return row.map(formatValue).join(delimiter);\n }\n\n function formatValue(text) {\n return reFormat.test(text) ? \"\\\"\" + text.replace(/\\\"/g, \"\\\"\\\"\") + \"\\\"\" : text;\n }\n\n return dsv;\n}\n" + ";return dsv")(); + +},{"fs":2}],8:[function(require,module,exports){ +module.exports = function(x, dims) { + if (!dims) dims = 'NSEW'; + if (typeof x !== 'string') return null; + var r = /^([0-9.]+)°? *(?:([0-9.]+)['’′‘] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/, + m = x.match(r); + if (!m) return null; + else if (m[4] && dims.indexOf(m[4]) === -1) return null; + else return (((m[1]) ? parseFloat(m[1]) : 0) + + ((m[2] ? parseFloat(m[2]) / 60 : 0)) + + ((m[3] ? parseFloat(m[3]) / 3600 : 0))) * + ((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1); +}; + +},{}],9:[function(require,module,exports){ +var polyline = {}; + +// Based off of [the offical Google document](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) +// +// Some parts from [this implementation](http://facstaff.unca.edu/mcmcclur/GoogleMaps/EncodePolyline/PolylineEncoder.js) +// by [Mark McClure](http://facstaff.unca.edu/mcmcclur/) + +function encode(coordinate, factor) { + coordinate = Math.round(coordinate * factor); + coordinate <<= 1; + if (coordinate < 0) { + coordinate = ~coordinate; + } + var output = ''; + while (coordinate >= 0x20) { + output += String.fromCharCode((0x20 | (coordinate & 0x1f)) + 63); + coordinate >>= 5; + } + output += String.fromCharCode(coordinate + 63); + return output; +} + +// This is adapted from the implementation in Project-OSRM +// https://github.com/DennisOSRM/Project-OSRM-Web/blob/master/WebContent/routing/OSRM.RoutingGeometry.js +polyline.decode = function(str, precision) { + var index = 0, + lat = 0, + lng = 0, + coordinates = [], + shift = 0, + result = 0, + byte = null, + latitude_change, + longitude_change, + factor = Math.pow(10, precision || 5); + + // Coordinates have variable length when encoded, so just keep + // track of whether we've hit the end of the string. In each + // loop iteration, a single coordinate is decoded. + while (index < str.length) { + + // Reset shift, result, and byte + byte = null; + shift = 0; + result = 0; + + do { + byte = str.charCodeAt(index++) - 63; + result |= (byte & 0x1f) << shift; + shift += 5; + } while (byte >= 0x20); + + latitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1)); + + shift = result = 0; + + do { + byte = str.charCodeAt(index++) - 63; + result |= (byte & 0x1f) << shift; + shift += 5; + } while (byte >= 0x20); + + longitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1)); + + lat += latitude_change; + lng += longitude_change; + + coordinates.push([lat / factor, lng / factor]); + } + + return coordinates; +}; + +polyline.encode = function(coordinates, precision) { + if (!coordinates.length) return ''; + + var factor = Math.pow(10, precision || 5), + output = encode(coordinates[0][0], factor) + encode(coordinates[0][1], factor); + + for (var i = 1; i < coordinates.length; i++) { + var a = coordinates[i], b = coordinates[i - 1]; + output += encode(a[0] - b[0], factor); + output += encode(a[1] - b[1], factor); + } + + return output; +}; + +if (typeof module !== undefined) module.exports = polyline; + +},{}],10:[function(require,module,exports){ +(function (process){ +toGeoJSON = (function() { + 'use strict'; + + var removeSpace = (/\s*/g), + trimSpace = (/^\s*|\s*$/g), + splitSpace = (/\s+/); + // generate a short, numeric hash of a string + function okhash(x) { + if (!x || !x.length) return 0; + for (var i = 0, h = 0; i < x.length; i++) { + h = ((h << 5) - h) + x.charCodeAt(i) | 0; + } return h; + } + // all Y children of X + function get(x, y) { return x.getElementsByTagName(y); } + function attr(x, y) { return x.getAttribute(y); } + function attrf(x, y) { return parseFloat(attr(x, y)); } + // one Y child of X, if any, otherwise null + function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; } + // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize + function norm(el) { if (el.normalize) { el.normalize(); } return el; } + // cast array x into numbers + function numarray(x) { + for (var j = 0, o = []; j < x.length; j++) o[j] = parseFloat(x[j]); + return o; + } + function clean(x) { + var o = {}; + for (var i in x) if (x[i]) o[i] = x[i]; + return o; + } + // get the content of a text node, if any + function nodeVal(x) { + if (x) { norm(x); } + return (x && x.firstChild && x.firstChild.nodeValue) || ''; + } + // get one coordinate from a coordinate array, if any + function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); } + // get all coordinates from a coordinate array as [[],[]] + function coord(v) { + var coords = v.replace(trimSpace, '').split(splitSpace), + o = []; + for (var i = 0; i < coords.length; i++) { + o.push(coord1(coords[i])); + } + return o; + } + function coordPair(x) { + var ll = [attrf(x, 'lon'), attrf(x, 'lat')], + ele = get1(x, 'ele'), + time = get1(x, 'time'); + if (ele) ll.push(parseFloat(nodeVal(ele))); + return { + coordinates: ll, + time: time ? nodeVal(time) : null + }; + } + + // create a new feature collection parent object + function fc() { + return { + type: 'FeatureCollection', + features: [] + }; + } + + var serializer; + if (typeof XMLSerializer !== 'undefined') { + serializer = new XMLSerializer(); + // only require xmldom in a node environment + } else if (typeof exports === 'object' && typeof process === 'object' && !process.browser) { + serializer = new (require('xmldom').XMLSerializer)(); + } + function xml2str(str) { + // IE9 will create a new XMLSerializer but it'll crash immediately. + if (str.xml !== undefined) return str.xml; + return serializer.serializeToString(str); + } + + var t = { + kml: function(doc) { + + var gj = fc(), + // styleindex keeps track of hashed styles in order to match features + styleIndex = {}, + // atomic geospatial types supported by KML - MultiGeometry is + // handled separately + geotypes = ['Polygon', 'LineString', 'Point', 'Track', 'gx:Track'], + // all root placemarks in the file + placemarks = get(doc, 'Placemark'), + styles = get(doc, 'Style'); + + for (var k = 0; k < styles.length; k++) { + styleIndex['#' + attr(styles[k], 'id')] = okhash(xml2str(styles[k])).toString(16); + } + for (var j = 0; j < placemarks.length; j++) { + gj.features = gj.features.concat(getPlacemark(placemarks[j])); + } + function kmlColor(v) { + var color, opacity; + v = v || ""; + if (v.substr(0, 1) === "#") v = v.substr(1); + if (v.length === 6 || v.length === 3) color = v; + if (v.length === 8) { + opacity = parseInt(v.substr(0, 2), 16) / 255; + color = v.substr(2); + } + return [color, isNaN(opacity) ? undefined : opacity]; + } + function gxCoord(v) { return numarray(v.split(' ')); } + function gxCoords(root) { + var elems = get(root, 'coord', 'gx'), coords = [], times = []; + if (elems.length === 0) elems = get(root, 'gx:coord'); + for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i]))); + var timeElems = get(root, 'when'); + for (var i = 0; i < timeElems.length; i++) times.push(nodeVal(timeElems[i])); + return { + coords: coords, + times: times + }; + } + function getGeometry(root) { + var geomNode, geomNodes, i, j, k, geoms = [], coordTimes = []; + if (get1(root, 'MultiGeometry')) return getGeometry(get1(root, 'MultiGeometry')); + if (get1(root, 'MultiTrack')) return getGeometry(get1(root, 'MultiTrack')); + if (get1(root, 'gx:MultiTrack')) return getGeometry(get1(root, 'gx:MultiTrack')); + for (i = 0; i < geotypes.length; i++) { + geomNodes = get(root, geotypes[i]); + if (geomNodes) { + for (j = 0; j < geomNodes.length; j++) { + geomNode = geomNodes[j]; + if (geotypes[i] == 'Point') { + geoms.push({ + type: 'Point', + coordinates: coord1(nodeVal(get1(geomNode, 'coordinates'))) + }); + } else if (geotypes[i] == 'LineString') { + geoms.push({ + type: 'LineString', + coordinates: coord(nodeVal(get1(geomNode, 'coordinates'))) + }); + } else if (geotypes[i] == 'Polygon') { + var rings = get(geomNode, 'LinearRing'), + coords = []; + for (k = 0; k < rings.length; k++) { + coords.push(coord(nodeVal(get1(rings[k], 'coordinates')))); + } + geoms.push({ + type: 'Polygon', + coordinates: coords + }); + } else if (geotypes[i] == 'Track' || + geotypes[i] == 'gx:Track') { + var track = gxCoords(geomNode); + geoms.push({ + type: 'LineString', + coordinates: track.coords + }); + if (track.times.length) coordTimes.push(track.times); + } + } + } + } + return { + geoms: geoms, + coordTimes: coordTimes + }; + } + function getPlacemark(root) { + var geomsAndTimes = getGeometry(root), i, properties = {}, + name = nodeVal(get1(root, 'name')), + styleUrl = nodeVal(get1(root, 'styleUrl')), + description = nodeVal(get1(root, 'description')), + timeSpan = get1(root, 'TimeSpan'), + extendedData = get1(root, 'ExtendedData'), + lineStyle = get1(root, 'LineStyle'), + polyStyle = get1(root, 'PolyStyle'); + + if (!geomsAndTimes.geoms.length) return []; + if (name) properties.name = name; + if (styleUrl && styleIndex[styleUrl]) { + properties.styleUrl = styleUrl; + properties.styleHash = styleIndex[styleUrl]; + } + if (description) properties.description = description; + if (timeSpan) { + var begin = nodeVal(get1(timeSpan, 'begin')); + var end = nodeVal(get1(timeSpan, 'end')); + properties.timespan = { begin: begin, end: end }; + } + if (lineStyle) { + var linestyles = kmlColor(nodeVal(get1(lineStyle, 'color'))), + color = linestyles[0], + opacity = linestyles[1], + width = parseFloat(nodeVal(get1(lineStyle, 'width'))); + if (color) properties.stroke = color; + if (!isNaN(opacity)) properties['stroke-opacity'] = opacity; + if (!isNaN(width)) properties['stroke-width'] = width; + } + if (polyStyle) { + var polystyles = kmlColor(nodeVal(get1(polyStyle, 'color'))), + pcolor = polystyles[0], + popacity = polystyles[1], + fill = nodeVal(get1(polyStyle, 'fill')), + outline = nodeVal(get1(polyStyle, 'outline')); + if (pcolor) properties.fill = pcolor; + if (!isNaN(popacity)) properties['fill-opacity'] = popacity; + if (fill) properties['fill-opacity'] = fill === "1" ? 1 : 0; + if (outline) properties['stroke-opacity'] = outline === "1" ? 1 : 0; + } + if (extendedData) { + var datas = get(extendedData, 'Data'), + simpleDatas = get(extendedData, 'SimpleData'); + + for (i = 0; i < datas.length; i++) { + properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value')); + } + for (i = 0; i < simpleDatas.length; i++) { + properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]); + } + } + if (geomsAndTimes.coordTimes.length) { + properties.coordTimes = (geomsAndTimes.coordTimes.length === 1) ? + geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes; + } + var feature = { + type: 'Feature', + geometry: (geomsAndTimes.geoms.length === 1) ? geomsAndTimes.geoms[0] : { + type: 'GeometryCollection', + geometries: geomsAndTimes.geoms + }, + properties: properties + }; + if (attr(root, 'id')) feature.id = attr(root, 'id'); + return [feature]; + } + return gj; + }, + gpx: function(doc) { + var i, + tracks = get(doc, 'trk'), + routes = get(doc, 'rte'), + waypoints = get(doc, 'wpt'), + // a feature collection + gj = fc(), + feature; + for (i = 0; i < tracks.length; i++) { + feature = getTrack(tracks[i]); + if (feature) gj.features.push(feature); + } + for (i = 0; i < routes.length; i++) { + feature = getRoute(routes[i]); + if (feature) gj.features.push(feature); + } + for (i = 0; i < waypoints.length; i++) { + gj.features.push(getPoint(waypoints[i])); + } + function getPoints(node, pointname) { + var pts = get(node, pointname), line = [], times = [], + l = pts.length; + if (l < 2) return; // Invalid line in GeoJSON + for (var i = 0; i < l; i++) { + var c = coordPair(pts[i]); + line.push(c.coordinates); + if (c.time) times.push(c.time); + } + return { + line: line, + times: times + }; + } + function getTrack(node) { + var segments = get(node, 'trkseg'), track = [], times = [], line; + for (var i = 0; i < segments.length; i++) { + line = getPoints(segments[i], 'trkpt'); + if (line.line) track.push(line.line); + if (line.times.length) times.push(line.times); + } + if (track.length === 0) return; + var properties = getProperties(node); + if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times; + return { + type: 'Feature', + properties: properties, + geometry: { + type: track.length === 1 ? 'LineString' : 'MultiLineString', + coordinates: track.length === 1 ? track[0] : track + } + }; + } + function getRoute(node) { + var line = getPoints(node, 'rtept'); + if (!line) return; + var routeObj = { + type: 'Feature', + properties: getProperties(node), + geometry: { + type: 'LineString', + coordinates: line + } + }; + if (line.times.length) routeObj.geometry.times = line.times; + return routeObj; + } + function getPoint(node) { + var prop = getProperties(node); + prop.sym = nodeVal(get1(node, 'sym')); + return { + type: 'Feature', + properties: prop, + geometry: { + type: 'Point', + coordinates: coordPair(node).coordinates + } + }; + } + function getProperties(node) { + var meta = ['name', 'desc', 'author', 'copyright', 'link', + 'time', 'keywords'], + prop = {}, + k; + for (k = 0; k < meta.length; k++) { + prop[meta[k]] = nodeVal(get1(node, meta[k])); + } + return clean(prop); + } + return gj; + } + }; + return t; +})(); + +if (typeof module !== 'undefined') module.exports = toGeoJSON; + +}).call(this,require('_process')) +},{"_process":4,"xmldom":3}],11:[function(require,module,exports){ +!function() { + var topojson = { + version: "1.6.8", + mesh: function(topology) { return object(topology, meshArcs.apply(this, arguments)); }, + meshArcs: meshArcs, + merge: function(topology) { return object(topology, mergeArcs.apply(this, arguments)); }, + mergeArcs: mergeArcs, + feature: featureOrCollection, + neighbors: neighbors, + presimplify: presimplify + }; + + function stitchArcs(topology, arcs) { + var stitchedArcs = {}, + fragmentByStart = {}, + fragmentByEnd = {}, + fragments = [], + emptyIndex = -1; + + // Stitch empty arcs first, since they may be subsumed by other arcs. + arcs.forEach(function(i, j) { + var arc = topology.arcs[i < 0 ? ~i : i], t; + if (arc.length < 3 && !arc[1][0] && !arc[1][1]) { + t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t; + } + }); + + arcs.forEach(function(i) { + var e = ends(i), + start = e[0], + end = e[1], + f, g; + + if (f = fragmentByEnd[start]) { + delete fragmentByEnd[f.end]; + f.push(i); + f.end = end; + if (g = fragmentByStart[end]) { + delete fragmentByStart[g.start]; + var fg = g === f ? f : f.concat(g); + fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg; + } else { + fragmentByStart[f.start] = fragmentByEnd[f.end] = f; + } + } else if (f = fragmentByStart[end]) { + delete fragmentByStart[f.start]; + f.unshift(i); + f.start = start; + if (g = fragmentByEnd[start]) { + delete fragmentByEnd[g.end]; + var gf = g === f ? f : g.concat(f); + fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf; + } else { + fragmentByStart[f.start] = fragmentByEnd[f.end] = f; + } + } else { + f = [i]; + fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f; + } + }); + + function ends(i) { + var arc = topology.arcs[i < 0 ? ~i : i], p0 = arc[0], p1; + if (topology.transform) p1 = [0, 0], arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; }); + else p1 = arc[arc.length - 1]; + return i < 0 ? [p1, p0] : [p0, p1]; + } + + function flush(fragmentByEnd, fragmentByStart) { + for (var k in fragmentByEnd) { + var f = fragmentByEnd[k]; + delete fragmentByStart[f.start]; + delete f.start; + delete f.end; + f.forEach(function(i) { stitchedArcs[i < 0 ? ~i : i] = 1; }); + fragments.push(f); + } + } + + flush(fragmentByEnd, fragmentByStart); + flush(fragmentByStart, fragmentByEnd); + arcs.forEach(function(i) { if (!stitchedArcs[i < 0 ? ~i : i]) fragments.push([i]); }); + + return fragments; + } + + function meshArcs(topology, o, filter) { + var arcs = []; + + if (arguments.length > 1) { + var geomsByArc = [], + geom; + + function arc(i) { + var j = i < 0 ? ~i : i; + (geomsByArc[j] || (geomsByArc[j] = [])).push({i: i, g: geom}); + } + + function line(arcs) { + arcs.forEach(arc); + } + + function polygon(arcs) { + arcs.forEach(line); + } + + function geometry(o) { + if (o.type === "GeometryCollection") o.geometries.forEach(geometry); + else if (o.type in geometryType) geom = o, geometryType[o.type](o.arcs); + } + + var geometryType = { + LineString: line, + MultiLineString: polygon, + Polygon: polygon, + MultiPolygon: function(arcs) { arcs.forEach(polygon); } + }; + + geometry(o); + + geomsByArc.forEach(arguments.length < 3 + ? function(geoms) { arcs.push(geoms[0].i); } + : function(geoms) { if (filter(geoms[0].g, geoms[geoms.length - 1].g)) arcs.push(geoms[0].i); }); + } else { + for (var i = 0, n = topology.arcs.length; i < n; ++i) arcs.push(i); + } + + return {type: "MultiLineString", arcs: stitchArcs(topology, arcs)}; + } + + function mergeArcs(topology, objects) { + var polygonsByArc = {}, + polygons = [], + components = []; + + objects.forEach(function(o) { + if (o.type === "Polygon") register(o.arcs); + else if (o.type === "MultiPolygon") o.arcs.forEach(register); + }); + + function register(polygon) { + polygon.forEach(function(ring) { + ring.forEach(function(arc) { + (polygonsByArc[arc = arc < 0 ? ~arc : arc] || (polygonsByArc[arc] = [])).push(polygon); + }); + }); + polygons.push(polygon); + } + + function exterior(ring) { + return cartesianRingArea(object(topology, {type: "Polygon", arcs: [ring]}).coordinates[0]) > 0; // TODO allow spherical? + } + + polygons.forEach(function(polygon) { + if (!polygon._) { + var component = [], + neighbors = [polygon]; + polygon._ = 1; + components.push(component); + while (polygon = neighbors.pop()) { + component.push(polygon); + polygon.forEach(function(ring) { + ring.forEach(function(arc) { + polygonsByArc[arc < 0 ? ~arc : arc].forEach(function(polygon) { + if (!polygon._) { + polygon._ = 1; + neighbors.push(polygon); + } + }); + }); + }); + } + } + }); + + polygons.forEach(function(polygon) { + delete polygon._; + }); + + return { + type: "MultiPolygon", + arcs: components.map(function(polygons) { + var arcs = []; + + // Extract the exterior (unique) arcs. + polygons.forEach(function(polygon) { + polygon.forEach(function(ring) { + ring.forEach(function(arc) { + if (polygonsByArc[arc < 0 ? ~arc : arc].length < 2) { + arcs.push(arc); + } + }); + }); + }); + + // Stitch the arcs into one or more rings. + arcs = stitchArcs(topology, arcs); + + // If more than one ring is returned, + // at most one of these rings can be the exterior; + // this exterior ring has the same winding order + // as any exterior ring in the original polygons. + if ((n = arcs.length) > 1) { + var sgn = exterior(polygons[0][0]); + for (var i = 0, t; i < n; ++i) { + if (sgn === exterior(arcs[i])) { + t = arcs[0], arcs[0] = arcs[i], arcs[i] = t; + break; + } + } + } + + return arcs; + }) + }; + } + + function featureOrCollection(topology, o) { + return o.type === "GeometryCollection" ? { + type: "FeatureCollection", + features: o.geometries.map(function(o) { return feature(topology, o); }) + } : feature(topology, o); + } + + function feature(topology, o) { + var f = { + type: "Feature", + id: o.id, + properties: o.properties || {}, + geometry: object(topology, o) + }; + if (o.id == null) delete f.id; + return f; + } + + function object(topology, o) { + var absolute = transformAbsolute(topology.transform), + arcs = topology.arcs; + + function arc(i, points) { + if (points.length) points.pop(); + for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length, p; k < n; ++k) { + points.push(p = a[k].slice()); + absolute(p, k); + } + if (i < 0) reverse(points, n); + } + + function point(p) { + p = p.slice(); + absolute(p, 0); + return p; + } + + function line(arcs) { + var points = []; + for (var i = 0, n = arcs.length; i < n; ++i) arc(arcs[i], points); + if (points.length < 2) points.push(points[0].slice()); + return points; + } + + function ring(arcs) { + var points = line(arcs); + while (points.length < 4) points.push(points[0].slice()); + return points; + } + + function polygon(arcs) { + return arcs.map(ring); + } + + function geometry(o) { + var t = o.type; + return t === "GeometryCollection" ? {type: t, geometries: o.geometries.map(geometry)} + : t in geometryType ? {type: t, coordinates: geometryType[t](o)} + : null; + } + + var geometryType = { + Point: function(o) { return point(o.coordinates); }, + MultiPoint: function(o) { return o.coordinates.map(point); }, + LineString: function(o) { return line(o.arcs); }, + MultiLineString: function(o) { return o.arcs.map(line); }, + Polygon: function(o) { return polygon(o.arcs); }, + MultiPolygon: function(o) { return o.arcs.map(polygon); } + }; + + return geometry(o); + } + + function reverse(array, n) { + var t, j = array.length, i = j - n; while (i < --j) t = array[i], array[i++] = array[j], array[j] = t; + } + + function bisect(a, x) { + var lo = 0, hi = a.length; + while (lo < hi) { + var mid = lo + hi >>> 1; + if (a[mid] < x) lo = mid + 1; + else hi = mid; + } + return lo; + } + + function neighbors(objects) { + var indexesByArc = {}, // arc index -> array of object indexes + neighbors = objects.map(function() { return []; }); + + function line(arcs, i) { + arcs.forEach(function(a) { + if (a < 0) a = ~a; + var o = indexesByArc[a]; + if (o) o.push(i); + else indexesByArc[a] = [i]; + }); + } + + function polygon(arcs, i) { + arcs.forEach(function(arc) { line(arc, i); }); + } + + function geometry(o, i) { + if (o.type === "GeometryCollection") o.geometries.forEach(function(o) { geometry(o, i); }); + else if (o.type in geometryType) geometryType[o.type](o.arcs, i); + } + + var geometryType = { + LineString: line, + MultiLineString: polygon, + Polygon: polygon, + MultiPolygon: function(arcs, i) { arcs.forEach(function(arc) { polygon(arc, i); }); } + }; + + objects.forEach(geometry); + + for (var i in indexesByArc) { + for (var indexes = indexesByArc[i], m = indexes.length, j = 0; j < m; ++j) { + for (var k = j + 1; k < m; ++k) { + var ij = indexes[j], ik = indexes[k], n; + if ((n = neighbors[ij])[i = bisect(n, ik)] !== ik) n.splice(i, 0, ik); + if ((n = neighbors[ik])[i = bisect(n, ij)] !== ij) n.splice(i, 0, ij); + } + } + } + + return neighbors; + } + + function presimplify(topology, triangleArea) { + var absolute = transformAbsolute(topology.transform), + relative = transformRelative(topology.transform), + heap = minAreaHeap(), + maxArea = 0, + triangle; + + if (!triangleArea) triangleArea = cartesianTriangleArea; + + topology.arcs.forEach(function(arc) { + var triangles = []; + + arc.forEach(absolute); + + for (var i = 1, n = arc.length - 1; i < n; ++i) { + triangle = arc.slice(i - 1, i + 2); + triangle[1][2] = triangleArea(triangle); + triangles.push(triangle); + heap.push(triangle); + } + + // Always keep the arc endpoints! + arc[0][2] = arc[n][2] = Infinity; + + for (var i = 0, n = triangles.length; i < n; ++i) { + triangle = triangles[i]; + triangle.previous = triangles[i - 1]; + triangle.next = triangles[i + 1]; + } + }); + + while (triangle = heap.pop()) { + var previous = triangle.previous, + next = triangle.next; + + // If the area of the current point is less than that of the previous point + // to be eliminated, use the latter's area instead. This ensures that the + // current point cannot be eliminated without eliminating previously- + // eliminated points. + if (triangle[1][2] < maxArea) triangle[1][2] = maxArea; + else maxArea = triangle[1][2]; + + if (previous) { + previous.next = next; + previous[2] = triangle[2]; + update(previous); + } + + if (next) { + next.previous = previous; + next[0] = triangle[0]; + update(next); + } + } + + topology.arcs.forEach(function(arc) { + arc.forEach(relative); + }); + + function update(triangle) { + heap.remove(triangle); + triangle[1][2] = triangleArea(triangle); + heap.push(triangle); + } + + return topology; + }; + + function cartesianRingArea(ring) { + var i = -1, + n = ring.length, + a, + b = ring[n - 1], + area = 0; + + while (++i < n) { + a = b; + b = ring[i]; + area += a[0] * b[1] - a[1] * b[0]; + } + + return area * .5; + } + + function cartesianTriangleArea(triangle) { + var a = triangle[0], b = triangle[1], c = triangle[2]; + return Math.abs((a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1])); + } + + function compareArea(a, b) { + return a[1][2] - b[1][2]; + } + + function minAreaHeap() { + var heap = {}, + array = [], + size = 0; + + heap.push = function(object) { + up(array[object._ = size] = object, size++); + return size; + }; + + heap.pop = function() { + if (size <= 0) return; + var removed = array[0], object; + if (--size > 0) object = array[size], down(array[object._ = 0] = object, 0); + return removed; + }; + + heap.remove = function(removed) { + var i = removed._, object; + if (array[i] !== removed) return; // invalid request + if (i !== --size) object = array[size], (compareArea(object, removed) < 0 ? up : down)(array[object._ = i] = object, i); + return i; + }; + + function up(object, i) { + while (i > 0) { + var j = ((i + 1) >> 1) - 1, + parent = array[j]; + if (compareArea(object, parent) >= 0) break; + array[parent._ = i] = parent; + array[object._ = i = j] = object; + } + } + + function down(object, i) { + while (true) { + var r = (i + 1) << 1, + l = r - 1, + j = i, + child = array[j]; + if (l < size && compareArea(array[l], child) < 0) child = array[j = l]; + if (r < size && compareArea(array[r], child) < 0) child = array[j = r]; + if (j === i) break; + array[child._ = i] = child; + array[object._ = i = j] = object; + } + } + + return heap; + } + + function transformAbsolute(transform) { + if (!transform) return noop; + var x0, + y0, + kx = transform.scale[0], + ky = transform.scale[1], + dx = transform.translate[0], + dy = transform.translate[1]; + return function(point, i) { + if (!i) x0 = y0 = 0; + point[0] = (x0 += point[0]) * kx + dx; + point[1] = (y0 += point[1]) * ky + dy; + }; + } + + function transformRelative(transform) { + if (!transform) return noop; + var x0, + y0, + kx = transform.scale[0], + ky = transform.scale[1], + dx = transform.translate[0], + dy = transform.translate[1]; + return function(point, i) { + if (!i) x0 = y0 = 0; + var x1 = (point[0] - dx) / kx | 0, + y1 = (point[1] - dy) / ky | 0; + point[0] = x1 - x0; + point[1] = y1 - y0; + x0 = x1; + y0 = y1; + }; + } + + function noop() {} + + if (typeof define === "function" && define.amd) define(topojson); + else if (typeof module === "object" && module.exports) module.exports = topojson; + else this.topojson = topojson; +}(); + +},{}],12:[function(require,module,exports){ +module.exports = parse; +module.exports.parse = parse; +module.exports.stringify = stringify; + +var numberRegexp = /^[-+]?([0-9]*\.[0-9]+|[0-9]+)([eE][-+]?[0-9]+)?/; + + /* + * Parse WKT and return GeoJSON. + * + * @param {string} _ A WKT geometry + * @return {?Object} A GeoJSON geometry object + */ +function parse(_) { + var parts = _.split(";"), + _ = parts.pop(), + srid = (parts.shift() || "").split("=").pop(); + + var i = 0; + + function $(re) { + var match = _.substring(i).match(re); + if (!match) return null; + else { + i += match[0].length; + return match[0]; + } + } + + function crs(obj) { + if (obj && srid.match(/\d+/)) { + obj.crs = { + type: 'name', + properties: { + name: 'urn:ogc:def:crs:EPSG::' + srid + } + }; + } + + return obj; + } + + function white() { $(/^\s*/); } + + function multicoords() { + white(); + var depth = 0, rings = [], stack = [rings], + pointer = rings, elem; + + while (elem = + $(/^(\()/) || + $(/^(\))/) || + $(/^(\,)/) || + $(numberRegexp)) { + if (elem == '(') { + stack.push(pointer); + pointer = []; + stack[stack.length - 1].push(pointer); + depth++; + } else if (elem == ')') { + pointer = stack.pop(); + // the stack was empty, input was malformed + if (!pointer) return; + depth--; + if (depth === 0) break; + } else if (elem === ',') { + pointer = []; + stack[stack.length - 1].push(pointer); + } else if (!isNaN(parseFloat(elem))) { + pointer.push(parseFloat(elem)); + } else { + return null; + } + white(); + } + + if (depth !== 0) return null; + return rings; + } + + function coords() { + var list = [], item, pt; + while (pt = + $(numberRegexp) || + $(/^(\,)/)) { + if (pt == ',') { + list.push(item); + item = []; + } else { + if (!item) item = []; + item.push(parseFloat(pt)); + } + white(); + } + if (item) list.push(item); + return list.length ? list : null; + } + + function point() { + if (!$(/^(point)/i)) return null; + white(); + if (!$(/^(\()/)) return null; + var c = coords(); + if (!c) return null; + white(); + if (!$(/^(\))/)) return null; + return { + type: 'Point', + coordinates: c[0] + }; + } + + function multipoint() { + if (!$(/^(multipoint)/i)) return null; + white(); + var c = multicoords(); + if (!c) return null; + white(); + return { + type: 'MultiPoint', + coordinates: c + }; + } + + function multilinestring() { + if (!$(/^(multilinestring)/i)) return null; + white(); + var c = multicoords(); + if (!c) return null; + white(); + return { + type: 'MultiLineString', + coordinates: c + }; + } + + function linestring() { + if (!$(/^(linestring)/i)) return null; + white(); + if (!$(/^(\()/)) return null; + var c = coords(); + if (!c) return null; + if (!$(/^(\))/)) return null; + return { + type: 'LineString', + coordinates: c + }; + } + + function polygon() { + if (!$(/^(polygon)/i)) return null; + white(); + return { + type: 'Polygon', + coordinates: multicoords() + }; + } + + function multipolygon() { + if (!$(/^(multipolygon)/i)) return null; + white(); + return { + type: 'MultiPolygon', + coordinates: multicoords() + }; + } + + function geometrycollection() { + var geometries = [], geometry; + + if (!$(/^(geometrycollection)/i)) return null; + white(); + + if (!$(/^(\()/)) return null; + while (geometry = root()) { + geometries.push(geometry); + white(); + $(/^(\,)/); + white(); + } + if (!$(/^(\))/)) return null; + + return { + type: 'GeometryCollection', + geometries: geometries + }; + } + + function root() { + return point() || + linestring() || + polygon() || + multipoint() || + multilinestring() || + multipolygon() || + geometrycollection(); + } + + return crs(root()); +} + +/** + * Stringifies a GeoJSON object into WKT + */ +function stringify(gj) { + if (gj.type === 'Feature') { + gj = gj.geometry; + } + + function pairWKT(c) { + if (c.length === 2) { + return c[0] + ' ' + c[1]; + } else if (c.length === 3) { + return c[0] + ' ' + c[1] + ' ' + c[2]; + } + } + + function ringWKT(r) { + return r.map(pairWKT).join(', '); + } + + function ringsWKT(r) { + return r.map(ringWKT).map(wrapParens).join(', '); + } + + function multiRingsWKT(r) { + return r.map(ringsWKT).map(wrapParens).join(', '); + } + + function wrapParens(s) { return '(' + s + ')'; } + + switch (gj.type) { + case 'Point': + return 'POINT (' + pairWKT(gj.coordinates) + ')'; + case 'LineString': + return 'LINESTRING (' + ringWKT(gj.coordinates) + ')'; + case 'Polygon': + return 'POLYGON (' + ringsWKT(gj.coordinates) + ')'; + case 'MultiPoint': + return 'MULTIPOINT (' + ringWKT(gj.coordinates) + ')'; + case 'MultiPolygon': + return 'MULTIPOLYGON (' + multiRingsWKT(gj.coordinates) + ')'; + case 'MultiLineString': + return 'MULTILINESTRING (' + ringsWKT(gj.coordinates) + ')'; + case 'GeometryCollection': + return 'GEOMETRYCOLLECTION (' + gj.geometries.map(stringify).join(', ') + ')'; + default: + throw new Error('stringify requires a valid GeoJSON Feature or geometry object as input'); + } +} + +},{}]},{},[1])(1) +}); \ No newline at end of file diff --git a/js/script.js b/js/script.js index 5f2dc04..ae7387e 100644 --- a/js/script.js +++ b/js/script.js @@ -702,6 +702,17 @@ Array.prototype.unique = function() { }, loadContacts : function() { + $.getJSON(OC.generateUrl('/apps/maps/getgps'), null, function parseGpxFiles(r) { + var layerArr = new Array(r.length); + for(i=0; i Date: Thu, 13 Aug 2015 20:03:25 +0200 Subject: [PATCH 2/3] moved gpx loading to own button/function --- js/script.js | 26 +++++++++++++++----------- templates/main.php | 3 +++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/js/script.js b/js/script.js index ae7387e..9549c79 100644 --- a/js/script.js +++ b/js/script.js @@ -234,6 +234,21 @@ Array.prototype.unique = function() { }, function() { toolKit.removeFavMarkers() }); + + $('.trackLayer').clickToggle(function() { + $.getJSON(OC.generateUrl('/apps/maps/getgps'), null, function parseGpxFiles(r) { + var layerArr = new Array(r.length); + for(i=0; iContacts +
  • + Show GPX-Tracks +
  • Amenity From f164c5c2b1d830d0de27a01216bf4729079aaf0b Mon Sep 17 00:00:00 2001 From: Vinzenz Rosenkranz Date: Thu, 13 Aug 2015 23:04:36 +0200 Subject: [PATCH 3/3] split gpx section in different actions --- js/script.js | 47 +++++++++++++++++++++++++++++++++++----------- templates/main.php | 7 ++++++- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/js/script.js b/js/script.js index 9549c79..d0411e4 100644 --- a/js/script.js +++ b/js/script.js @@ -235,18 +235,43 @@ Array.prototype.unique = function() { toolKit.removeFavMarkers() }); - $('.trackLayer').clickToggle(function() { - $.getJSON(OC.generateUrl('/apps/maps/getgps'), null, function parseGpxFiles(r) { - var layerArr = new Array(r.length); - for(i=0; i
  • - Show GPX-Tracks + Show GPX-Tracks +
  • Amenity