Skip to content

Instantly share code, notes, and snippets.

@romuloceccon
Created October 25, 2012 21:43
Show Gist options
  • Save romuloceccon/3955626 to your computer and use it in GitHub Desktop.
Save romuloceccon/3955626 to your computer and use it in GitHub Desktop.
Google maps javascript api path editor
x1, y1 = 1.0, 2.2
x2, y2 = 5.0, 3.3
x3, y3 = -10.0, -100.0
dx12 = x1 - x2
dy12 = y1 - y2
den = dx12 ** 2 + dy12 ** 2
x4 = (x3 * dx12 ** 2 - dy12 * (x1 * (y2 - y3) - x2 * (y1 - y3))) / den
y4 = (y3 * dy12 ** 2 - dx12 * (y1 * (x2 - x3) - y2 * (x1 - x3))) / den
print x4, " ", y4, "\n"
dx12 = x1 - x2
dy12 = y1 - y2
k = (dx12 * (y3 - y1) - dy12 * (x3 - x1)) / (dx12 ** 2 + dy12 ** 2)
x4 = x3 + k * dy12
y4 = y3 - k * dx12
print x4, " ", y4, "\n"
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta charset="UTF-8">
<style type="text/css">
html { height: 100% }
body { height: 100%; margin: 0; padding: 0 }
#map_canvas { height: 100% }
</style>
<script type="text/javascript"
src="http://maps.googleapis.com/maps/api/js?key=AIzaSyDflN5fMc6kgt5C1vSt8Durt1zNFp2IGN0&sensor=false">
</script>
<script>
var map;
var directionsService;
var startPoint = null;
var poly;
var polyPath;
var drawMode = 'r';
var segments = [];
var markers = [];
var stops = [];
var actionList;
var streetView;
var circleIcon = { path: google.maps.SymbolPath.CIRCLE, scale: 3 };
var stopIcon = { path: 'M 0,0 0,-20 A 10,10 0 1 1 0,-40 A 10,10 0 1 1 0,-20', strokeWeight: 3, strokeColor: 'blue' };
var linkIcon = { path: google.maps.SymbolPath.CIRCLE, scale: 3, strokeColor: 'red' };
var attachedStopIcon = { path: 'M 0,0 0,-20 A 10,10 0 1 1 0,-40 A 10,10 0 1 1 0,-20', strokeWeight: 3, strokeColor: 'green' };
var routeCursor = 'pointer';
var stopCursor = 'crosshair';
var eraseCursor = 'not-allowed';
var curitiba = new google.maps.LatLng(-25.40, -49.27);
var mapOptions = {
zoom: 15,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: curitiba,
draggableCursor: routeCursor
};
var polyOptions = {
strokeColor: '#000000',
strokeOpacity: 0.7,
strokeWeight: 2,
icons: [{
icon: { path: google.maps.SymbolPath.FORWARD_CLOSED_ARROW, scale: 1.5 },
offset: '99px',
repeat: '100px' }]
};
var linkOptions = {
strokeColor: 'red',
strokeOpacity: 1.0,
strokeWeight: 2,
};
// ============================================================
var wb = {};
wb.ActionList = function() {
this.actions = [];
this.current = -1;
};
wb.ActionList.prototype.do = function(action) {
action.do();
var s = this.current + 1;
this.actions.splice(s, this.actions.length - s, action);
this.current = this.actions.length - 1;
};
wb.ActionList.prototype.undo = function() {
if (this.current >= 0)
{
this.actions[this.current].undo();
this.current -= 1;
}
};
wb.ActionList.prototype.redo = function() {
if (this.actions.length > this.current + 1)
{
this.actions[this.current + 1].do();
this.current += 1;
}
};
wb.DrawStartPoint = function(position) {
this.position = position;
};
wb.DrawStartPoint.prototype.do = function() {
startPoint = this.position;
redrawPath();
};
wb.DrawStartPoint.prototype.undo = function() {
startPoint = null;
redrawPath();
};
wb.DrawRouteSegment = function(segment) {
this.segment = segment;
};
wb.DrawRouteSegment.prototype.do = function() {
segments.push(this.segment);
redrawPath();
};
wb.DrawRouteSegment.prototype.undo = function() {
segments.pop();
redrawPath();
};
wb.DrawBusStop = function(position) {
var m = new google.maps.Marker({
position: position,
icon: stopIcon
});
var s = { marker: m, link: null };
google.maps.event.addListener(m, 'click', function () {
if (drawMode == 'x')
{
actionList.do(new wb.EraseBusStop(s, stops.indexOf(s)));
}
else if (drawMode == 'p')
{
streetView.getPanorama().setPosition(m.getPosition());
}
else if (!stop.link)
{
var p1 = m.getPosition();
var p2 = closestPointFromPoly(p1);
if (p1 != null && p2 != null)
actionList.do(new wb.DrawBusStopLink(s, p2));
}
});
this.stop = s;
};
wb.DrawBusStop.prototype.do = function() {
this.stop.marker.setMap(map);
stops.push(this.stop);
};
wb.DrawBusStop.prototype.undo = function() {
this.stop.marker.setMap(null);
stops.splice(stops.indexOf(this.stop), 1);
};
wb.DrawBusStopLink = function(stop, p2) {
var p1 = stop.marker.getPosition();
var o = [];
var line = new google.maps.Polyline(linkOptions);
line.getPath().push(p1);
line.getPath().push(p2);
o.push(new google.maps.Marker({ position: p1, icon: linkIcon }));
o.push(new google.maps.Marker({ position: p2, icon: linkIcon }));
o.push(line);
var f = function() {
if (drawMode == 'x')
actionList.do(new wb.EraseBusStopLink(stop));
};
o.forEach(function(a) { google.maps.event.addListener(a, 'click', f) });
this.stop = stop;
this.objs = o;
};
wb.DrawBusStopLink.prototype.do = function() {
this.objs.forEach(function(a) { a.setMap(map) });
this.stop.link = this.objs;
};
wb.DrawBusStopLink.prototype.undo = function() {
this.objs.forEach(function(a) { a.setMap(null) });
this.stop.link = this.objs;
};
wb.EraseBusStop = function(stop, index) {
this.stop = stop;
this.index = index;
};
wb.EraseBusStop.prototype.do = function() {
this.stop.marker.setMap(null);
if (this.stop.link)
this.stop.link.forEach(function(a) { a.setMap(null) });
stops.splice(this.index, 1);
};
wb.EraseBusStop.prototype.undo = function() {
this.stop.marker.setMap(map);
if (this.stop.link)
this.stop.link.forEach(function(a) { a.setMap(map) });
stops.splice(this.index, 0, this.stop);
};
wb.EraseBusStopLink = function(stop) {
this.stop = stop;
this.objs = stop.link;
};
wb.EraseBusStopLink.prototype.do = function() {
this.objs.forEach(function(a) { a.setMap(null) });
this.stop.link = null;
};
wb.EraseBusStopLink.prototype.undo = function() {
this.objs.forEach(function(a) { a.setMap(map) });
this.stop.link = this.objs;
};
wb.StreetView = function(ownerMap) {
var container = document.createElement('div');
container.style.padding = '5px';
container.style.display = 'none';
container.index = 1;
var previewDiv = document.createElement('div');
previewDiv.style.minWidth = '400px';
previewDiv.style.minHeight = '300px';
container.appendChild(previewDiv);
var panorama = new google.maps.StreetViewPanorama(previewDiv,
{ position: curitiba, pov: { heading: 0, pitch: 10, zoom: 1 }, visible: false });
ownerMap.setStreetView(panorama);
ownerMap.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(container);
google.maps.event.addListener(panorama, 'visible_changed', function() {
if (panorama.getVisible())
{
drawMode = 'p';
container.style.display = '';
}
else
{
if (drawMode == 'p')
drawMode = 'r';
container.style.display = 'none';
}
});
this.panorama = panorama;
this.container = container;
};
wb.StreetView.prototype.getPanorama = function() {
return this.panorama;
};
// ============================================================
function initialize() {
directionsService = new google.maps.DirectionsService();
map = new google.maps.Map(document.getElementById('map_canvas'), mapOptions);
poly = new google.maps.Polyline(polyOptions);
poly.setMap(map);
polyPath = poly.getPath();
actionList = new wb.ActionList();
streetView = new wb.StreetView(map);
google.maps.event.addListener(map, 'click', onMapClick);
}
function keypress(e) {
var code;
if (!e)
var e = window.event;
if (e.keyCode)
code = e.keyCode;
else if (e.which)
code = e.which;
var character = String.fromCharCode(code);
if (character == 's' || character == 't' || character == 'x')
streetView.getPanorama().setVisible(false);
if (character == 'u')
{
actionList.undo();
}
else if (character == 'r')
{
actionList.redo();
}
else if (character == 'p')
{
drawMode = 'p';
map.setOptions({ draggableCursor: routeCursor })
streetView.getPanorama().setVisible(true);
}
else if (character == 's')
{
drawMode = 's';
map.setOptions({ draggableCursor: stopCursor })
}
else if (character == 't')
{
drawMode = 'r';
map.setOptions({ draggableCursor: routeCursor })
}
else if (character == 'x')
{
drawMode = 'x';
map.setOptions({ draggableCursor: eraseCursor })
}
}
function redrawPath() {
while (null != polyPath.pop())
;
for (var m = markers.pop(); m != null; m = markers.pop())
m.setMap(null);
if (segments.length == 0)
{
if (startPoint != null)
drawCircle(startPoint);
}
else
{
drawCircle(segments[0][0]);
}
for (var i = 0; i < segments.length; i++)
{
for (var j = 0; j < segments[i].length; j++)
polyPath.push(segments[i][j]);
drawCircle(segments[i][segments[i].length - 1]);
}
}
function drawCircle(position) {
var m = new google.maps.Marker({
position: position,
map: map,
icon: circleIcon
});
markers.push(m);
}
// searches the closest polyline point to latLng, considering the
// coordinate system as an euclidean space (won't work across big
// distances or near the poles)
function closestPointFromPoly(latLng) {
if (polyPath.length == 0)
return null;
if (polyPath.length == 1)
return polyPath.getAt(0);
var minDistanceLatLng = polyPath.getAt(0);
var minDistance = google.maps.geometry.spherical.computeDistanceBetween(
latLng, minDistanceLatLng);
for (var i = 0; i < polyPath.length - 1; i++)
{
var p1 = polyPath.getAt(i);
var p2 = polyPath.getAt(i + 1);
var dx12 = p1.Ya - p2.Ya;
var dy12 = p1.Za - p2.Za;
var k = (dx12 * (latLng.Za - p1.Za) - dy12 * (latLng.Ya - p1.Ya)) /
(dx12 * dx12 + dy12 * dy12);
var p4 = new google.maps.LatLng(latLng.Ya + k * dy12, latLng.Za - k * dx12);
var p;
// is p4 between p1 and p2? (takes into account horizontal/vertical lines)
if (Math.abs(p1.Ya - p2.Ya) > 0.00001 && (p1.Ya - p4.Ya) * (p4.Ya - p2.Ya) >= 0 ||
Math.abs(p1.Za - p2.Za) > 0.00001 && (p1.Za - p4.Za) * (p4.Za - p2.Za) >= 0)
p = p4;
else
p = p2;
var distance = google.maps.geometry.spherical.computeDistanceBetween(
latLng, p);
if (distance < minDistance)
{
minDistance = distance;
minDistanceLatLng = p;
}
}
return minDistanceLatLng;
};
function onMapClick(event) {
if (drawMode == 's')
{
actionList.do(new wb.DrawBusStop(event.latLng));
return;
}
if (drawMode == 'r')
{
if (startPoint == null)
{
actionList.do(new wb.DrawStartPoint(event.latLng));
}
else
{
var request = {
origin: startPoint,
destination: event.latLng,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
if (segments.length == 0)
{
request.origin = startPoint;
}
else
{
var s = segments[segments.length - 1];
request.origin = s[s.length - 1];
}
directionsService.route(request, onRouteResult);
}
}
}
function onRouteResult(response, status) {
if (status != google.maps.DirectionsStatus.OK)
return;
var segment = [];
var legs = response.routes[0].legs;
if (legs.length == 0)
return;
var steps = legs[0].steps;
for (var step = 0; step < steps.length; step++)
{
path = steps[step].path;
for (p = 0; p < path.length; p++)
{
if (step == 0 || p > 0)
segment.push(path[p]);
}
}
if (segment.length > 0)
actionList.do(new wb.DrawRouteSegment(segment));
};
google.maps.event.addDomListener(window, 'load', initialize);
google.maps.event.addDomListener(window, 'keypress', keypress);
</script>
</head>
<body>
<div id="map_canvas" style="width:100%; height:100%"></div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment