Google Apps Script 및 Leaflet.js를 사용하여 대화형 XY 이미지 플롯 구축
Google Maps has a ton of features for plotting points on a map, but what if you want to plot points on an image? These XY Image Plot maps are commonly used for floor maps, job site inspections, and even games.
In this guide, I'll show you how to create an interactive map with draggable points using Leaflet.js and Google Apps Script. We'll cover everything from setting up the map to integrating data from Google Sheets, and deploying it as a web app.
This guide will cover:
Setting up Leaflet.js in a Google Apps Script HTML Service
Displaying Markers using data from Google Sheets
Updating Sheets row when a Marker is moved
Creating new Markers from the map and saving to Sheets
Deleting a marker from the web app
Setting up Leaflet.js in a Google Apps Script HTML Service
Leaflet.js is one of the most popular open-source mapping libraries. It's light-weight, easy to use, and had great documentation. They support a ton of different map types, including "CRS.Simple", or Coordinate Reference System, which allows you to supply a background image.
Google Sheets Set Up
Start out by creating a sheet named map_pin with the following structure:
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; }
저장한 다음 배포를 클릭하고 웹 앱으로 게시하세요. 그런 다음 새 배포에 대한 링크를 열면 Leaflet.js가 뉴욕 지도를 표시하는 것을 볼 수 있습니다.
그럼 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으로 설정합니다.
저장을 클릭한 다음 배포>배포 테스트를 클릭하여 새 지도 유형을 확인하세요. 이제 배경 이미지가 있는 지도와 중앙에 마커가 표시됩니다.
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 }
다음 섹션의 HTML에서 더 쉽게 작업할 수 있도록 핀을 JSON으로 반환합니다.
이제 이 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}`); }); }); }
저장한 다음 테스트 배포를 엽니다. 이제 시트 데이터에서 마커가 생성되었습니다!
각 핀에는 해당 행의 제목이 포함된 팝업이 있습니다. 이 시점에서 핀을 드래그할 수 있지만 새 위치를 저장하는 기능이 여전히 필요합니다.
드래그 시 마커 위치 저장
새 위치를 저장하려면 클라이언트 측에서 이벤트를 캡처하는 HTML 함수와 서버 측 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; } } }
테스트 배포를 저장하고 새로 고칩니다. 이제 마커를 드래그하면 시트 업데이트가 표시됩니다!
새 포인트 추가
이제 기존 포인트를 이동할 수 있지만 새 포인트를 추가하는 것은 어떨까요? 이번에도 HTML과 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; }
한 번 더 저장하고 테스트 배포를 새로 고칩니다. 이제 빈 곳을 클릭하면 제목을 입력하고 새 마커를 저장할 수 있습니다!
마커 삭제
마지막으로 마커를 삭제하는 방법을 추가하여 지도 보기에서 완전한 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undress AI Tool
무료로 이미지를 벗다

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Stock Market GPT
더 현명한 결정을 위한 AI 기반 투자 연구

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

CSS 속성 선택기를 통해 JavaScript의 데이터 속성을 사용하여 요소를 선택하고 문서를 사용하여 문서를 사용하여이를 달성하십시오. 1. [data-attribute]를 사용하여 지정된 데이터 속성 (모든 값)이있는 요소를 선택하십시오. 2. [data-attribute = "value"]를 사용하여 속성 값이 정확히 일치하는 요소를 선택하십시오. 3. Data-User-ID가 DataSet.userId에 해당하는 Element.Dataset을 통해 데이터 속성에 액세스하십시오.

이 기사는 동적 데이터 중심 테스트를 위해 pytest 및 selenium을 사용할 때 런타임에 생성 된 데이터를 직접 처리 할 수없는 @pytest.mark.mark.martrize 데코레이터가 직접 처리 할 수없는 문제를 해결하는 것을 목표로합니다. 우리는 pytest.mark.marketrize의 한계를 탐구하고 Pytest의 pytest_generate_tests 후크 기능을 통해 Selenium 동적 데이터 수집을 기반으로 매개 변수화 된 테스트를 우아하게 구현하는 방법을 자세히 소개하여 테스트 사례의 유연성과 효율성을 보장합니다.

이 기사는 JQuery 팝업 창에서 외부 링크 리디렉션 버튼을 리디렉션하는 문제를 해결하는 것을 목표로합니다. 사용자가 여러 외부 링크를 연속적으로 클릭하면 팝업의 점프 버튼이 항상 첫 번째 클릭 링크를 가리킬 수 있습니다. 핵심 솔루션은 OFF ( 'Click') 메소드를 사용하여 새 이벤트의 각 바인딩 전에 이전 이벤트 핸들러를 취소하여 점프 동작이 항상 최신 대상 URL을 가리키므로 정확하고 제어 가능한 링크 리디렉션을 달성하는 것입니다.

이 기사는 JavaScript를 사용하여 정확한 타이밍 카운터를 구축하는 방법에 대해 자세히 설명합니다. 카운터는 분에 한 번 증가하지만 사전 설정 근무일 (월요일 ~ 금요일)과 근무 시간 (예 : 오전 6시에서 오후 8시) 이내에 만 운행됩니다. 작동하지 않는 시간에는 증가를 일시 중지 할 수 있지만 현재 값을 표시하고 매월 첫날에 자동으로 재설정하여 계산 로직의 정확성과 유연성을 보장합니다.

이 기사는 JavaScript를 사용하여 이미지를 클릭하는 효과를 얻는 방법을 소개합니다. 핵심 아이디어는 HTML5의 데이터-* 속성을 사용하여 대체 이미지 경로를 저장하고 JavaScript를 통해 클릭 이벤트를 듣고 SRC 속성을 동적으로 전환하여 이미지 전환을 실현하는 것입니다. 이 기사는 일반적으로 사용되는 대화식 효과를 이해하고 마스터하는 데 도움이되는 자세한 코드 예제 및 설명을 제공합니다.

이 기사에서는 JavaScript 스크립트가 웹 개발에서 DOM 요소를 생성하기 전에로드 및 실행될 때 JavaScript 스크립트에 효과적으로 액세스하고 조작 할 수있는 방법을 살펴 봅니다. 우리는 세 가지 핵심 전략을 소개합니다. 기능 반환 값을 통해 요소 참조를 직접 통과시키고, 모듈 간 통신을 달성하기 위해 사용자 정의 이벤트를 사용하고, 돌연변이 관상 서버를 사용하여 DOM 구조 변경을 듣습니다. 이러한 방법을 사용하면 개발자가 JavaScript 실행 타이밍과 동적 컨텐츠로드 사이의 과제를 해결할 수 있도록하여 스크립트가 드래그 가능하게 만드는 등 후속 추가 요소를 올바르게 작동시킬 수 있습니다.

ES2023은 JavaScript의 성숙한 진화를 나타내는 여러 가지 실용적인 업데이트를 도입했습니다. 1.array.prototype.findlast () 및 FindlastIndex () 메소드는 배열 끝에서 검색을 지원하여 로그 처리 효율성 또는 구성의 효율성을 향상시킵니다. 2. Hashbang Syntax (#!/usr/bin/envnode)는 JavaScript 파일을 UNIX와 같은 시스템에서 직접 실행할 수 있습니다. 3.Error.cause는 오류 체인을 지원하여 예외 디버깅 기능을 향상시킵니다. 4. 약점 및 세트의 사양은 교차 엔진 일관성을 향상시킨다. 앞으로 데코레이터 (단계 3), 레코드 및 튜플 (
