From 3da5347e7d07e3473229c4278b547bcb1684875c Mon Sep 17 00:00:00 2001 From: Eike Send Date: Tue, 18 Feb 2025 22:59:31 +0100 Subject: [PATCH] Simplify, refactor and repair map matching demo --- map_matching/conf/env.conf | 10 - map_matching/css/classic.css | 4 - map_matching/css/leaflet.label.css | 56 ---- map_matching/css/mapzen-common.css | 35 --- map_matching/css/optimized_route.css | 287 ------------------- map_matching/index-internal.html | 113 -------- map_matching/index.html | 378 ++++++++++++++++++++------ map_matching/js/LICENSE.txt | 20 -- map_matching/js/MIT-LICENCE.txt | 20 -- map_matching/js/jquery.columns.min.js | 9 - map_matching/js/main.js | 354 ------------------------ map_matching/js/map_matching.js | 267 ------------------ map_matching/main.js | 169 ++++++++++++ map_matching/style.css | 70 +++++ 14 files changed, 527 insertions(+), 1265 deletions(-) delete mode 100644 map_matching/conf/env.conf delete mode 100644 map_matching/css/classic.css delete mode 100644 map_matching/css/leaflet.label.css delete mode 100644 map_matching/css/mapzen-common.css delete mode 100644 map_matching/css/optimized_route.css delete mode 100644 map_matching/index-internal.html delete mode 100755 map_matching/js/LICENSE.txt delete mode 100644 map_matching/js/MIT-LICENCE.txt delete mode 100644 map_matching/js/jquery.columns.min.js delete mode 100644 map_matching/js/main.js delete mode 100644 map_matching/js/map_matching.js create mode 100644 map_matching/main.js create mode 100644 map_matching/style.css diff --git a/map_matching/conf/env.conf b/map_matching/conf/env.conf deleted file mode 100644 index 972c6ff..0000000 --- a/map_matching/conf/env.conf +++ /dev/null @@ -1,10 +0,0 @@ -var server = { - local: "http://localhost:8002/trace_attributes", - dev: "https://valhalla.dev.mapzen.com/trace_attributes", - prod:"https://valhalla.mapzen.com/trace_attributes" -} -var accessToken = { - local: "", - dev: "valhalla-t_16n1c", - prod:"valhalla-UdVXVeg" -} diff --git a/map_matching/css/classic.css b/map_matching/css/classic.css deleted file mode 100644 index f1f0d29..0000000 --- a/map_matching/css/classic.css +++ /dev/null @@ -1,4 +0,0 @@ -.columns .ui-table{border-collapse:collapse;border-width:1px 1px 0 1px;border-style:solid;border-color:#ccc;width:100%}.columns .ui-table thead tr{background-image:-webkit-linear-gradient(top, #dbdbdb 10%, #b8b8b8 100%);background-image:linear-gradient(to bottom, #dbdbdb 10%, #b8b8b8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#DBDBDB', endColorstr='#B8B8B8',GradientType=0 );color:#333;font-size:14px;font-weight:bold;text-align:left}.columns .ui-table thead tr th{padding:5px 5px 5px 8px;border-right:1px solid #878787;border-bottom:1px solid #878787}.columns .ui-table thead tr th:first-child{border-left:1px solid #ccc}.columns .ui-table thead tr th:last-child{border-right:1px solid #ccc}.columns .ui-table thead tr th .ui-arrow{display:block;float:right;font-size:10px;width:10px}.columns .ui-table thead tr th.ui-table-sort-up,.columns .ui-table thead tr th.ui-table-sort-down{background:-webkit-linear-gradient(top, #d0d9e4 10%, #94a3c0 100%);background:linear-gradient(to bottom, #d0d9e4 10%, #94a3c0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#D0D9E4', endColorstr='#94A3C0',GradientType=0 )}.columns .ui-table tbody{font-size:14px}.columns .ui-table tbody tr td{border-right:1px solid #ccc;padding:12px}.columns .ui-table tbody tr.ui-table-rows-even{background:#F1F4F8}.columns .ui-table tbody tr.ui-table-rows-odd{background:#ffffff}.columns .ui-table-footer{background-image:-webkit-linear-gradient(top, #cbcbcb 10%, #aaa 100%);background-image:linear-gradient(to bottom, #cbcbcb 10%, #aaa 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#CBCBCB', endColorstr='#AAAAAA',GradientType=0 );border-top:1px solid #878787;width:100%;padding:8px 0;font-size:11px;text-align:left;color:#333}.columns .ui-table-footer span{vertical-align:middle}.columns .ui-table-footer .ui-table-size,.columns .ui-table-footer .ui-table-results,.columns .ui-table-footer .ui-table-controls{display:inline-block;width:32%}.columns .ui-table-footer .ui-table-size{padding-left:20px}.columns .ui-table-footer .ui-table-results{text-align:center}.columns .ui-table-footer .ui-table-controls{text-align:right}.columns .ui-table-footer .ui-table-control-next,.columns .ui-table-footer .ui-table-control-prev,.columns .ui-table-footer .ui-table-control-disabled{display:inline-block;background-image:-webkit-linear-gradient(top, #fdfdfd 10%, #c0bfbe 100%);background-image:linear-gradient(to bottom, #fdfdfd 10%, #c0bfbe 100%);background-color:transparent;border:1px solid #333;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;list-style:none;margin:0;padding:5px;vertical-align:middle;font-weight:bold;color:#333;cursor:pointer;text-align:center}.columns .ui-table-footer .ui-table-control-disabled img{opacity:0.5}.columns .ui-columns-search{font-size:14px;background:-webkit-linear-gradient(top, #d1d1d1 10%, #a7a7a8 100%);background:linear-gradient(to bottom, #d1d1d1 10%, #a7a7a8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#D1D1D1', endColorstr='#A7A7A8',GradientType=0 );padding:10px;border-bottom:1px solid #878787;text-align:right}.columns .ui-columns-search input{width:200px;border-radius:10px;padding:4px 10px 4px 25px;border:2px solid transparent;background-image:url(../images/search.png);background-position:5px center;background-repeat:no-repeat}.columns .ui-columns-search input:focus{border:2px solid #6196CD;outline:none} -.columns { - margin: 20px auto !important; -} diff --git a/map_matching/css/leaflet.label.css b/map_matching/css/leaflet.label.css deleted file mode 100644 index b926d33..0000000 --- a/map_matching/css/leaflet.label.css +++ /dev/null @@ -1,56 +0,0 @@ -.leaflet-label { - //background: rgb(235, 235, 235); - //background: rgba(235, 235, 235, 0.81); - //background: #585858; - //background-clip: padding-box; - //border-color: #777; - //border-color: rgba(0,0,0,0.25); - //border-radius: 4px; - //border-style: solid; - //border-width: 4px; - color: #FFFFFF; - //color: #111; - display: block; - font: 12px/20px "Helvetica Neue", Arial, Helvetica, sans-serif; - font-weight: bold; - padding: 1px 6px; - position: absolute; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - pointer-events: none; - white-space: nowrap; - z-index: 6; -} - -.leaflet-label.leaflet-clickable { - cursor: pointer; - pointer-events: auto; -} - -.leaflet-label:before, -.leaflet-label:after { - border-top: 6px solid transparent; - border-bottom: 6px solid transparent; - content: none; - position: absolute; - top: 5px; -} - -.leaflet-label:before { - border-right: 6px solid black; - border-right-color: inherit; - left: -10px; -} - -.leaflet-label:after { - border-left: 6px solid black; - border-left-color: inherit; - right: -10px; -} - -.leaflet-label-right:before, -.leaflet-label-left:after { - content: ""; -} diff --git a/map_matching/css/mapzen-common.css b/map_matching/css/mapzen-common.css deleted file mode 100644 index c64916c..0000000 --- a/map_matching/css/mapzen-common.css +++ /dev/null @@ -1,35 +0,0 @@ -/* button styles */ - -.btn { - border-radius: 0; - border-width: 1px; - text-transform: uppercase; - font-weight: 600; - padding: 10px 16px; -} - - -.btn-mapzen { - border-color: #d4645c;; - background-color: #d4645c;; - color: #fff; - text-shadow: none; -} - -.btn-mapzen:hover, .btn-mapzen:focus { - border-color: #993434; - background-color: #993434; - color: #fff; -} - -.btn-transparent { - background: transparent; - border-color: #444;; - color: #444;; -} - -.btn-transparent:hover, .btn-transparent:focus { - background-color: #e5e5e5; - border-color: #444;; - color: #444;; -} \ No newline at end of file diff --git a/map_matching/css/optimized_route.css b/map_matching/css/optimized_route.css deleted file mode 100644 index cf5a6e6..0000000 --- a/map_matching/css/optimized_route.css +++ /dev/null @@ -1,287 +0,0 @@ -html { - width: 100%; - height: 100%; -} - -body { - font: 13px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; - width: 100%; - height: 100%; - color: #383a3a; - min-height: 600px; -} - -.container-fluid { - height: 100%; - margin: 0; - padding: 0; -} - -.control-container { - width: 500px; - height: 100%; - float: left; - background-color: #eee; - padding: 20px; - overflow-y: auto; -} - -#map { - width: calc( 100% - 500px); - height: 100%; - float: left; -} - -.tableView { - padding-top: 20px; -} - -.instruction { - text-align: center; - font-weight: 600; - margin: 20px 0; -} - -/* these are for blocking ui */ -div[class*="Wrapper"] { - background-color: #fff; - position: relative; - padding: 10px; - margin: 10px 0; - text-align: center; -} - -div[class*="Blocker"] { - position: absolute; - left: 0; - top: 0; - z-index: 1050; -} - -.block { - width: 100%; - height: 100%; - background-color:rgba(238,238,238,0.5); -} - - -/* optimize type button */ -.stitched { - padding: 8px; - margin-right: 7px; - margin-bottom: 20px; - background: #FFFFFF; - color: #A4A4A4; - font-size: 16px; - border: 2px dashed #DADADA; - box-shadow: 0; -} - -.stitched.selected { - color: #68c175; - border: 2px solid #99cfc1; - cursor: default; -} - -button:focus { - outline: 2px solid #9ed7a7; -} - -.done { - background-color: #fff; - padding: 3px 8px; - margin: 15px auto; - width: auto; - text-align: center; - border: 1px solid #666; - cursor: pointer; -} - -ol { - padding: 0 30px; -} - -li { - list-style-type: none; - width: 100%; - height: 45px; - border-bottom: 1px solid #31783c; - position: relative; - margin: 5px 0; -} -li .marker { - width: 28px; - height: 36px; - margin-left: 5px; - margin-top: 5px; - background-repeat: no-repeat; - float: left; - color: #fff; - padding-top: 5px; - font-weight: 600; - text-align: center; -} - -li .start { background-image:url(../../matrix/resource/matrix_pin_start.png); } -li .end { background-image:url(../../matrix/resource/matrix_pin_end.png);} - -li .geocode { - font-size: 14px; - position: absolute; - left: 40px; - bottom: 10px; -} - -li .placeholder.geocode { - color: #ccc; -} - - -.routingBtns { - //float: right; -} - -.btnWrapper::after { - content: ""; - display: table; - clear: both; -} - -.plain { - float: left; - background: transparent; - border: none; - color: #68c175; - padding: 10px 16px; - margin-top: 2px; -} - -.btnOptimize { - background-color: #68c175; - float: left; - padding: 10px 26px; - border: 1px solid #68c175; - color: #fff; - text-transform: uppercase; -} - -.btnOptimize:hover { - background-color: #31783c; - border-color: #31783c; -} - -.leaflet-routing-alt tr { - min-height: 40px; - height: 80px; - border-bottom: 1px solid #eee; -} - -.leaflet-routing-icon { - -webkit-background-size: 240px 20px; - background-size: 240px 20px; - background-repeat: no-repeat; - margin: 0; - content: ''; - display: inline-block; - vertical-align: top; - width: 20px; -} - -.leaflet-routing-icon h2 { - width: 20px; - margin-left: 11px; - margin-bottom: 20px; - color: white; -} - -.leaflet-routing-icon img{ - z-index: -1; - margin-top: -60px; - position: relative; - bottom: -15px; - } - -.leaflet-routing-container .start { - font-size: 18px; - min-height: 60px; - line-height: 60px; - padding-left: 50px; - background-image: url('../../matrix/resource/matrix_pin_start.png'); - background-repeat: no-repeat; - background-position: 5px 8px; - background-size: 45px 55px; - letter-spacing: 0.5px; -} - -.leaflet-routing-container .dest{ - font-size: 18px; - line-height:60px; - min-height:40px; - padding-left:50px; - background-image: url('../../matrix/resource/matrix_pin_end.png'); - background-repeat: no-repeat; - background-position: 5px 8px; - background-size: 45px 55px; - letter-spacing: 0.5px; -} - -/* vehicle mode*/ - -.vehicleBox { - //width: 170px; - // float: left; -} - -.vehicleBox .vehicle { - width: 50px; - height: 41px; - float: left; - background-color: transparent; - // border: 2px dashed #DADADA; - margin-right: 5px; - background-image: url('../../matrix/images/modes.svg'); - background-size: 150px 41px; - background-repeat: no-repeat; -} -.vehicleBox .vehicle.active { - color: #68c175; - border: 2px solid #68c175;; -} - -.bike { background-position: -50px 0;} -.pedestrian { background-position: -100px 0;} - -.leaflet-label-right:before, -.leaflet-label-left:after { - content: none; -} - -html.is-iframed-demo .container-fluid { - padding-left: 0; - padding-right: 0; -} - -@media (max-width: 767px) { - html.is-iframed-demo #map { - height: calc( 100% - 550px ); - } - .container-fluid { - width: 100%; - height: auto; - } - .control-container { - width: 100%; - height: auto; - } - #map { - width: 500px; - } -} - -html.is-iframed-demo .not-map-part { - margin: 0 auto; -} - -html.is-iframed-demo .hide-if-iframed { - display: none; -} \ No newline at end of file diff --git a/map_matching/index-internal.html b/map_matching/index-internal.html deleted file mode 100644 index 6fca34e..0000000 --- a/map_matching/index-internal.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -
-
- logo - -
-

Select an environment

- -
-
-
- - - - - -
- -
-
- -
-

Options

-

Radius:

-
- -
-

GeoJSON

- - -
- -
-
-

Locations

-
    -
  1. -
    {{point.index}}
    - {{point.latlon}} -
  2. -
  3. -
    - {{endgeocode}} -
  4. -
-
{{end_mapInstruction}}
-
-
-
-
- - -
- -
-
- -
-
-
JSON Optimized Route Response Link
-
-
-
-
- - - - - - - - - - - - - - - - - diff --git a/map_matching/index.html b/map_matching/index.html index 3b975c9..bd5ef83 100644 --- a/map_matching/index.html +++ b/map_matching/index.html @@ -1,107 +1,305 @@ - + + + - + - - - - - - - + + + + + + - - - - - + + - - -
-
- logo - -
-
-
-
- - - - -
- -
+ +
+
+ Valhalla Logo +
+ + +
-

Options

-

Radius:

+

Options

+

Radius:

-

GeoJSON

- - -
- -
-
-

Locations

-
    -
  1. -
    {{point.index}}
    - {{point.latlon}} -
  2. -
  3. -
    - {{endgeocode}} -
  4. -
-
{{end_mapInstruction}}
-
-
+

GeoJSON

+ +
- -
- -
-
- -
-
-
JSON Optimized Route Response Link
+
+
-
-
- - - - - - - - - - - - - - - - + + \ No newline at end of file diff --git a/map_matching/js/LICENSE.txt b/map_matching/js/LICENSE.txt deleted file mode 100755 index e445cd3..0000000 --- a/map_matching/js/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2014, Michael Eisenbraun (http://eisenbraun.github.io/columns/) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/map_matching/js/MIT-LICENCE.txt b/map_matching/js/MIT-LICENCE.txt deleted file mode 100644 index 1ace2f3..0000000 --- a/map_matching/js/MIT-LICENCE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright 2012 Jacob Toye - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/map_matching/js/jquery.columns.min.js b/map_matching/js/jquery.columns.min.js deleted file mode 100644 index 9764f56..0000000 --- a/map_matching/js/jquery.columns.min.js +++ /dev/null @@ -1,9 +0,0 @@ -/*** - * Copyright (c) 2014 - * Licensed under the MIT License. - * - * Author: Michael Eisenbraun - * Version: 2.2.2 - * Requires: jQuery 1.7.2+ - * Documentation: http://eisenbraun.github.io/columns/ - */if(!window.console)var console={log:function(){}};(function(e){e.fn.columns=function(n){var r=[],i=Array.prototype.slice.call(arguments,1);typeof n=="string"?this.each(function(){var t=e.data(this,"columns");if(typeof t=="undefined"||!e.isFunction(t[n]))return e.error('No such method "'+n+'" for Columns');var s=t[n].apply(t,i);s!==undefined&&s!==t&&r.push(s)}):this.each(function(){e.data(this,"columns")||e.data(this,"columns",new t(this,n))});return r.length===0?this.data("columns"):r.length===1?r[0]:r};var t=function(t,n){this.$el=e(t);n&&e.extend(this,n);this.VERSION="2.2.2";this.sort=function(){function n(e,n,r){n=n?-1:1;return function(i,s){i=i[e];s=s[e];if(t.test(i)&&t.test(s)){i=new Date(i);i=Date.parse(i);s=new Date(s);s=Date.parse(s)}else if(typeof r!="undefined"){i=r(i);s=r(s)}return is?n*1:0}}var e=this,t=/^(Jan|January|Feb|February|Mar|March|Apr|April|May|Jun|June|Jul|July|Aug|August|Sep|September|Oct|October|Nov|November|Dec|December|(0?\d{1})|(10|11|12))(-|\s|\/|\.)(0?[1-9]|(1|2)[0-9]|3(0|1))(-|\s|\/|\.|,\s)(19|20)?\d\d$/i;e.total&&e.sortBy&&typeof e.data[0][e.sortBy]!="undefined"&&e.data.sort(n(e.sortBy,e.reverse))};this.filter=function(){var t=this,n=t.searchableFields.length;if(t.query){var r=new RegExp(t.query,"gi");t.data=e.grep(t.data,function(e){for(var i=0;i'):i.push('');e.each(t.schema,function(e,n){n.hide||(n.template?i.push(""+t.chevron(n.template,r)+""):i.push(""+r[n.key]+""))});i.push("");return i}function i(){var n=[];n.push("");t.showRowsMenu=n.join("")}function s(){t.rows=[];t.total?e.each(t.data,function(e,i){e===0&&n();t.rows.push(r(e,i).join(""))}):t.rows.push('No Results')}var t=this;t.resetData();t.searching&&t.filter();t.sorting&&t.sort();t.paginating&&t.paginate();s();i();var o={prevPage:t.page-1,nextPage:t.page+1,prevPageExists:t.pageExists(t.page-1),nextPageExists:t.pageExists(t.page+1),resultRange:t.range,tableTotal:t.total,showRowsMenu:t.showRowsMenu,rows:t.rows,headers:t.thead,query:t.query,search:t.search,table:t.table};e.extend(t.view,o);t.plugins&&e.each(t.plugins,function(e,n){typeof ColumnsPlugins!="undefined"&&typeof ColumnsPlugins[n]!="undefined"&&ColumnsPlugins[n].create.call(t)});if(t.search){t.$el.html(t.chevron(t.template,t.view));t.search=!1}else{e("[data-columns-table]",t.$el).remove();t.$el.append(t.chevron(t.template,t.view))}return!0};this.init=function(){function n(){t.schema=[];e.each(t.data[0],function(e){t.schema.push({header:e,key:e})})}function r(){t.searchableFields=[];e.each(t.data[0],function(e){t.searchableFields.push(e)})}function i(){t.sortableFields=[];e.each(t.data[0],function(e){t.sortableFields.push(e)})}function s(){e.ajax({url:t.templateFile,async:!1,success:function(e){t.template=e},error:function(){e.error("Template could not be found.")}})}var t=this;if(e.isArray(t.data)){t.master=[];t.view={};t.$el.addClass("columns");t.$el.on("click",".ui-table-sortable",function(n){var r=e(this).data("columns-sortby");t.sortBy===r&&(t.reverse=t.reverse?!1:!0);t.sortBy=r;t.sortHandler(n)});t.$el.on("click",".ui-table-control-next, .ui-table-control-prev",function(n){t.page=e(this).data("columns-page");t.pageHandler(n)});t.$el.on("keyup",".ui-table-search",function(n){t.query=e(this).val();t.searchHandler(n)});t.$el.on("change",".ui-table-size select",function(n){t.size=parseInt(e(this).val());t.sizeHandler(n)});t.plugins&&e.each(t.plugins,function(e,n){typeof ColumnsPlugins!="undefined"&&typeof ColumnsPlugins[n]!="undefined"&&ColumnsPlugins[n].init.call(t)});t.conditioning&&t.condition();t.schema||n();t.searchableFields||r();t.sortableFields||i();t.templateFile&&s();e.extend(t.master,t.data);t.create()}else e.error('The "data" parameter must be an array.')};this.init()};t.prototype={evenRowClass:"ui-table-rows-even",oddRowClass:"ui-table-rows-odd",liveSearch:!0,page:1,pages:1,plugins:null,query:null,reverse:!1,pagination:!0,schema:null,search:!0,searchableFields:null,showRows:[10,20,30,50],size:20,sortableFields:null,sortBy:null,table:!0,templateFile:null,template:' {{#search}} {{/search}} {{#table}}
{{#headers}} {{#sortable}} {{/sortable}} {{#notSortable}} {{/notSortable}} {{#sortedUp}} {{/sortedUp}} {{#sortedDown}} {{/sortedDown}} {{/headers}} {{#rows}} {{{.}}} {{/rows}}
{{header}}{{header}}{{header}} {{header}}
{{/table}} ',conditioning:!0,paginating:!0,searching:!0,sorting:!0,pageHandler:function(){this.create()},searchHandler:function(e){this.liveSearch?this.create():e.keyCode=="13"&&this.create()},sizeHandler:function(){this.create()},sortHandler:function(){this.page=1;this.create()},destroy:function(){this.$el.data("columns",null);this.$el.empty();return!0},getObject:function(){return this},getPage:function(){return this.page},getQuery:function(){return this.query},getRange:function(){return this.range},getRows:function(){return this.rows},getShowRowsMenu:function(){return this.showRowsMenu},getTemplate:function(){return this.template},getThead:function(){return this.thead},getTotal:function(){return this.total},getVersion:function(){return this.VERSION},getView:function(){return this.view},gotoPage:function(e){if(this.pageExists(e)){this.page=e;this.create();return!0}return!1},pageExists:function(e){return e>0&&e<=this.pages?!0:!1},resetData:function(e){this.data=this.master.slice(0);return this.data},setMaster:function(t){if(e.isArray(t)){this.master=t;return!0}return!1},setPage:function(e){this.page=this.pageExists(e)?e:this.page;return this.page},setRange:function(){var e=(this.page-1)*this.size,t=e+this.size"'\/]/g,function(e){return f[e]})}function m(t,r){function m(){if(f&&!l)while(u.length)delete o[u.pop()];else u=[];f=!1;l=!1}function x(e){typeof e=="string"&&(e=e.split(h,2));if(!n(e)||e.length!==2)throw new Error("Invalid tags: "+e);w=new RegExp(i(e[0])+"\\s*");E=new RegExp("\\s*"+i(e[1]));S=new RegExp("\\s*"+i("}"+e[1]))}if(!t)return[];var s=[],o=[],u=[],f=!1,l=!1,w,E,S;x(r||e.tags);var T=new b(t),N,C,k,L,A,O;while(!T.eos()){N=T.pos;k=T.scanUntil(w);if(k)for(var M=0,_=k.length;M<_;++M){L=k.charAt(M);a(L)?u.push(o.length):l=!0;o.push(["text",L,N,N+1]);N+=1;L==="\n"&&m()}if(!T.scan(w))break;f=!0;C=T.scan(v)||"name";T.scan(c);if(C==="="){k=T.scanUntil(p);T.scan(p);T.scanUntil(E)}else if(C==="{"){k=T.scanUntil(S);T.scan(d);T.scanUntil(E);C="&"}else k=T.scanUntil(E);if(!T.scan(E))throw new Error("Unclosed tag at "+T.pos);A=[C,k,N,T.pos];o.push(A);if(C==="#"||C==="^")s.push(A);else if(C==="/"){O=s.pop();if(!O)throw new Error('Unopened section "'+k+'" at '+N);if(O[1]!==k)throw new Error('Unclosed section "'+O[1]+'" at '+N)}else C==="name"||C==="{"||C==="&"?l=!0:C==="="&&x(k)}O=s.pop();if(O)throw new Error('Unclosed section "'+O[1]+'" at '+T.pos);return y(g(o))}function g(e){var t=[],n,r;for(var i=0,s=e.length;i0?r[r.length-1][4]:t;break;default:n.push(i)}}return t}function b(e){this.string=e;this.tail=e;this.pos=0}function w(e,t){this.view=e==null?{}:e;this.cache={".":this.view};this.parent=t}function E(){this.cache={}}var t=Object.prototype.toString,n=Array.isArray||function(e){return t.call(e)==="[object Array]"},s=RegExp.prototype.test,u=/\S/,f={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"},c=/\s*/,h=/\s+/,p=/\s*=/,d=/\s*\}/,v=/#|\^|\/|>|\{|&|=|!/;b.prototype.eos=function(){return this.tail===""};b.prototype.scan=function(e){var t=this.tail.match(e);if(!t||t.index!==0)return"";var n=t[0];this.tail=this.tail.substring(n.length);this.pos+=n.length;return n};b.prototype.scanUntil=function(e){var t=this.tail.search(e),n;switch(t){case-1:n=this.tail;this.tail="";break;case 0:n="";break;default:n=this.tail.substring(0,t);this.tail=this.tail.substring(t)}this.pos+=n.length;return n};w.prototype.push=function(e){return new w(e,this)};w.prototype.lookup=function(e){var t=this.cache,n;if(e in t)n=t[e];else{var i=this,s,o;while(i){if(e.indexOf(".")>0){n=i.view;s=e.split(".");o=0;while(n!=null&&o":if(!s)continue;c=r(s)?s(l[1]):s[l[1]];c!=null&&(u+=this.renderTokens(this.parse(c),i,s,c));break;case"&":c=i.lookup(l[1]);c!=null&&(u+=c);break;case"name":c=i.lookup(l[1]);c!=null&&(u+=e.escape(c));break;case"text":u+=l[1]}}return u};e.name="mustache.js";e.version="0.8.1";e.tags=["{{","}}"];var S=new E;e.clearCache=function(){return S.clearCache()};e.parse=function(e,t){return S.parse(e,t)};e.render=function(e,t,n){return S.render(e,t,n)};e.to_html=function(t,n,i,s){var o=e.render(t,n,i);if(!r(s))return o;s(o)};e.escape=l;e.Scanner=b;e.Context=w;e.Writer=E;return e}); \ No newline at end of file diff --git a/map_matching/js/main.js b/map_matching/js/main.js deleted file mode 100644 index 165778e..0000000 --- a/map_matching/js/main.js +++ /dev/null @@ -1,354 +0,0 @@ -var app = angular.module('optimized_route', []); -var hash_params = L.Hash.parseHash(location.hash); - -var envServer = "production"; -var envToken = accessToken.prod; -var serviceUrl = server.prod; -var sentManyToManyEnd = false; -var optimized_route = true; - -function selectEnv() { - $("#env_dropdown").find("option:selected").each(function() { - envServer = $(this).text(); - getEnvToken(); - }); -} - -selectEnv(); - -function handleChange(evt) { - var sel = document.getElementById('selector'); - for (var i = 0; i < sel.options.length; i++) { - var results = sel.options[i].text + " " + sel.options[i].value; - sel.options[i].innerHTML = results; - } -} - -function getEnvToken() { - switch (envServer) { - case "localhost": - envToken = accessToken.local; - serviceUrl = server.local; - break; - case "development": - envToken = accessToken.dev; - serviceUrl = server.dev; - break; - case "production": - envToken = accessToken.prod; - serviceUrl = server.prod; - break; - } -} - -app.run(function($rootScope) { - var hash_loc = hash_params ? hash_params : { - center : { - lat : 40.7486, - lng : -73.9690 - }, - zoom : 13 - }; - $rootScope.geobase = { - zoom : hash_loc.zoom, - lat : hash_loc.center.lat, - lon : hash_loc.center.lng - }; - $(document).on('new-location', function(e) { - $rootScope.geobase = { - zoom : e.zoom, - lat : e.lat, - lon : e.lon - }; - }); -}); - - -//hooks up to the div whose data-ng-controller attribute matches this name -app.controller('OptimizedRouteController', function($scope, $rootScope, $sce, $http) { - var road = L.tileLayer('http://b.tile.openstreetmap.org/{z}/{x}/{y}.png', { - attribution : '© OpenStreetMap contributers' - }), - cycle = L.tileLayer('http://b.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=f8f13e0070864ac3ad996f7bf7beb9af', { - attribution : 'Maps © Thunderforest, ;Data © OpenStreetMap contributors' - }), elevation = L.tileLayer('http://b.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png?apikey=f8f13e0070864ac3ad996f7bf7beb9af', { - attribution : 'Maps © Thunderforest, ;Data © OpenStreetMap contributors' - }); - - var mapMatchingControl; - - var mapMatch = function () { - var traceCoords = $scope.endPoints.map(function(gLoc) { - return [parseFloat(gLoc.lon), parseFloat(gLoc.lat)]; - }); - - var trace = { - type: 'MultiPoint', - coordinates: traceCoords - }; - - if (mapMatchingControl) { - mapMatchingControl.removeFrom(map); - } - mapMatchingControl = L.mapMatching(trace, { - externalTraceLayer: L.layerGroup(markers), - serviceUrlParams: {api_key: envToken, mode: $scope.mode, - search_radius: document.getElementById('radius').value }, - serviceUrl: serviceUrl - }).addTo(map); - - update(true, traceCoords, $scope.mode); - }; - - var mapMatchingGeoJSONControl; - - var mapMatchGeoJSON = function (traceGeoJSON) { - var markers = { - 'type': 'MultiPoint', - 'coordinates': traceGeoJSON.coordinates || (traceGeoJSON.geometry && traceGeoJSON.geometry.coordinates) - }; - - if (mapMatchingGeoJSONControl) { - mapMatchingGeoJSONControl.removeFrom(map); - } - mapMatchingGeoJSONControl = L.mapMatching(traceGeoJSON, { - serviceUrlParams: {api_key: envToken, mode: $scope.mode, - search_radius: document.getElementById('radius').value }, - serviceUrl: serviceUrl - }).addTo(map); - - update(true, traceGeoJSON, $scope.mode); - }; - - var baseMaps = { - "Road" : road, - "Cycle" : cycle, - "Elevation" : elevation - }; - - //leaflet slippy map - var map = L.map('map', { - zoom : $rootScope.geobase.zoom, - zoomControl : true, - layers : [ road ], - center : [ $rootScope.geobase.lat, $rootScope.geobase.lon ] - }); - - // var sequence = new Sequence(map); - - // If iframed, we're going to have to disable some of the touch interaction - // to not hijack page scroll. See Stamen's Checklist for Maps: http://content.stamen.com/stamens-checklist-for-maps - if (window.self !== window.top) { - map.scrollWheelZoom.disable(); - } - - L.control.layers(baseMaps, null).addTo(map); - - // If iframed, we're going to have to disable some of the touch interaction - // to not hijack page scroll. See Stamen's Checklist for Maps: http://content.stamen.com/stamens-checklist-for-maps - if (window.self !== window.top) { - map.scrollWheelZoom.disable(); - } - - var getOriginIcon = function() { - return new L.Icon({ - iconUrl : '../matrix/resource/matrix_pin_start.png', - iconSize : [ 30, 36 ], - shadowUrl: null - }); - }; - - var getDestinationIcon = function() { - return new L.Icon({ - iconUrl : '../matrix/resource/matrix_pin_end.png', - iconSize : [ 30, 36 ], - shadowUrl: null - }); - }; - - //Number of locations - var hash = new L.Hash(map); - var markers = []; - var remove_markers = function() { - for (var i = 0; i < markers.length; i++) { - map.removeLayer(markers[i]); - } - markers = []; - }; - - - var parseHash = function() { - var hash = window.location.hash; - if (hash.indexOf('#') === 0) - hash = hash.substr(1); - return hash.split('&'); - }; - - var parseParams = function(pieces) { - var parameters = {}; - pieces.forEach(function(e, i, a) { - var parts = e.split('='); - if (parts.length < 2) - parts.push(''); - parameters[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); - }); - return parameters; - }; - - var update = function(show, coords, costing) { - // update the permalink hash - var pieces = parseHash(); - var extra = ''; - pieces.forEach(function(e, i, a) { - if (e.length && e.slice(0, 'locations='.length) != 'locations=' && e.slice(0, 'costing='.length) != 'costing=' && e.slice(0, 'directions_options='.length) != 'directions_options=') - extra = extra + (extra.length ? '&' : '') + e; - }); - var parameter = '&costing=' + JSON.stringify(costing); - window.location.hash = '#' + extra + parameter; - document.getElementById('permalink').innerHTML = "Map Matching Permalink"; - }; - - var hashRoute = function() { - document.getElementById('permalink').innerHTML = "Map Matching Permalink"; - }; - - $rootScope.$on('map.setView', function(ev, geo, zoom) { - map.setView(geo, zoom || 8); - }); - - $rootScope.$on('map.dropDestMarker', function(ev, geo, locCount) { - var marker = new L.marker(geo, { - icon : getDestinationIcon(), - draggable:true - }).bindLabel((locCount).toString(), (locCount < 10) ? { - position: [geo.lat,geo.lon], - noHide: true, - offset: [-9,-12] - } : { - position: [geo.lat,geo.lon], - noHide: true, - offset: [-13,-12] - }); - map.addLayer(marker); - markers.push(marker); - marker.on('dragend', function(event){ - var marker = event.target; - var position = marker.getLatLng(); - marker.setLatLng(position,{draggable:'true'}).bindPopup(position); - var latlon = position.lat.toFixed(6) + ' , '+ position.lng.toFixed(6); - var latLngIndex = parseInt(marker.label._content); - $scope.endPoints.splice(latLngIndex-1,1,{index: (latLngIndex), lat:position.lat, lon: position.lng,latlon: latlon}); - $scope.$apply(); - mapMatch(); - return; - }); - }); - - $scope.renderHtml = function(html_code) { - return $sce.trustAsHtml(html_code); - }; - - $scope.setMode = function(mode) { - $scope.mode = mode; - mapMatch(); - }; - - // show something to start with but only if it was requested - $(window).load(function(e) { - hashRoute(); - }); - - var reset_form = function() { - $scope.endPoints = []; - }; - - //set up map events - var counterText = 1; - map.on('click', function(e) { - if (!markers.length) { - $scope.manyToManyClick(e); - } - - var geo = { - 'lat' : e.latlng.lat.toFixed(6), - 'lon' : e.latlng.lng.toFixed(6) - }; - - $rootScope.$emit('map.dropDestMarker', [ geo.lat, geo.lon ], counterText); - var latlon = geo.lat + ' , '+ geo.lon; - $scope.endPoints.push({ - index: (counterText), - lat: geo.lat, - lon: geo.lon, - latlon: latlon - }); - $scope.$apply(); - counterText++; - - mapMatch(); - }); - - var traceLayer; - $('#geojson_match').click(function () { - $scope.clearAll(); - var geojson = JSON.parse($('#geojson').val()); - if (traceLayer) { - map.removeLayer(traceLayer); - } - traceLayer = L.geoJson(geojson, { - style: { - color: '#ff7800' - } - }).addTo(map); - map.fitBounds(traceLayer.getBounds()); - mapMatchGeoJSON(geojson); - }); - - var clearBtn = document.getElementById("clear_btn"); - - $scope.mode = 'auto'; - $scope.endPoints = []; - $scope.editingFocus = 'start_points'; - $scope.appView = 'control'; - - $scope.backToControlView = function(e) { - $scope.appView = 'control'; - }; - - $scope.clearRouteShape = function(e) { - }; - - $scope.clearAll = function(e) { - $scope.endPoints = []; - $scope.appView = 'control'; - $scope.editingFocus = 'start_points'; - sentManyToManyEnd = false; - counterText = 1; - - if (mapMatchingControl) { - mapMatchingControl.removeFrom(map); - } - mapMatchingControl = null; - - markers.forEach(function (marker) { - map.removeLayer(marker); - }); - - markers = []; - window.location.hash = ""; - }; - - $scope.goToEndPoints = function(e) { - $scope.editingFocus = 'end_points'; - }; - - $scope.manyToManyClick = function(e) { - reset_form(); - $scope.start_mapInstruction = " Click on the map to add a point"; - $scope.end_mapInstruction = " Click on the map to add points"; - $scope.startgeocode = "lat, long"; - $scope.endgeocode = "lat, long"; - getEnvToken(); - }; - -}); diff --git a/map_matching/js/map_matching.js b/map_matching/js/map_matching.js deleted file mode 100644 index c0380d6..0000000 --- a/map_matching/js/map_matching.js +++ /dev/null @@ -1,267 +0,0 @@ -(function () { - 'use strict'; - - var coordToLatLng = function (coord) { - var lng = coord[0], lat = coord[1]; - return L.latLng(lat, lng); - }; - - var readTraceCoords = function (geo) { - if (geo && geo.coordinates) { - return geo.coordinates; - } else if (geo && geo.geometry && geo.geometry.coordinates) { - return geo.geometry.coordiantes; - } else { - return null; - } - }; - - var defaultTraceBuilder = function (geoTrace, options) { - var coords = readTraceCoords(geoTrace); - if (!coords) { - return null; - } - options = options || {draggable: true}; - var circles = L.GeoJSON.coordsToLatLngs(coords).map(function (latlng) { - return L.marker(latlng, options); - }); - return L.layerGroup(circles); - }; - - var readMatchCoords = function (geo) { - try { - return geo.properties.matched_coordinates; - } catch (err) { - return null; - } - }; - - var defaultMatchPointBuilder = function (geo, options) { - var matchCoords = readMatchCoords(geo); - var circles = matchCoords.filter(function (coord) { - return coord != null; - }).map(function (coord) { - return L.circleMarker(coordToLatLng(coord), options); - }); - return L.layerGroup(circles); - }; - - var defaultMatchLineBuilder = function (geoTrace, geoResults, options) { - var traceCoords = readTraceCoords(geoTrace); - if (!traceCoords) { - return null; - } - - var matchCoords = readMatchCoords(geoResults); - if (!matchCoords) { - return null; - } - - var lines = traceCoords.map(function (coord, idx) { - return matchCoords[idx]? [coordToLatLng(coord), coordToLatLng(matchCoords[idx])] : null; - }).filter(function (coord) { return coord !== null; }); - - return L.multiPolyline(lines, options); - }; - - var defaultMatchRouteBuilder = function (geo, options) { - return L.geoJson(geo, options); - }; - - var encode = function (coordinates) { - var output = []; - //handy lambda to turn an integer into an encoded string - var serialize = function(number) { - //move the bits left 1 position and flip all the bits if it was a negative number - number = number < 0 ? ~(number << 1) : (number << 1); - //write 5 bit chunks of the number - while (number >= 0x20) { - var nextValue = (0x20 | (number & 0x1f)) + 63; - output.push(String.fromCharCode(nextValue)); - number >>= 5; - } - //write the last chunk - number += 63; - output.push(String.fromCharCode(number)); - }; - - //this is an offset encoding so we remember the last point we saw - var last_lon = 0, last_lat = 0; - //for each point - coordinates.forEach(function(p) { - //shift the decimal point 6 places to the right, floor and cast to int - var lon = Math.floor(p[0] * 1e6) | 0; - var lat = Math.floor(p[1] * 1e6) | 0; - //encode each coordinate, lat first for some reason - serialize(lat - last_lat); - serialize(lon - last_lon); - //remember the last one we encountered - last_lon = lon; - last_lat = lat; - }); - return output.join(''); - }; - - function decode(encoded) { - //six degrees of precision in valhalla - var inv = 1.0 / 1e6; - var decoded = []; - var previous = [0,0]; - var i = 0; - //for each byte - while(i < encoded.length) { - //for each coord (lat, lon) - var ll = [0,0] - for(var j = 0; j < 2; j++) { - var shift = 0; - var byte = 0x20; - //keep decoding bytes until you have this coord - while(byte >= 0x20) { - byte = encoded.charCodeAt(i++) - 63; - ll[j] |= (byte & 0x1f) << shift; - shift += 5; - } - //add previous offset to get final value and remember for next one - ll[j] = previous[j] + (ll[j] & 1 ? ~(ll[j] >> 1) : (ll[j] >> 1)); - previous[j] = ll[j]; - } - //scale by precision and chop off long coords also flip the positions so - //its the far more standard lon,lat instead of lat,lon - decoded.push([ll[1] * inv,ll[0] * inv]); - } - //hand back the list of coordinates - return decoded; - }; - - var geoJsonToTrace = function (geojson, options) { - //convert to trace format - var trace = { - 'costing': options.serviceUrlParams.mode, - 'search_radius': parseFloat(options.serviceUrlParams.search_radius), - 'shape_match': 'map_snap', - 'filters':{ - 'attributes':['edge.way_id','edge.begin_shape_index','edge.end_shape_index','matched.point','matched.edge_index','matched.begin_route_discontinuity','matched.end_route_discontinuity','shape'], - 'action':'include' - } - }; - //dont bother with non numbers - if(!isFinite(trace.search_radius)) - delete trace['search_radius']; - //clean up url - delete options.serviceUrlParams['mode']; - delete options.serviceUrlParams['search_radius']; - //encode the coordinates to send - trace['encoded_polyline'] = encode(geojson['coordinates']); - return trace; - }; - - var attributesToGeoJson = function (attributes) { - //decode the shape - var shape = decode(attributes.shape); - //turn the continuous runs of shape indicies into multilinestrings - var multilines = []; - var matched = []; - var start = 0; - for(var p of attributes.matched_points) { - //keep every matched point - matched.push([p.lon, p.lat]); - //starts a discontinuity so make a linestring up to and including this point - if(p.begin_route_discontinuity) - multilines.push(shape.slice(start, attributes.edges[p.edge_index].end_shape_index + 1)); - //ends a discontinuity so make a linestring start here - else if(p.end_route_discontinuity) - start = attributes.edges[p.edge_index].begin_shape_index; - } - //get the last bit - if(start < shape.length) - multilines.push(shape.slice(start, shape.length)); - //hand it back as geojson - return { - "type": "Feature", - "geometry": { - "type": "MultiLineString", - "coordinates": multilines - }, - "properties": { - "matched_coordinates": matched - } - }; - }; - - L.MapMatching = L.Control.extend({ - options: { - serviceUrl: 'http://valhalla.mapzen.com/trace_attributes', - serviceUrlParams: {}, - traceBuilder: defaultTraceBuilder, - matchLineBuilder: defaultMatchLineBuilder, - matchPointBuilder: defaultMatchPointBuilder, - matchRouteBuilder: defaultMatchRouteBuilder - }, - - initialize: function (trace, options) { - this.trace = geoJsonToTrace(trace, options); - L.Util.setOptions(this, options); - }, - - onAdd: function (map) { - if (this.options.externalTraceLayer) { - this.traceLayer = this.options.externalTraceLayer; - } else { - this.traceLayer = this.options.traceBuilder.call(this, this.trace); - if (this.traceLayer) { - this.traceLayer.addTo(map); - } - } - this.match(map); - return L.DomUtil.create('div', 'my-custom-control'); - }, - - match: function (map) { - this.onRemove(map); - - var control = this, geoTrace = this.trace; - - var urlParams = $.param(this.options.serviceUrlParams), - url = this.options.serviceUrl + (urlParams? ('?' + urlParams) : ''), - requestBody = JSON.stringify(geoTrace); - - return $.post(url, requestBody, function (resp) { - if (control._map !== map) { - return; - } - - var geoResults = attributesToGeoJson(resp); - - control.matchPointLayer = control.options.matchPointBuilder.call(control, geoResults); - if (control.matchPointLayer) { - control.matchPointLayer.addTo(map); - } - - control.matchLineLayer = control.options.matchLineBuilder.call(control, geoTrace, geoResults); - if (control.matchLineLayer) { - control.matchLineLayer.addTo(map); - } - - control.matchRouteLayer = control.options.matchRouteBuilder.call(control, geoResults); - if (control.matchRouteLayer) { - control.matchRouteLayer.addTo(map); - } - }, 'json'); - }, - - onRemove: function (map) { - if (this.traceLayer) - map.removeLayer(this.traceLayer); - if (this.matchPointLayer) - map.removeLayer(this.matchPointLayer); - if (this.matchLineLayer) - map.removeLayer(this.matchLineLayer); - if (this.matchRouteLayer) - map.removeLayer(this.matchRouteLayer); - } - }); - - L.mapMatching = function(trace, options) { - return new L.MapMatching(trace, options); - }; -})(); diff --git a/map_matching/main.js b/map_matching/main.js new file mode 100644 index 0000000..5eeacd7 --- /dev/null +++ b/map_matching/main.js @@ -0,0 +1,169 @@ +const serviceUrl = 'https://valhalla1.openstreetmap.de/trace_attributes' +const currentLocation = { lng: -122.424058, lat: 37.805689 } +let mode = 'auto' +let map +let draw +let geojsonFeatureCollection = { type: 'FeatureCollection', features: [] } + +function setMode (m) { + mode = arguments[0] + document.querySelectorAll('.vehicleBox button').forEach(button => { + button.classList.toggle('active', button.getAttribute('name') === m) + }) + geojsonMatch() +} + +document.addEventListener('DOMContentLoaded', () => { + map = new maplibregl.Map({ + style: 'https://tiles.openfreemap.org/styles/positron', + center: currentLocation, + zoom: 15.7, + container: 'map' + }) + + draw = new MapboxDraw({ + displayControlsDefault: false, + defaultMode: 'draw_line_string' + }) + map.addControl(draw, 'top-left') + map.on('draw.create', function (e) { + document.getElementById('geojson').value = JSON.stringify(e.features[0].geometry) + geojsonMatch() + }) + + map.once('styledata', () => { + map.addSource('geojsonSource', { + type: 'geojson', + data: geojsonFeatureCollection + }) + + map.addLayer({ + id: 'geojsonLayer', + type: 'line', + source: 'geojsonSource', + layout: {}, + paint: { + 'line-color': ['get', 'color'], + 'line-width': 4 + } + }) + }) +}) + +function geojsonMatch () { + if (document.getElementById('geojson').value === '') { return } + + mapMatcher.geojson = JSON.parse(document.getElementById('geojson').value) + mapMatcher.mode = mode + mapMatcher.search_radius = document.getElementById('radius').value + mapMatcher.serviceUrl = serviceUrl + mapMatcher.matchedCoordinates = [] + mapMatcher.match() + draw.deleteAll() + draw.changeMode('draw_line_string') +} + +const mapMatcher = { + match: function () { + this.removeLayers() + + geojsonFeatureCollection.features.push({ + type: 'Feature', + geometry: this.geojson, + properties: { color: '#ff3400' } + }) + map.getSource('geojsonSource').setData(geojsonFeatureCollection) + + const bounds = turf.bbox(this.geojson) + map.fitBounds(bounds, { padding: 20 }) + + const _this = this + + fetch(serviceUrl, { + method: 'POST', + body: JSON.stringify(this.createJsonPostParams()) + }).then(response => response.json()).then(resp => { + _this.matchingResponse = resp + _this.setMatchResult() + _this.updateGeojsonSource() + }) + }, + + removeLayers: function () { + geojsonFeatureCollection = { type: 'FeatureCollection', features: [] } + map.getSource('geojsonSource').setData(geojsonFeatureCollection) + }, + + updateGeojsonSource: function () { + const _this = this + const lines = this.geojson.coordinates.map(function (coord, idx) { + if (_this.matchedCoordinates[idx]) { + return [coord, _this.matchedCoordinates[idx]] + } + return null + }).filter(function (coord) { return coord !== null }) + + const matchingPointsLineFeature = turf.lineStrings(lines, { color: '#0000ff' }) + + geojsonFeatureCollection.features = geojsonFeatureCollection.features.concat(matchingPointsLineFeature.features) + geojsonFeatureCollection.features = geojsonFeatureCollection.features.concat(this.matchResult.features) + + map.getSource('geojsonSource').setData(geojsonFeatureCollection) + }, + + createJsonPostParams: function () { + return { + encoded_polyline: polyline.fromGeoJSON(this.geojson, 6), + costing: this.mode, + shape_match: 'map_snap', + trace_options: { + search_radius: parseFloat(this.search_radius), + turn_penalty_factor: 300 + }, + filters: { + attributes: [ + 'edge.names', + 'edge.way_id', + 'edge.begin_shape_index', + 'edge.end_shape_index', + 'matched.point', + 'matched.edge_index', + 'matched.begin_route_discontinuity', + 'matched.end_route_discontinuity', + 'shape' + ], + action: 'include' + } + } + }, + + setMatchResult: function () { + // decode the shape + const shape = polyline.decode(this.matchingResponse.shape, 6) + // turn the continuous runs of shape indicies into multilinestrings + let multilines = [] + this.matchedCoordinates = [] + let start = 0 + for (const p of this.matchingResponse.matched_points) { + // keep every matched point + this.matchedCoordinates.push([p.lon, p.lat]) + if (p.begin_route_discontinuity) { + // starts a discontinuity so make a linestring up to and including this point + multilines.push(shape.slice(start, this.matchingResponse.edges[p.edge_index].end_shape_index + 1)) + } else if (p.end_route_discontinuity) { + // ends a discontinuity so make a linestring start here + start = this.matchingResponse.edges[p.edge_index].begin_shape_index + } + } + // get the last bit + if (start < shape.length) { + multilines.push(shape.slice(start, shape.length)) + } + // reverse the coordinates because polyline decodes to [lat, lon], but geojson is [lon, lat] + multilines = multilines.map(function (line) { + return line.map((coord) => coord.reverse()) + }) + // hand it back as geojson + this.matchResult = turf.lineStrings(multilines, { color: '#00ff00' }) + } +} \ No newline at end of file diff --git a/map_matching/style.css b/map_matching/style.css new file mode 100644 index 0000000..21093c7 --- /dev/null +++ b/map_matching/style.css @@ -0,0 +1,70 @@ +html { + width: 100%; + height: 100%; +} + +body { + font: 13px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; + width: 100%; + height: 100%; + color: #383a3a; + min-height: 600px; + padding: 0; + margin: 0; +} + +.container { + height: 100%; + margin: 0; + padding: 0; + display: flex; + flex-direction: row; + flex-wrap: wrap; + width: 100%; +} + +#controls { + width: 500px; + background-color: #eee; + padding: 20px; + overflow-y: auto; + text-align: center; +} + +#map-container { + height: 100%; + flex-grow: 1; +} + +#map { + width: 100%; + height: 100%; +} + +#geojson { + width: 100%; + height: 150px; +} + +.vehicleBox .vehicle { + width: 50px; + height: 41px; + background-color: transparent; + margin-right: 5px; + background-image: url('../matrix/images/modes.svg'); + background-size: 150px 41px; + background-repeat: no-repeat; +} + +.vehicleBox .vehicle.active { + color: #68c175; + border: 2px solid #68c175; +} + +.bike { + background-position: -50px 0; +} + +.pedestrian { + background-position: -100px 0; +} \ No newline at end of file