fromLatLngToDivPixel не дает одинаковые координаты в другом масштабе viewBox - PullRequest
0 голосов
/ 12 октября 2018

У меня есть SVG с определенными и постоянными границами, используемыми в классе OverlayView на картах Google. И моя цель - нарисовать соответствующие границы регионов при нажатии на местоположение на карте, если выбранное местоположение находится внутри этой границы.Вместо того, чтобы использовать путь пути Google по умолчанию для рисования полигонов, я решил использовать SVG-элементы пути.И чтобы избежать использования нескольких элементов SVG, я хотел использовать несколько элементов пути (полигоны для областей) в одном SVG.Для этого, учитывая, что пользователь будет изменять уровень масштабирования, чтобы адаптировать любой уровень масштабирования, я применил атрибут viewBox для масштабирования по отношению к уровню масштабирования карты.Поэтому основная идея заключается в том, что при изменении уровня масштабирования карты все элементы контура внутри одного тега SVG также выравниваются соответственно по мере необходимости.Несмотря на то, что все работает нормально, при нажатии на разные уровни масштабирования существуют небольшие расхождения между одними и теми же границами.Я не могу решить, что не так.

Мой код такой, как показано ниже:

Я очень благодарен, если кто-нибудь поможет мне указать, где я делаю ошибку в этом коде.

Спасибо.

ПРИМЕЧАНИЕ: чтобы понять проблему и увидеть проблему в действии, вы можете проверить мой сайт.Поскольку не все земельные участки еще определены, где-то в середине экрана, где находится здание и где в середине находится Гренландия, вы можете щелкнуть и увидеть проблему, щелкнув тот же регион после некоторого панорамирования и масштабирования, и вы увидитеувидеть границы не перекрываются.Но прежде всего, сначала вы должны нажать на строку меню «Get Info» внизу, которая устанавливает режим для выбора региона на карте.WEB: https://www.mikkins.com/landplot/11.php

<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<div class="menu">
    <div class="title">MENU</div>
    <div class="wrapper"><div class="button">Get Info</div></div>
    <ul class="nav">
      <li><a href="#">Home</a></li>
      <li><a href="#">About</a></li>
      <li><a href="#">Work</a></li>
      <li><a href="#">Resources</a></li>
      <li><a href="#">Contact</a></li>
    </ul>
</div>
<div class="intro" id="GMAP"></div>
<svg id="svg1"  xmlns="http://www.w3.org/2000/svg">
</svg>
<script>
    var overlay;
    var polygonReturn=new Array();
    var polygonBounds=new Array();
    var _svgOW;

 function initGMap()
          {                                  
            var mapOptions={ center: {lat:40.88227, lng:29.251796} ,
                                        zoom: 16     ,
                                        mapTypeId:'satellite',
                                        disableDefaultUI: false,
                                        draggableCursor: 'auto',
                                        scrollwheel: false 
                                          };  
            $GMAP=new 
  google.maps.Map(document.getElementById('GMAP'),mapOptions);
            overlay=prepareOverlay($GMAP);



 document.querySelector('.button').addEventListener('click', 
 function(e) 
   {
                    //toggle between pressed and not pressed states 
 for button     
                    e.target.classList.toggle('pressed');
                    if(e.target.className.split(' 
 ').indexOf('pressed')>-1)
                    {
                        $GMAP.setOptions({draggableCursor: 
  'crosshair'});

 google.maps.event.addListener($GMAP,'click',function(evt){
                            //if button is pressed then we are in 
polygon info request mode
                            fetch("/findpolygon.php? 
lat="+evt.latLng.lat()+"&lng="+evt.latLng.lng())
                                    .then(function(response){ return 
response.text();}).
                                    then(function(strarr){

interimSlice=strarr.split('%');

polygonReturn=interimSlice[0].split(',');
                                        console.log(polygonReturn);

polygonInfo=JSON.parse(interimSlice[1]).features[0].properties;
                                        var pixelPath="";
                                        var point=new Array();


polygonReturn.forEach((polygon)=>{
                                            point=polygon.split(' ');

u=_svgOW.projection.fromLatLngToDivPixel(new 

google.maps.LatLng({lat:parseFloat(point[1]), 
lng:parseFloat(point[0])})                              
        u.x=(u.x-parseFloat(_svgOW.svg.style.left)) / 
            (1<<$GMAP.getZoom());
        u.y=(u.y-parseFloat(_svgOW.svg.style.top)) / 
            (1<<$GMAP.getZoom());

        pixelPath+=`${u.x} ${u.y}L`;                                                
            });
        pixelPath="M"+pixelPath;
        pixelPath=pixelPath.slice(0,-2);
        //Definition of new path element
 var svgPath =     
 document.createElementNS('http://www.w3.org/2000/svg', 'path');

 svgPath.setAttribute('id','path3');

 svgPath.setAttribute('fill','none');

 svgPath.setAttribute('stroke','yellow');
 svgPath.setAttribute('stroke-width','0.000008');
 svgPath.setAttribute('d',pixelPath);                                        
 overlay.addNewElement('#svg1',svgPath);
})                                  
 .catch(error=>console.error('Error: ',error));        
                            });

                    } else {
                        $GMAP.setOptions({draggableCursor: 'auto'});

 google.maps.event.clearListeners($GMAP,'click');
                        }

          });
      }


 function prepareOverlay(map){   

 class SVGOverlay extends google.maps.OverlayView {


    constructor(bounds, svg, map) {
        super();

        this.bounds = bounds;
        this.svg = svg;

        super.setMap(map);
    }

    onAdd() {
        const svg = this.svg;
        svg.style.position = 'absolute';

        //Add the SVG element to a map pane/layer that is able to 
 receive mouse events:
        const panes = super.getPanes();
        panes.overlayMouseTarget.appendChild(svg);
        const projection = super.getProjection(),
              bounds = this.bounds,
              sw = 
 projection.fromLatLngToDivPixel(bounds.getSouthWest()),
              ne = 
 projection.fromLatLngToDivPixel(bounds.getNorthEast());

        //Place the SVG element;
        var vbox=sw.x+" "+ne.y+" "+(ne.x - sw.x)+" "+(sw.y - ne.y);
        this.svg.setAttribute("viewBox",vbox);

    }

    /**
        Whenever we need to (re)draw the overlay on the map, including 
 when first added.
    */
    draw() {

        //Here, we need to find the correct on-screen position for our 
 image.
        //To achieve that, we simply ask the map's projection to 
 calculate viewport pixels from the image's lat/lng bounds:
              const projection = super.getProjection(),
              bounds = this.bounds,
              sw = 
projection.fromLatLngToDivPixel(bounds.getSouthWest()),
              ne = 
projection.fromLatLngToDivPixel(bounds.getNorthEast());

              var scale = 1 << (map.getZoom());

        //Place/resize the SVG element:
        const s = this.svg.style;
        s.left = sw.x + 'px';
        s.top  = ne.y + 'px';
        s.width  = (ne.x - sw.x) + 'px';
        s.height = (sw.y - ne.y) + 'px';

         var vbox="0 0 "+(ne.x - sw.x)/scale+" "+(sw.y - ne.y)/scale;
        this.svg.setAttribute("viewBox",vbox);


        }

    } 



   function addEvent(target, type, handler) {
    const targets = (typeof target === 'string') ? 
  Array.from(document.querySelectorAll(target))
                                                 : [target];
    targets.forEach(t => google.maps.event.addDomListener(t, type, 
 handler));
}

 function initOverlay() {
    //Say which area we want the image to occupy:
    const svgBounds = new google.maps.LatLngBounds(
        new google.maps.LatLng(35, 25),
        new google.maps.LatLng(44, 46),
    );
    _svgOW=new SVGOverlay(svgBounds, mySVG, map);

    addEvent('path', 'click', e => {
        console.log('Clicked!');
        e.currentTarget.style.fill = '#' + Math.floor(Math.random() * 
  0xfffff);
        e.stopPropagation();
    });
    addEvent('path', 'dblclick', e => {
        //Avoid zooming here:
        e.stopPropagation();
    });
   }

 addEvent(window, 'load', initOverlay);
 var TILE_SIZE=256;
 return {
    addNewElement: function (toWhere,element)
    {
        document.querySelector(toWhere).append(element)
    },

    }
 }        

 </script>
 <script async defer src="https://maps.googleapis.com/maps/api/js? 
 key=MY_APIKEY&callback=initGMap&language=&signed_in=false">
 </script>            
 </body>

</html>
...