Clip Google Maps API ImageMapType vers un polygone

Comment puis-je Clipper un type de carte dans Google Maps à un polygone arbitraire. Par exemple, si j'ai une coutume ImageMapType qui couvre une grande zone (c.-à-d. tout le monde), mais je veux le montrer seulement à l'intérieur d'un polygone donné (c.-à-d. un pays).

Existe-t-il un moyen de clipper le ImageMapType sur un polygone donné, ou d'implémenter un MapType personnalisé pour obtenir ce comportement? Il devrait permettre de zoomer et de faire le ménage normalement.

le le reste de la carte devrait rester le même, et il y aurait un MapType couvrant seulement une zone spécifique. Par conséquent, il n'est pas possible de simplement superposer un polygone pour couvrir les zones en dehors du polygone pour afficher exactement ce qui est nécessaire.

Comme suit:

Australia map with a clipped overlay on South Australia

la coupure Côté Serveur n'est pas une option.

56
demandé sur Nicolas 2014-06-19 20:11:25

6 réponses

j'ai écrit le code pour un type de carte de superposition qui fait ce que vous voulez. Assurez-vous de vérifier dans vos navigateurs cibles. Violon

function ClipMapType(polygon, map) {
  this.tileSize = new google.maps.Size(256, 256);
  this.polygon = polygon;
  this.map = map;
}

ClipMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
  var map = this.map;
  var scale = Math.pow(2, zoom);
  if (coord.y < 0 || coord.y >= scale) return ownerDocument.createElement('div');
  var tileX = ((coord.x % scale) + scale) % scale;
  var tileY = coord.y;
  // Your url pattern below
  var url = "https://khms0.google.com/kh/v=694&x=" + tileX + "&y=" + tileY + "&z=" + zoom;
  var image = new Image();
  image.src = url;

  var canvas = ownerDocument.createElement('canvas');
  canvas.width = this.tileSize.width;
  canvas.height = this.tileSize.height;
  var context = canvas.getContext('2d');

  var xdif = coord.x * this.tileSize.width;
  var ydif = coord.y * this.tileSize.height;

  var ring = this.polygon.getArray()[0];
  var points = ring.getArray().map(function(x) {
    var worldPoint = map.getProjection().fromLatLngToPoint(x);
    return new google.maps.Point((worldPoint.x) * scale - xdif, (worldPoint.y) * scale - ydif);
  });

  image.onload = function() {
    context.beginPath();
    context.moveTo(points[0].x, points[0].y);
    var count = points.length;
    for (var i = 0; i < count; i++) {
      context.lineTo(points[i].x, points[i].y);
    }
    context.lineTo(points[count - 1].x, points[count - 1].y);

    context.clip();
    context.drawImage(image, 0, 0);
    context.closePath();
  };

  return canvas;
};

function initMap() {
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 4,
    center: {
      lat: 15,
      lng: 15
    }
  });
  var polygon = new google.maps.Data.Polygon([
    [{
      lat: 0,
      lng: 0
    }, {
      lat: 30,
      lng: 30
    }, {
      lat: 0,
      lng: 30
    }]
  ]);
  var mapType = new ClipMapType(polygon, map);
  map.overlayMapTypes.insertAt(0, mapType);
}
html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}
#map {
  height: 100%;
}
<div id="map"></div>
<script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap">
</script>

comment ça marche

fondamentalement ClipMapType classe est une interface MapType. getTile méthode de cette interface est appelé avec les coordonnées de la tuile et le niveau de zoom pour obtenir la tuile pour chaque tuile. ClipMapType crée un élément de toile pour agir comme une tuile et dessine l'image de tuile clippée à l'intérieur du polygone. Si la performance est importante, elle peut être optimisée pour fonctionner plus rapidement.

Avertissement

L'utilisation de serveurs Google tile par piratage de L'URL, viole probablement les conditions de service de Google Maps. Je l'ai utilisé pour la démonstration et ne recommande pas de l'utiliser dans la production. Ma réponse est une tentative pour vous donner un aperçu pour vous créer votre propre solution.

11
répondu Gökhan Kurt 2016-08-03 06:56:54

vous avez besoin de Google Maps perse? Je sais que Openlayers 3 offre un meilleur soutien pour ce genre de choses. Par exemple, jetez un oeil à ce .

si vous devez vraiment utiliser Google Maps, je vous suggère d'implémenter votre propre MapType et de générer les tuiles nécessaires pour couvrir vous-même votre zone polygonale en utilisant MapTiler . (Maptier génère aussi un exemple D'implémentation de Google Maps pour vous, donc cela ne devrait pas être trop difficile.)

2
répondu Danny Hoek 2016-02-27 02:34:08

vous pouvez placer un DIV au-dessus de votre carte, avec un positionnement absolu et un indice z élevé. ensuite, appliquez un masque de polygone à cette DIV comme ceci: -webkit-clip-path: polygon(0 0, 0 100%, 100% 0);

1
répondu Manuel Alejandro 2014-08-04 20:51:18

vous pouvez utiliser l'option canvas.toDataURI() dans HTML5 pour obtenir l'url qui est requise pour getTileUrl() de ImageMapType .

getTileUrl: function(coord, zoom) {
    var normalizedCoord = getNormalizedCoord(coord, zoom);
    if (!normalizedCoord) {
      return null;
    }
    var bound = Math.pow(2, zoom);
    // reset and clip the preloaded image in a hidden canvas to your required height and width

    clippedImage = canvas.toDataURL();
    return clippedImage;
    }
1
répondu cnvzmxcvmcx 2017-05-23 11:53:34

je vois que vous ne pouvez pas utiliser les stratégies normales de masquage parce que vous devez être capable de voir la couche inférieure. Puis-je suggérer la suite plus complète de SVG? voir ici .

la compatibilité du navigateur est bonne mais pas excellente, mais vous pouvez absolument accomplir ce que vous essayez ici (à moins que vous n'ayez besoin de parcourir/zoomer la carte, alors vous êtes vissé jusqu'à ce que Maps implémente une telle chose).

1
répondu Reed Spool 2016-02-27 02:29:00

vous pouvez utiliser un clippath svg, ainsi que la balise SVG de foreignobject pour mettre un document html dans le svg puis le clip il à la forme désirée comme CE code pris de codepen.io / yoksel / pen / oggRwR:

@import url(http://fonts.googleapis.com/css?family=Arvo:700);

.svg {
  display: block;
  width: 853px;
  height: 480px;
  margin: 2em auto;
	}

text {
  font: bold 5.3em/1 Arvo, Arial sans-serif;
	}
<svg class="svg">
    <clippath id="cp-circle">
      <circle r="180" cx="50%" cy="42%"></circle>
      <text
            text-anchor="middle"
            x="50%"
            y="98%"
            >Soldier Of Fortune</text>
    </clippath>
  
    <g clip-path="url(#cp-circle)">   
   	<foreignObject width="853" x="0"
                y="0" height="480">
      <body xmlns="http://www.w3.org/1999/xhtml">
        <iframe width="853" height="480" src="//www.youtube.com/embed/RKrNdxiBW3Y" frameborder="0" allowfullscreen></iframe>
      </body>
    </foreignObject>
   </g>	
</svg>

http://codepen.io/yoksel/pen/oggRwR

1
répondu Paul Humphreys 2016-03-29 12:48:07