Widget:Custom map

提供:メタファー リファンタジオ 攻略Wiki
2024年11月5日 (火) 23:17時点におけるヘイグ運営用アカウント (トーク | 投稿記録)による版
移動先:案内検索


<script type="text/javascript"> let map; var drawnItems; var drawControl; var editMode = false; window.savePopupContent = savePopupContent;

// 表示する画像 var imageBase = {

 url: ,
 width: ,          // 画像のサイズ
 height: 

};

// 地図初期化 var imageBounds = L.latLngBounds(

 [0, 0],
 [imageBase.height, imageBase.width],
 

);

map = L.map('map', {

 crs: L.CRS.Simple,
 maxBounds: imageBounds.pad(0.5),
 minZoom: , // minZoomを0に設定
 maxZoom: ,

}); map.fitBounds(imageBounds); L.imageOverlay(imageBase.url, imageBounds,{

 attribution: '<a href="https://h1g.jp/" target="_blank">【ヘイグ】</a>'

}).addTo(map);

var drawnItems = new L.FeatureGroup(); map.addLayer(drawnItems);


// Leaflet.Draw var drawnItems = new L.FeatureGroup(); map.addLayer(drawnItems);

drawControl = new L.Control.Draw({

   edit: {
       featureGroup: drawnItems,
       poly: {
           allowIntersection: false
       }
   },
   draw: {
       polygon: false,
       polyline: false,
       rectangle: false,
       circle: true,
       marker: true,
       circlemarker: false
   }

}); map.addControl(drawControl);

// 初期状態では編集モードを無効にする drawControl.remove();

map.on(L.Draw.Event.CREATED, function (event) {

   var layer = event.layer;
   if (layer instanceof L.Marker) {
       layer.setIcon(iconDefinitions.icon1);
       layer.options.popupData = {title: , content: , iconType: 'icon1'};
       var popupContent = 

'

' +
           '<textarea id="popup-title" cols="30" rows="1" placeholder="タイトル"></textarea>' +
           '<textarea id="popup-content" cols="30" rows="2" placeholder="内容"></textarea>' +
           '<select id="icon-type">' +
           '<option value="icon1" selected>アイコン1</option>' +
           '<option value="icon2">アイコン2</option>' +
           '<option value="icon3">アイコン3</option>' +
           '<option value="icon4">アイコン4</option>' +
           '<option value="icon5">アイコン5</option>' +
           '<option value="icon6">アイコン6</option>' +
           '</select>' +
           '<button onclick="savePopupContent(this)">保存</button>' +
'

';

       layer.bindPopup(popupContent);
   } else {
       layer.bindPopup('No description');
   }
   createEditablePopup(layer);
   drawnItems.addLayer(layer);
   if (layer instanceof L.Marker) {
       layer.openPopup();
   }

});

//////////////////権限を確認 function checkUserGroup(group, callback) {

   $.ajax({
       url: mw.util.wikiScript('api'),
       data: {
           action: 'query',
           meta: 'userinfo',
           uiprop: 'groups',
           format: 'json'
       },
       type: 'GET',
       success: function(data) {
           var userGroups = data.query.userinfo.groups;
           var isInGroup = userGroups.indexOf(group) !== -1;
           callback(isInGroup);
       },
       error: function() {
           console.error('Failed to check user group');
           callback(false);
       }
   });

} ////////////////////////////////////////////////////////////// // アイコンの定義 var iconDefinitions = {

   icon1: L.icon({
     iconUrl: ,
     shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
     iconSize: [25, 41],
     iconAnchor: [12, 41],
     popupAnchor: [1, -41],
     shadowSize: [41, 41]
   }),
   icon2: L.icon({
     iconUrl: ,
     shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
     iconSize: [25, 41],
     iconAnchor: [12, 41],
     popupAnchor: [1, -41],
     shadowSize: [41, 41]
   }),
   icon3: L.icon({
     iconUrl: ,
     shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
     iconSize: [25, 41],
     iconAnchor: [12, 41],
     popupAnchor: [1, -41],
     shadowSize: [41, 41]
   }),
   icon4: L.icon({
     iconUrl: ,
     shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
     iconSize: [25, 41],
     iconAnchor: [12, 41],
     popupAnchor: [1, -41],
     shadowSize: [41, 41]
   }),
   icon5: L.icon({
     iconUrl: ,
     shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
     iconSize: [25, 41],
     iconAnchor: [12, 41],
     popupAnchor: [1, -41],
     shadowSize: [41, 41]
   }),
   icon6: L.icon({
     iconUrl: ,
     shadowUrl: 'https://dq.h1g.jp/img/marker-icon-img/marker-shadow.png',
     iconSize: [25, 41],
     iconAnchor: [12, 41],
     popupAnchor: [1, -41],
     shadowSize: [41, 41]
   })

};


// ポップアップの作成 function createEditablePopup(layer) {

   var popupData = layer.options.popupData || {};
   var title = popupData.title || ;
   var content = popupData.content || ;
   var iconType = popupData.iconType || 'icon1';
   layer.on('popupopen', function() {
       var popup = this.getPopup();
       var popupData = this.options.popupData || {};
       var title = popupData.title || ;
       var content = popupData.content || ;
       var iconType = popupData.iconType || 'icon1';


       // タイトルと内容が両方空の場合、ポップアップを表示しない
       if (!editMode && title ===  && content === ) {
           layer.closePopup();
           // カーソルをデフォルトに設定
           layer._icon.style.cursor = 'default';
           return;
       }
       if (editMode) {  // 編集モードの場合のみtextareaを表示
           var iconSelector = ;
           if (layer instanceof L.Marker) {
               iconSelector = '<select id="icon-type">' +
                   '<option value="icon1"' + (iconType === 'icon1' ? ' selected' : ) + '>アイコン1</option>' +
                   '<option value="icon2"' + (iconType === 'icon2' ? ' selected' : ) + '>アイコン2</option>' +
                   '<option value="icon3"' + (iconType === 'icon3' ? ' selected' : ) + '>アイコン3</option>' +
                   '<option value="icon4"' + (iconType === 'icon4' ? ' selected' : ) + '>アイコン4</option>' +
                   '<option value="icon5"' + (iconType === 'icon5' ? ' selected' : ) + '>アイコン5</option>' +
                   '<option value="icon6"' + (iconType === 'icon6' ? ' selected' : ) + '>アイコン6</option>' +
               '</select>';
           }
           var editableContent = 

'

' +
               '<textarea id="popup-title" cols="60" rows="3" placeholder="タイトル">' + title + '</textarea>' +
               '<textarea id="popup-content" cols="60" rows="10" placeholder="内容">' + content + '</textarea>' +
               iconSelector +
               '<button onclick="savePopupContent(this)">保存</button>' +
'

';

           popup.setContent(editableContent);
       } else {
           // 編集モードでない場合は表示用のコンテンツを設定
           if (title ===  && content === ) {
               layer.unbindPopup(); // タイトルと内容が空の場合はポップアップを表示しない
           } else {
               var displayContent = '' + title + '
' + content; var renderedContent = renderMediaWikiContent(displayContent); popup.setContent(renderedContent); } } });
   // 既にポップアップが設定されている場合に備え、再設定
   if (!(title ===  && content === )) {
       var displayContent = '' + title + '
' + content; var renderedContent = renderMediaWikiContent(displayContent); layer.bindPopup(renderedContent); }

}



// MediaWikiコンテンツのレンダリング function renderMediaWikiContent(content) {

   var renderedContent = ;
   $.ajax({
       url: mw.util.wikiScript('api'),
       data: {
           action: 'parse',
           text: content,
           format: 'json'
       },
       async: false,
       success: function(data) {
           renderedContent = data.parse.text['*'];
       },
       error: function() {
           console.error('Failed to render MediaWiki content');
       }
   });
   return renderedContent;

}


// ポップアップの内容を保存 function savePopupContent(button) {

   var popup = button.closest('.leaflet-popup');
   var content = popup.querySelector('.leaflet-popup-content');
   var title = content.querySelector('#popup-title').value;
   var text = content.querySelector('#popup-content').value;
   var iconType = content.querySelector('#icon-type') ? content.querySelector('#icon-type').value : null;
   
   var layer = drawnItems.getLayers().find(function(layer) {
       return layer.getPopup() && layer.getPopup().getElement() === popup;
   });
   
   if (layer) {
       var savedContent = '' + title + '
' + text; layer.setPopupContent(savedContent); layer.options.popupData = {title: title, content: text, iconType: iconType}; if (layer instanceof L.Marker && iconType) { var icon = iconDefinitions[iconType] || iconDefinitions.icon1; layer.setIcon(icon); } layer.closePopup(); layer.openPopup(); } else { console.error('Layer not found'); }

}


// 編集イベントのリスナーも追加 map.on(L.Draw.Event.EDITED, function (event) {

   var layers = event.layers;
   layers.eachLayer(function (layer) {
       drawnItems.addLayer(layer);
   });

});

// 削除イベントのリスナーも追加 map.on(L.Draw.Event.DELETED, function (event) {

   var layers = event.layers;
   layers.eachLayer(function (layer) {
       drawnItems.removeLayer(layer);
   });

});

// 編集ボタン var editButton = L.easyButton({

   states: [{
       stateName: 'enable-edit',
       icon: '<img src="https://dq.h1g.jp/img/marker-icon-img/edit-solid.svg">',
       title: 'マップを編集する',
       onClick: function(btn, map) {

// checkUserGroup('map-edit-member', function(isInGroup) {

           checkUserGroup('sysop', function(isInGroup) {
               if (isInGroup) {
                   editMode = true;
                   map.addControl(drawControl);
                   btn.state('disable-edit');
                   updateAllPopups();
                   saveButton.addTo(map); // saveButtonを表示する
               } else {
                   alert('あなたには編集権限がありません。\n攻略に参加することでマップが編集できるようになります。');
               }
           });
       }
   }, {
       stateName: 'disable-edit',
       icon: '<img src="https://dq.h1g.jp/img/marker-icon-img/edit-solid.svg">',
       title: '編集の終了',
       onClick: function(btn, map) {
           editMode = false;
           drawControl.remove();
           btn.state('enable-edit');
           updateAllPopups();
           saveButton.remove(); // saveButtonを非表示にする
       }
   }]

}).addTo(map);

function updateAllPopups() {

   drawnItems.eachLayer(function(layer) {
       if (layer.getPopup()) {
           layer.closePopup();
           if (editMode) {
               createEditablePopup(layer);
               layer.openPopup();
           } else if (!(layer.options.popupData && layer.options.popupData.title ===  && layer.options.popupData.content === )) {
               layer.bindPopup(layer.options.popupData.title + "
" + layer.options.popupData.content); } } });

}

// 保存ボタン var saveButton = L.easyButton('<img src="https://dq.h1g.jp/img/marker-icon-img/save-solid.svg">', function() {

   if (editMode) {
       var geoJSONData = convertToGeoJSON(drawnItems);
       if (geoJSONData) {

// console.log(geoJSONData);

           saveToWikiPage(geoJSONData);
           saveButton.remove(); // saveButtonを非表示にする
       } else {
           alert('Error: Invalid GeoJSON data');
       }
   } else {
       alert('Please enable edit mode before saving.');
   }

}, '変更を保存');



function loadPinsFromWikiPage() {

   var host = window.location.origin;
   var geojsonPage = "";
   var url = host + "/zelda_eow/index.php/" + geojsonPage;
   $.ajax({
       type: "GET",
       url: url,
       dataType: "html",
       success: function(htmlContent) {
           try {

// console.log("HTML Content: ", htmlContent); // 取得したHTMLをコンソールに出力

               var parser = new DOMParser();
               var doc = parser.parseFromString(htmlContent, "text/html");
               var scriptTag = doc.querySelector('#mw-content-text script');
               if (!scriptTag) {
                   throw new Error("Script tag not found");
               }
               var scriptContent = scriptTag.textContent.trim();
               var jsonDataMatch = scriptContent.match(/var GeoJson =(\{[\s\S]*\});/);
               if (!jsonDataMatch || jsonDataMatch.length < 2) {
                   throw new Error("GeoJSON data not found in script tag");
               }
               var geoJSONData = jsonDataMatch[1];
               if (!geoJSONData) {
                   throw new Error("GeoJSON data is empty");
               }
               var parsedData = JSON.parse(geoJSONData);
               processGeoJSONData(parsedData);
           } catch (error) {
               console.error("Error processing data:", error);

// console.log("Raw HTML content:", htmlContent); // console.log("Extracted script content:", scriptContent);

               if (typeof geoJSONData !== 'undefined') {

// console.log("Extracted GeoJSON data:", geoJSONData);

               }
           }
       },
       error: function(xhr, status, error) {

// console.error("Error loading data:", error); // console.log("XHR status:", status); // console.log("XHR response:", xhr.responseText);

       }
   });

}


function processGeoJSONData(geoJSON) {

   drawnItems.clearLayers();
   L.geoJSON(geoJSON, {
       pointToLayer: function (feature, latlng) {
           var iconType = feature.properties.iconType || 'icon1';
           var icon = iconDefinitions[iconType] || iconDefinitions.icon1;
           
           if (feature.properties.radius) {
               return L.circle(latlng, {
                   radius: feature.properties.radius,
                   tags: feature.properties.tags
               });
           } else {
               return L.marker(latlng, {
                   icon: icon,
                   tags: feature.properties.tags
               });
           }
       },
       onEachFeature: function (feature, layer) {
           var popupContent = '' + feature.properties.title + '
' + feature.properties.content; layer.bindPopup(popupContent); layer.options.popupData = { title: feature.properties.title, content: feature.properties.content, iconType: feature.properties.iconType, tags: feature.properties.tags }; createEditablePopup(layer);
           drawnItems.addLayer(layer);
       }
   });

}



////////////////////////////////////////////////////////////////////////////// function convertToGeoJSON(drawnItems) {

   var geoJSON = {
       "type": "FeatureCollection",
       "features": []
   };
   drawnItems.eachLayer(function(layer) {
       var feature = layer.toGeoJSON();
       var popupData = layer.options.popupData || {};
       feature.properties = {
           title: popupData.title || ,
           content: popupData.content || ,
           iconType: popupData.iconType || 'icon1',
           tags: popupData.tags || [getTagFromIconType(popupData.iconType || 'icon1')]
       };
       if (layer instanceof L.Circle) {
           feature.properties.radius = layer.getRadius();
           feature.geometry = {
               type: "Point",
               coordinates: [layer.getLatLng().lng, layer.getLatLng().lat]
           };
       } else if (layer instanceof L.Marker) {
           feature.geometry = {
               type: "Point",
               coordinates: [layer.getLatLng().lng, layer.getLatLng().lat]
           };
       } else {
           // その他のタイプのレイヤーは無視する
           return;
       }
       geoJSON.features.push(feature);
   });
   // GeoJSONデータの有効性をチェック
   try {
       JSON.parse(JSON.stringify(geoJSON));
   } catch (error) {
       console.error("Invalid GeoJSON data:", error);
       return null;
   }
   return JSON.stringify(geoJSON, null, 2); // 整形されたJSONを返す

}


function getTagFromIconType(iconType) {

   switch (iconType) {
       case 'icon1':
           return ;
       case 'icon2':
           return ;
       case 'icon3':
           return ;
       case 'icon4':
           return ;
       case 'icon5':
           return ;
       case 'icon6':
           return ;
       default:
           return ;
   }

}

 // フィルタボタンの定義

// Leaflet.Control.TagFilterButton の設定 L.control.tagFilterButton({

   data: [
       ,
       ,
       ,
       ,
       ,
       
   ],
   icon: '<img src="filter.png">',
   filterOnEveryClick: true

}).addTo(map);


function saveToWikiPage(geoJSONData) {

   var formattedData = geoJSONData;
   $.ajax({
       type: "POST",
       url: 'https://prd-h1g-elb-2067013247.ap-northeast-1.elb.amazonaws.com/api.php',
       data: {
           action: 'edit',
           title: ,
           text: formattedData,
           token: mw.user.tokens.get('csrfToken'),
           format: 'json'
       },
       success: function(response) {

// console.log("Save response:", response);

           if (response.edit && response.edit.result === 'Success') {
               alert('データは正常に保存されました');
               editMode = false;
               drawControl.remove();
               editButton.state('enable-edit');
               saveButton.remove(); // saveButtonを非表示にする
               
               setTimeout(function() {
                   loadPinsFromWikiPage();
               }, 1000);
           } else {
               alert('Error saving data: ' + JSON.stringify(response));
           }
       },
       error: function(xhr, status, error) {
           console.error("Save error:", error);

// console.log("XHR status:", status); // console.log("XHR response:", xhr.responseText);

           alert('Error saving data: ' + error);
       }
   });

} map.on(L.Draw.Event.CREATED, function (event) {

   var layer = event.layer;
   if (layer instanceof L.Marker) {
       layer.setIcon(iconDefinitions.icon1);
       layer.options.popupData = {title: , content: , iconType: 'icon1'};
   }
   createEditablePopup(layer);
   drawnItems.addLayer(layer);

});


//////////////////////////////////////////////////// // ページ読み込み時にデータを読み込む $(document).ready(function() {

   setTimeout(function() {
       map.invalidateSize();
       loadPinsFromWikiPage();
   }, 500);  // 少し長めの遅延を設定

}); </script>

</includeonly>