Как я могу создать ионный поповер из многоугольника leafletjs? - PullRequest
0 голосов
/ 25 июня 2018

Я использую Leaflet JS для рисования полигонов на карте.

Я могу рисовать фигуры и сохранять фигуры в базе данных в формате GeoJSON следующим образом:

.ts file

...
    let layer = event.layer;
    let geometry = layer.toGeoJSON();
    this.drawLayer.addLayer(layer);
}

Я вызываю метод в методе ngOnInit для перерисовки фигур:

drawPolygonShape(data) {
    if (data.polygon.geometry) {
        let shape = {
            type: data.polygon.type,
            geometry: {
                type: data.polygon.geometry.type,
                coordinates: data.polygon.geometry.coordinates
            },
            properties: {}
        };

        L.geoJSON(shape, {
            onEachFeature: this.onEachFeature
        }).addTo(this.myMap);
    }
}


...


onEachFeature(feature, layer) {
    layer.on('click', event => {
        // layer.bindPopup('Hello World'); // Works great
        let popover = this.popoverCtrl.create('MyComponent', { layer: layer });
        popover.present();
    });
}

Я импортирую MyComponent в файл модуля, поэтому я знаю, что он доступен. Тем не менее, я всегда получаю следующее сообщение об ошибке:

Невозможно прочитать свойство 'create' из неопределенного

Итак, где-то есть проблема с синхронизацией или областью действия, которая некорректно работает с событием click.

Кажется, это проблема области видимости, поскольку любой компонент выдает ту же ошибку. Любые предложения с благодарностью!

EDIT

Спасибо @ghybs. Я пытался добавить this в качестве третьего аргумента к событию click, но я все еще получаю ту же ошибку:

    onEachFeature(feature, layer) {
    layer.on('click', event => {
        // layer.bindPopup('Hello World'); // Works great
        let popover = this.popoverCtrl.create('MyComponent', { layer: layer });
        popover.present();
    }, this);
}

РЕДАКТИРОВАТЬ 2

Спасибо, @ghybs!

Мне интересно ваше второе предложение - я настраиваю карту следующим образом:

let mapOptions: any = {
    position: 'topright',
    draw: {
        polyline: false,
        ...
    }
}

...

let drawControl = new L.Control.Draw(mapOptions);
this.myMap.addControl(drawControl);

this.myMap.on(L.Draw.Event.CREATED, this.onCreatePolygon.bind(this));

Теперь .bind(this) имеет больше смысла - onCreatePolygon - это метод, который я использую для сохранения формы.

Как вы предлагаете мне делегировать событие click для каждой фигуры?

this.myMap.on(L.Draw.Event.CLICK, this.MYCLICKHANDLER.bind(this));

(очевидно, я не знаком с этим, поэтому я ценю все ваше время.)

1 Ответ

0 голосов
/ 26 июня 2018

В вашем случае у вас есть проблема контекста double , так как вы также передаете свой метод onEachFeature, который будет вызываться с контекстом this, который уже отличается от вашего экземпляра класса.

Вы можете сделать onEachFeature: this.onEachFeature.bind(this) вместе со своим layer.on("click", cb, this)

Вы также можете использовать делегирование событий, подключив прослушиватель к вашей группе слоев GeoJSON вместо каждой отдельной функции, чтобы избавиться от одного из контекстов:

var geoJsonData = {
  "type": "Point",
  "coordinates": [2.35, 48.86]
};

class Component {
  constructor(mapId) {
    this.myMap = L.map(mapId).setView([48.86, 2.35], 11);

    L.geoJSON(geoJsonData).addTo(this.myMap).on("click", event => {
      console.log(event.target); // this is the GeoJSON Layer Group.
      console.log(event.layer); // this is the individual child feature.
      let popover = this.popoverCtrl.create('MyComponent');
      popover.present();
    }, this); // Not even needing the 3rd arg since you use a fat arrow function, which does not have its own context.

    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(this.myMap);
  }
}

Component.prototype.popoverCtrl = { // Dummy popoverCtrl
  create(content) {
    dummyPopoverContent = content;
    return {
      present() {
        alert(dummyPopoverContent);
      },
    };
  },
};

var dummyPopoverContent = '';

new Component('map');
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>

<div id="map" style="height: 180px"></div>

См. Также запуск функции при нажатии на кружок - листовка


Что касается вашего последнего вопроса, с 1-м замечанием выше вы можете переписать:

this.myMap.on(L.Draw.Event.CREATED, this.onCreatePolygon.bind(this));

в

this.myMap.on(L.Draw.Event.CREATED, this.onCreatePolygon, this);

Делегирование событий в данном случае не представляется актуальным, поскольку вы уже подключили одиночный слушатель к вашей карте, а не к отдельным слоям.

...