0

I follow the post Change map opacity outside circle of Google Maps JavaScript API v3, but I have multi circles and sometimes they are intersecting. In the intersecting, they are not transparent. How I can set them transparent?

Map have multi circles

Code On jsfiddle.net

Thank you.

// This example uses the Google Maps JavaScript API's Data layer
// to create a rectangular polygon with 2 holes in it.
const places = [
  {
    center: { "lat": 1.3512492664554796, "lng": 103.85072488875811 },
    radius: 2000
  },
  {
    center: { "lat": 1.3225896205754812, "lng": 103.86600275130694 },
    radius: 2000
  },
  {
    center:{ "lat": 1.3136655910729036, "lng": 103.88866205306475 },
    radius: 2000
  },
  {
    center: { "lat": 1.305427997082587, "lng": 103.83613367171709 },
    radius: 2000
  }
];

let map;

const mapDefault = {
    
};

function initMap() {
    map = new google.maps.Map(document.getElementById('map'), mapDefault);
  const bounds = new google.maps.LatLngBounds();
  
  let pathsCircle = [];
  
  places.forEach(place => {
    bounds.extend(place.center);
    pathsCircle.push(drawCircle(place.center, place.radius, 1));
  });

  map.fitBounds(bounds);
  
  const worldCoords = [
    new google.maps.LatLng(-85.1054596961173, -180),
    new google.maps.LatLng(85.1054596961173, -180),
    new google.maps.LatLng(85.1054596961173, 180),
    new google.maps.LatLng(-85.1054596961173, 180),
    new google.maps.LatLng(-85.1054596961173, 0)
  ];
  
  new google.maps.Polygon({
    paths: [worldCoords, ...pathsCircle],
    strokeColor: '#fff',
    strokeOpacity: 0,
    strokeWeight: 0,
    fillColor: '#000',
    fillOpacity: 0.3,
    map,
  });
}

function drawCircle(point, radius, dir) {
}

That is my code.

Dzung Nguyen
  • 67
  • 1
  • 9

1 Answers1

2

To avoid the non-transparent intersections, the circles need to be combined into a single polygon.

One option would be to use the JSTS library to compute the union of the circles.

var geometryFactory = new jsts.geom.GeometryFactory();

var poly1,poly2,polyunion;
var polys = [];
for (var i=0; i<pathsCircle.length; i++) {
   if (i==0) {
     poly1 = geometryFactory.createPolygon(geometryFactory.createLinearRing(array2JSTS(pathsCircle[i])));
     poly1.normalize();
     polys[i] = poly1;

   } else {
     poly2 = geometryFactory.createPolygon(geometryFactory.createLinearRing(array2JSTS(pathsCircle[i])));
     poly2.normalize();
     polys[i] = polys[i-1].union(poly2);
     polys[i].normalize();
   }
}

  polys[i-1].normalize();
  var boundary = polys[i-1].getBoundary();
  var outputPath = jsts2googleMaps(boundary);

var jsts2googleMaps = function (geometry) {
  var coordArray = geometry.getCoordinates();
  GMcoords = [];
  for (var i = 0; i < coordArray.length; i++) {
    GMcoords.push(new google.maps.LatLng(coordArray[i].x, coordArray[i].y));
  }
  return GMcoords;
}
var array2JSTS = function(boundaries) {
  var coordinates = [];
  for (var i = 0; i < boundaries.length; i++) {
    coordinates.push(new jsts.geom.Coordinate(
        boundaries[i].lat, boundaries[i].lng));
  }
  return coordinates;
};

proof of concept fiddle

screenshot of resulting map

code snippet:

const places = [
  {
    center: { "lat": 1.3512492664554796, "lng": 103.85072488875811 },
    radius: 2000
  },
  {
    center: { "lat": 1.3225896205754812, "lng": 103.86600275130694 },
    radius: 2000
  },
  {
    center:{ "lat": 1.3136655910729036, "lng": 103.88866205306475 },
    radius: 2000
  },
  {
    center: { "lat": 1.305427997082587, "lng": 103.83613367171709 },
    radius: 2000
  }
];

let map;

const mapDefault = {
    center: places[0].center,
    zoom: 10,
    minZoom: 1,
    maxZoom: 19,
    clickableIcons: false
};

function initMap() {
    map = new google.maps.Map(document.getElementById('map'), mapDefault);
  const bounds = new google.maps.LatLngBounds();
  
  let pathsCircle = [];
  
  places.forEach(place => {
    bounds.extend(place.center);
    pathsCircle.push(drawCircle(place.center, place.radius, 1));
  });

  map.fitBounds(bounds);
  
  const worldCoords = [
    new google.maps.LatLng(-85.1054596961173, -180),
    new google.maps.LatLng(85.1054596961173, -180),
    new google.maps.LatLng(85.1054596961173, 180),
    new google.maps.LatLng(-85.1054596961173, 180),
    new google.maps.LatLng(-85.1054596961173, 0)
  ];
var geometryFactory = new jsts.geom.GeometryFactory();

var poly1,poly2,polyunion;
var polys = [];
for (var i=0; i<pathsCircle.length; i++) {
   if (i==0) {
     poly1 = geometryFactory.createPolygon(geometryFactory.createLinearRing(array2JSTS(pathsCircle[i])));
     poly1.normalize();
     polys[i] = poly1;

   } else {
     poly2 = geometryFactory.createPolygon(geometryFactory.createLinearRing(array2JSTS(pathsCircle[i])));
     poly2.normalize();
     polys[i] = polys[i-1].union(poly2);
     polys[i].normalize();
   }
}

  polys[i-1].normalize();
  var boundary = polys[i-1].getBoundary();
  var outputPath = jsts2googleMaps(boundary);

new google.maps.Polygon({
    paths: [worldCoords, outputPath],
    strokeColor: '#fff',
    strokeOpacity: 0,
    strokeWeight: 0,
    fillColor: '#000',
    fillOpacity: 0.3,
    map,
  });
}

function drawCircle(point, radius, dir) {
  let d2r = Math.PI / 180;   // degrees to radians 
  let r2d = 180 / Math.PI;   // radians to degrees 
  let earthsradius = 6378137; // 6378137 is the radius of the earth in metters
  let points = 128; // number of point to draw Circle

  // find the raidus in lat/lon 
  let rlat = (radius / earthsradius) * r2d;
  let rlng = rlat / Math.cos(point.lat * d2r);

  let extp = [];

  let start, end;
  if (dir == 1) {  // one extra here makes sure we connect the
    start = 0; end = points + 1
  } else {
    start = points + 1; end = 0
  }
  for (let i = start; (dir == 1 ? i < end : i > end); i = i + dir) {
    let theta = Math.PI * (i / (points / 2));
    const ey = point.lng + (rlng * Math.cos(theta)); // center a + radius x * cos(theta) 
    const ex = point.lat + (rlat * Math.sin(theta)); // center b + radius y * sin(theta) 
    extp.push({
      lat: ex,
      lng: ey,
    });
  }
  return extp;
}
var jsts2googleMaps = function (geometry) {
  var coordArray = geometry.getCoordinates();
  GMcoords = [];
  for (var i = 0; i < coordArray.length; i++) {
    GMcoords.push(new google.maps.LatLng(coordArray[i].x, coordArray[i].y));
  }
  return GMcoords;
}
var array2JSTS = function(boundaries) {
  var coordinates = [];
  for (var i = 0; i < boundaries.length; i++) {
    coordinates.push(new jsts.geom.Coordinate(
        boundaries[i].lat, boundaries[i].lng));
  }
  return coordinates;
};
/* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
#map {
  height: 100%;
}

/* Optional: Makes the sample page fill the window. */
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}
<!DOCTYPE html>
<html>
  <head>
    <title>Data Layer: Polygon</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
    <script src="https://cdn.jsdelivr.net/npm/jsts@2.8.1/dist/jsts.js"></script>
    <!-- jsFiddle will insert css and js -->
  </head>
  <body>
    <div id="map"></div>

    <!-- Async script executes immediately and must be after any DOM elements used in callback. -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&v=weekly&channel=2"
      async
    ></script>
  </body>
</html> 
geocodezip
  • 158,664
  • 13
  • 220
  • 245
  • Thanks for your answer. I got some issues if we set strokeColor and exists one or more circles are not intersecting. I have resolved it as the link [link](https://jsfiddle.net/z0h4etad/) . After all, thank you so much. – Dzung Nguyen Mar 17 '22 at 08:49