soiz1 commited on
Commit
8e9453b
·
verified ·
1 Parent(s): e11742b

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +438 -435
index.html CHANGED
@@ -1,16 +1,16 @@
1
-
2
  <!DOCTYPE html>
3
  <html lang="ja">
 
4
  <head>
5
- <link rel="preconnect" href="https://fonts.googleapis.com">
6
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
7
- <link href="https://fonts.googleapis.com/css2?family=Yomogi&display=swap" rel="stylesheet">
8
  <meta charset="UTF-8">
9
  <meta name="viewport" content="width=device-width, initial-scale=1">
10
  <title>マーカー編集機能付きのLeafletマップ</title>
11
- <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" />
12
  <style>
13
- body{
14
  font-family: "Yomogi", cursive;
15
  font-weight: 400;
16
  font-style: normal;
@@ -55,11 +55,13 @@ body::-webkit-scrollbar-thumb {
55
  }
56
  </style>
57
  </head>
 
58
  <body>
59
  <div id="loading">Loading...</div>
60
- <img src="https://lh3.googleusercontent.com/d/1Wo9oLj4D6JEsT_MWUZ4VyaIy10uLN3q0" />
61
- <button id="edit-next-marker" style="font-family: inherit; font-weight: 700; font-style: normal;">次のマーカーを編集</button>
62
- <div id="map" style="width:90%; margin:5%;"></div>
 
63
  <div id="marker-editor">
64
  <h3>マーカーを編集</h3>
65
  <label for="marker-lat">緯度:</label>
@@ -87,29 +89,32 @@ body::-webkit-scrollbar-thumb {
87
  <span id="icon-width-value">25</span>px
88
  <label for="icon-height">アイコンの高さ:</label>
89
  <input type="range" id="icon-height" min="10" max="100" value="41">
90
- <span id="icon-height-value">41</span>px
91
- </div>
92
  <label for="marker-popup">ポップアップHTML:</label>
93
- <textarea id="marker-popup" rows="4"></textarea>
 
94
  <label for="marker-tooltip">ツールチップHTML:</label>
95
- <textarea id="marker-tooltip" rows="4"></textarea>
 
96
  <button id="save-marker" style="font-family: inherit; font-weight: 800; font-style: normal;">OK</button>
97
  </div>
98
- <textarea id="output-html" rows="20" cols="100" readonly hidden></textarea><div id="output-code" style="word-break: break-all;">ここに生成されたHTMLが表示されます。</div><button id="copyButton" style="font-family: inherit; font-weight: 700; font-style: normal;">コードをコピー</button><br>
 
 
 
 
99
  <button id="generate-html" style="width: 50%; padding: 10px; border: none; background-color: #007bff; color: #fff; font-size: 16px; border-radius: 4px; cursor: pointer; margin: 20px; font-family: inherit; font-weight: 800; font-style: normal;">HTMLを生成</button>
100
  <!-- HTML入力エリアの追加 -->
101
-
102
-
103
  <script>
104
- const output = document.getElementById('output-code');
105
  output.innerHTML = hljs.highlight('html', "ここに生成されたHTMLが表示されます。").value;
106
- output.classList.add('hljs');</script>
 
107
  <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
108
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/mono-blue.min.css">
109
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js"></script>
110
-
111
- <script>
112
- window.onload = function() {
113
  const loading = document.getElementById('loading');
114
  loading.style.opacity = '0';
115
  setTimeout(() => {
@@ -117,266 +122,417 @@ body::-webkit-scrollbar-thumb {
117
  loadMapFromStorage(); // ストレージからマップを読み込む
118
  }, 500);
119
  };
120
- </script>
121
-
122
-
123
  <script>
124
-
125
  function saveMapToStorage() {
126
- const markers = [];
127
- map.eachLayer((layer) => {
128
- if (layer instanceof L.Marker) {
129
- const marker = layer;
130
- const icon = marker.options.icon;
131
- const { lat, lng } = marker.getLatLng();
132
- markers.push({
133
- lat: lat,
134
- lng: lng,
135
- iconUrl: icon.options.iconUrl,
136
- iconSize: icon.options.iconSize,
137
- popupContent: marker.getPopup() ? marker.getPopup().getContent() : '',
138
- tooltipContent: marker.getTooltip() ? marker.getTooltip().getContent() : '',
139
- });
140
- }
141
- });
142
- localStorage.setItem('leafletMap', JSON.stringify(markers));
143
- }
144
-
145
- function loadMapFromStorage() {
146
- const storedMarkers = JSON.parse(localStorage.getItem('leafletMap'));
147
- if (!storedMarkers) {
148
- console.warn('No markers found in local storage.');
149
- return;
150
- }
151
-
152
- if (!map) {
153
- console.error('Map is not initialized.');
154
- return;
155
  }
156
-
157
- storedMarkers.forEach((data) => {
158
- if (!data.iconUrl || !data.iconSize) {
159
- console.error('Icon data is incomplete.');
 
160
  return;
161
  }
162
-
163
- const icon = L.icon({
164
- iconUrl: data.iconUrl,
165
- iconSize: data.iconSize,
166
- iconAnchor: [data.iconSize[0] / 2, data.iconSize[1]],
167
- popupAnchor: [0, -data.iconSize[1]],
168
- tooltipAnchor: [data.iconSize[0] / 2, -data.iconSize[1] / 2],
169
- });
170
- const marker = L.marker([data.lat, data.lng], { icon: icon }).addTo(map);
171
- if (data.popupContent) marker.bindPopup(data.popupContent);
172
- if (data.tooltipContent) marker.bindTooltip(data.tooltipContent);
173
-
174
- // ⭐ここから追加⭐
175
- marker.on("mouseover", function() {
176
- hoveredMarker = marker;
177
- console.log("Marker hovered:", marker);
178
- });
179
- marker.on("mouseout", function() {
180
- if (hoveredMarker === marker) {
181
- hoveredMarker = null;
182
- console.log("Marker no longer hovered");
183
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  });
185
- // ⭐ここまで追加⭐
186
-
187
- });
188
- }
189
-
190
- function updatePreviewSize() {
191
- var e = document.getElementById("icon-width").value;
192
- var t = document.getElementById("icon-height").value;
193
- var n = document.getElementById("icon-preview");
194
- n.style.width = e + "px";
195
- n.style.height = t + "px";
196
- document.getElementById("icon-width-value").textContent = e;
197
- document.getElementById("icon-height-value").textContent = t;
198
- if (editingMarker) {
199
- var o = document.querySelector('input[name="icon-source"]:checked').value === "url" ? document.getElementById("marker-icon-url").value : n.src;
200
- var i = L.icon({
201
- iconUrl: o,
202
- iconSize: [e, t],
203
- iconAnchor: [e / 2, t],
204
- popupAnchor: [0, -t],
205
- tooltipAnchor: [e / 2, -t / 2]
206
- });
207
- editingMarker.setIcon(i);
208
- saveMapToStorage();
209
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  }
211
-
212
- function openEditor(e) {
213
- const t = e.getLatLng();
214
- document.getElementById("marker-lat").value = t.lat;
215
- document.getElementById("marker-lng").value = t.lng;
216
- document.getElementById("marker-popup").value = e.getPopup() ? e.getPopup().getContent() : "";
217
- document.getElementById("marker-tooltip").value = e.getTooltip() ? e.getTooltip().getContent() : "";
218
- document.getElementById("marker-editor").style.display = "block";
219
- editingMarker = e;
220
-
221
- // ここから追加
222
- const icon = e.options.icon;
223
- if (icon && icon.options) {
224
- if (icon.options.iconUrl) {
225
- // URLから読み込むラジオボタンを選択
226
- document.querySelector('input[name="icon-source"][value="url"]').checked = true;
227
- document.getElementById("icon-url-input").style.display = "block";
228
- document.getElementById("icon-upload-input").style.display = "none";
229
- document.getElementById("marker-icon-url").value = icon.options.iconUrl;
230
- document.getElementById("icon-preview").src = icon.options.iconUrl;
231
- document.getElementById("icon-preview").style.display = 'block';
232
- // 高さと幅の設定を表示
233
- document.getElementById("icon-settings").style.display = "block";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  } else {
235
- // URLから読み込むラジオボタンを選択
236
- document.querySelector('input[name="icon-source"][value="upload"]').checked = true;
237
- document.getElementById("icon-url-input").style.display = "none";
238
- document.getElementById("icon-upload-input").style.display = "block";
239
- document.getElementById("marker-icon-url").value = icon.options.iconUrl;
240
- document.getElementById("icon-preview").src = icon.options.iconUrl;
241
- document.getElementById("icon-preview").style.display = 'block';
242
- // 高さと幅の設定を表示
243
- document.getElementById("icon-settings").style.display = "block";
244
  }
245
- document.getElementById("icon-width").value = icon.options.iconSize[0];
246
- document.getElementById("icon-height").value = icon.options.iconSize[1];
247
- document.getElementById("icon-width-value").textContent = icon.options.iconSize[0];
248
- document.getElementById("icon-height-value").textContent = icon.options.iconSize[1];
249
- }
250
- // ここまで追加
251
-
252
- updatePreviewSize();
253
- }
254
-
255
- function generateMapHTML() {
256
- const e = [];
257
- map.eachLayer((function(t) {
258
- if (t instanceof L.Marker) {
259
- const n = t;
260
- const o = n.options.icon;
261
- const i = o.options.iconUrl;
262
- const r = o.options.iconSize;
263
- const c = n.getLatLng();
264
- const l = n.getPopup() ? n.getPopup().getContent() : "";
265
- const a = n.getTooltip() ? n.getTooltip().getContent() : "";
266
- e.push({
267
- lat: c.lat,
268
- lng: c.lng,
269
- iconUrl: i,
270
- iconWidth: r[0],
271
- iconHeight: r[1],
272
- popupContent: l,
273
- tooltipContent: a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  });
 
 
 
 
275
  }
276
- }));
277
- const t = map.getCenter();
278
- const n = map.getZoom();
279
- let o = `
280
- <div id="map" style="height: 600px; width: 100%;"></div>
281
- <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" />
282
- <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"><\/script>
283
- <script>
284
- var map = L.map('map').setView([${t.lat}, ${t.lng}], ${n});
285
- L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
286
- attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
287
- }).addTo(map);
288
-
289
- ${e.map(e => `
290
- var icon = L.icon({
291
- iconUrl: '${e.iconUrl}',
292
- iconSize: [${e.iconWidth}, ${e.iconHeight}],
293
- iconAnchor: [${e.iconWidth} / 2, ${e.iconHeight}],
294
- popupAnchor: [0, -${e.iconHeight}],
295
- tooltipAnchor: [${e.iconWidth} / 2, -${e.iconHeight} / 2]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  });
297
-
298
- var marker = L.marker([${e.lat}, ${e.lng}], {
299
- icon: icon,
300
- zIndexOffset: 1000
301
- }).addTo(map);
302
-
303
- ${e.popupContent ? `marker.bindPopup('${e.popupContent.replace(/'/g, "\\'").replace(/<\/script>/g, "<\\/script>")}');` : ""}
304
- ${e.tooltipContent ? `marker.bindTooltip('${e.tooltipContent.replace(/'/g, "\\'").replace(/<\/script>/g, "<\\/script>")}');` : ""}
305
- `).join("\n")}
306
- <\/script>
307
- `;
308
- o = o.replace(/iconUrl: 'marker-icon\.png'/g, `iconUrl: '${location.origin}/marker-icon.png'`);
309
- document.getElementById("output-html").value = o;
310
- const input = document.getElementById('output-html').value;
311
- const output = document.getElementById('output-code');
312
- output.innerHTML = hljs.highlight('html', input).value;
313
- output.classList.add('hljs');
314
  }
315
-
316
- function resizeImage(e, t, n, o) {
317
- const i = new FileReader();
318
- i.onload = function(e) {
319
- const i = new Image();
320
- i.onload = function() {
321
- const e = document.createElement("canvas");
322
- e.width = t;
323
- e.height = n;
324
- e.getContext("2d").drawImage(i, 0, 0, t, n);
325
- o(e.toDataURL());
326
- };
327
- i.src = e.target.result;
328
- };
329
- i.readAsDataURL(e);
 
330
  }
331
-
332
- document.getElementById("marker-icon-upload").addEventListener("change", function() {
333
- const e = this.files[0];
334
- const t = document.getElementById("icon-preview");
335
- if (e) {
336
- resizeImage(e, parseInt(document.getElementById("icon-width").value), parseInt(document.getElementById("icon-height").value), function(imageDataUrl) {
337
- t.src = imageDataUrl;
338
- t.style.display = "block";
339
- document.getElementById("icon-settings").style.display = "block"; // 高さと幅の設定を表示
340
- updatePreviewSize();
341
- });
342
- } else {
343
- t.style.display = "none";
344
- document.getElementById("icon-settings").style.display = "none"; // アップロードされていない場合は非表示
345
  }
346
- });
347
-
348
-
349
- document.getElementById("load-icon-url").addEventListener("click", function() {
350
- const e = document.getElementById("marker-icon-url").value;
351
- const t = document.getElementById("icon-preview");
352
- if (e) {
353
- t.src = e;
354
- t.onload = function() {
355
- t.style.display = "block";
356
- document.getElementById("icon-settings").style.display = "block";
357
- updatePreviewSize();
358
- };
359
- t.onerror = function() {
360
- alert("画像の読み込みに失敗しました。URLを確認してください。");
361
- t.style.display = "none";
362
- document.getElementById("icon-settings").style.display = "none";
363
- };
364
- } else {
365
- t.style.display = "none";
366
- document.getElementById("icon-settings").style.display = "none";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
  }
368
- });
369
-
370
- document.getElementById("icon-width").addEventListener("input", updatePreviewSize);
371
- document.getElementById("icon-height").addEventListener("input", updatePreviewSize);
372
-
373
- const map = L.map("map").setView([33.321797711641395, 130.52061378343208], 16);
374
- L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' }).addTo(map);
375
-
376
- let editingMarker = null;
377
- let hoveredMarker = null;
378
-
379
- map.on("click", function(e) {
380
  if (editingMarker) {
381
  const t = e.latlng;
382
  editingMarker.setLatLng([t.lat, t.lng]);
@@ -391,197 +547,44 @@ document.getElementById("marker-icon-upload").addEventListener("change", functio
391
  n.bindTooltip("新しいマーカーのツールチップ");
392
  n.on("mouseover", function() {
393
  hoveredMarker = n;
394
- console.log("Marker hovered:", n);
395
  });
396
  n.on("mouseout", function() {
397
- hoveredMarker === n && (hoveredMarker = null, console.log("Marker no longer hovered"));
398
  });
 
399
  openEditor(n);
400
- }
401
- });
402
-
403
- document.querySelectorAll('input[name="icon-source"]').forEach(function(e) {
404
- e.addEventListener("change", function() {
405
- const value = this.value;
406
- if (value === "url") {
407
- document.getElementById("icon-url-input").style.display = "block";
408
- document.getElementById("icon-upload-input").style.display = "none";
409
- } else {
410
- document.getElementById("icon-url-input").style.display = "none";
411
- document.getElementById("icon-upload-input").style.display = "block";
412
- }
413
- updatePreviewSize();
414
- });
415
- });
416
-
417
- document.getElementById("save-marker").addEventListener("click", function() {
418
- if (editingMarker) {
419
- const lat = parseFloat(document.getElementById("marker-lat").value);
420
- const lng = parseFloat(document.getElementById("marker-lng").value);
421
- const popupContent = document.getElementById("marker-popup").value;
422
- const tooltipContent = document.getElementById("marker-tooltip").value;
423
-
424
- const iconSource = document.querySelector('input[name="icon-source"]:checked').value;
425
- let iconUrl = "";
426
-
427
- if (iconSource === "url") {
428
- iconUrl = document.getElementById("marker-icon-url").value;
429
- } else if (iconSource === "upload") {
430
- const file = document.getElementById("marker-icon-upload").files[0];
431
- if (file) {
432
- // Blob URLからData URLに変換する処理
433
- resizeImage(file, parseInt(document.getElementById("icon-width").value), parseInt(document.getElementById("icon-height").value), function(dataUrl) {
434
- iconUrl = dataUrl;
435
- applyIconAndSaveMarker(lat, lng, popupContent, tooltipContent, iconUrl);
436
- });
437
  saveMapToStorage();
438
- return; // 非同期処理が完了するまで待つためここでリターン
439
  }
440
  }
441
-
442
- // URLの場合や、アップロードファイルがない場合の処理
443
- applyIconAndSaveMarker(lat, lng, popupContent, tooltipContent, iconUrl);
444
- }
445
- });
446
-
447
- function applyIconAndSaveMarker(lat, lng, popupContent, tooltipContent, iconUrl) {
448
- const iconWidth = parseInt(document.getElementById("icon-width").value);
449
- const iconHeight = parseInt(document.getElementById("icon-height").value);
450
-
451
- editingMarker.setLatLng([lat, lng]);
452
- if (iconUrl) {
453
- const icon = L.icon({
454
- iconUrl: iconUrl,
455
- iconSize: [iconWidth, iconHeight],
456
- iconAnchor: [iconWidth / 2, iconHeight],
457
- popupAnchor: [0, -iconHeight],
458
- tooltipAnchor: [iconWidth / 2, -iconHeight / 2]
459
- });
460
- editingMarker.setIcon(icon);
461
- }
462
-
463
- editingMarker.bindPopup(popupContent);
464
- editingMarker.bindTooltip(tooltipContent);
465
-
466
- document.getElementById("marker-editor").style.display = "none";
467
- editingMarker = null;
468
- saveMapToStorage();
469
- }
470
-
471
-
472
- document.addEventListener("keydown", function(e) {
473
- if (e.key === "e" && hoveredMarker) {
474
- openEditor(hoveredMarker);
475
- }
476
- });
477
-
478
- (function() {
479
- const e = document.getElementById("marker-editor");
480
- let t, n, o = false;
481
- e.addEventListener("mousedown", function(i) {
482
- if (!i.target.closest("input, textarea, button")) {
483
- t = i.clientX - e.getBoundingClientRect().left;
484
- n = i.clientY - e.getBoundingClientRect().top;
485
- o = true;
486
- }
487
- });
488
- document.addEventListener("mousemove", function(i) {
489
- if (o) {
490
- e.style.left = i.clientX - t + "px";
491
- e.style.top = i.clientY - n + "px";
492
- }
493
- });
494
- document.addEventListener("mouseup", function() {
495
- o = false;
496
- });
497
- })();
498
- document.getElementById("copyButton").onclick = function() {
499
- const textToCopy = document.getElementById("output-code").innerText;
500
- navigator.clipboard.writeText(textToCopy).then(() => {
501
- alert("テキストがコピーされました!");
502
- }).catch(err => {
503
- console.error('コピーに失敗しました:', err);
504
- });
505
- };
506
-
507
- document.getElementById("generate-html").addEventListener("click", generateMapHTML);
508
-
509
- let nextMarkerEdit = null;
510
-
511
- document.getElementById("edit-next-marker").addEventListener("click", function() {
512
- nextMarkerEdit = true;
513
- alert("次にクリックするマーカーを編集します。");
514
- });
515
-
516
- map.on("click", function(e) {
517
- if (nextMarkerEdit) {
518
  const clickedMarkers = [];
 
 
519
  map.eachLayer(function (layer) {
520
  if (layer instanceof L.Marker) {
521
  const distance = map.distance(e.latlng, layer.getLatLng());
522
- if (distance < 20) {
523
  clickedMarkers.push(layer);
524
  }
525
  }
526
  });
527
-
 
528
  if (clickedMarkers.length > 0) {
529
  openEditor(clickedMarkers[0]);
530
  }
531
- nextMarkerEdit = false;
532
- } else {
533
- // 既存のクリックイベント処理
534
- if (editingMarker) {
535
- const t = e.latlng;
536
- editingMarker.setLatLng([t.lat, t.lng]);
537
- document.getElementById("marker-lat").value = t.lat;
538
- document.getElementById("marker-lng").value = t.lng;
539
- updatePreviewSize();
540
- saveMapToStorage();
541
- } else {
542
- const t = e.latlng;
543
- const n = L.marker(t).addTo(map);
544
- n.bindPopup("新しいマーカー");
545
- n.bindTooltip("新しいマーカーのツールチップ");
546
- n.on("mouseover", function() {
547
- hoveredMarker = n;
548
- });
549
- n.on("mouseout", function() {
550
- hoveredMarker === n && (hoveredMarker = null);
551
- });
552
- document.GetelementById("marker-icon-url").value = "https://unpkg.com/leaflet@1.9.3/dist/images/marker-icon-2x.png";
553
- openEditor(n);
554
- saveMapToStorage();
555
- document.GetelementById("marker-icon-url").value = "https://unpkg.com/leaflet@1.9.3/dist/images/marker-icon-2x.png";
556
- }
557
- }
558
- });
559
-
560
- // マーカー移動時にも保存
561
- map.on("markerdragend", function(e) {
562
- saveMapToStorage(); // マーカー移動後に保存
563
- });
564
-
565
- map.on("contextmenu", function (e) {
566
- const clickedMarkers = [];
567
-
568
- // クリックされた位置と既存のマーカーの距離を計算
569
- map.eachLayer(function (layer) {
570
- if (layer instanceof L.Marker) {
571
- const distance = map.distance(e.latlng, layer.getLatLng());
572
- if (distance < 20) { // 近い距離(ピクセル相当の距離)内のマーカーを検出
573
- clickedMarkers.push(layer);
574
- }
575
- }
576
  });
577
-
578
- // クリックされたーカーあれば、最初の1つ対して編集を開く
579
- if (clickedMarkers.length > 0) {
580
- openEditor(clickedMarkers[0]);
581
- }
582
- });
583
-
584
- // マップが動いたときに保存
585
  </script>
586
  </body>
 
587
  </html>
 
 
1
  <!DOCTYPE html>
2
  <html lang="ja">
3
+
4
  <head>
5
+ <link rel="preconnect" href="https://fonts.googleapis.com">
6
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
7
+ <link href="https://fonts.googleapis.com/css2?family=Yomogi&display=swap" rel="stylesheet">
8
  <meta charset="UTF-8">
9
  <meta name="viewport" content="width=device-width, initial-scale=1">
10
  <title>マーカー編集機能付きのLeafletマップ</title>
11
+ <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css">
12
  <style>
13
+ body{
14
  font-family: "Yomogi", cursive;
15
  font-weight: 400;
16
  font-style: normal;
 
55
  }
56
  </style>
57
  </head>
58
+
59
  <body>
60
  <div id="loading">Loading...</div>
61
+ <img src="https://lh3.googleusercontent.com/d/1Wo9oLj4D6JEsT_MWUZ4VyaIy10uLN3q0">
62
+ <button id="edit-next-marker" style="font-family: inherit; font-weight: 700; font-style: normal;">次のマーカーを編集</button>
63
+ <div id="map" style="width:90%; margin:5%;">
64
+ </div>
65
  <div id="marker-editor">
66
  <h3>マーカーを編集</h3>
67
  <label for="marker-lat">緯度:</label>
 
89
  <span id="icon-width-value">25</span>px
90
  <label for="icon-height">アイコンの高さ:</label>
91
  <input type="range" id="icon-height" min="10" max="100" value="41">
92
+ <span id="icon-height-value">41</span>px</div>
 
93
  <label for="marker-popup">ポップアップHTML:</label>
94
+ <textarea id="marker-popup" rows="4">
95
+ </textarea>
96
  <label for="marker-tooltip">ツールチップHTML:</label>
97
+ <textarea id="marker-tooltip" rows="4">
98
+ </textarea>
99
  <button id="save-marker" style="font-family: inherit; font-weight: 800; font-style: normal;">OK</button>
100
  </div>
101
+ <textarea id="output-html" rows="20" cols="100" readonly hidden>
102
+ </textarea>
103
+ <div id="output-code" style="word-break: break-all;">ここに生成されたHTMLが表示されます。</div>
104
+ <button id="copyButton" style="font-family: inherit; font-weight: 700; font-style: normal;">コードをコピー</button>
105
+ <br>
106
  <button id="generate-html" style="width: 50%; padding: 10px; border: none; background-color: #007bff; color: #fff; font-size: 16px; border-radius: 4px; cursor: pointer; margin: 20px; font-family: inherit; font-weight: 800; font-style: normal;">HTMLを生成</button>
107
  <!-- HTML入力エリアの追加 -->
 
 
108
  <script>
109
+ const output = document.getElementById('output-code');
110
  output.innerHTML = hljs.highlight('html', "ここに生成されたHTMLが表示されます。").value;
111
+ output.classList.add('hljs');
112
+ </script>
113
  <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
114
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/styles/mono-blue.min.css">
115
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.5.1/highlight.min.js"></script>
116
+ <script>
117
+ window.onload = function() {
 
118
  const loading = document.getElementById('loading');
119
  loading.style.opacity = '0';
120
  setTimeout(() => {
 
122
  loadMapFromStorage(); // ストレージからマップを読み込む
123
  }, 500);
124
  };
125
+ </script>
 
 
126
  <script>
 
127
  function saveMapToStorage() {
128
+ const markers = [];
129
+ map.eachLayer((layer) => {
130
+ if (layer instanceof L.Marker) {
131
+ const marker = layer;
132
+ const icon = marker.options.icon;
133
+ const { lat, lng } = marker.getLatLng();
134
+ markers.push({
135
+ lat: lat,
136
+ lng: lng,
137
+ iconUrl: icon.options.iconUrl,
138
+ iconSize: icon.options.iconSize,
139
+ popupContent: marker.getPopup() ? marker.getPopup().getContent() : '',
140
+ tooltipContent: marker.getTooltip() ? marker.getTooltip().getContent() : '',
141
+ });
142
+ }
143
+ });
144
+ localStorage.setItem('leafletMap', JSON.stringify(markers));
 
 
 
 
 
 
 
 
 
 
 
 
145
  }
146
+
147
+ function loadMapFromStorage() {
148
+ const storedMarkers = JSON.parse(localStorage.getItem('leafletMap'));
149
+ if (!storedMarkers) {
150
+ console.warn('No markers found in local storage.');
151
  return;
152
  }
153
+
154
+ if (!map) {
155
+ console.error('Map is not initialized.');
156
+ return;
157
+ }
158
+
159
+ storedMarkers.forEach((data) => {
160
+ if (!data.iconUrl || !data.iconSize) {
161
+ console.error('Icon data is incomplete.');
162
+ return;
 
 
 
 
 
 
 
 
 
 
 
163
  }
164
+
165
+ const icon = L.icon({
166
+ iconUrl: data.iconUrl,
167
+ iconSize: data.iconSize,
168
+ iconAnchor: [data.iconSize[0] / 2, data.iconSize[1]],
169
+ popupAnchor: [0, -data.iconSize[1]],
170
+ tooltipAnchor: [data.iconSize[0] / 2, -data.iconSize[1] / 2],
171
+ });
172
+ const marker = L.marker([data.lat, data.lng], { icon: icon }).addTo(map);
173
+ if (data.popupContent) marker.bindPopup(data.popupContent);
174
+ if (data.tooltipContent) marker.bindTooltip(data.tooltipContent);
175
+
176
+ // ⭐ここから追加⭐
177
+ marker.on("mouseover", function() {
178
+ hoveredMarker = marker;
179
+ console.log("Marker hovered:", marker);
180
+ });
181
+ marker.on("mouseout", function() {
182
+ if (hoveredMarker === marker) {
183
+ hoveredMarker = null;
184
+ console.log("Marker no longer hovered");
185
+ }
186
+ });
187
+ // ⭐ここまで追加⭐
188
+
189
  });
190
+ }
191
+
192
+ function updatePreviewSize() {
193
+ var e = document.getElementById("icon-width").value;
194
+ var t = document.getElementById("icon-height").value;
195
+ var n = document.getElementById("icon-preview");
196
+ n.style.width = e + "px";
197
+ n.style.height = t + "px";
198
+ document.getElementById("icon-width-value").textContent = e;
199
+ document.getElementById("icon-height-value").textContent = t;
200
+ if (editingMarker) {
201
+ var o = document.querySelector('input[name="icon-source"]:checked').value === "url" ? document.getElementById("marker-icon-url").value : n.src;
202
+ var i = L.icon({
203
+ iconUrl: o,
204
+ iconSize: [e, t],
205
+ iconAnchor: [e / 2, t],
206
+ popupAnchor: [0, -t],
207
+ tooltipAnchor: [e / 2, -t / 2]
208
+ });
209
+ editingMarker.setIcon(i);
210
+ saveMapToStorage();
211
+ }
 
 
212
  }
213
+
214
+ function openEditor(e) {
215
+ const t = e.getLatLng();
216
+ document.getElementById("marker-lat").value = t.lat;
217
+ document.getElementById("marker-lng").value = t.lng;
218
+ document.getElementById("marker-popup").value = e.getPopup() ? e.getPopup().getContent() : "";
219
+ document.getElementById("marker-tooltip").value = e.getTooltip() ? e.getTooltip().getContent() : "";
220
+ document.getElementById("marker-editor").style.display = "block";
221
+ editingMarker = e;
222
+
223
+ // ここから追加
224
+ const icon = e.options.icon;
225
+ if (icon && icon.options) {
226
+ if (icon.options.iconUrl) {
227
+ // URLから読み込むラジオボタンを選択
228
+ document.querySelector('input[name="icon-source"][value="url"]').checked = true;
229
+ document.getElementById("icon-url-input").style.display = "block";
230
+ document.getElementById("icon-upload-input").style.display = "none";
231
+ document.getElementById("marker-icon-url").value = icon.options.iconUrl;
232
+ document.getElementById("icon-preview").src = icon.options.iconUrl;
233
+ document.getElementById("icon-preview").style.display = 'block';
234
+ // 高さと幅の設定を表示
235
+ document.getElementById("icon-settings").style.display = "block";
236
+ } else {
237
+ // URLから読み込むラジオボタンを選択
238
+ document.querySelector('input[name="icon-source"][value="upload"]').checked = true;
239
+ document.getElementById("icon-url-input").style.display = "none";
240
+ document.getElementById("icon-upload-input").style.display = "block";
241
+ document.getElementById("marker-icon-url").value = icon.options.iconUrl;
242
+ document.getElementById("icon-preview").src = icon.options.iconUrl;
243
+ document.getElementById("icon-preview").style.display = 'block';
244
+ // 高さと幅の設定を表示
245
+ document.getElementById("icon-settings").style.display = "block";
246
+ }
247
+ document.getElementById("icon-width").value = icon.options.iconSize[0];
248
+ document.getElementById("icon-height").value = icon.options.iconSize[1];
249
+ document.getElementById("icon-width-value").textContent = icon.options.iconSize[0];
250
+ document.getElementById("icon-height-value").textContent = icon.options.iconSize[1];
251
  }
252
+ // ここまで追加
253
+
254
+ updatePreviewSize();
255
+ }
256
+
257
+ function generateMapHTML() {
258
+ const e = [];
259
+ map.eachLayer((function(t) {
260
+ if (t instanceof L.Marker) {
261
+ const n = t;
262
+ const o = n.options.icon;
263
+ const i = o.options.iconUrl;
264
+ const r = o.options.iconSize;
265
+ const c = n.getLatLng();
266
+ const l = n.getPopup() ? n.getPopup().getContent() : "";
267
+ const a = n.getTooltip() ? n.getTooltip().getContent() : "";
268
+ e.push({
269
+ lat: c.lat,
270
+ lng: c.lng,
271
+ iconUrl: i,
272
+ iconWidth: r[0],
273
+ iconHeight: r[1],
274
+ popupContent: l,
275
+ tooltipContent: a
276
+ });
277
+ }
278
+ }));
279
+ const t = map.getCenter();
280
+ const n = map.getZoom();
281
+ let o = `
282
+ <div id="map" style="height: 600px; width: 100%;">
283
+ <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" />
284
+ <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"><\/script>
285
+ <script>
286
+ var map = L.map('map').setView([${t.lat}, ${t.lng}], ${n});
287
+ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
288
+ attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap contributors'
289
+ }).addTo(map);
290
+
291
+ ${e.map(e => `
292
+ var icon = L.icon({
293
+ iconUrl: '${e.iconUrl}',
294
+ iconSize: [${e.iconWidth}, ${e.iconHeight}],
295
+ iconAnchor: [${e.iconWidth} / 2, ${e.iconHeight}],
296
+ popupAnchor: [0, -${e.iconHeight}],
297
+ tooltipAnchor: [${e.iconWidth} / 2, -${e.iconHeight} / 2]
298
+ });
299
+
300
+ var marker = L.marker([${e.lat}, ${e.lng}], {
301
+ icon: icon,
302
+ zIndexOffset: 1000
303
+ }).addTo(map);
304
+
305
+ ${e.popupContent ? `marker.bindPopup('${e.popupContent.replace(/'/g, "\\'").replace(/<\/script>/g, "<\\/script>")}');` : ""}
306
+ ${e.tooltipContent ? `marker.bindTooltip('${e.tooltipContent.replace(/'/g, "\\'").replace(/<\/script>/g, "<\\/script>")}');` : ""}
307
+ `).join("\n")}
308
+ <\/script>
309
+ `;
310
+ o = o.replace(/iconUrl: 'marker-icon\.png'/g, `iconUrl: '${location.origin}/marker-icon.png'`);
311
+ document.getElementById("output-html").value = o;
312
+ const input = document.getElementById('output-html').value;
313
+ const output = document.getElementById('output-code');
314
+ output.innerHTML = hljs.highlight('html', input).value;
315
+ output.classList.add('hljs');
316
+ }
317
+
318
+ function resizeImage(e, t, n, o) {
319
+ const i = new FileReader();
320
+ i.onload = function(e) {
321
+ const i = new Image();
322
+ i.onload = function() {
323
+ const e = document.createElement("canvas");
324
+ e.width = t;
325
+ e.height = n;
326
+ e.getContext("2d").drawImage(i, 0, 0, t, n);
327
+ o(e.toDataURL());
328
+ };
329
+ i.src = e.target.result;
330
+ };
331
+ i.readAsDataURL(e);
332
+ }
333
+
334
+ document.getElementById("marker-icon-upload").addEventListener("change", function() {
335
+ const e = this.files[0];
336
+ const t = document.getElementById("icon-preview");
337
+ if (e) {
338
+ resizeImage(e, parseInt(document.getElementById("icon-width").value), parseInt(document.getElementById("icon-height").value), function(imageDataUrl) {
339
+ t.src = imageDataUrl;
340
+ t.style.display = "block";
341
+ document.getElementById("icon-settings").style.display = "block"; // 高さと幅の設定を表示
342
+ updatePreviewSize();
343
+ });
344
  } else {
345
+ t.style.display = "none";
346
+ document.getElementById("icon-settings").style.display = "none"; // アップロードされていない場合は非表示
 
 
 
 
 
 
 
347
  }
348
+ });
349
+
350
+
351
+ document.getElementById("load-icon-url").addEventListener("click", function() {
352
+ const e = document.getElementById("marker-icon-url").value;
353
+ const t = document.getElementById("icon-preview");
354
+ if (e) {
355
+ t.src = e;
356
+ t.onload = function() {
357
+ t.style.display = "block";
358
+ document.getElementById("icon-settings").style.display = "block";
359
+ updatePreviewSize();
360
+ };
361
+ t.onerror = function() {
362
+ alert("画像の読み込みに失敗しました。URLを確認してください。");
363
+ t.style.display = "none";
364
+ document.getElementById("icon-settings").style.display = "none";
365
+ };
366
+ } else {
367
+ t.style.display = "none";
368
+ document.getElementById("icon-settings").style.display = "none";
369
+ }
370
+ });
371
+
372
+ document.getElementById("icon-width").addEventListener("input", updatePreviewSize);
373
+ document.getElementById("icon-height").addEventListener("input", updatePreviewSize);
374
+
375
+ const map = L.map("map").setView([33.321797711641395, 130.52061378343208], 16);
376
+ L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap contributors' }).addTo(map);
377
+
378
+ let editingMarker = null;
379
+ let hoveredMarker = null;
380
+
381
+ map.on("click", function(e) {
382
+ if (editingMarker) {
383
+ const t = e.latlng;
384
+ editingMarker.setLatLng([t.lat, t.lng]);
385
+ document.getElementById("marker-lat").value = t.lat;
386
+ document.getElementById("marker-lng").value = t.lng;
387
+ updatePreviewSize();
388
+ saveMapToStorage();
389
+ } else {
390
+ const t = e.latlng;
391
+ const n = L.marker(t).addTo(map);
392
+ n.bindPopup("新しいマーカー");
393
+ n.bindTooltip("新しいマーカーのツールチップ");
394
+ n.on("mouseover", function() {
395
+ hoveredMarker = n;
396
+ console.log("Marker hovered:", n);
397
  });
398
+ n.on("mouseout", function() {
399
+ hoveredMarker === n && (hoveredMarker = null, console.log("Marker no longer hovered"));
400
+ });
401
+ openEditor(n);
402
  }
403
+ });
404
+
405
+ document.querySelectorAll('input[name="icon-source"]').forEach(function(e) {
406
+ e.addEventListener("change", function() {
407
+ const value = this.value;
408
+ if (value === "url") {
409
+ document.getElementById("icon-url-input").style.display = "block";
410
+ document.getElementById("icon-upload-input").style.display = "none";
411
+ } else {
412
+ document.getElementById("icon-url-input").style.display = "none";
413
+ document.getElementById("icon-upload-input").style.display = "block";
414
+ }
415
+ updatePreviewSize();
416
+ });
417
+ });
418
+
419
+ document.getElementById("save-marker").addEventListener("click", function() {
420
+ if (editingMarker) {
421
+ const lat = parseFloat(document.getElementById("marker-lat").value);
422
+ const lng = parseFloat(document.getElementById("marker-lng").value);
423
+ const popupContent = document.getElementById("marker-popup").value;
424
+ const tooltipContent = document.getElementById("marker-tooltip").value;
425
+
426
+ const iconSource = document.querySelector('input[name="icon-source"]:checked').value;
427
+ let iconUrl = "";
428
+
429
+ if (iconSource === "url") {
430
+ iconUrl = document.getElementById("marker-icon-url").value;
431
+ } else if (iconSource === "upload") {
432
+ const file = document.getElementById("marker-icon-upload").files[0];
433
+ if (file) {
434
+ // Blob URLからData URLに変換する処理
435
+ resizeImage(file, parseInt(document.getElementById("icon-width").value), parseInt(document.getElementById("icon-height").value), function(dataUrl) {
436
+ iconUrl = dataUrl;
437
+ applyIconAndSaveMarker(lat, lng, popupContent, tooltipContent, iconUrl);
438
  });
439
+ saveMapToStorage();
440
+ return; // 非同期処理が完了するまで待つためここでリターン
441
+ }
442
+ }
443
+
444
+ // URLの場合や、アップロードファイルがない場合の処理
445
+ applyIconAndSaveMarker(lat, lng, popupContent, tooltipContent, iconUrl);
 
 
 
 
 
 
 
 
 
 
446
  }
447
+ });
448
+
449
+ function applyIconAndSaveMarker(lat, lng, popupContent, tooltipContent, iconUrl) {
450
+ const iconWidth = parseInt(document.getElementById("icon-width").value);
451
+ const iconHeight = parseInt(document.getElementById("icon-height").value);
452
+
453
+ editingMarker.setLatLng([lat, lng]);
454
+ if (iconUrl) {
455
+ const icon = L.icon({
456
+ iconUrl: iconUrl,
457
+ iconSize: [iconWidth, iconHeight],
458
+ iconAnchor: [iconWidth / 2, iconHeight],
459
+ popupAnchor: [0, -iconHeight],
460
+ tooltipAnchor: [iconWidth / 2, -iconHeight / 2]
461
+ });
462
+ editingMarker.setIcon(icon);
463
  }
464
+
465
+ editingMarker.bindPopup(popupContent);
466
+ editingMarker.bindTooltip(tooltipContent);
467
+
468
+ document.getElementById("marker-editor").style.display = "none";
469
+ editingMarker = null;
470
+ saveMapToStorage();
 
 
 
 
 
 
 
471
  }
472
+
473
+
474
+ document.addEventListener("keydown", function(e) {
475
+ if (e.key === "e" && hoveredMarker) {
476
+ openEditor(hoveredMarker);
477
+ }
478
+ });
479
+
480
+ (function() {
481
+ const e = document.getElementById("marker-editor");
482
+ let t, n, o = false;
483
+ e.addEventListener("mousedown", function(i) {
484
+ if (!i.target.closest("input, textarea, button")) {
485
+ t = i.clientX - e.getBoundingClientRect().left;
486
+ n = i.clientY - e.getBoundingClientRect().top;
487
+ o = true;
488
+ }
489
+ });
490
+ document.addEventListener("mousemove", function(i) {
491
+ if (o) {
492
+ e.style.left = i.clientX - t + "px";
493
+ e.style.top = i.clientY - n + "px";
494
+ }
495
+ });
496
+ document.addEventListener("mouseup", function() {
497
+ o = false;
498
+ });
499
+ })();
500
+ document.getElementById("copyButton").onclick = function() {
501
+ const textToCopy = document.getElementById("output-code").innerText;
502
+ navigator.clipboard.writeText(textToCopy).then(() => {
503
+ alert("テキストがコピーされました!");
504
+ }).catch(err => {
505
+ console.error('コピーに失敗しました:', err);
506
+ });
507
+ };
508
+
509
+ document.getElementById("generate-html").addEventListener("click", generateMapHTML);
510
+
511
+ let nextMarkerEdit = null;
512
+
513
+ document.getElementById("edit-next-marker").addEventListener("click", function() {
514
+ nextMarkerEdit = true;
515
+ alert("次にクリックするマーカーを編集します。");
516
+ });
517
+
518
+ map.on("click", function(e) {
519
+ if (nextMarkerEdit) {
520
+ const clickedMarkers = [];
521
+ map.eachLayer(function (layer) {
522
+ if (layer instanceof L.Marker) {
523
+ const distance = map.distance(e.latlng, layer.getLatLng());
524
+ if (distance < 20) {
525
+ clickedMarkers.push(layer);
526
+ }
527
+ }
528
+ });
529
+
530
+ if (clickedMarkers.length > 0) {
531
+ openEditor(clickedMarkers[0]);
532
  }
533
+ nextMarkerEdit = false;
534
+ } else {
535
+ // 既存の��リックイベント処理
 
 
 
 
 
 
 
 
 
536
  if (editingMarker) {
537
  const t = e.latlng;
538
  editingMarker.setLatLng([t.lat, t.lng]);
 
547
  n.bindTooltip("新しいマーカーのツールチップ");
548
  n.on("mouseover", function() {
549
  hoveredMarker = n;
 
550
  });
551
  n.on("mouseout", function() {
552
+ hoveredMarker === n && (hoveredMarker = null);
553
  });
554
+ document.GetelementById("marker-icon-url").value = "https://unpkg.com/leaflet@1.9.3/dist/images/marker-icon-2x.png";
555
  openEditor(n);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
556
  saveMapToStorage();
557
+ document.GetelementById("marker-icon-url").value = "https://unpkg.com/leaflet@1.9.3/dist/images/marker-icon-2x.png";
558
  }
559
  }
560
+ });
561
+
562
+ // マーカー移動時にも保存
563
+ map.on("markerdragend", function(e) {
564
+ saveMapToStorage(); // マーカー移動後に保存
565
+ });
566
+
567
+ map.on("contextmenu", function (e) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
568
  const clickedMarkers = [];
569
+
570
+ // クリックされた位置と既存のマーカーの距離を計算
571
  map.eachLayer(function (layer) {
572
  if (layer instanceof L.Marker) {
573
  const distance = map.distance(e.latlng, layer.getLatLng());
574
+ if (distance < 20) { // 近い距離(ピクセル相当の距離)内のマーカーを検出
575
  clickedMarkers.push(layer);
576
  }
577
  }
578
  });
579
+
580
+ // クリックされたマーカーがあれば、最初の1つに対して編集を開く
581
  if (clickedMarkers.length > 0) {
582
  openEditor(clickedMarkers[0]);
583
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
584
  });
585
+
586
+ // マップ動いたとき保存
 
 
 
 
 
 
587
  </script>
588
  </body>
589
+
590
  </html>