Tremor
Tremor

Reputation: 31

Using google maps polyline to draw bezier curve

I'm trying to draw a bezier curve in google maps by using a SVG path in a Polyline. At first I used a Marker instead similar to Curved line between two near points in google maps, which gave the results that I'm after. However, since it's not possible to drag the map under the marker, I can't use this method.

So I switched to a Polyline instead of a marker. Now I get the same good results when I zoom out, but when I zoom in the curve becomes "cropped".

Here is the code:

function initialize() {
    var mapOptions = {
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };

    var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

    var coord1 = new google.maps.LatLng(49.165876, -123.152446);
    var coord2 = new google.maps.LatLng(25.786328, -80.193694);
    var bounds = new google.maps.LatLngBounds();
    bounds.extend(coord1);
    bounds.extend(coord2);
    map.fitBounds(bounds);

    pLineOpt = {
        path: [coord1, coord2],
        strokeWeight: 4,
        strokeOpacity: 0,
        map: map,
    }

    pLine = new google.maps.Polyline(pLineOpt);

    var markers = [
        new google.maps.Marker({
            position: coord1,
            map: map
        }),
        new google.maps.Marker({
            position: coord2,
            map: map
        })
    ];

    google.maps.event.addListener(map, 'zoom_changed', function () {
        //points
        var p1 = map.getProjection().fromLatLngToPoint(coord1);
        var p2 = map.getProjection().fromLatLngToPoint(coord2);
        //distance between points
        var d = new google.maps.Point(p2.x - p1.x, p2.y - p1.y);
        var lengthSqr = d.x * d.x + d.y * d.y;
        //middle point
        var m = new google.maps.Point(d.x / 2, d.y / 2);
        //slope of perpendicular line
        var perpK = -d.x / d.y;
        //distance to control point
        var ratioDistanceControlLengthSqr = 9;
        var controlDSqr = lengthSqr / ratioDistanceControlLengthSqr;
        var p3dX = Math.sqrt(controlDSqr / (Math.pow(perpK, 2) + 1));
        var p3dY = perpK * p3dX;
        //control point
        var p3 = new google.maps.Point(m.x - p3dX, m.y - p3dY);
        //curve path
        var path = "M 0 0 q " + p3.x + " " + p3.y + " " + d.x + " " + d.y;
        //calc scale                
        var zoom = map.getZoom();
        var scale = 1 / (Math.pow(2, -zoom));

        var icon = {
            path: path,
            scale: scale,
            strokeWeight: 3,
            strokeOpacity: 1,
        };

        pLineOpt.icons = [{
            fixedRotation: true,
            icon: icon,
            offset: '0'
        }];
        pLine.setOptions(pLineOpt);
    });
}

google.maps.event.addDomListener(window, 'load', initialize);

I have made a jsfiddle with the code: http://jsfiddle.net/s7djLzyd/3/

Does anyone know why the Polyline is cropped when zooming, and if there is a way around this?

Thanks

Upvotes: 3

Views: 9246

Answers (2)

geocodezip
geocodezip

Reputation: 161334

From this related question: Google Maps API: Bézier curve polyline wrap

var curvedLine = new GmapsCubicBezier(
      49.165876, -123.152446, 
      33.811192,-115.032444, 
      30.820807,-123.749998, 
      25.786328, -80.193694, 
      0.01, map);

example fiddle

screenshot of resulting map

code snippet:

var map;
var origLoc = new google.maps.LatLng(45, -85);

function initialize() {
  var mapOptions = {
    center: new google.maps.LatLng(33.811192, -115.032444),
    zoom: 3
  };
  map = new google.maps.Map(document.getElementById("map"), mapOptions);

  var coord1 = new google.maps.LatLng(49.165876, -123.152446);
  var coord2 = new google.maps.LatLng(25.786328, -80.193694);
  var marker1 = new google.maps.Marker({
    position: coord1,
    title: "marker 1",
    map: map
  });
  var marker2 = new google.maps.Marker({
    position: coord2,
    title: "marker 2",
    map: map
  });


  var curvedLine = new GmapsCubicBezier(
    49.165876, -123.152446,
    33.811192, -115.032444,
    30.820807, -123.749998,
    25.786328, -80.193694,
    0.01, map);
}
google.maps.event.addDomListener(window, 'load', initialize);

var GmapsCubicBezier = function(lat1, long1, lat2, long2, lat3, long3, lat4, long4, resolution, map) {

  var points = [];

  for (it = 0; it <= 1; it += resolution) {
    points.push(this.getBezier({
      x: lat1,
      y: long1
    }, {
      x: lat2,
      y: long2
    }, {
      x: lat3,
      y: long3
    }, {
      x: lat4,
      y: long4
    }, it));
  }

  for (var i = 0; i < points.length - 1; i++) {
    var Line = new google.maps.Polyline({
      path: [new google.maps.LatLng(points[i].x, points[i].y), new google.maps.LatLng(points[i + 1].x, points[i + 1].y, false)],
      geodesic: true,
      strokeOpacity: 1,
      strokeColor: 'black',
      /* icons: [{
          icon: {
              path: 'M 0,-2 0,2',
              strokeColor: 'violet',
              strokeOpacity: 1,
              strokeWeight: 4
          },
          repeat: '36px'
      }, {
          icon: {
              path: 'M -1,-2 -1,2',
              strokeColor: 'black',
              strokeOpacity: 1,
              strokeWeight: 2
          },
          repeat: '36px'
      }] */
    });
    Line.setMap(map);
  }
  // connect end of line to first point
  var Line = new google.maps.Polyline({
      path: [new google.maps.LatLng(lat1,long1),new google.maps.LatLng(points[points.length-1].x, points[points.length-1].y)],
      geodesic: true,
      strokeOpacity: 1,
      strokeColor: 'black',
      /* icons: [{
          icon: {
              path: 'M 0,-2 0,2',
              strokeColor: 'violet',
              strokeOpacity: 1,
              strokeWeight: 4
          },
          repeat: '36px'
      }, {
          icon: {
              path: 'M -1,-2 -1,2',
              strokeColor: 'black',
              strokeOpacity: 1,
              strokeWeight: 2
          },
          repeat: '36px'
      }] */
    });
    Line.setMap(map);
  
  return Line;
};


GmapsCubicBezier.prototype = {

  B1: function(t) {
    return t * t * t;
  },
  B2: function(t) {
    return 3 * t * t * (1 - t);
  },
  B3: function(t) {
    return 3 * t * (1 - t) * (1 - t);
  },
  B4: function(t) {
    return (1 - t) * (1 - t) * (1 - t);
  },
  getBezier: function(C1, C2, C3, C4, percent) {
    var pos = {};
    pos.x = C1.x * this.B1(percent) + C2.x * this.B2(percent) + C3.x * this.B3(percent) + C4.x * this.B4(percent);
    pos.y = C1.y * this.B1(percent) + C2.y * this.B2(percent) + C3.y * this.B3(percent) + C4.y * this.B4(percent);
    return pos;
  }
};
html,
body,
#map {
  height: 100%;
  margin: 0px;
  padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=geometry"></script>
<div id="map" style="float:left;width:100%;height:100%;"></div>

Upvotes: 2

Eko Junaidi Salam
Eko Junaidi Salam

Reputation: 1681

You need to fix your Polyline Options :

pLineOpt = {
    path: [coord1, coord2],
    geodesic: true,
    strokeColor: '#000',
    strokeOpacity: 1.0,
    strokeWeight: 4
}

Please try this code snippet : May be this is what you want... :)

function initialize() {
    var mapOptions = {
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };

    var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

    var coord1 = new google.maps.LatLng(49.165876, -123.152446);
    var coord2 = new google.maps.LatLng(25.786328, -80.193694);
    var bounds = new google.maps.LatLngBounds();
    bounds.extend(coord1);
    bounds.extend(coord2);
    map.fitBounds(bounds);

    pLineOpt = {
        path: [coord1, coord2],
        geodesic: true,
        strokeColor: '#000',
        strokeOpacity: 1.0,
        strokeWeight: 4
    }

    pLine = new google.maps.Polyline(pLineOpt);

    var markers = [
    new google.maps.Marker({
        position: coord1,
        map: map
    }),
    new google.maps.Marker({
        position: coord2,
        map: map
    })];

    pLine.setMap(map);

    google.maps.event.addListener(map, 'zoom_changed', function () {

    });
}

google.maps.event.addDomListener(window, 'load', initialize);
html, body, #map-canvas {
    height: 100%;
    width: 100%;
    margin: 0px;
    padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry,places&ext=.js"></script>

<div id="map-canvas"></div>

Upvotes: 2

Related Questions