質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Leaflet

Leafletは、Web上で地図を作成するためのJavaScriptライブラリ。人気のあるJavaScript地図ライブラリのうちの一つでオープンソースです。軽量でインタラクティブな地図を手軽に表示することができます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

2916閲覧

Leaflet クリックしたマーカーの情報を表示したい

okiron9619

総合スコア5

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Leaflet

Leafletは、Web上で地図を作成するためのJavaScriptライブラリ。人気のあるJavaScript地図ライブラリのうちの一つでオープンソースです。軽量でインタラクティブな地図を手軽に表示することができます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/10/10 05:41

編集2020/10/10 06:31

前提・実現したいこと

Leafetを用いて、円を描画し、円をクリックした時に、各円の情報をアラートとして表示させたいです。

geojson形式の中に緯度経度や今回表示させたい情報(id)が格納されています。
pythonにてgeojsonデータを作成し、ajax通信を用い、javascript内にて扱っています。
■■な機能を実装中に以下のエラーメッセージが発生しました。

発生している問題・エラーメッセージ

クリックイベントの中にどのようにコードを書けばよいかわからない状況です。

function clickEvt(e){ alert('この部分が該当します'); }

該当のソースコード

connection.js(ajax通信部分)

1if (typeof C === 'undefined'){ 2 var C = {}; 3} 4/** 5 * 全ノードを取得する. 6 */ 7C.getAllNodeList = function() { 8 $.ajax({ 9 url: 'get_all_node_list/', 10 method: 'GET', 11 data: { 12 }, 13 timeout: 10000, 14 dataType: "json", 15 }).done(function(response) { 16 var nodeListGeojson = response; 17 V.showNodesLayer(nodeListGeojson); 18 }).fail(function(response) { 19 alert('Error!'); 20 }); 21}

canvas.js(マーカー描画部分)

1if (typeof V === 'undefined'){ 2 var V = {}; 3} 4 $('#index_page').ready(function() { 5 C.getAllNodeList(); 6 }); 7 if (typeof V === 'undefined'){ 8 var V = {}; 9 } 10 var map = L.map('map').setView([35.016689, 135.674900], 16); 11 12 var tileLayer = new L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{ 13 attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>', 14 maxZoom: 19 15 }); 16 tileLayer.addTo(map); 17 V.showNodesLayer = function(geojson) {//←'geojson'がpythonから受け取ったデータです。 18 var hidingMarker = function(feature, latlng) { 19 if(feature.properties.hide == 'true'){ 20 return new L.CircleMarker(latlng, { 21 radius: 30, 22 color: "#00ff00", 23 fillColor: '#00ff00', 24 fillOpacity: 0.2, 25 }) 26 } 27 }; 28 L.geoJson(geojson, {pointToLayer: hidingMarker},).addTo(map).on( 'click', function(e) { clickEvt(e); }); 29 function onEachFeature(feature, layer) { 30 if (feature.properties && feature.properties.popupContent) { 31 layer.bindPopup(feature.properties.popupContent); 32 } 33 } 34 L.geoJson(geojson, { 35 onEachFeature: onEachFeature 36 }).addTo(map); 37 function clickEvt(e){ 38 alert(); 39 } 40 41 }

views_models.py(geojsonデータの作成部分)の一部

1from math import cos, sqrt 2import numpy as np 3class NodeLatlngMapper: 4 """ノードマッパー""" 5 def as_dict(self, node1, node2): 6 return { 7 "type": "FeatureCollection", 8 "features": [ 9 { 10 "type": "Feature", 11 "properties": { 12 'node': { 13 'node_id': node1.node_id, 14 }, 15 'hide': 'true', 16 'popupContent': 'これは'+ str(node1.node_id) + '番目です。', 17 }, 18 "geometry": { 19 "type": "Point", 20 "coordinates": [node1.latlng.x,node1.latlng.y], 21 }, 22 }, 23 ]}

views.py

1from django.shortcuts import render, get_object_or_404 2from django.views.generic import View 3from .models import Mareas_Nodes_Latlng 4from .models import Mareas_Links_Nodes 5from .view_models import NodeLatlngMapper 6from .view_models import LinkNode 7from django.utils.decorators import method_decorator 8from django.http.response import HttpResponse 9import json 10class GetAllNodeListView(View): 11 ##@method_decorator(login_required()) 12 def get(self, request, *args, **kwargs): 13 # オブジェクトの取得 14 node_list = Mareas_Nodes_Latlng.objects.all().order_by('node_id') 15 # レスポンスの生成 16 features = [] 17 #features = [NodeLatlngMapper(node).as_dict() for node in node_list] 18 for node1, node2 in zip(node_list, node_list[1:]): 19 features.append(NodeLatlngMapper().as_dict(node1, node2)) 20 response = { 21 'features': features, 22 } 23 # レスポンス 24 response_json = json.dumps(response) 25 return HttpResponse(response_json, content_type='application/json') 26get_all_node_list = GetAllNodeListView.as_view()
from django.urls import path from . import views app_name = 'rsl_road' urlpatterns = [ path('', views.index, name='index'), path('get_all_node_list/', views.get_all_node_list, name='get_all_node_list'), ]

htmlコード(冗長部分があるかもしれません)

1index.html 2{% extends "base.html" %} 3{% load static %} 4{% block extra_css %}{% endblock %} 5{% block content %} 6{% endblock %} 7 8{% block extra_js %} 9{% endblock %} 10 11base.html 12<!doctype html> 13{% load static %} 14<html lang="ja"> 15<head> 16 <meta charset="utf-8"> 17 <title>{{ page_title }}</title> 18 {# --- css --- #} 19 <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" /> 20 <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script> 21 <script src="http://code.jquery.com/jquery-latest.js"></script> 22 <link rel="stylesheet" href="{% static 'rsl_road/css/main.css' %}"> 23 {% block extra_css %}{% endblock %} 24</head> 25<body> 26 <div class="container"> 27 <div id="map"></div> 28 </div> 29 {% block content %}{% endblock %} 30 <script type="text/javascript" src="{% static 'rsl_road/js/canvas.js' %}"></script> 31 <script type="text/javascript" src="{% static 'rsl_road/js/connection.js' %}"></script> 32</body> 33</html>

試したこと

以下のコードを打つことで、クリックではありませんが、idの表示をすることはできました。
console.log(geojson.features[0].features[0].properties.node.node_id);

補足情報(FW/ツールのバージョンなど)

leaflet1.7.1を使用しています。(このversionではないといけない理由は特にありません)
python3.8,
LinuxMint,にて実行しています
必要な情報が抜けている可能性があります。教えていただけましたら幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sfdust

2020/10/10 05:52 編集

+ pythonのバージョンや実行しているOSの情報を書いてください。 + pythonコードにおいて、NodeLatlngMappeクラスだけが示されており、 肝心のインスタンス生成部分のコードが記載されていません。 また、一部のjavascrypt部分だけ記載されており、肝心の、pythonからgeojsonを受け取る部分等やその外のhtmlコードが抹消されているように思えます。 どこに改善点やバグがあるかもわかりませんので、可能な限り、すべてのコードを記載してください。
okiron9619

2020/10/10 06:29

返答ありがとうございます。 記述していただいた必要事項を質問文に記載いたしました。 不足部分があるかもしれません、申し訳ありません。
sfdust

2020/10/10 12:06 編集

回答を修正しました。
guest

回答1

0

ベストアンサー

下記のコードは以下の点を修正点として反映しています。

  • グローバル配列circlesに、各地点データcircleを格納。
  • L.geoJson()関数の実行時、onEachFeature引数は使用せず、pointToLayer引数を指定するだけでクリックイベントの登録とpopupContentの紐づけまで完了させています。
  • L.CircleMarker -> L.circleMarker が正しいです。
(略) var circles = [] //circleを格納するためのグローバル配列 V.showNodesLayer = function (geojson) { var hidingMarker = function (feature, latlng) { if (feature.properties.hide == 'true') { // 地点データの作成とクリックイベントの登録 circle = L.circleMarker( latlng, { radius: 30, color: "#00ff00", fillColor: '#00ff00', fillOpacity: 0.2, } ).bindPopup(feature.properties.popupContent) .addTo(map) .on( 'click', function(e) { clickEvt(e); }); // 作成した地点をグローバル配列に格納する。 circles.push(circle) return circle } } // 地点データを紐付ける L.geoJson(geojson, {pointToLayer: hidingMarker}) function clickEvt(e) { // カスタマイズしたpropertyは、e.target.feature.properties経由でアクセスできます。 p = e.target.feature.properties // geometry.coordinateは、e.latlng経由でアクセスできます。 alert('node_id:' + p.node.node_id + '\n緯度:' + e.latlng.lat + '\n経度:' + e.latlng.lng); } }

参考:
https://leafletjs.com/reference-1.7.1.html#geojson
https://leafletjs.com/examples/geojson/

投稿2020/10/10 07:54

編集2020/10/10 15:30
sfdust

総合スコア1135

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

okiron9619

2020/10/10 15:13

返信遅くなりすみません。回答、誤字の指摘、参考URLの添付、ありがとうございます。 2点質問があります。 地点を格納するための配列を用意し、戻り値としてその配列を指定した点(回答して頂いた1つ目の+) L.geojsonメソッドではなく、geoJson()関数の処理の段階でクリックイベントを紐づけした点(回答して頂いた2つ目の+) 勉強不足で申し訳ありませんが、教えていただけましたら幸いです。
sfdust

2020/10/11 03:34 編集

1つ目 >点を格納するための配列用意し、戻り値としてその配列を指定した点: コードをよく見ていただきたいのですが、hidingMarker()関数内で戻り値に指定しているのは、ローカル変数circleであって、グローバル変数配列circles[]ではありません。 circleをグローバル変数配列であるcirclesに格納することによって、関数を抜けてもローカル変数circleが保持されるようにしています。 2つめ > L.geojsonメソッドではなく、geoJson()関数の処理の段階でクリックイベントを紐づけした点 コメントを書き直しましたが、正しくは、「 L.geojsonメソッドで、pointToLayerを指定してhidingMarkerを紐づける処理をする段階で、一気にマウスイベントの登録とpopupContentの紐づけを行っている」ということになります。 このようにした理由は、元コードのように L.geoJson(geojson, {pointToLayer: hidingMarker}) の後ろに function onEachFeature(feature, layer) { if (feature.properties && feature.properties.popupContent) { layer.bindPopup(feature.properties.popupContent); } } L.geoJson(geojson, { onEachFeature: onEachFeature }).addTo(map); も書いてしまうと、サークルと、マーカーが同時に表示されてしまうからです。 この場合、サークルをクリックしたときだけでなく、マーカーをクリックしたときにも、ポップアップラベルがそれぞれ異なる位置に表示されます。 (もちろん同時に表示されてもよいというのであれば、残しても構いませんが) L.geoJson()関数は、少々わかりにくいものとなっています。 かみ砕いて書くと L.geoJson(GEOJSON, {pointToLayer: FUNCTION}) と書くことによって + GEOJSONに含まれている各地点データが、L(Leafletオブジェクト=アプリの親玉)に順次取り込まれる。 + その取り込みの際、pointToLayer引数に指定された関数FUNCTIONに、GEOJSON内の各地点データが渡される + Leafletオブジェクトは、FUNCTION関数内で戻り値に指定されたオブジェクトを、表示用レイヤーデータとして取り込む(マーカーやサークル、ポリゴンなど) という仕組みになっているようです。 公式チュートリアルでは、onEachFeaturey引数を使ってポップアップを追加する例が記載されていましたが、私自身は、onEachFeature引数を使ってマーカーではなく「サークル」に対してポップアップとマウスイベント登録を個別に紐づけるやり方を見つけることができませんでした。 なので苦肉の策?としてpointToLayer引数を使っています。
okiron9619

2020/10/11 06:11

丁寧な説明ありがとうございます。 1つ目に関してです。 オブジェクト指向言語であるため、以前の私のコードではなく、ローカル変数として扱えるようにしておいたほうが良い。 2つ目に関してです。 以前のコードでは、仰っているようにポップアップラベルが異なる位置に同時に表示されていました。(理想としては、sfdust様に回答して頂いたようなものを考えていました。) 2つ目の後半部分に関しては、勉強不足が故に理解にもうすこし時間かかると思います。すみません。 pointToLayerを使用し、異なる位置に同時にポップアップラベルが表示されないようにする(1つにする?) というように現在では解釈しています。 認識間違いがあれば申し訳ありません。 重ね重ねになりますが、丁寧な説明をしていただきありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問