このチュートリアルでは、 Maps API for JavaScript を使用して地図上の原点と目的地のマーカーをプロットし、それらのマーカー間の最速ルートを計算して表示する方法を示します。 このチュートリアルでは、ユーザーが経由地 マーカーを追加または削除した場合、または既存のマーカーの位置を変更した場合に、デフォルトルートを動的に再計算する方法について説明します。
作成した HTML コンテナに、 Maps API for JavaScript を使用してマップを表示し、マップの対話を有効にする JavaScript コードを追加します。
<script> 作成した HTML ファイルの要素内で、次のコード スニペット を貼り付けるか、参照します。
// Initiate and authenticate your connection to the HERE platform:const platform =newH.service.Platform({'apikey':'Your API key'});// Obtain the default map types from the platform object:const defaultLayers = platform.createDefaultLayers();// Instantiate (and display) a map:var map =newH.Map(
document.getElementById("map"),// Center the map on Great Britain with the zoom level of 6:
defaultLayers.vector.normal.map,{zoom:6,center:{lat:53.480759,lng:-2.242631}});// MapEvents enables the event system.// The behavior variable implements default interactions for pan/zoom (also on mobile touch environments).const behavior =newH.mapevents.Behavior(newH.mapevents.MapEvents(map));// Enable dynamic resizing of the map, based on the current size of the enclosing cntainer
window.addEventListener('resize',()=> map.getViewPort().resize());// Create the default UI:var ui =H.ui.UI.createDefault(map, defaultLayers,);
コード スニペット で apikey 、変数の値を独自の API キー に置き換えます。
結果: 結果の HTML ファイルでは、次 6の例に示すように、イギリスを中心としたベース マップ がのズーム レベル でレンダリングされます。
地図上に原点と目的地をプロットします
地図で、原点と目的地を表すマーカーを追加します。
getMarkerIcon() カスタム SVG スタイルを各マーカーに適用する関数を作成します。
/**
* Returns an instance of H.map.Icon to style the markers
* @param {number|string} id An identifier that will be displayed as marker label
*
* @return {H.map.Icon}
*/functiongetMarkerIcon(id){const svgCircle =`<svg width="30" height="30" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g id="marker">
<circle cx="15" cy="15" r="10" fill="#0099D8" stroke="#0099D8" stroke-width="4" />
<text x="50%" y="50%" text-anchor="middle" fill="#FFFFFF" font-family="Arial, sans-serif" font-size="12px" dy=".3em">${id}</text>
</g></svg>`;returnnewH.map.Icon(svgCircle,{anchor:{x:10,y:10}});}
/**
* Create an instance of H.map.Marker and add it to the map
*
* @param {object} position An object with 'lat' and 'lng' properties defining the position of the marker
* @param {string|number} id An identifier that will be displayed as marker label
* @return {H.map.Marker} The instance of the marker that was created
*/functionaddMarker(position, id){const marker =newH.map.Marker(position,{data:{
id
},icon:getMarkerIcon(id),});
map.addObject(marker);return marker;}
次の例に示すように、原点マーカーと目的地マーカーの座標を定義します。
const origin ={lat:55.953251,lng:-3.188267};// Edinburghconst destination ={lat:51.507797,lng:-0.128604};// London
addMarker() この関数を呼び出して、異なる ID を使用して、指定した場所の地図上に原点マーカーと目的地マーカーをプロットします。
/**
* Handler for the H.service.RoutingService8#calculateRoute call
*
* @param {object} response The response object returned by calculateRoute method
*/functionrouteResponseHandler(response){const sections = response.routes[0].sections;const lineStrings =[];
sections.forEach((section)=>{// convert Flexible Polyline encoded string to geometry
lineStrings.push(H.geo.LineString.fromFlexiblePolyline(section.polyline));});const multiLineString =newH.geo.MultiLineString(lineStrings);const bounds = multiLineString.getBoundingBox();// Create the polyline for the routeif(routePolyline){// If the routePolyline we just set the new geometry
routePolyline.setGeometry(multiLineString);}else{// routePolyline is not yet defined, instantiate a new H.map.Polyline
routePolyline =newH.map.Polyline(multiLineString,{style:{lineWidth:5}});}// Add the polyline to the map
map.addObject(routePolyline);}
/**
* Listen to the dragstart and store the relevant position information of the marker
*/
map.addEventListener('dragstart',function(ev){const target = ev.target;const pointer = ev.currentPointer;if(target instanceofH.map.Marker){// Disable the default draggability of the underlying map
behavior.disable(H.mapevents.Behavior.Feature.PANNING);var targetPosition = map.geoToScreen(target.getGeometry());// Calculate the offset between mouse and target's position// when starting to drag a marker object
target['offset']=newH.math.Point(
pointer.viewportX - targetPosition.x, pointer.viewportY - targetPosition.y);}},false);
/**
* Listen to the drag event and move the position of the marker as necessary
*/
map.addEventListener('drag',function(ev){const target = ev.target;const pointer = ev.currentPointer;if(target instanceofH.map.Marker){
target.setGeometry(
map.screenToGeo(pointer.viewportX - target['offset'].x, pointer.viewportY - target['offset'].y));}},false);
/**
* Listen to the dragend and update the route
*/
map.addEventListener('dragend',function(ev){const target = ev.target;if(target instanceofH.map.Marker){// re-enable the default draggability of the underlying map// when dragging has completed
behavior.enable(H.mapevents.Behavior.Feature.PANNING);const coords = target.getGeometry();const markerId = target.getData().id;// Update the routing params `origin` and `destination` properties// in case we dragging either the origin or the destination markerif(markerId ==='A'){
routingParams.origin =`${coords.lat},${coords.lng}`;}elseif(markerId ==='B'){
routingParams.destination =`${coords.lat},${coords.lng}`;}updateRoute();}},false);
は MultiValueQueryParameter 、原点と終点の間に複数の経由地 の座標を保持する文字列パラメーターを作成します。 この文字列が HERE Routing API クエリに追加されます。
updateRoute() 次の例に示すように、経由地 を含めるように機能を調整します。
functionupdateRoute(){// Add waypoints the route must pass through
routingParams.via =newH.service.Url.MultiValueQueryParameter(
waypoints.map(wp=>`${wp.getGeometry().lat},${wp.getGeometry().lng}`));
router.calculateRoute(routingParams, routeResponseHandler, console.error);}
via このパラメータでは、オリジンと宛先の間でルートが通過する必要がある追加の経由地 が追加されます。
tap イベントのマップイベントリスナーを追加します。
/**
* Listen to the tap event to add a new waypoint
*/
map.addEventListener('tap',function(ev){const target = ev.target;const pointer = ev.currentPointer;const coords = map.screenToGeo(pointer.viewportX, pointer.viewportY);if(!(target instanceofH.map.Marker)){const marker =addMarker(coords, waypoints.length +1);
waypoints.push(marker);updateRoute();}});
/**
* Listen to the dbltap event to remove a waypoint
*/
map.addEventListener('dbltap',function(ev){const target = ev.target;if(target instanceofH.map.Marker){// Prevent the origin or destination markers from being removedif(['origin','destination'].indexOf(target.getData().id)!==-1){return;}const markerIdx = waypoints.indexOf(target);if(markerIdx !==-1){// Remove the marker from the array of way points
waypoints.splice(markerIdx,1)// Iterate over the remaining waypoints and update their data
waypoints.forEach((marker, idx)=>{const id = idx +1;// Update marker's id
marker.setData({
id
});// Update marker's icon to show its new id
marker.setIcon(getMarkerIcon(id))});}// Remove the marker from the map
map.removeObject(target);updateRoute();}});
次のコードを試す前 apikey に、パラメーターの値をご自身の API キー に置き換えてください。
//BOILERPLATE CODE TO INITIALIZE THE MAPconst platform =newH.service.Platform({'apikey':'Your API Key'});// Obtain the default map types from the platform object:const defaultLayers = platform.createDefaultLayers();// Instantiate (and display) a map:var map =newH.Map(
document.getElementById("map"),
defaultLayers.vector.normal.map,{zoom:6,center:{lat:53.480759,lng:-2.242631}});// MapEvents enables the event system// Behavior implements default interactions for pan/zoom (also on mobile touch environments)const behavior =newH.mapevents.Behavior(newH.mapevents.MapEvents(map));// Disable zoom on double-tap to allow removing waypoints on double-tap
behavior.disable(H.mapevents.Behavior.Feature.DBL_TAP_ZOOM);
window.addEventListener('resize',()=> map.getViewPort().resize());// Create the default UI:var ui =H.ui.UI.createDefault(map, defaultLayers,);// ROUTING LOGIC STARTS HERE// This variable holds the instance of the route polylinelet routePolyline;/**
* Handler for the H.service.RoutingService8#calculateRoute call
*
* @param {object} response The response object returned by calculateRoute method
*/functionrouteResponseHandler(response){const sections = response.routes[0].sections;const lineStrings =[];
sections.forEach((section)=>{// convert Flexible Polyline encoded string to geometry
lineStrings.push(H.geo.LineString.fromFlexiblePolyline(section.polyline));});const multiLineString =newH.geo.MultiLineString(lineStrings);const bounds = multiLineString.getBoundingBox();// Create the polyline for the routeif(routePolyline){// If the routePolyline we just set has the new geometry
routePolyline.setGeometry(multiLineString);}else{// If routePolyline is not yet defined, instantiate a new H.map.Polyline
routePolyline =newH.map.Polyline(multiLineString,{style:{lineWidth:5}});}// Add the polyline to the map
map.addObject(routePolyline);}/**
* Returns an instance of H.map.Icon to style the markers
* @param {number|string} id An identifier that will be displayed as marker label
*
* @return {H.map.Icon}
*/functiongetMarkerIcon(id){const svgCircle =`<svg width="30" height="30" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g id="marker">
<circle cx="15" cy="15" r="10" fill="#0099D8" stroke="#0099D8" stroke-width="4" />
<text x="50%" y="50%" text-anchor="middle" fill="#FFFFFF" font-family="Arial, sans-serif" font-size="12px" dy=".3em">${id}</text>
</g></svg>`;returnnewH.map.Icon(svgCircle,{anchor:{x:10,y:10}});}/**
* Create an instance of H.map.Marker and add it to the map
*
* @param {object} position An object with 'lat' and 'lng' properties defining the position of the marker
* @param {string|number} id An identifier that will be displayed as marker label
* @return {H.map.Marker} The instance of the marker that was created
*/functionaddMarker(position, id){const marker =newH.map.Marker(position,{data:{
id
},icon:getMarkerIcon(id),// Enable smooth draggingvolatility:true});// Enable draggable markers
marker.draggable =true;
map.addObject(marker);return marker;}/**
* This method calls the routing service to retrieve the route line geometry
*/functionupdateRoute(){
routingParams.via =newH.service.Url.MultiValueQueryParameter(
waypoints.map(wp=>`${wp.getGeometry().lat},${wp.getGeometry().lng}`));// Call the routing service with the defined parameters
router.calculateRoute(routingParams, routeResponseHandler, console.error);}// ADD MARKERS FOR ORIGIN/DESTINATIONconst origin ={lat:55.953251,lng:-3.188267};// Edinburghconst destination ={lat:51.507797,lng:-0.128604};// Londonconst originMarker =addMarker(origin,'A');const destinationMarker =addMarker(destination,'B');// CALCULATE THE ROUTE BETWEEN THE TWO WAYPOINTS// This array holds instances of H.map.Marker representing the route waypointsconst waypoints =[]// Define the routing service parametersconst routingParams ={'origin':`${origin.lat},${origin.lng}`,'destination':`${destination.lat},${destination.lng}`,// defines multiple waypoints'via':newH.service.Url.MultiValueQueryParameter(waypoints),'transportMode':'car','return':'polyline'};// Get an instance of the H.service.RoutingService8 serviceconst router = platform.getRoutingService(null,8);// Call the routing service with the defined parameters and display the routeupdateRoute();/**
* Listen to the dragstart and store relevant position information of the marker
*/
map.addEventListener('dragstart',function(ev){const target = ev.target;const pointer = ev.currentPointer;if(target instanceofH.map.Marker){// Disable the default draggability of the underlying map
behavior.disable(H.mapevents.Behavior.Feature.PANNING);var targetPosition = map.geoToScreen(target.getGeometry());// Calculate the offset between mouse and target's position// when starting to drag a marker object
target['offset']=newH.math.Point(
pointer.viewportX - targetPosition.x, pointer.viewportY - targetPosition.y);}},false);/**
* Listen to the dragend and update the route
*/
map.addEventListener('dragend',function(ev){const target = ev.target;if(target instanceofH.map.Marker){// re-enable the default draggability of the underlying map// when dragging has completed
behavior.enable(H.mapevents.Behavior.Feature.PANNING);const coords = target.getGeometry();const markerId = target.getData().id;// Update the routing params `origin` and `destination` properties// in case we dragging either the origin or the destination markerif(markerId ==='A'){
routingParams.origin =`${coords.lat},${coords.lng}`;}elseif(markerId ==='B'){
routingParams.destination =`${coords.lat},${coords.lng}`;}updateRoute();}},false);/**
* Listen to the drag event and move the position of the marker as necessary
*/
map.addEventListener('drag',function(ev){const target = ev.target;const pointer = ev.currentPointer;if(target instanceofH.map.Marker){
target.setGeometry(
map.screenToGeo(pointer.viewportX - target['offset'].x, pointer.viewportY - target['offset'].y));}},false);/**
* Listen to the tap event to add a new waypoint
*/
map.addEventListener('tap',function(ev){const target = ev.target;const pointer = ev.currentPointer;const coords = map.screenToGeo(pointer.viewportX, pointer.viewportY);if(!(target instanceofH.map.Marker)){const marker =addMarker(coords, waypoints.length +1);
waypoints.push(marker);updateRoute();}});/**
* Listen to the dbltap event to remove a waypoint
*/
map.addEventListener('dbltap',function(ev){const target = ev.target;if(target instanceofH.map.Marker){// Prevent origin or destination markers from being removedif(['origin','destination'].indexOf(target.getData().id)!==-1){return;}const markerIdx = waypoints.indexOf(target);if(markerIdx !==-1){// Remove the marker from the array of way points
waypoints.splice(markerIdx,1)// Iterate over the remaining waypoints and update their data
waypoints.forEach((marker, idx)=>{const id = idx +1;// Update marker's id
marker.setData({
id
});// Update marker's icon to show its new id
marker.setIcon(getMarkerIcon(id))});}// Remove the marker from the map
map.removeObject(target);updateRoute();}});