ホームページ  >  記事  >  ウェブフロントエンド  >  Google Apps Script と Leaflet.js を使用したインタラクティブな XY 画像プロットの構築

Google Apps Script と Leaflet.js を使用したインタラクティブな XY 画像プロットの構築

WBOY
WBOYオリジナル
2024-09-08 22:35:08906ブラウズ

Google マップには地図上に点をプロットするための機能がたくさんありますが、画像上に点をプロットしたい場合はどうすればよいでしょうか?これらの XY 画像プロット マップは、フロア マップ、現場検査、さらにはゲームにもよく使用されます。

このガイドでは、Leaflet.js と Google Apps Script を使用して、ドラッグ可能なポイントを含むインタラクティブなマップを作成する方法を説明します。地図の設定から Google スプレッドシートのデータの統合、ウェブ アプリとしての展開まで、すべてを説明します。

このガイドの内容は次のとおりです:

  • Google Apps Script HTML サービスでの Leaflet.js のセットアップ

  • Google スプレッドシートのデータを使用してマーカーを表示する

  • マーカーが移動されたときにシート行を更新する

  • 地図から新しいマーカーを作成し、スプレッドシートに保存します

  • Web アプリからマーカーを削除する

Google Apps Script HTML サービスで Leaflet.js をセットアップする

Leaflet.js は、最も人気のあるオープンソース マッピング ライブラリの 1 つです。軽量で使いやすく、ドキュメントも充実しています。これらは、背景画像を提供できる「CRS.Simple」または座標参照システムを含む、さまざまなマップ タイプをサポートしています。

Google スプレッドシートのセットアップ

まず、次の構造を持つ、map_pin という名前のシートを作成します。

id title x y
1 test1 10 30
2 test2 50 80

次に、[拡張機能] メニューから Apps Script を開きます。

HTMLファイルの作成

まず、ライブラリを動作させるために、Leaflet ドキュメントの基本的な例から始めます。完全な例は、こちらのクイック スタート ガイドでご覧いただけます。

Index という名前の新しい HTML ファイルを追加し、コンテンツを次のように設定します。

<!DOCTYPE html>
<html>
<head>
  <title>Quick Start - Leaflet</title>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" />
  <style>
    #map {
      height: 400px;
    }
  </style>
</head>
<body>
  <div id="map"></div>

  <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
  <script>
    var map = L.map('map').setView([40.73, -73.99], 13);

    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      maxZoom: 19,
      attribution: '© OpenStreetMap'
    }).addTo(map);

    var marker = L.marker([40.73, -73.99]).addTo(map)
      .bindPopup('Test Popup Message')
      .openPopup();
  </script>
</body>
</html>

次に、Code.gs ファイルを次のように更新します。

function doGet() {
  const html = HtmlService.createHtmlOutputFromFile('Index')
    .setTitle('Map with Draggable Points')
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
  return html;
}

保存し、[デプロイ] をクリックして、Web アプリとして公開します。次に、新しいデプロイメントのリンクを開くと、Leaflet.js がニューヨークの地図を表示しているのが表示されます。

Building an Interactive XY Image Plot with Google Apps Script and Leaflet.js

OK、これは Leaflet を使用した通常の地図の例です。次に、背景画像を提供できる CRS.Simple マップ タイプに移ります。

リーフレット チュートリアルのこの例を使用して HTML を更新します。

<!DOCTYPE html>
<html>
<head>
  <title>CRS Simple Example - Leaflet</title>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" />
  <style>
    #map {
      height: 400px;
      width: 600px;
    }
    body {
      margin: 0;
      padding: 0;
    }
  </style>
</head>
<body>
  <div id="map"></div>

  <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
  <script>
    // Set up the map with a simple CRS (no geographic projection)
    var map = L.map('map', {
      crs: L.CRS.Simple,
      minZoom: -1,
      maxZoom: 4
    });

    // Define the dimensions of the image
    var bounds = [[0, 0], [1000, 1000]];
    var image = L.imageOverlay('https://leafletjs.com/examples/crs-simple/uqm_map_full.png', bounds).addTo(map);

    // Set the initial view of the map to show the whole image
    map.fitBounds(bounds);

    // Optional: Add a marker or other elements to the map
    var marker = L.marker([500, 500]).addTo(map)
      .bindPopup('Center of the image')
      .openPopup();
  </script>
</body>
</html>

ここでは 1000 x 1000 ピクセルの画像を指定し、中心マーカーを 500、500 に設定します。

保存をクリックし、次に展開>展開のテストをクリックして、新しいマップ タイプを確認します。これで、背景画像と中央にマーカーがプロットされた地図が完成したはずです。

Building an Interactive XY Image Plot with Google Apps Script and Leaflet.js

Google スプレッドシートのデータを使用して地図を初期化する

次に、シートのデータを使用して、マップ上に一連のマーカーを設定します。

まず、マーカーの位置を取得する関数を Code.gs ファイルに追加します。

function getPinData(){
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sh = ss.getSheetByName('map_pin');
  const data = sh.getDataRange().getValues();
  const json = arrayToJSON(data);
  //Logger.log(json);
  return json
}

function arrayToJSON(data=getPinData()){
  const headers = data[0];
  const rows = data.slice(1);
  let jsonData = [];
  for(row of rows){
    const obj = {};
    headers.forEach((h,i)=>obj[h] = row[i]);
    jsonData.push(obj)
  }
  //Logger.log(jsonData)
  return jsonData
}

ここではピンを JSON として返しているので、次のセクションの HTML での作業が簡単になります。

次に、この JSON をループする関数を HTML に追加し、マップが読み込まれた後にマップ ピンを作成します。

// Add map pins from sheet data
    google.script.run.withSuccessHandler(addMarkers).getPinData();

    function addMarkers(mapPinData) {
      mapPinData.forEach(pin => {
        const marker = L.marker([pin.x, pin.y], {
          draggable: true
        }).addTo(map);

        marker.bindPopup(`<b>${pin.title}`).openPopup();

        marker.on('dragend', function(e) {
          const latLng = e.target.getLatLng();
          console.log(`Marker ${pin.title} moved to: ${latLng.lat}, ${latLng.lng}`);
        });
      });
    }

保存して、テスト展開を開きます。これで、シート データからマーカーが生成されたはずです!

Building an Interactive XY Image Plot with Google Apps Script and Leaflet.js

各ピンには、その行のタイトルを含むポップアップがあります。この時点でピンはドラッグ可能ですが、新しい位置を保存する関数がまだ必要です。

ドラッグ時のマーカー位置の保存

新しい位置を保存するには、2 つの関数が必要です。1 つはクライアント側でイベントをキャプチャする HTML 内の関数で、もう 1 つはサーバー側の Code.gs ファイルに新しい位置を保存する関数です。

次のコマンドを使用して HTML を更新します。

    function addMarkers(mapPinData) {
      mapPinData.forEach(pin => {
        const { id, title, x, y } = pin;
        const marker = L.marker([x, y], {
          draggable: true
        }).addTo(map);

        marker.bindPopup(`<b>${title}</b>`).openPopup();

        marker.on('dragend', function(e) {
          const latLng = e.target.getLatLng();
          console.log(`Marker ${title} moved to: ${latLng.lat}, ${latLng.lng}`);
          saveMarkerPosition({ id, title, lat: latLng.lat, lng: latLng.lng });
        });
      });
    }

    function saveMarkerPosition({ id, title, lat, lng }) {
      google.script.run.saveMarkerPosition({ id, title, lat, lng });
    }

次に、関数を Code.gs ファイルに追加して、場所を保存します。

function saveMarkerPosition({ id, lat, lng }) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sh = ss.getSheetByName('map_pin');
  const data = sh.getDataRange().getValues();

  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === id) {  // ID column (index 0)
      sh.getRange(i + 1, 3).setValue(lat);  // latitude column
      sh.getRange(i + 1, 4).setValue(lng);  // longitude column
      break;
    }
  }
}

テスト展開を保存し、更新します。マーカーをドラッグするとシートが更新されるのが確認できるはずです!

Building an Interactive XY Image Plot with Google Apps Script and Leaflet.js

新しいポイントを追加する

既存のポイントを移動できるようになりましたが、新しいポイントを追加する場合はどうすればよいでしょうか?繰り返しますが、2 つの関数が必要になります。1 つは HTML に、もう 1 つは Code.gs ファイルにあります。

まず、ユーザーが地図上の空いている場所をクリックしたときにプロンプ​​トを開く関数を HTML に追加し、その値をサーバー関数に渡します。

    // Function to add a new pin
    map.on('click', function(e) {
      const latLng = e.latlng;
      const title = prompt('Enter a title for the new pin:');
      if (title) {
        google.script.run.withSuccessHandler(function(id) {
          addNewMarker({ id, title, lat: latLng.lat, lng: latLng.lng });
        }).addNewPin({ title, lat: latLng.lat, lng: latLng.lng });
      }
    });

    function addNewMarker({ id, title, lat, lng }) {
      const marker = L.marker([lat, lng], {
        draggable: true
      }).addTo(map);

      marker.bindPopup(`<b>${title}</b>`).openPopup();

      marker.on('dragend', function(e) {
        const latLng = e.target.getLatLng();
        saveMarkerPosition({ id, title, lat: latLng.lat, lng: latLng.lng });
      });
    }

次に、関数を Code.gs に追加して新しい行を保存します。

function addNewPin({ title, lat, lng }) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sh = ss.getSheetByName('map_pin');

  // Check if there are any rows present, if not initialize ID
  const lastRow = sh.getLastRow();
  let newId = 1;

  if (lastRow > 0) {
    const lastId = sh.getRange(lastRow, 1).getValue();
    newId = lastId + 1;
  }

  sh.appendRow([newId, title, lat, lng]);

  return newId;
}

もう一度保存して、テスト展開を更新します。空の場所をクリックすると、タイトルを入力して新しいマーカーを保存できるようになりました!

Building an Interactive XY Image Plot with Google Apps Script and Leaflet.js

マーカーの削除

最後に、マーカーを削除する方法を追加して、マップ ビューで完全な CRUD アプリを提供する必要があります。

マーカーの追加関数を更新して、ポップアップに削除ボタンを追加します:

      const popupContent = `<b>${title}</b><br><button onclick="deleteMarker(${id})">Delete Marker</button>`;
      marker.bindPopup(popupContent).openPopup();

次に、クライアント側から削除するための関数を追加します。

// Function to delete a marker
  function deleteMarker(id) {
    const confirmed = confirm('Are you sure you want to delete this marker?');
    if (confirmed) {
      google.script.run.withSuccessHandler(() => {
        // Refresh the markers after deletion
        google.script.run.withSuccessHandler(addMarkers).getPinData();
      }).deleteMarker(id);
    }
  }

次に、一致する関数を Code.gs ファイルに追加します。

function deleteMarker(id) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sh = ss.getSheetByName('map_pin');
  const data = sh.getDataRange().getValues();

  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === id) {  // ID column (index 0)
      sh.deleteRow(i + 1);  // Delete the row
      break;
    }
  }
}

次は何ですか?

各マーカーへの他のデータ ポイントの追加、動的な背景画像、その他のクリック アンド ドラッグ インタラクションなど、ここからできることはたくさんあります。ゲームも作れるかも!使用例についてのアイデアはありますか?以下にコメントを書き込んでください!

以上がGoogle Apps Script と Leaflet.js を使用したインタラクティブな XY 画像プロットの構築の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。