soiz1 commited on
Commit
c20b278
·
verified ·
1 Parent(s): 37e11aa

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +349 -210
index.html CHANGED
@@ -1149,24 +1149,56 @@
1149
  document.getElementById("add-plugin").addEventListener("click", addPlugin);
1150
  }
1151
 
1152
- // レイヤーエディタ表示
1153
- function showLayerEditor() {
1154
- document.getElementById("layer-editor").style.display = "block";
1155
- switchLayerTab('base');
1156
- updateBaseLayerForm();
1157
- updateOverlayLayerForm();
1158
- updateOtherLayerForm();
1159
- }
1160
-
1161
- // レイヤーエディタを非表示
1162
- function hideLayerEditor() {
1163
- document.getElementById("layer-editor").style.display = "none";
1164
- if (currentEditingLayer) {
1165
- map.removeLayer(currentEditingLayer);
1166
- currentEditingLayer = null;
1167
- overlayCoords = [];
1168
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1169
  }
 
 
1170
 
1171
  // レイヤータブを切り替え
1172
  function switchLayerTab(tabId) {
@@ -1202,32 +1234,69 @@
1202
  }
1203
  }
1204
 
1205
- // オーバーレイレイヤーフォーム更新
1206
- function updateOverlayLayerForm() {
1207
- const layerType = document.getElementById("overlay-layer-type").value;
1208
-
1209
- // 現在編集中のレイヤーをクリア
1210
- if (currentEditingLayer) {
1211
- map.removeLayer(currentEditingLayer);
1212
- currentEditingLayer = null;
1213
- }
1214
-
1215
- overlayCoords = [];
1216
- updateOverlayCoordsList();
1217
-
1218
- // 新しいレイヤーを作成
1219
- if (layerType === 'polyline') {
1220
- currentEditingLayer = L.polyline([], JSON.parse(document.getElementById("overlayer-options").value || '{}')).addTo(map);
1221
- } else if (layerType === 'polygon') {
1222
- currentEditingLayer = L.polygon([], JSON.parse(document.getElementById("overlayer-options").value || '{}')).addTo(map);
1223
- } else if (layerType === 'circle') {
1224
- currentEditingLayer = L.circle([0, 0], JSON.parse(document.getElementById("overlayer-options").value || '{}')).addTo(map);
1225
- } else if (layerType === 'circlemarker') {
1226
- currentEditingLayer = L.circleMarker([0, 0], JSON.parse(document.getElementById("overlayer-options").value || '{}')).addTo(map);
1227
- } else if (layerType === 'marker') {
1228
- currentEditingLayer = L.marker([0, 0], JSON.parse(document.getElementById("overlayer-options").value || '{}')).addTo(map);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1229
  }
 
 
1230
  }
 
 
1231
 
1232
  // その他レイヤーフォームを更新
1233
  function updateOtherLayerForm() {
@@ -1240,61 +1309,72 @@
1240
  }
1241
  }
1242
 
1243
- // ベースレイヤーを追加
1244
- function addBaseLayer() {
1245
- const layerType = document.getElementById("base-layer-type").value;
1246
- const layerName = prompt("レイヤー名を入力してください", "新しいレイヤー");
1247
-
1248
- if (!layerName) return;
1249
-
1250
- let layer;
1251
- let options = {};
1252
-
1253
- try {
1254
- const optionsText = document.getElementById("tile-layer-options").value;
1255
- if (optionsText) {
1256
- options = JSON.parse(optionsText);
1257
- }
1258
- } catch (e) {
1259
- alert("オプションのJSONが不正です");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1260
  return;
1261
  }
1262
-
1263
- if (layerType === 'tile') {
1264
- const url = document.getElementById("tile-layer-url").value;
1265
- const attribution = document.getElementById("tile-layer-attribution").value;
1266
-
1267
- if (!url) {
1268
- alert("タイルURLを入力してください");
1269
- return;
1270
- }
1271
-
1272
- layer = L.tileLayer(url, {
1273
- attribution: attribution,
1274
- ...options
1275
- }).addTo(map);
1276
- } else if (layerType === 'canvas') {
1277
  layer = L.canvas(options).addTo(map);
1278
  } else if (layerType === 'svg') {
1279
  layer = L.svg(options).addTo(map);
1280
  } else if (layerType === 'grid') {
1281
  layer = L.gridLayer(options).addTo(map);
1282
  }
1283
-
1284
- if (layer) {
1285
- layers.push({
1286
- id: 'layer-' + Date.now(),
1287
- name: layerName,
1288
- type: layerType,
1289
- layer: layer,
1290
- options: options
1291
- });
1292
-
1293
- saveCurrentMapToStorage();
1294
- updateLayerTree();
1295
- hideLayerEditor();
1296
- }
1297
- }
 
1298
 
1299
  // オーバーレイレイヤーを追加
1300
  function addOverlayLayer() {
@@ -1476,143 +1556,202 @@
1476
  }
1477
 
1478
  // レイヤーツリーを更新
1479
- function updateLayerTree() {
1480
- const layerTreeContent = document.getElementById("layer-tree-content");
1481
- layerTreeContent.innerHTML = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1482
 
1483
- // ベースレイヤー
1484
- const baseLayers = layers.filter(l =>
1485
- l.type === 'tile' || l.type === 'canvas' || l.type === 'svg' || l.type === 'grid'
1486
- );
 
 
1487
 
1488
- if (baseLayers.length > 0) {
1489
- const baseHeader = document.createElement('div');
1490
- baseHeader.className = 'layer-tree-item';
1491
- baseHeader.textContent = 'ベースレイヤー';
1492
- baseHeader.addEventListener('click', function() {
1493
- this.classList.toggle('expanded');
1494
- document.getElementById('base-layers-group').classList.toggle('expanded');
1495
- });
1496
- layerTreeContent.appendChild(baseHeader);
1497
-
1498
- const baseGroup = document.createElement('div');
1499
- baseGroup.id = 'base-layers-group';
1500
- baseGroup.className = 'layer-tree-item-group';
1501
-
1502
- baseLayers.forEach(layer => {
1503
- const layerItem = document.createElement('div');
1504
- layerItem.className = 'layer-tree-item';
1505
- layerItem.textContent = layer.name;
1506
- layerItem.addEventListener('click', function(e) {
1507
- e.stopPropagation();
1508
- // レイヤーを選択状態にする
1509
- document.querySelectorAll('.layer-tree-item').forEach(item => {
1510
- item.classList.remove('selected');
1511
- });
1512
- this.classList.add('selected');
1513
- // レイヤーを中央に表示
1514
- if (layer.layer.getBounds) {
1515
- map.fitBounds(layer.layer.getBounds());
1516
- } else if (layer.layer.getLatLng) {
1517
- map.setView(layer.layer.getLatLng(), map.getZoom());
1518
- }
1519
- });
1520
- baseGroup.appendChild(layerItem);
1521
- });
1522
-
1523
- layerTreeContent.appendChild(baseGroup);
1524
- }
1525
 
1526
- // オーバーレイレイヤー
1527
- const overlayLayers = layers.filter(l =>
1528
- l.type === 'marker' || l.type === 'polyline' || l.type === 'polygon' ||
1529
- l.type === 'circle' || l.type === 'circlemarker' || l.type === 'geojson' ||
1530
- l.type === 'image' || l.type === 'video'
1531
- );
1532
 
1533
- if (overlayLayers.length > 0) {
1534
- const overlayHeader = document.createElement('div');
1535
- overlayHeader.className = 'layer-tree-item';
1536
- overlayHeader.textContent = 'オーバーレイレイヤー';
1537
- overlayHeader.addEventListener('click', function() {
1538
- this.classList.toggle('expanded');
1539
- document.getElementById('overlay-layers-group').classList.toggle('expanded');
1540
- });
1541
- layerTreeContent.appendChild(overlayHeader);
1542
 
1543
- const overlayGroup = document.createElement('div');
1544
- overlayGroup.id = 'overlay-layers-group';
1545
- overlayGroup.className = 'layer-tree-item-group';
 
 
1546
 
1547
- overlayLayers.forEach(layer => {
1548
- const layerItem = document.createElement('div');
1549
- layerItem.className = 'layer-tree-item';
1550
- layerItem.textContent = layer.name;
1551
- layerItem.addEventListener('click', function(e) {
1552
- e.stopPropagation();
1553
- // レイヤーを選択状態にする
1554
- document.querySelectorAll('.layer-tree-item').forEach(item => {
1555
- item.classList.remove('selected');
1556
- });
1557
- this.classList.add('selected');
1558
- // レイヤーを中央に表示
1559
- if (layer.layer.getBounds) {
1560
- map.fitBounds(layer.layer.getBounds());
1561
- } else if (layer.layer.getLatLng) {
1562
- map.setView(layer.layer.getLatLng(), map.getZoom());
1563
- }
1564
- });
1565
- overlayGroup.appendChild(layerItem);
1566
  });
1567
 
1568
- layerTreeContent.appendChild(overlayGroup);
1569
- }
1570
-
1571
- // その他レイヤー
1572
- const otherLayers = layers.filter(l =>
1573
- l.type === 'layergroup' || l.type === 'featuregroup' || l.type === 'control' ||
1574
- l.type === 'heatmap' || l.type === 'cluster' || l.type === 'vectorgrid' ||
1575
- l.type === 'custom'
1576
- );
1577
-
1578
- if (otherLayers.length > 0) {
1579
- const otherHeader = document.createElement('div');
1580
- otherHeader.className = 'layer-tree-item';
1581
- otherHeader.textContent = 'その他レイヤー';
1582
- otherHeader.addEventListener('click', function() {
1583
- this.classList.toggle('expanded');
1584
- document.getElementById('other-layers-group').classList.toggle('expanded');
1585
  });
1586
- layerTreeContent.appendChild(otherHeader);
1587
 
1588
- const otherGroup = document.createElement('div');
1589
- otherGroup.id = 'other-layers-group';
1590
- otherGroup.className = 'layer-tree-item-group';
1591
 
1592
- otherLayers.forEach(layer => {
1593
- const layerItem = document.createElement('div');
1594
- layerItem.className = 'layer-tree-item';
1595
- layerItem.textContent = layer.name;
1596
- layerItem.addEventListener('click', function(e) {
1597
- e.stopPropagation();
1598
- // レイヤーを選択状態にする
1599
- document.querySelectorAll('.layer-tree-item').forEach(item => {
1600
- item.classList.remove('selected');
1601
- });
1602
- this.classList.add('selected');
1603
- // レイヤーを中央に表示
1604
- if (layer.layer.getBounds) {
1605
- map.fitBounds(layer.layer.getBounds());
1606
- } else if (layer.layer.getLatLng) {
1607
- map.setView(layer.layer.getLatLng(), map.getZoom());
1608
- }
1609
  });
1610
- otherGroup.appendChild(layerItem);
 
 
 
 
 
 
 
1611
  });
1612
 
1613
- layerTreeContent.appendChild(otherGroup);
1614
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1615
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1616
 
1617
  // プラグインマネージャーを表示
1618
  function showPluginManager() {
 
1149
  document.getElementById("add-plugin").addEventListener("click", addPlugin);
1150
  }
1151
 
1152
+ // レイヤーエディタ表示関数を改善
1153
+ function showLayerEditor() {
1154
+ const editor = document.getElementById("layer-editor");
1155
+ editor.style.display = "block";
1156
+
1157
+ // 画面中央に表示
1158
+ editor.style.left = "50%";
1159
+ editor.style.top = "50%";
1160
+ editor.style.transform = "translate(-50%, -50%)";
1161
+
1162
+ // タブをリセット
1163
+ switchLayerTab('base');
1164
+ updateBaseLayerForm();
1165
+ updateOverlayLayerForm();
1166
+ updateOtherLayerForm();
1167
+
1168
+ // フォーカスを設定
1169
+ setTimeout(() => {
1170
+ const firstInput = editor.querySelector('input, select, textarea');
1171
+ if (firstInput) firstInput.focus();
1172
+ }, 100);
1173
+ }
1174
+
1175
+ // タブ切り替え関数を改善
1176
+ function switchLayerTab(tabId) {
1177
+ // タブを非アクティブ化
1178
+ document.querySelectorAll('.layer-tab').forEach(tab => {
1179
+ tab.classList.remove('active');
1180
+ });
1181
+
1182
+ // タブコンテンツを非表示
1183
+ document.querySelectorAll('.layer-tab-content').forEach(content => {
1184
+ content.classList.remove('active');
1185
+ });
1186
+
1187
+ // 選択されたタブをアクティブ化
1188
+ const tab = document.querySelector(`.layer-tab[data-tab="${tabId}"]`);
1189
+ if (tab) {
1190
+ tab.classList.add('active');
1191
+ document.getElementById(`${tabId}-tab`).classList.add('active');
1192
+
1193
+ // 現在編集中のレイヤーをクリア
1194
+ if (currentEditingLayer) {
1195
+ map.removeLayer(currentEditingLayer);
1196
+ currentEditingLayer = null;
1197
+ overlayCoords = [];
1198
+ updateOverlayCoordsList();
1199
  }
1200
+ }
1201
+ }
1202
 
1203
  // レイヤータブを切り替え
1204
  function switchLayerTab(tabId) {
 
1234
  }
1235
  }
1236
 
1237
+ // オーバーレイレイヤーフォーム更新時にプレビューを強化
1238
+ function updateOverlayLayerForm() {
1239
+ const layerType = document.getElementById("overlay-layer-type").value;
1240
+ let options = {};
1241
+
1242
+ try {
1243
+ const optionsText = document.getElementById("overlayer-options").value;
1244
+ if (optionsText) {
1245
+ options = JSON.parse(optionsText);
1246
+ }
1247
+ } catch (e) {
1248
+ console.error("Options JSON error:", e);
1249
+ }
1250
+
1251
+ // 現在編集中のレイヤーをクリア
1252
+ if (currentEditingLayer) {
1253
+ map.removeLayer(currentEditingLayer);
1254
+ currentEditingLayer = null;
1255
+ }
1256
+
1257
+ overlayCoords = [];
1258
+ updateOverlayCoordsList();
1259
+
1260
+ // オプションフォームのプレースホルダーを設定
1261
+ let placeholder = '{"color": "#ff0000", "weight": 5}';
1262
+
1263
+ // 新しいレイヤーを作成
1264
+ switch(layerType) {
1265
+ case 'polyline':
1266
+ currentEditingLayer = L.polyline([], options).addTo(map);
1267
+ break;
1268
+ case 'polygon':
1269
+ currentEditingLayer = L.polygon([], options).addTo(map);
1270
+ placeholder = '{"color": "#ff0000", "fillColor": "#ff0000", "weight": 5}';
1271
+ break;
1272
+ case 'circle':
1273
+ currentEditingLayer = L.circle([0, 0], options).addTo(map);
1274
+ placeholder = '{"radius": 500, "color": "#ff0000", "fillColor": "#ff0000"}';
1275
+ break;
1276
+ case 'circlemarker':
1277
+ currentEditingLayer = L.circleMarker([0, 0], options).addTo(map);
1278
+ placeholder = '{"radius": 10, "color": "#ff0000", "fillColor": "#ff0000"}';
1279
+ break;
1280
+ case 'marker':
1281
+ currentEditingLayer = L.marker([0, 0], options).addTo(map);
1282
+ placeholder = '{"draggable": true}';
1283
+ break;
1284
+ }
1285
+
1286
+ document.getElementById("overlayer-options").placeholder = placeholder;
1287
+
1288
+ // オプション変更時のリアルタイム更新
1289
+ document.getElementById("overlayer-options").addEventListener('input', function() {
1290
+ try {
1291
+ const newOptions = JSON.parse(this.value);
1292
+ if (currentEditingLayer && currentEditingLayer.setStyle) {
1293
+ currentEditingLayer.setStyle(newOptions);
1294
  }
1295
+ } catch (e) {
1296
+ // JSONが無効な場合は無視
1297
  }
1298
+ });
1299
+ }
1300
 
1301
  // その他レイヤーフォームを更新
1302
  function updateOtherLayerForm() {
 
1309
  }
1310
  }
1311
 
1312
+
1313
+
1314
+ // ベースレイヤー追加関数にバリデーションを追加
1315
+ function addBaseLayer() {
1316
+ const layerType = document.getElementById("base-layer-type").value;
1317
+ const layerName = prompt("レイヤー名を入力してください", "新しいレイヤー");
1318
+
1319
+ if (!layerName) return;
1320
+
1321
+ let layer;
1322
+ let options = {};
1323
+
1324
+ try {
1325
+ const optionsText = document.getElementById("tile-layer-options").value;
1326
+ if (optionsText) {
1327
+ options = JSON.parse(optionsText);
1328
+ }
1329
+ } catch (e) {
1330
+ alert("オプションのJSONが不正です:\n" + e.message);
1331
+ return;
1332
+ }
1333
+
1334
+ if (layerType === 'tile') {
1335
+ const url = document.getElementById("tile-layer-url").value;
1336
+ const attribution = document.getElementById("tile-layer-attribution").value;
1337
+
1338
+ if (!url) {
1339
+ alert("タイルURLを入力してください");
1340
+ return;
1341
+ }
1342
+
1343
+ // URLバリデーション
1344
+ if (!url.includes('{z}') || !url.includes('{x}') || !url.includes('{y}')) {
1345
+ if (!confirm("タイルURLに{z}, {x}, {y}のプレースホルダーが含まれていません。続行しますか?")) {
1346
  return;
1347
  }
1348
+ }
1349
+
1350
+ layer = L.tileLayer(url, {
1351
+ attribution: attribution,
1352
+ ...options
1353
+ }).addTo(map);
1354
+ }
1355
+ } else if (layerType === 'canvas') {
 
 
 
 
 
 
 
1356
  layer = L.canvas(options).addTo(map);
1357
  } else if (layerType === 'svg') {
1358
  layer = L.svg(options).addTo(map);
1359
  } else if (layerType === 'grid') {
1360
  layer = L.gridLayer(options).addTo(map);
1361
  }
1362
+
1363
+ if (layer) {
1364
+ layers.push({
1365
+ id: 'layer-' + Date.now(),
1366
+ name: layerName,
1367
+ type: layerType,
1368
+ layer: layer,
1369
+ options: options
1370
+ });
1371
+
1372
+ saveCurrentMapToStorage();
1373
+ updateLayerTree();
1374
+ hideLayerEditor();
1375
+ alert(`レイヤー「${layerName}」を追加しました`);
1376
+ }
1377
+ }
1378
 
1379
  // オーバーレイレイヤーを追加
1380
  function addOverlayLayer() {
 
1556
  }
1557
 
1558
  // レイヤーツリーを更新
1559
+ // レイヤーツリーの改善
1560
+ function updateLayerTree() {
1561
+ const layerTreeContent = document.getElementById("layer-tree-content");
1562
+ layerTreeContent.innerHTML = '';
1563
+
1564
+ // レイヤーをタイプ別に分類
1565
+ const layerTypes = {
1566
+ 'base': ['tile', 'canvas', 'svg', 'grid'],
1567
+ 'overlay': ['marker', 'polyline', 'polygon', 'circle', 'circlemarker', 'geojson', 'image', 'video'],
1568
+ 'other': ['layergroup', 'featuregroup', 'control', 'heatmap', 'cluster', 'vectorgrid', 'custom']
1569
+ };
1570
+
1571
+ // 各タイプごとに表示
1572
+ Object.entries(layerTypes).forEach(([typeName, typeList]) => {
1573
+ const typeLayers = layers.filter(l => typeList.includes(l.type));
1574
+
1575
+ if (typeLayers.length > 0) {
1576
+ // タイプヘッダー
1577
+ const header = document.createElement('div');
1578
+ header.className = 'layer-tree-item';
1579
+ header.innerHTML = `
1580
+ <span class="layer-tree-toggle">▸</span>
1581
+ ${typeName === 'base' ? 'ベースレイヤー' :
1582
+ typeName === 'overlay' ? 'オーバーレイレイヤー' : 'その他レイヤー'}
1583
+ <span class="layer-count">(${typeLayers.length})</span>
1584
+ `;
1585
 
1586
+ const groupId = `${typeName}-layers-group`;
1587
+ header.addEventListener('click', function() {
1588
+ this.querySelector('.layer-tree-toggle').textContent =
1589
+ this.querySelector('.layer-tree-toggle').textContent === '▸' ? '▾' : '▸';
1590
+ document.getElementById(groupId).classList.toggle('expanded');
1591
+ });
1592
 
1593
+ layerTreeContent.appendChild(header);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1594
 
1595
+ // レイヤーグループ
1596
+ const group = document.createElement('div');
1597
+ group.id = groupId;
1598
+ group.className = 'layer-tree-item-group';
 
 
1599
 
1600
+ typeLayers.forEach(layer => {
1601
+ const layerItem = document.createElement('div');
1602
+ layerItem.className = 'layer-tree-item';
 
 
 
 
 
 
1603
 
1604
+ // レイヤーアイコン
1605
+ const icon = document.createElement('span');
1606
+ icon.className = 'layer-tree-icon';
1607
+ icon.innerHTML = getLayerIcon(layer.type);
1608
+ layerItem.appendChild(icon);
1609
 
1610
+ // レイヤー名
1611
+ const nameSpan = document.createElement('span');
1612
+ nameSpan.textContent = layer.name;
1613
+ nameSpan.className = 'layer-name';
1614
+ layerItem.appendChild(nameSpan);
1615
+
1616
+ // 操作ボタン
1617
+ const btnGroup = document.createElement('div');
1618
+ btnGroup.className = 'layer-tree-buttons';
1619
+
1620
+ const editBtn = document.createElement('button');
1621
+ editBtn.className = 'layer-tree-btn edit-btn';
1622
+ editBtn.title = '編集';
1623
+ editBtn.innerHTML = '✏️';
1624
+ editBtn.addEventListener('click', (e) => {
1625
+ e.stopPropagation();
1626
+ editLayer(layer);
 
 
1627
  });
1628
 
1629
+ const deleteBtn = document.createElement('button');
1630
+ deleteBtn.className = 'layer-tree-btn delete-btn';
1631
+ deleteBtn.title = '削除';
1632
+ deleteBtn.innerHTML = '🗑️';
1633
+ deleteBtn.addEventListener('click', (e) => {
1634
+ e.stopPropagation();
1635
+ deleteLayer(layer);
 
 
 
 
 
 
 
 
 
 
1636
  });
 
1637
 
1638
+ btnGroup.appendChild(editBtn);
1639
+ btnGroup.appendChild(deleteBtn);
1640
+ layerItem.appendChild(btnGroup);
1641
 
1642
+ layerItem.addEventListener('click', function(e) {
1643
+ if (e.target.closest('.layer-tree-btn')) return;
1644
+
1645
+ // レイヤーを選択状態にする
1646
+ document.querySelectorAll('.layer-tree-item').forEach(item => {
1647
+ item.classList.remove('selected');
 
 
 
 
 
 
 
 
 
 
 
1648
  });
1649
+ this.classList.add('selected');
1650
+
1651
+ // レイヤーを中央に表示
1652
+ if (layer.layer.getBounds) {
1653
+ map.fitBounds(layer.layer.getBounds());
1654
+ } else if (layer.layer.getLatLng) {
1655
+ map.setView(layer.layer.getLatLng(), map.getZoom());
1656
+ }
1657
  });
1658
 
1659
+ group.appendChild(layerItem);
1660
+ });
1661
+
1662
+ layerTreeContent.appendChild(group);
1663
+ }
1664
+ });
1665
+
1666
+ // 初期状態で最初のグループを展開
1667
+ const firstGroup = document.querySelector('.layer-tree-item-group');
1668
+ if (firstGroup) {
1669
+ firstGroup.classList.add('expanded');
1670
+ const firstHeader = document.querySelector('.layer-tree-item');
1671
+ if (firstHeader) {
1672
+ firstHeader.querySelector('.layer-tree-toggle').textContent = '▾';
1673
+ }
1674
+ }
1675
+ }
1676
+
1677
+ // レイヤーアイコンを取得
1678
+ function getLayerIcon(type) {
1679
+ const icons = {
1680
+ 'tile': '🧩',
1681
+ 'canvas': '🎨',
1682
+ 'svg': '🖌️',
1683
+ 'grid': '🔲',
1684
+ 'marker': '📍',
1685
+ 'polyline': '➖',
1686
+ 'polygon': '🔶',
1687
+ 'circle': '⭕',
1688
+ 'circlemarker': '🔵',
1689
+ 'layergroup': '📁',
1690
+ 'featuregroup': '📂',
1691
+ 'control': '🎚️',
1692
+ 'heatmap': '🔥',
1693
+ 'cluster': '👥',
1694
+ 'vectorgrid': '🧊'
1695
+ };
1696
+ return icons[type] || '🔘';
1697
+ }
1698
+
1699
+ // レイヤー編集関数
1700
+ function editLayer(layer) {
1701
+ showLayerEditor();
1702
+
1703
+ // レイヤータイプに応じたタブを選択
1704
+ let tabId = 'other';
1705
+ if (['tile', 'canvas', 'svg', 'grid'].includes(layer.type)) {
1706
+ tabId = 'base';
1707
+ } else if (['marker', 'polyline', 'polygon', 'circle', 'circlemarker', 'geojson', 'image', 'video'].includes(layer.type)) {
1708
+ tabId = 'overlay';
1709
+ }
1710
+
1711
+ switchLayerTab(tabId);
1712
+
1713
+ // フォームに値を設定
1714
+ document.getElementById(`${tabId}-layer-type`).value = layer.type;
1715
+
1716
+ if (tabId === 'base' && layer.type === 'tile') {
1717
+ document.getElementById("tile-layer-url").value = layer.layer._url;
1718
+ document.getElementById("tile-layer-attribution").value = layer.layer.options.attribution || '';
1719
+ document.getElementById("tile-layer-options").value = JSON.stringify(
1720
+ Object.fromEntries(
1721
+ Object.entries(layer.layer.options)
1722
+ .filter(([key]) => !['attribution'].includes(key))
1723
+ ), null, 2
1724
+ );
1725
+ } else if (tabId === 'overlay') {
1726
+ document.getElementById("overlayer-options").value = JSON.stringify(layer.options, null, 2);
1727
+
1728
+ // 座標を設定
1729
+ if (['polyline', 'polygon', 'circle', 'circlemarker', 'marker'].includes(layer.type)) {
1730
+ overlayCoords = layer.layer.getLatLngs ? layer.layer.getLatLngs() :
1731
+ layer.layer.getLatLng ? [layer.layer.getLatLng()] : [];
1732
+ updateOverlayCoordsList();
1733
  }
1734
+ } else if (tabId === 'other') {
1735
+ document.getElementById("other-layer-options").value = JSON.stringify(layer.options, null, 2);
1736
+ }
1737
+
1738
+ // 既存のレイヤーを削除
1739
+ const index = layers.findIndex(l => l.id === layer.id);
1740
+ if (index !== -1) {
1741
+ layers.splice(index, 1);
1742
+ map.removeLayer(layer.layer);
1743
+ }
1744
+ }
1745
+
1746
+ // レイヤー削除関数
1747
+ function deleteLayer(layer) {
1748
+ if (confirm(`レイヤー「${layer.name}」を削除しますか?`)) {
1749
+ map.removeLayer(layer.layer);
1750
+ layers = layers.filter(l => l.id !== layer.id);
1751
+ saveCurrentMapToStorage();
1752
+ updateLayerTree();
1753
+ }
1754
+ }
1755
 
1756
  // プラグインマネージャーを表示
1757
  function showPluginManager() {