web-dev-qa-db-ja.com

Leaflet.drawでマーカーの選択を取得するにはどうすればよいですか?

コンテキスト:

マップを作成し、約300個のランダムマーカーを配置しました。ポップアップ内のリンクをクリックしてマーカーを「選択」し、データを表示するための選択をアクティブにすることができます。円、長方形、カスタムシェイプなどのシェイプを描画するための、Leaflet.drawプラグインもあります。これを使用して、いくつかのマーカーを「選択」したいと思います。

問題

描画されたleaflet.drawシェイプ内にあるマーカーのリーフレットマーカーオブジェクトを取得して、編集できるようにするにはどうすればよいですか?選択できないようです。マーカーがまったく選択されていないか、すべて選択されています。

不要なコードから削除されたコードスニペット:

const drawControl = new L.Control.Draw({
    draw: {
        marker   : false,
        polygon  : true,
        polyline : false,
        rectangle: true,
        circle   : {
            metric: 'metric'
        }
    },
    edit: false
});

const map = L.map('map', {
    layers: [streets, light]
}).setView([CONFIG.MAP.LATITUDE, CONFIG.MAP.LONGITUDE], CONFIG.MAP.ZOOMLEVEL)

map.addControl(drawControl);

map.on(L.Draw.Event.DRAWSTOP, e => {

    const hello = e.target;

    console.log(hello);
    e.target.eachLayer(layer => {
        if (layer.options.icon) {
            console.log(layer);
        }
    });

});
9
roberrrt-s

必要なことのほとんどは、Leafletのユーティリティメソッドを使用して非常に簡単に実行できます。 L.Polygonのような複雑な形状でこれを実行する場合は、 TurfJS のようなものが必要になります。

L.Circleの場合、円の中心間の距離を計算し、それを半径と比較する必要があります。

var marker = new L.Marker(...),
    circle = new L.Circle(...);

var contains = circle.getLatLng().distanceTo(marker.getLatLng()) < circle.getRadius();

L.Rectangleの場合、その境界オブジェクトをフェッチし、containsメソッドを使用する必要があります。

var marker = new L.Marker(...),
    rectangle = new L.Rectangle(...);

var contains = rectangle.getBounds().contains(marker.getLatLng());

複雑なポリゴンについて述べたように、私はTurfを使用しますが、そこにはもっと多くのライブラリとプラグインがあります。 Turfのinsideメソッドを使用した例を次に示します。 GeoJSONポイントとポリゴンフィーチャをパラメータとして使用するため、変換に注意してください。

var marker = new L.Marker(...),
    polygon = new L.Polygon(...);

var contains = turf.inside(marker.toGeoJSON(), polygon.toGeoJSON());

それらをそれぞれのクラスの便利なメソッドにラップすることができます。

L.Polygon.include({
    contains: function (latLng) {
        return turf.inside(new L.Marker(latLng).toGeoJSON(), this.toGeoJSON());
    } 
});

L.Rectangle.include({
    contains: function (latLng) {
        return this.getBounds().contains(latLng);
    }
});

L.Circle.include({
    contains: function (latLng) {
        return this.getLatLng().distanceTo(latLng) < this.getRadius();
    }
});

var marker = new L.Marker(...),
    polygon = new L.Polygon(...),
    rectangle = new L.Rectangle(...),
    circle = new L.Circle(...);

polygon.contains(marker.getLatLng());
rectangle.contains(marker.getLatLng());
circle.contains(marker.getLatLng());

ポリゴンメソッドを実装する場合、長方形メソッドは必要ないことに注意してください。長方形はポリゴンから拡張されているため、メソッドを継承します。完成させるためにそこに残しました。

これで、マーカーを繰り返して比較するのは簡単です。

map.on(L.Draw.Event.CREATED, function (e) {
    markers.eachLayer(function (marker) {
        if (!e.layer.contains(marker.getLatLng())) {
            marker.remove();
        }
    });
});

お役に立てば幸いです。これが実用的なスニペットです。

var map = new L.Map('leaflet', {
    'center': [0, 0],
    'zoom': 0
});

var markers = new L.LayerGroup().addTo(map);

for (var i = 0; i < 300; i++) {
    var marker = new L.Marker([
        (Math.random() * (90 - -90) + -90).toFixed(5) * 1,
        (Math.random() * (180 - -180) + -180).toFixed(5) * 1
    ]).addTo(markers);
}

new L.Control.Draw({
    draw: {
        marker   : false,
        polygon  : true,
        polyline : false,
        rectangle: true,
        circle   : {
            metric: 'metric'
        }
    },
    edit: false
}).addTo(map);

L.Polygon.include({
    contains: function (latLng) {
        return turf.inside(new L.Marker(latLng).toGeoJSON(), this.toGeoJSON());
    } 
});

L.Rectangle.include({
    contains: function (latLng) {
        return this.getBounds().contains(latLng);
    }
});

L.Circle.include({
    contains: function (latLng) {
        return this.getLatLng().distanceTo(latLng) < this.getRadius();
    }
});

map.on(L.Draw.Event.CREATED, function (e) {
    markers.eachLayer(function (marker) {
        if (!e.layer.contains(marker.getLatLng())) {
            marker.remove();
        }
    });
});
body {
    margin: 0;
}

html, body, #leaflet {
    height: 100%;
}
<!DOCTYPE html>
<html>
  <head>
    <title>Leaflet 1.0.3</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link type="text/css" rel="stylesheet" href="//unpkg.com/[email protected]/dist/leaflet.css" />
    <link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.css" />
  </head>
  <body>
    <div id="leaflet"></div>
    <script type="application/javascript" src="//unpkg.com/[email protected]/dist/leaflet.js"></script>
    <script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.js"></script>
    <script type="application/javascript" src="//unpkg.com/@turf/turf@latest/turf.min.js"></script>
  </body>
</html>
13
iH8

クールな例をありがとう@ iH8。繰り返しを避けるためにさらに進んだ

_markers.eachLayer(function (marker) {
    ...
}
_

代わりにマーカーの配列を使用して、追加のメソッドでラッパーを拡張しました。


最初に、LayerGroupにすべてのマーカーを含むキー値を持つオブジェクトがあることに気づきました。私は単にそのオブジェクトを使用してマーカーの配列を作成します:

_// In the on draw event
...
// Set an array containing all the markers
var markers = jsonToArray(layerGroup._layers); 
...

function jsonToArray(jsonObject) {
  var result = [];
  var keys = Object.keys(jsonObject);
  keys.forEach(function (key) {
    result.Push(jsonObject[key]);
  });
  return result;
}
_

次に、変更されたcontains()メソッドでラッパーを再利用します。

_  L.Rectangle.include({
    // Single marker case
    contains: function (marker) {
      return this.getBounds().contains(marker.getLatLng());
    },
    // Array of markers
    contains: function (markers) {
      var markersContained = [];
      markers.forEach(marker => {
        markersContained.Push(this.getBounds().contains(marker.getLatLng()));
      })
      return markersContained;
    }
  });

  L.Circle.include({
    contains: function (marker) {
      return this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius();
    },
    contains: function (markers) {
      var markersContained = [];
      markers.forEach(marker => {
        markersContained.Push(this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius());
      })
      return markersContained;
    }
  });
_

そして最後に、描画イベントで、マーカーが中に含まれているかどうかを確認します。

_  map.on(L.Draw.Event.CREATED, function (geometry) {
    // Set an array containing all the markers
    var markers = jsonToArray(layerGroup._layers);

    var result = geometry.layer.contains(markers);
    console.log('result => ', result);
  });
_
_function jsonToArray(jsonObject) {
  var result = [];
  var keys = Object.keys(jsonObject);
  keys.forEach(function (key) {
    result.Push(jsonObject[key]);
  });
  return result;
}

var map = new L.Map('leaflet', {
    'center': [0, 0],
    'zoom': 0
});

var layerGroup = new L.LayerGroup().addTo(map);

for (var i = 0; i < 10; i++) {
    var marker = new L.Marker([
        (Math.random() * (90 - -90) + -90).toFixed(5) * 1,
        (Math.random() * (180 - -180) + -180).toFixed(5) * 1
    ]).addTo(layerGroup);
}

new L.Control.Draw({
    draw: {
        marker   : false,
        polygon  : false,
        polyline : false,
        rectangle: true,
        circle   : {
            metric: 'metric'
        }
    },
    edit: false
}).addTo(map);

// Define contains() method for each geometry
L.Rectangle.include({
  contains: function (marker) {
    return this.getBounds().contains(marker.getLatLng());
  },
  contains: function (markers) {
    var markersContained = [];
    markers.forEach(marker => {
      markersContained.Push(this.getBounds().contains(marker.getLatLng()));
    })
    return markersContained;
  }
});

L.Circle.include({
  contains: function (marker) {
    return this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius();
  },
  contains: function (markers) {
    var markersContained = [];
    markers.forEach(marker => {
      markersContained.Push(this.getLatLng().distanceTo(marker.getLatLng()) < this.getRadius());
    })
    return markersContained;
  }
});

map.on(L.Draw.Event.CREATED, function (geometry) {
  // Set an array containing all the markers
  var markers = jsonToArray(layerGroup._layers);

  var result = geometry.layer.contains(markers);
  console.log('result => ', result);
});_
_body {
    margin: 0;
}

html, body, #leaflet {
    height: 100%;
}_
_<!DOCTYPE html>
<html>
  <head>
    <title>Leaflet 1.0.3</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link type="text/css" rel="stylesheet" href="//unpkg.com/[email protected]/dist/leaflet.css" />
    <link type="text/css" rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.css" />
  </head>
  <body>
    <div id="leaflet"></div>
    <script type="application/javascript" src="//unpkg.com/[email protected]/dist/leaflet.js"></script>
    <script type="application/javascript" src="//cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw.js"></script>
  </body>
</html>_
2
Alex Beugnet

私はそれを使用しました:

L.Circle.include({
    contains: function (latLng) {
        return this.getLatLng().distanceTo(latLng) < this.getRadius();
    }
});

エッジ上にあるが円内にはないポイントも判断されます。

0
Husir