program story

Google Maps JS API ImageMapType을 다각형에 클리핑

inputbox 2020. 12. 26. 10:02
반응형

Google Maps JS API ImageMapType을 다각형에 클리핑


Google지도의 MapType을 임의의 다각형으로 자르려면 어떻게해야합니까? 예를 들어 넓은 영역 (즉, 전 세계)을 포함 하는 사용자 정의 ImageMapType 이 있지만 지정된 다각형 (즉, 한 국가) 내에서만 표시하려는 경우입니다.

ImageMapType을 주어진 다각형에 클리핑하거나이 동작을 달성하기 위해 사용자 지정 MapType을 구현하는 방법이 있습니까? 정상적으로 확대 / 축소 및 이동이 가능해야합니다.

나머지지도는 동일하게 유지되어야하며 특정 지역 만 포함하는 MapType이 있습니다. 따라서 필요한 것만 표시하기 위해 다각형 외부 영역을 덮기 위해 단순히 다각형을 오버레이하는 것은 불가능합니다.

이렇게 :

남호주에 오버레이가 잘린 호주지도

서버 측 클리핑은 옵션이 아닙니다.


원하는 작업을 수행하는 오버레이지도 유형에 대한 코드를 작성했습니다. 대상 브라우저에서 테스트해야합니다. 깡깡이

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>

작동 원리

기본적으로 ClipMapType클래스는 MapType 인터페이스입니다. getTile이 인터페이스의 메서드는 타일 좌표 및 확대 / 축소 수준으로 호출되어 모든 타일에 대한 타일을 가져옵니다. ClipMapType타일 ​​역할을 할 캔버스 요소를 만들고 다각형 내부에 잘린 타일 이미지를 그립니다. 성능이 중요한 경우 더 빠르게 작업하도록 최적화 할 수 있습니다.

부인 성명

URL을 해킹하여 Google 타일 서버를 사용하면 Google지도 서비스 약관에 위배됩니다. 데모 용으로 사용했으며 프로덕션에서는 사용하지 않는 것이 좋습니다. 내 대답은 자신 만의 솔루션을 만들 수있는 통찰력을 제공하려는 시도입니다.


Do you require Google Maps perse? I know Openlayers 3 provides better support for this kind of stuff. For example, take a look at this.

If you really must use Google Maps, I suggest implementing your own MapType and generate the tiles needed to cover your polygon area yourself using MapTiler. (MapTiler also generates an example Google Maps implementation for you, so that shouldn't be too hard.)


You could place a DIV above your map, with absolute positioning and high z-index. then, apply a polygon mask to that DIV like this: -webkit-clip-path: polygon(0 0, 0 100%, 100% 0);


You can use the canvas.toDataURI() option in HTML5 to obtain the url that is required for getTileUrl() of 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;
    }

I see that you can't use normal masking strategies because you need to be able to see the lower layer. May I suggest SVG's more complete clipping suite? See here.

The browser compatibility is good but not great, but you can absolutely accomplish what you're trying here (unless you need to pan/zoom the Map, then you're screwed until Maps implements such a thing).


You could use an svg clippath, together with the foreignobject svg tag to put a html document within the svg then clip it to the desired shape like this code taken from 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

참조 URL : https://stackoverflow.com/questions/24311350/clip-google-maps-js-api-imagemaptype-to-a-polygon

반응형