2014-09-28 91 views
1

首先,我想說我不太經驗Google Maps Javascript API v3(我唯一的經驗是最近3天)。我已成功地顯示與標記列表的地圖,並使用DirectionsService將它們連接起來,但有時我的名單是相當大的,我得到了以下錯誤:請求實體太大 - 谷歌地圖方向錯誤413

Failed to load resource: the server responded with a status of 413 (Request Entity Too Large) 

這是我的代碼:

// List of all locations for device 
var locations = []; 
// example: locations = [ 
//  {datetime: '2014/09/28 20:20', location: '41.99999 21.99999 30.0'}, 
//  ... {...} ... may be more than 200 entries for locations 
//  {datetime: '2014/09/28 20:25', location: '41.99999 21.99999 30.0'} 
// ] 

var map; 
var markers = []; 
var bounds = new google.maps.LatLngBounds(); 
var pathPoints = []; 
var infoWindow = new google.maps.InfoWindow(); 
var accuracy = new google.maps.Circle({ 
    fillColor: '#ff4080', 
    fillOpacity: 0.5, 
    strokeOpacity: 0, 
    zIndex: 0 
}); 
var path = new google.maps.Polyline(polyOptions); 
var geocoder; 
var directionsService = new google.maps.DirectionsService(); 
var directionsDisplay; 
var polyOptions = { 
    geodesic: true, 
    strokeColor: '#28b8b8', 
    strokeOpacity: 1.0, 
    strokeWeight: 8, 
    zIndex: 1 
} 
function showInfoWindow(marker, datetime, acc){ 
    geocoder = new google.maps.Geocoder(); 
    geocoder.geocode({ 
     'latLng': marker.getPosition() 
    }, function(results, status) { 
     if (status == google.maps.GeocoderStatus.OK) { 
      if (results[1]) { 
       infoWindow.close(); 
       var date = datetime.split(" ")[0]; 
       var time = datetime.split(" ")[1]; 
       var content = '<div class="infowindow">' 
         + results[1].formatted_address.trim() + '<br />' 
         + 'Date: ' + date + '<br />' 
         + 'Time: ' + time + '<br />' 
         + 'Accuracy: ' + acc + 'm' 
         + '</div>'; 
       infoWindow.setContent(content); 
       infoWindow.open(map, marker); 
       accuracy.setMap(null); 
       accuracy.setMap(map); 
       accuracy.setCenter(marker.getPosition()); 
       accuracy.setRadius(acc/1.6); 
      } else { 
       // alert('No results found'); 
      } 
     } else { 
      alert('Geocoder failed due to: ' + status); 
     } 
    }); 
} 
function addMultiMarker(latLng, num, datetime, acc){ 
    // Create marker at provided location 
    var marker = new google.maps.Marker({ 
     position: latLng, 
     map: map, 
     icon: image_circle, 
     title: 'Location #' + num, 
     zIndex: num + 1 
    }); 
    // On marker click center it inside map and show infoWindow 
    google.maps.event.addListener(marker, 'click', function() { 
     map.panTo(marker.getPosition()); 
     showInfoWindow(marker, datetime, acc); 
    }); 
    return marker; 
} 
function showRoute() { 
    var rendererOptions = { 
     draggable: false, 
     hideRouteList: true, 
     suppressMarkers: true, 
     infoWindow: infoWindow, 
     polylineOptions: polyOptions, 
     map: map 
    }; 
    directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions); 
    var len = markers.length; 
    var start = markers[0].getPosition(); 
    var end = markers[len - 1].getPosition(); 
    new google.maps.event.trigger(markers[len - 1], 'click'); 
    var wayPts = []; 
    for(var i = 1; i < len - 1; i++){ 
     wayPts.push({ 
      location: markers[i].getPosition(), 
      stopover: true 
     }); 
    } 
    var request = { 
     origin: start, 
     destination: end, 
     waypoints: wayPts, 
     optimizeWaypoints: true, 
     travelMode: google.maps.TravelMode.DRIVING 
    }; 
    directionsService.route(request, function(response, status) { 
     if (status == google.maps.DirectionsStatus.OK) { 
      directionsDisplay.setDirections(response); 
     } 
    }); 
} 
function showMapPeriod(periodStart, periodEnd){ 
    // Simple map options 
    var mapOptions = { 
     zoom: 15, 
     center: new google.maps.LatLng(41, 21), 
     mapTypeId : google.maps.MapTypeId.ROADMAP, 
     mapTypeControl: true, 
     mapTypeControlOptions: { 
      style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR, 
      position: google.maps.ControlPosition.TOP_RIGHT 
     }, 
     zoomControl: true, 
     zoomControlOptions: { 
      style: google.maps.ZoomControlStyle.LARGE, 
      position: google.maps.ControlPosition.LEFT_CENTER 
     }, 
     panControl: false, 
     streetViewControl: false 
    }; 
    $("#map").html(""); 
    // Create and show map 
    openMapContainer(); // just a function that shows the map <div> element 
    map = new google.maps.Map(document.getElementById('map'), mapOptions); 
    // Create and display markers 
    bounds = new google.maps.LatLngBounds(); 
    markers = []; 
    var len = 0; 
    for(var i = periodStart; i <= periodEnd; i++, len++){ 
     var loc_vals = locations[i].location.trim().split(" "); 
     var lat = parseFloat(loc_vals[0]); 
     var lng = parseFloat(loc_vals[1]); 
     var acc = parseFloat(loc_vals[2]); 
     // Create marker at provided location 
     var datetime = locations[i].datetime; 
     var latLng = new google.maps.LatLng(lat, lng); 
     markers[len] = addMultiMarker(latLng, len+1, datetime, acc); 
     bounds.extend(latLng); 
    } 
    showRoute(); 
    map.fitBounds(bounds); 
} 

那麼我的代碼部分工作,如果有人可以幫助我消除這個問題,我將非常感激。爲了更好地解釋它,我需要某種解決方案來請求Directions提供很多(200+)路標或某種方式來連接路段中的位置(我並不真正需要路線,但我不想連接地理位置簡單Polyline)。

編輯:Here我已經提供了一個簡單的演示,看到在line 15只是取消註釋的問題。

+0

請提供一個展示此問題的示例。 – geocodezip 2014-09-28 22:40:55

+0

如何更改這些以展示此問題? – geocodezip 2014-09-29 03:57:20

+0

在這裏[小提琴](http://jsfiddle.net/o3zqhsaz/6/),你可以看到點沒有連接 – kiko283 2014-09-30 06:55:10

回答

5

因爲沒有人能夠幫助我解決我的問題,我必須自己解決它。我正在回答我自己的問題,因爲這對許多人來說似乎都是一個問題,並且在網絡上解釋不夠,所以這可能會幫助有類似問題的開發人員。

無論如何,讓我們來談談。該錯誤是因爲谷歌限制拋出OxyDesign建議的,錯誤是:

  • google.maps.DirectionsResult.MAX_WAYPOINTS_EXCEEDED - 這是因爲我發送的請求與起源目的地和超過8(谷歌限制)航點

,我很容易解決(I只是分裂與作爲下一個的所述第一點的一個請求的最後一個點的10個點的塊的陣列),但是然後我得到另一個錯誤:

  • google.maps.DirectionsResult.OVER_QUERY_LIMIT - 這是因爲我試圖每秒發送超過10次(再次限制Google)請求。

這需要多一點實驗,搜索和測試來解決,但我解決了它。

現在,這裏是爲我工作的代碼(至少在發佈的時間,直到谷歌改變的東西):

// list of randomly generated locations (max 288) 
var locations = []; 
for(var i=0; i<288; i++){ 
    locations[i] = { 
     datetime: '2014/10/01 12:10', 
     location: (51 + Math.random()) + 
     ' ' + (-0.5 + Math.random()) + ' 30.0' 
    }; 
} 
// Marker images 
var image_pin = new google.maps.MarkerImage(
    'http://stedkomerc.com.mk/gpslocator/images/mPin.svg', 
    new google.maps.Size(25, 41), // size 
    new google.maps.Point(0, 0), // origin, top-left corner 
    new google.maps.Point(12, 40) // anchor 
); 
var image_circle = new google.maps.MarkerImage(
    'http://stedkomerc.com.mk/gpslocator/images/mCircle.svg', 
    new google.maps.Size(19, 19), // size 
    new google.maps.Point(0, 0), // origin, top-left corner 
    new google.maps.Point(9, 9) // anchor 
); 
// Variables 
var map; 
var bounds = new google.maps.LatLngBounds(); 
var markers = []; 
var pathPoints = []; 
var geocoder; 
var infoWindow = new google.maps.InfoWindow(); 
var accuracy = new google.maps.Circle({ 
    fillColor: '#ff4080', 
    fillOpacity: 0.4, 
    strokeOpacity: 0, 
    zIndex: 0 
}); 
var polyOptions = { 
    geodesic: true, 
    strokeColor: '#28b8b8', 
    strokeOpacity: 1.0, 
    strokeWeight: 8, 
    zIndex: 1 
}; 
var path = new google.maps.Polyline(polyOptions); 
var directionsService = new google.maps.DirectionsService(); 
var directions = []; 
var rendererOptions = { 
    draggable: false, 
    hideRouteList: true, 
    suppressMarkers: true, 
    preserveViewport: true, 
    infoWindow: infoWindow, 
    polylineOptions: polyOptions 
}; 
var requests = []; 
var MAX_POINTS_PER_REQUEST = 10; // 8*waypts Google limit + start + end 
var MAX_REQUESTS_PER_SECOND = 10; // Google limit 
// functions 
function showInfoWindow(marker, datetime, acc){ 
    geocoder = new google.maps.Geocoder(); 
    geocoder.geocode({ 
     'latLng': marker.getPosition() 
    }, function(results, status) { 
     if (status == google.maps.GeocoderStatus.OK) { 
      if (results[1]) { 
       infoWindow.close(); 
       var date = datetime.split(" ")[0]; 
       var time = datetime.split(" ")[1]; 
       var content = '<div class="infowindow">' + 
        results[1].formatted_address.trim() + '<br />' + 
        'Date: ' + date + '<br />' + 
        'Time: ' + time + '<br />' + 
        'Accuracy: ' + acc + 'm' + 
        '</div>'; 
       infoWindow.setContent(content); 
       infoWindow.open(map, marker); 
       accuracy.setMap(null); 
       accuracy.setMap(map); 
       accuracy.setCenter(marker.getPosition()); 
       accuracy.setRadius(acc); 
      } 
     } else { 
      console.log('Geocoder failed due to: ' + status); 
     } 
    }); 
} 
function addMultiMarker(latLng, num, datetime, acc){ 
    // Create marker at provided location 
    var marker = new google.maps.Marker({ 
     position: latLng, 
     map: map, 
     icon: image_circle, 
     title: 'Location #' + num, 
     zIndex: num + 1 
    }); 
    // On marker click center it inside map and show infoWindow 
    google.maps.event.addListener(marker, 'click', function() { 
     //map.panTo(marker.getPosition()); 
     showInfoWindow(marker, datetime, acc); 
    }); 
    return marker; 
} 
function connectMarkersPolyline(mrkrs){ 
    path.setMap(map); 
    pathPoints = path.getPath(); 
    len = mrkrs.length; 
    for(var i = 0; i < len; i++){ 
     pathPoints.push(mrkrs[i].getPosition()); 
    } 
} 
function connectMarkersRoute(mrkrs, part, maxParts){ 
    var directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions); 
    directionsDisplay.setMap(map); 
    var len = mrkrs.length; 
    var start = mrkrs[0].getPosition(); 
    var end = mrkrs[len - 1].getPosition(); 
    var wayPts = []; 
    for(var i = 1; i < len - 1; i++){ 
     wayPts.push({ 
      location: mrkrs[i].getPosition(), 
      stopover: true 
     }); 
    } 
    var request = { 
     origin: start, 
     destination: end, 
     waypoints: wayPts, 
     optimizeWaypoints: false, 
     travelMode: google.maps.TravelMode.DRIVING, 
     unitSystem: google.maps.UnitSystem.METRIC 
    }; 
    directionsService.route(request, function(response, status) { 
     if (status == google.maps.DirectionsStatus.OK) { 
      // request status OK, display route 
      directionsDisplay.setDirections(response); 
      // save it in array in case we want to remove it later 
      directions.push(directionsDisplay); 
      // if not last chunk, send next chunk after 100ms 
      // 1 request per 100ms => 10 requests per 1s 
      if(part+1 < maxParts) 
       setTimeout(connectMarkersRoute(requests[part+1], part+1, maxParts), 100); 
      else showLastMarker(); 
     } else if (status == google.maps.DirectionsStatus.OVER_QUERY_LIMIT) { 
      // if we get error, send same request after bigger delay (120ms) 
      setTimeout(connectMarkersRoute(requests[part], part, maxParts), 120); 
     } else { 
      // if all fails, connect with simple polyline 
      console.log('Directions failed due to: ' + status); 
      connectMarkersPolyline(mrkrs); 
     } 
    }); 
} 
function connectMarkers(markers){ 
    path.setMap(null); 
    path.setPath([]); 
    directions = []; 
    requests = []; 
    var len = markers.length; 
    console.log('connecting ' + len + ' markers'); 
    var i, j; 
    // split markers array into chunks of 10 (start + waypts + end) 
    for(i=0; i<len; i+=MAX_POINTS_PER_REQUEST-1){ 
     if(i<len-1) 
      requests.push(markers.slice(i, i+MAX_POINTS_PER_REQUEST)); 
    } 
    // send first chunk to connectMarkersRoute() 
    connectMarkersRoute(requests[0], 0, requests.length); 
} 
function showMapPeriod(periodStart, periodEnd){ 
    // Map options 
    var mapOptions = { 
     zoom: 16, 
     center: new google.maps.LatLng(41.995922, 21.431465), 
     mapTypeId : google.maps.MapTypeId.ROADMAP, 
     mapTypeControl: true, 
     mapTypeControlOptions: { 
      style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR, 
      position: google.maps.ControlPosition.TOP_RIGHT 
     }, 
     zoomControl: true, 
     zoomControlOptions: { 
      style: google.maps.ZoomControlStyle.LARGE, 
      position: google.maps.ControlPosition.LEFT_CENTER 
     }, 
     panControl: false, 
     streetViewControl: false 
    }; 
    $("#map").html(""); 
    //openMapContainer(); 
    // Create and show map 
    map = new google.maps.Map(document.getElementById('map'), mapOptions); 
    // Create and display markers 
    bounds = new google.maps.LatLngBounds(); 
    markers = []; 
    var len = 0; 
    for(var i = periodStart; i <= periodEnd; i++, len++){ 
     var loc_vals = locations[i].location.trim().split(" "); 
     var lat = parseFloat(loc_vals[0]); 
     var lng = parseFloat(loc_vals[1]); 
     var acc = parseFloat(loc_vals[2]); 
     // Create marker at provided location 
     var datetime = locations[i].datetime; 
     var latLng = new google.maps.LatLng(lat, lng); 
     markers[len] = addMultiMarker(latLng, len+1, datetime, acc); 
     bounds.extend(latLng); 
    } 
    connectMarkers(markers); 
    map.fitBounds(bounds); 
    if(map.getZoom() > 16) map.setZoom(16); 
} 
function showLastMarker(){ 
    new google.maps.event.trigger(markers[markers.length - 1], 'click'); 
} 
// show map 
showMapPeriod(1, 280); 
// -------- 

正如你所看到的,我所做的唯一真正的變化是showRoute()功能變爲connectMarkers()與處理兩種錯誤的connectMarkersRoute()connectMarkersPolyline()相結合。可以看到工作示例here。加載所有路由塊需要一點時間,但至少可以工作。希望這可以幫助別人。

請注意,Google的每日限制還有2500 Directions個請求,所以要小心。話雖如此,這個答案甚至可以用於比200個地點更大的請求,我已經在1250個地點進行了測試,結果很有效。

2

似乎有此服務Gmaps Waypoints(或,我試着和它的工作,直到39,然後40沒有),有沒有辦法做到這一點的另一種方式,除了與折線的限制,但你不希望它,所以我認爲沒有可行的解決方案...

+0

非常感謝您的信息,我讀了有關的限制,現在我正在尋找某種解決方法 – kiko283 2014-09-28 23:40:47

+0

好的,祝你好運!而且,如果您找到解決方案,請在此處添加。謝謝 – OxyDesign 2014-09-29 09:19:50

+0

我發現了一個解決方案,你可以在我的答案中看到它[下面](http://stackoverflow.com/questions/26088925/request-entity-too-large-google-map-directions-error-413/#26153175 )。 – kiko283 2014-10-02 09:55:07