2012-05-22 160 views
12

Tôi đã tạo Bản đồ Google và vẽ một đường polyline trên đó. Sau đó tôi đã thêm một điểm đánh dấu vào đầu polyine (các coords giống như các coords bắt đầu của polyline).Thao tác kéo Điểm đánh dấu của Google Maps V3 vào Polyline

Điều tôi muốn có thể làm là lấy và kéo điểm đánh dấu nhưng để nó "dính" vào polyline sao cho bạn chỉ có thể kéo nó dọc theo đường polyline và không đi hoặc sang bên cạnh.

Có thể hạn chế điểm đánh dấu có thể kéo vào đường dẫn trong GM V3 không? Nếu không, bất cứ ai có thể nghĩ làm thế nào điều này có thể được thực hiện? Có khả năng chụp điểm đánh dấu đến điểm gần nhất trên đường dẫn khi người dùng đánh rơi nó, nhưng tôi muốn có hiệu ứng "kéo dọc theo đường dẫn" mượt mà hơn.

Rất vui khi có đề xuất ArcGis. Đã không cung cấp mã vì đây là một câu hỏi lý thuyết.

Hãy cho tôi biết nếu tôi cần giải thích thêm.

Cảm ơn trước

Trả lời

13

Ok nên tôi đã giải quyết được vấn đề này. Nó không chính xác thanh lịch, và tôi chắc chắn nó có thể được cải thiện nhưng đây là khái niệm chung tôi đã đưa ra:

Tôi tạo một mảng các điểm latlng từ một tệp GPX, nhưng chúng chỉ ghi điểm mỗi 20 hoặc là. Đó không phải là đủ granularity cho các mục đích của tôi vì vậy những gì tôi đã làm là tôi đệm mảng điểm với khoảng 10 điểm (trên một đường tuyến tính) giữa mỗi cặp điểm đăng bởi GPX:

$.each(array_of_points_to_pad, function(key, pt) { 
    var current_point = pt;//The current point 
    var next_point = array_of_points_to_pad[key + 1];//The point immediately after the current point 

    //Check that we're not on the last point 
    if (typeof next_point !== 'undefined') { 
     //Get a 10th of the difference in latitude between current and next points 
     var lat_incr = (next_point.lat() - current_point.lat())/10; 

     //Get a 10th of the difference in longitude between current and next points 
     var lng_incr = (next_point.lng() - current_point.lng())/10; 

     //Add the current point to a new padded_points array 
     padded_points.push(current_point); 

     //Now add 10 additional points at lat_incr & lng_incr intervals between current and next points (in the new padded_points array) 
     for (var i = 1; i <= 10; i++) { 
      var new_pt = new google.maps.LatLng(current_point.lat() + (i * lat_incr), current_point.lng() + (i * lng_incr)); 
      padded_points.push(new_pt); 
     } 
    } 
}); 

Bây giờ tôi có một mảng tinh tế hơn của các điểm, tôi sử dụng này để vẽ một polyline. Đường polyline đệm sẽ trông không khác với polyline được vẽ mà không có phần đệm, vì tất cả các điểm bổ sung đều nằm trên một đường thẳng "tuyến tính-chim bay" tuyến tính giữa các điểm hiện có.

var line = new google.maps.Polyline({ 
    path: polyline_path_points_padded, 
    strokeColor: '#ff0000', 
    strokeOpacity: 1.0, 
    strokeWeight: 2 
}); 
line.setMap(map); 

Bây giờ tôi thêm một dấu hiệu có thể kéo vào đầu dòng:

var latLng = new google.maps.LatLng(startlat,startlng); 
var marker = new google.maps.Marker({ 
    position: latLng, 
    map: map, 
    draggable:true 
}); 

Tất cả những gì còn lại để làm là kiểm soát kéo và dragend sự kiện đánh dấu này:

google.maps.event.addDomListener(marker,'dragend',function(e){ 
    marker.setPosition(find_closest_point_on_path(e.latLng,padded_points)); 
}); 

google.maps.event.addDomListener(marker,'drag',function(e){ 
    marker.setPosition(find_closest_point_on_path(e.latLng,padded_points)); 
}); 

Ở đây chúng ta chỉ cần gửi latLng của điểm đánh dấu đến hàm find_closest_point_on_path() trong khi kéo và khi điểm đánh dấu bị bỏ. Chúng tôi gửi mảng điểm đệm như một đường dẫn để tìm kiếm.

Chức năng trông như thế này:

function find_closest_point_on_path(marker_pt,path_pts){ 
    distances = new Array(); 
    distance_keys = new Array(); 
    $.each(path_pts,function(key, path_pt){ 
     var R = 6371; // km 
     var dLat = (path_pt.lat()-marker_pt.lat()).toRad(); 
     var dLon = (path_pt.lng()-marker_pt.lng()).toRad(); 
     var lat1 = marker_pt.lat().toRad(); 
     var lat2 = path_pt.lat().toRad(); 

     var a = Math.sin(dLat/2) * Math.sin(dLat/2) + 
       Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); 
     var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
     var d = R * c; 
     //Store the key of the point on the path that matches this distance 
     distance_keys[d] = key; 

    }); 
      //Return the latLng pt on the path for the second closest point 
    return path_pts[distance_keys[_.min(distances)]+1]; 
} 

gì chức năng này thực hiện (với sự giúp đỡ của một độ chức năng radian) là nó tìm thấy khoảng cách giữa các vị trí mốc và tất cả các điểm trên đường dây. Sau đó, nó tìm điểm gần nhất với điểm đánh dấu và trả về tọa độ cho điểm gần nhất tiếp theo sau điểm đó. Bằng cách này, khi bạn kéo hoặc thả các điểm đánh dấu nó "snaps" đến điểm tiếp theo (thay vì bị mắc kẹt tại một chỗ).

Working JS Fiddle Dưới:

http://jsfiddle.net/Z5GwW/4/

Có không qua trình duyệt thử nghiệm. Làm việc trong phiên bản Chrome mới nhất.

+1

Đang cố gắng để giải quyết vấn đề này bản thân mình trên một nền tảng di động, tất cả các chức năng trig đó là một chút đáng sợ cho một biểu thức chạy o n mỗi tic kéo, tôi có thể đề nghị tính toán một [khoảng cách Manhattan] đơn giản (http://en.wikipedia.org/wiki/Taxicab_geometry) cần đủ chính xác trên thang điểm tương đối và chỉ sử dụng các phép tính số học cơ bản – jmaculate

0

Cảm ơn bạn đã giải pháp này.

Để có được nó làm việc mà không phụ thuộc, tôi đã phải sửa đổi một vài dòng:

Thứ nhất, kiểm tra toRad() chức năng tồn tại:

if (typeof(Number.prototype.toRad) === "undefined") { 
 
\t Number.prototype.toRad = function() { 
 
\t  return this * Math.PI/180; 
 
\t } 
 
\t }

Và cũng , tẩy _. phụ thuộc bằng cách thay thế mã trở lại:

return path_pts[distance_keys[ Math.min(...distances) ]+1];

và cuối cùng, bao gồm khoảng cách [] trước distancekeys []

distances[key] = d; 
 
distance_keys[d] = key;

Các vấn đề liên quan