Browse Source

Better UI, ditch LRM

Phyks (Lucas Verney) 2 years ago
parent
commit
a3fd4c211c
5 changed files with 125 additions and 98 deletions
  1. 5
    2
      package.json
  2. 9
    45
      src/App.vue
  3. 9
    3
      src/components/ElevationGraph.vue
  4. 101
    47
      src/components/RouteMap.vue
  5. 1
    1
      src/main.js

+ 5
- 2
package.json View File

@@ -11,9 +11,12 @@
11 11
     "build": "node build/build.js"
12 12
   },
13 13
   "dependencies": {
14
+    "@mapbox/polyline": "^0.2.0",
15
+    "isomorphic-fetch": "^2.2.1",
14 16
     "leaflet": "^1.3.1",
15
-    "leaflet-routing-machine": "^3.2.7",
16
-    "lrm-graphhopper": "^1.2.0",
17
+    "moment": "^2.20.1",
18
+    "polyline-encoded": "0.0.8",
19
+    "pretty-metric": "^1.1.0",
17 20
     "vue": "^2.5.2",
18 21
     "vue-dygraphs": "^0.1.1",
19 22
     "vue-router": "^3.0.1",

+ 9
- 45
src/App.vue View File

@@ -2,8 +2,6 @@
2 2
     <v-app>
3 3
         <v-navigation-drawer
4 4
             persistent
5
-            :mini-variant="miniVariant"
6
-            :clipped="clipped"
7 5
             v-model="drawer"
8 6
             enable-resize-watcher
9 7
             fixed
@@ -24,48 +22,13 @@
24 22
                 </v-list-tile>
25 23
             </v-list>
26 24
         </v-navigation-drawer>
27
-        <v-toolbar
28
-            app
29
-            :clipped-left="clipped"
30
-            >
25
+        <v-toolbar app>
31 26
             <v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
32
-            <v-btn icon @click.stop="miniVariant = !miniVariant">
33
-                <v-icon v-html="miniVariant ? 'chevron_right' : 'chevron_left'"></v-icon>
34
-            </v-btn>
35
-            <v-btn icon @click.stop="clipped = !clipped">
36
-                <v-icon>web</v-icon>
37
-            </v-btn>
38
-            <v-btn icon @click.stop="fixed = !fixed">
39
-                <v-icon>remove</v-icon>
40
-            </v-btn>
41 27
             <v-toolbar-title v-text="title"></v-toolbar-title>
42
-            <v-spacer></v-spacer>
43
-            <v-btn icon @click.stop="rightDrawer = !rightDrawer">
44
-                <v-icon>menu</v-icon>
45
-            </v-btn>
46 28
         </v-toolbar>
47 29
         <v-content>
48 30
             <router-view></router-view>
49 31
         </v-content>
50
-        <v-navigation-drawer
51
-            temporary
52
-            :right="right"
53
-            v-model="rightDrawer"
54
-            fixed
55
-            app
56
-            >
57
-            <v-list>
58
-                <v-list-tile @click="right = !right">
59
-                    <v-list-tile-action>
60
-                        <v-icon>compare_arrows</v-icon>
61
-                    </v-list-tile-action>
62
-                    <v-list-tile-title>Switch drawer (click me)</v-list-tile-title>
63
-                </v-list-tile>
64
-            </v-list>
65
-        </v-navigation-drawer>
66
-        <v-footer :fixed="fixed" app>
67
-            <span>&copy; 2017</span>
68
-        </v-footer>
69 32
     </v-app>
70 33
 </template>
71 34
 
@@ -73,19 +36,20 @@
73 36
 export default {
74 37
     data() {
75 38
         return {
76
-            clipped: false,
77
-            drawer: true,
78
-            fixed: false,
39
+            drawer: false,
79 40
             items: [{
80 41
                 icon: 'bubble_chart',
81 42
                 title: 'Inspire',
82 43
             }],
83
-            miniVariant: false,
84
-            right: true,
85
-            rightDrawer: false,
86
-            title: 'Vuetify.js',
44
+            title: 'Hervé',
87 45
         };
88 46
     },
89 47
     name: 'App',
90 48
 };
91 49
 </script>
50
+
51
+<style>
52
+.application .leaflet-bar a {
53
+    color: black;
54
+}
55
+</style>

+ 9
- 3
src/components/ElevationGraph.vue View File

@@ -1,14 +1,20 @@
1 1
 <template>
2
-    <dygraphs :graphData="graphData" :graphOptions="{}"></dygraphs>
2
+    <dygraphs :graphData="graphData" :graphOptions="graphOptions" :graphStyle="{width: '100%', height: '100px'}"></dygraphs>
3 3
 </template>
4 4
 
5 5
 <script>
6 6
 export default {
7 7
     props: ['elevations'],
8
+    data() {
9
+        return {
10
+            graphOptions: {
11
+                labels: ['Distance', 'Elevation'],
12
+            },
13
+        };
14
+    },
8 15
     computed: {
9 16
         graphData() {
10
-            const csv = `Index,Elevation\n${this.elevations.map((item, index) => `${index},${item}`).join('\n')}`;
11
-            return csv;
17
+            return this.elevations;
12 18
         },
13 19
     },
14 20
 };

+ 101
- 47
src/components/RouteMap.vue View File

@@ -1,20 +1,22 @@
1 1
 <template>
2
-    <v-container>
2
+    <v-container class="fill-width fill-height">
3 3
         <v-layout row class="fill-width">
4
-            <v-flex xs12>
4
+            <v-flex xs8>
5 5
                 <div class="fill-height fill-width">
6
-                    <v-map>
6
+                    <v-map :bounds="bounds">
7 7
                         <v-tilelayer url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"></v-tilelayer>
8
-                        <v-routing-machine
9
-                            :waypoints="[startPoint, endPoint]"
10
-                            :options="routingOptions"
11
-                            ></v-routing-machine>
8
+                        <v-marker :lat-lng="startPoint.latlng" :autopan="true" :draggable="true" v-on:l-drag="(ev) => { startPoint.latlng = ev.latlng; startPoint.isDragged = true; }" v-on:l-dragend="getPaths"></v-marker>
9
+                        <v-marker :lat-lng="endPoint.latlng" :autopan="true" :draggable="true" v-on:l-drag="(ev) => { endPoint.latlng = ev.latlng; endPoint.isDragged = true; }" v-on:l-dragend="getPaths"></v-marker>
10
+                        <v-polyline v-if="latLngs" :latLngs="latLngs"></v-polyline>
11
+                        <v-polyline v-if="startLatLngs" :latLngs="startLatLngs" dashArray="5, 5"></v-polyline>
12
+                        <v-polyline v-if="endLatLngs" :latLngs="endLatLngs" dashArray="5, 5"></v-polyline>
12 13
                     </v-map>
13 14
                 </div>
14 15
             </v-flex>
15
-        </v-layout>
16
-        <v-layout row>
17
-            <v-flex xs12>
16
+            <v-flex xs4 text-xs-center>
17
+                <h2>De {{ startPoint.name }} à {{ endPoint.name }}</h2>
18
+                <h3>{{ time }}, {{ distance }}</h3>
19
+
18 20
                 <ElevationGraph :elevations="elevations"></ElevationGraph>
19 21
             </v-flex>
20 22
         </v-layout>
@@ -22,16 +24,15 @@
22 24
 </template>
23 25
 
24 26
 <script>
25
-// TODO: have a proportional height
26 27
 import L from 'leaflet';
27 28
 import iconRetinaUrl from 'leaflet/dist/images/marker-icon-2x.png';
28 29
 import iconUrl from 'leaflet/dist/images/marker-icon.png';
29 30
 import shadowUrl from 'leaflet/dist/images/marker-shadow.png';
30
-import 'leaflet-routing-machine';
31
-import 'lrm-graphhopper';
31
+import moment from 'moment';
32
+import polyline from '@mapbox/polyline';
33
+import prettyMetric from 'pretty-metric';
32 34
 
33 35
 import ElevationGraph from './ElevationGraph.vue';
34
-import Vue2LeafletRoutingMachine from './Vue2LeafletRoutingMachine.vue';
35 36
 
36 37
 // Fix for a bug in Leaflet default icon
37 38
 // see https://github.com/PaulLeCam/react-leaflet/issues/255#issuecomment-261904061
@@ -43,49 +44,101 @@ L.Icon.Default.mergeOptions({
43 44
 });
44 45
 
45 46
 
46
-L.Routing.RV = L.Routing.GraphHopper.extend({
47
-    initialize(options) {
48
-        this.elevations = [];
49
-        return L.Routing.GraphHopper.prototype.initialize.call(
50
-            this,
51
-            '',
52
-            options,
53
-        );
54
-    },
55
-
56
-    _routeDone(response, inputWaypoints, callback, context) {
57
-        this.elevations = response.paths[0].elevations;
58
-
59
-        return L.Routing.GraphHopper.prototype._routeDone.call(
60
-            this, response, inputWaypoints, callback, context,
61
-        );
62
-    },
63
-});
64
-
65
-
66 47
 export default {
67 48
     components: {
68
-        'v-routing-machine': Vue2LeafletRoutingMachine,
69 49
         ElevationGraph,
70 50
     },
51
+    created() {
52
+        this.getPaths();
53
+    },
71 54
     data() {
72 55
         return {
73
-            routingOptions: {
74
-                router: new L.Routing.RV(
75
-                    {
76
-                        serviceUrl: 'http://127.0.0.1:8081/api/1/route',
77
-                    },
78
-                ),
79
-                addWaypoints: false,
80
-                routeWhileDragging: true,
56
+            startPoint: {
57
+                latlng: L.latLng([48.818783, 2.319883]),
58
+                isDragged: false,
59
+                name: null,
81 60
             },
82
-            startPoint: [48.818783, 2.319883],
83
-            endPoint: [48.841132, 2.384841],
61
+            endPoint: {
62
+                latlng: L.latLng([48.841132, 2.384841]),
63
+                isDragged: false,
64
+                name: null,
65
+            },
66
+            paths: null,
84 67
         };
85 68
     },
69
+    methods: {
70
+        getPaths() {
71
+            fetch(`http://127.0.0.1:8081/api/1/route?point=${this.startPoint.latlng.lat},${this.startPoint.latlng.lng}&point=${this.endPoint.latlng.lat},${this.endPoint.latlng.lng}&instructions=true&type=json`)
72
+                .then(response => response.json())
73
+                .then((json) => {
74
+                    this.paths = json.paths;
75
+                    this.startPoint.name = 'TODO';
76
+                    this.endPoint.name = 'TODO';
77
+                    this.startPoint.isDragged = false;
78
+                    this.endPoint.isDragged = false;
79
+                });
80
+        },
81
+    },
86 82
     computed: {
87 83
         elevations() {
88
-            return this.routingOptions.router.elevations;
84
+            if (!this.paths) {
85
+                return [];
86
+            }
87
+            return this.paths[0].elevations;
88
+        },
89
+        bounds() {
90
+            if (this.paths && this.paths[0].bbox) {
91
+                return [
92
+                    [
93
+                        this.paths[0].bbox[1],
94
+                        this.paths[0].bbox[0],
95
+                    ],
96
+                    [
97
+                        this.paths[0].bbox[3],
98
+                        this.paths[0].bbox[2],
99
+                    ],
100
+                ];
101
+            }
102
+            return [
103
+                [
104
+                    Math.min(this.startPoint.latlng.lat, this.endPoint.latlng.lat),
105
+                    Math.min(this.startPoint.latlng.lng, this.endPoint.latlng.lng),
106
+                ],
107
+                [
108
+                    Math.max(this.startPoint.latlng.lat, this.endPoint.latlng.lat),
109
+                    Math.max(this.startPoint.latlng.lng, this.endPoint.latlng.lng),
110
+                ],
111
+            ];
112
+        },
113
+        latLngs() {
114
+            if (!this.paths) {
115
+                return null;
116
+            }
117
+            return polyline.decode(this.paths[0].points);
118
+        },
119
+        startLatLngs() {
120
+            if (!this.latLngs || this.startPoint.isDragged) {
121
+                return null;
122
+            }
123
+            return [this.startPoint.latlng, this.latLngs[0]];
124
+        },
125
+        endLatLngs() {
126
+            if (!this.latLngs || this.endPoint.isDragged) {
127
+                return null;
128
+            }
129
+            return [this.latLngs[this.latLngs.length - 1], this.endPoint.latlng];
130
+        },
131
+        time() {
132
+            if (!this.paths) {
133
+                return null;
134
+            }
135
+            return moment.duration(this.paths[0].time).humanize();
136
+        },
137
+        distance() {
138
+            if (!this.paths) {
139
+                return null;
140
+            }
141
+            return prettyMetric(this.paths[0].distance).humanize();
89 142
         },
90 143
     },
91 144
 };
@@ -94,9 +147,10 @@ export default {
94 147
 <style scoped>
95 148
 .fill-width {
96 149
     width: 100%;
150
+    max-width: 100%;
97 151
 }
98 152
 
99 153
 .fill-height {
100
-    height: 300px;
154
+    height: 100%;
101 155
 }
102 156
 </style>

+ 1
- 1
src/main.js View File

@@ -6,7 +6,6 @@ import VueDygraphs from 'vue-dygraphs/dist/vue-dygraphs.common';
6 6
 import Vue2Leaflet from 'vue2-leaflet';
7 7
 import 'vuetify/dist/vuetify.min.css';
8 8
 import 'leaflet/dist/leaflet.css';
9
-import 'leaflet-routing-machine/dist/leaflet-routing-machine.css';
10 9
 
11 10
 import App from './App.vue';
12 11
 import router from './router';
@@ -17,6 +16,7 @@ Vue.use(VueDygraphs);
17 16
 Vue.component('v-map', Vue2Leaflet.Map);
18 17
 Vue.component('v-tilelayer', Vue2Leaflet.TileLayer);
19 18
 Vue.component('v-marker', Vue2Leaflet.Marker);
19
+Vue.component('v-polyline', Vue2Leaflet.Polyline);
20 20
 
21 21
 Vue.config.productionTip = false;
22 22