在上一篇中,尝试给出三条备选路线方案,只是看看是不够的,还需要做些交互式的操作支持。

1 Visual Tweaks

首先,这里我们做点小小的视觉调整,让路线和位置更漂亮一点。例如:

给路线的加上半透明效果,在drawRoute()中增加:

1
2
3
var routeLine = new H.map.Polyline(strip, {
style: { strokeColor: 'rgba(0, 85, 170, 0.5)', lineWidth: 3 }
})

再给配送的起点、终点,快递员的当前位置赋予不同的显示符号,在map.js中修改addMarker()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
HEREMap.prototype.addMarker = function (coordinates, icon) {
// Add an markerOptions object
var markerOptions = {}
// three different icons for origin, destination and the user's current position
var icons = {
iceCream: {
url: './images/marker-gelato.svg',
options: {
size: new H.math.Size(26, 34),
anchor: new H.math.Point(14, 34)
}
},
origin: {
url: './images/origin.png',
options: {
size: new H.math.Size(32, 32),
anchor: new H.math.Point(12, 36)
}
},
destination: {
url: './images/destination.png',
options: {
size: new H.math.Size(32, 32),
anchor: new H.math.Point(12, 36)
}
}
}

if (icons[icon]) {
markerOptions = {
icon: new H.map.Icon(icons[icon].url, icons[icon].options)
}
}

var marker = new H.map.Marker(coordinates, markerOptions)
this.map.addObject(marker)

return marker
}

2 Route Selection

在显示的三条路线中,允许用户选择一条作为最佳选项,那么我们需要在onSuccess()中增加一个回调函数来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var onSuccess = function (result) {
if (result.response.route) {
var routeLineGroup = new H.map.Group()

var routes = result.response.route.map(function (route) {
var routeLine = drawRoute(route)
routeLineGroup.addObject(routeLine)

return {
route: route,
routeLine: routeLine
}
})

map.addObject(routeLineGroup)
map.setViewBounds(routeLineGroup.getBounds())

onRouteSelection(routes[0])
}
}

为了在地图上高亮出选中的路线,就需要给Polyline指定不同的制图符号,

1
2
3
4
var routeLineStyles = {
normal: { strokeColor: 'rgba(0, 85, 170, 0.5)', lineWidth: 3 },
selected: { strokeColor: 'rgba(255, 0, 0, 0.7)', lineWidth: 7 }
}

路线选择的目的是为了允许用户用户点选prefer的道路,因此我们需要增加一个函数,允许渲染引擎更改道路的符号,onRouteSelection()

1
2
3
var onRouteSelection = function (route) {
console.log('A route has been selected.', route)
}

为了测试以上逻辑的正确与否,做个简单测试,在onSuccess()中调用onRouteSelection(),并且将返回结果中的第一条路线作为参数传入。

1
2
// pass the first route as argument for temperary testing
onRouteSelection(routes[0])

到这里,你可能会发现被选中的道路可能位于其他道路之下,因此在道路的公共部分出现了叠加的多层效果。为了确保所选道路在所有道路之上显示,我们可以设置下渲染顺序,即 z-index。如下例子中,10 为更接近上层的渲染顺序。

1
2
3
4
5
6
 if (selectedRoute) {
selectedRoute.routeLine.setStyle(routeLineStyles.normal).setZIndex(1)
}
route.routeLine.setStyle(routeLineStyles.selected).setZIndex(10)
selectedRoute = route
}

这样就清爽了很多。

3 Route Selection Panel

这一步我们最后完善与道路的“交互”。 增加一个小的面板指示已经选择的道路。我们将这一部分的功能也放到另外一个独立的脚本文件中,在 scripts目录下新建一个routes_panel.js的文件。当然,不要忘记在 html 页面中增加加载此脚本文件的语句。 <script src="scripts/routes_panel.js"></script>

另外,在html文件中需要增加一个容器来渲染路线选择面板。

1
2
3
<div id="route-panel">
<ul></ul>
</div>

定义 HERERoutesPanel 类,用于渲染路线选择面板中的内容,详见我的GitHub 中 routes_panel.js 的内容。

4 Directions

HERE Routing API 也会返回自然语言形式的导航信息(direction information),继续再 HERERoutesPanel类中增加内容:

1
2
3
4
5
6
7
8
var renderRouteElement = function (route, i) {
var element = document.createElement('li')

var routeSummary = route.route.summary
element.innerHTML = renderRouteTitle(routeSummary, i)

var maneuvers = route.route.leg[0].maneuver
element.innerHTML += renderManeuvers(maneuvers)

上面代码中, leg 是什么? 一个leg代表的是两个 waypoint之间的路线部分,求算一条路线至少要有起点和终点两个 waypoint,其他的waypoint 可以是途经点。见 Developer doc:Waypoints

看起来HERE已经提供了 pre-formatted maneuver instruction string,那么就直接用好了。

1
2
3
4
5
6
7
8
9
var renderManeuvers = function (maneuvers) {
return [
'<ol class="directions">',
maneuvers.map(function (maneuver) {
return '<li>' + maneuver.instruction + '</li>'
}).join(''),
'</ol>'
].join('')
}

这篇Tutorial的原文巨长,看得我一度想放弃,因为最近工作忙碌的关系,断断续续总算看完了; 并且参照原文思路和示例代码review完结。


original resource Part4: Advanced Routing

complete code Github - kikitaMoon/HERE_JS_Who_Wants_Icecream