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:
la coupure Côté Serveur n'est pas une option.
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.
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.)
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);
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;
}
- pour régler et redimensionner l'image pour corriger la dimension, utilisez
canvas.drawImage()
- pour clipper l'image à partir de la toile à n'importe quelle dimension non rectangulaire, utilisez le
canvas clip()
Exemple de code pour toile de détourage .
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).
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>