Created
March 21, 2026 20:54
-
-
Save SaturnXIII/905acc166ce54ddcd3a97bb2358fb484 to your computer and use it in GitHub Desktop.
ARCGIS MARKER TOOL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * ╔══════════════════════════════════════════════════════════════════════════════╗ | |
| * ║ ARCGIS MARKER TOOL v4.0 ║ | |
| * ║ Script pour ajouter des marqueurs sur ArcGIS Instant Media ║ | |
| * ║ ║ | |
| * ║ SHIFT+CLIC pour ajouter un marqueur ║ | |
| * ║ Conversion automatique Lambert93 → WGS84 pour Google Maps ║ | |
| * ╚══════════════════════════════════════════════════════════════════════════════╝ | |
| * | |
| * UTILISATION: | |
| * 1. Ouvrir https://www.arcgis.com/apps/instant/media/index.html?appid=59873b0b206e4aefae712dc2cdda200c | |
| * 2. Ouvrir les DevTools (F12) → Console | |
| * 3. Copier-coller ce script entier et appuyer sur Entrée | |
| * 4. SHIFT+CLIQUER sur la carte pour ajouter un marqueur | |
| */ | |
| (async function() { | |
| 'use strict'; | |
| // Polyfills pour tanh et atanh | |
| Math.tanh = Math.tanh || function(x) { | |
| if(x === Infinity) return 1; | |
| if(x === -Infinity) return -1; | |
| return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x)); | |
| }; | |
| Math.atanh = Math.atanh || function(x) { | |
| return Math.log((1+x)/(1-x)) / 2; | |
| }; | |
| // Charger proj4js pour conversion précise | |
| if (typeof proj4 === 'undefined') { | |
| console.log('⏳ Chargement de proj4js...'); | |
| await new Promise((resolve, reject) => { | |
| const script = document.createElement('script'); | |
| script.src = 'https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.9.2/proj4.min.js'; | |
| script.onload = resolve; | |
| script.onerror = reject; | |
| document.head.appendChild(script); | |
| }); | |
| // Définir Lambert 93 manuellement | |
| proj4.defs('EPSG:2154', '+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +units=m +no_defs'); | |
| console.log('✓ proj4js chargé avec EPSG:2154'); | |
| } | |
| console.log('%c🗺️ ArcGIS Marker Tool v4.0 - Chargement...', 'color: #0079C1; font-size: 16px; font-weight: bold;'); | |
| const CONFIG = { | |
| markerSize: 14, | |
| markerOutlineColor: [255, 255, 255], | |
| markerOutlineWidth: 2 | |
| }; | |
| let state = { | |
| markers: [], | |
| markerCount: 0, | |
| viewElement: null, | |
| view: null, | |
| isInitialized: false, | |
| dblclickHandler: null, | |
| rightClickHandler: null, | |
| spatialReference: null | |
| }; | |
| // ═══════════════════════════════════════════════════════════════════════════════ | |
| // CONVERSION LAMBERT 93 → WGS84 | |
| // Utilise proj4js pour conversion précise | |
| // ═══════════════════════════════════════════════════════════════════════════════ | |
| const CoordinateConverter = { | |
| lambert93ToWGS84(x, y) { | |
| if (typeof proj4 !== 'undefined') { | |
| const result = proj4('EPSG:2154', 'WGS84', [x, y]); | |
| return { lat: result[1], lng: result[0] }; | |
| } | |
| // Fallback: approximation simple pour la France | |
| // Paris: Lambert93 (656672, 6861882) → WGS84 (48.8566, 2.3522) | |
| // Facteurs approximatifs | |
| const factX = 0.0000365; | |
| const factY = 0.000063; | |
| const offsetX = 2.3; | |
| const offsetY = 48.0; | |
| return { | |
| lat: (y - 6850000) * factY + offsetY, | |
| lng: (x - 655000) * factX + offsetX | |
| }; | |
| }, | |
| convert(x, y, sr) { | |
| if (Math.abs(y) <= 90 && Math.abs(x) <= 180) { | |
| return { lat: y, lng: x }; | |
| } | |
| if (sr === 2154 || sr === 102110 || sr === 32631 || sr === 32632) { | |
| return this.lambert93ToWGS84(x, y); | |
| } | |
| if (x > 100000 || y > 1000000) { | |
| return this.lambert93ToWGS84(x, y); | |
| } | |
| return { lat: y, lng: x }; | |
| } | |
| }; | |
| const Utils = { | |
| formatCoord(num, decimals = 6) { | |
| if (num === null || num === undefined || isNaN(num)) return null; | |
| return Number(num.toFixed(decimals)); | |
| }, | |
| generateId() { | |
| return `marker_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; | |
| }, | |
| getRandomColor() { | |
| const hue = Math.floor(Math.random() * 360); | |
| const saturation = 70 + Math.floor(Math.random() * 30); | |
| const lightness = 45 + Math.floor(Math.random() * 20); | |
| s = saturation / 100; l = lightness / 100; | |
| const a = s * Math.min(l, 1 - l); | |
| const f = n => { | |
| const k = (n + hue / 30) % 12; | |
| return l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); | |
| }; | |
| return [Math.round(f(0) * 255), Math.round(f(8) * 255), Math.round(f(4) * 255)]; | |
| }, | |
| googleMapsUrl(lat, lng) { | |
| return `https://www.google.com/maps?q=${lat},${lng}`; | |
| } | |
| }; | |
| const UI = { | |
| panel: null, | |
| createPanel() { | |
| this.removePanel(); | |
| const panel = document.createElement('div'); | |
| panel.id = 'arcgis-marker-panel'; | |
| panel.innerHTML = ` | |
| <style> | |
| #arcgis-marker-panel { | |
| position: fixed; top: 10px; right: 10px; width: 280px; | |
| background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); | |
| border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,0.4); | |
| font-family: 'Segoe UI', sans-serif; z-index: 2147483647; | |
| overflow: visible; color: #e0e0e0; | |
| border: 1px solid rgba(0,122,193,0.3); max-height: 80vh; | |
| display: flex; flex-direction: column; | |
| } | |
| #arcgis-marker-panel .panel-header { | |
| background: linear-gradient(90deg, #0079C1 0%, #005a87 100%); | |
| padding: 10px 12px; display: flex; align-items: center; | |
| justify-content: space-between; cursor: move; | |
| } | |
| #arcgis-marker-panel .panel-title { | |
| font-size: 12px; font-weight: 600; color: white; | |
| } | |
| #arcgis-marker-panel .panel-close { | |
| background: rgba(255,255,255,0.2); border: none; color: white; | |
| width: 20px; height: 20px; border-radius: 50%; cursor: pointer; | |
| font-size: 11px; | |
| } | |
| #arcgis-marker-panel .panel-body { padding: 10px; overflow-y: auto; flex: 1; } | |
| #arcgis-marker-panel .stats-row { | |
| display: flex; justify-content: space-around; padding: 8px; | |
| background: rgba(0,122,193,0.15); border-radius: 6px; margin-bottom: 8px; | |
| } | |
| #arcgis-marker-panel .stat-value { font-size: 16px; font-weight: 700; color: #00d4ff; } | |
| #arcgis-marker-panel .stat-label { font-size: 8px; text-transform: uppercase; color: #888; } | |
| #arcgis-marker-panel .coords-display { | |
| background: rgba(0,0,0,0.3); border-radius: 6px; padding: 8px; | |
| margin-bottom: 8px; font-family: monospace; font-size: 11px; min-height: 45px; | |
| } | |
| #arcgis-marker-panel .coord-value { color: #00ff88; line-height: 1.4; } | |
| #arcgis-marker-panel .coord-empty { color: #666; font-style: italic; font-size: 10px; } | |
| #arcgis-marker-panel .marker-list { max-height: 100px; overflow-y: auto; margin-bottom: 8px; } | |
| #arcgis-marker-panel .marker-item { | |
| display: flex; align-items: center; padding: 5px 6px; | |
| background: rgba(255,255,255,0.05); border-radius: 4px; | |
| margin-bottom: 4px; font-size: 10px; gap: 6px; | |
| } | |
| #arcgis-marker-panel .marker-color { width: 10px; height: 10px; border-radius: 50%; } | |
| #arcgis-marker-panel .marker-coords { color: #00d4ff; font-family: monospace; flex: 1; } | |
| #arcgis-marker-panel .marker-link { | |
| background: #4285F4; border: none; color: white; | |
| width: 16px; height: 16px; border-radius: 3px; cursor: pointer; | |
| font-size: 9px; opacity: 0; text-decoration: none; | |
| display: flex; align-items: center; justify-content: center; | |
| } | |
| #arcgis-marker-panel .marker-item:hover .marker-delete, | |
| #arcgis-marker-panel .marker-item:hover .marker-link { opacity: 1; } | |
| #arcgis-marker-panel .btn-group { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 5px; margin-bottom: 5px; } | |
| #arcgis-marker-panel .btn { pointer-events: auto !important; } | |
| #arcgis-marker-panel .full-width { width: 100%; margin-bottom: 8px; } | |
| #arcgis-marker-panel .gmap-link { | |
| display: flex; align-items: center; justify-content: center; gap: 6px; | |
| padding: 8px; margin-bottom: 8px; | |
| background: #4285F4; color: white; border: none; | |
| border-radius: 6px; font-size: 11px; cursor: pointer; | |
| text-decoration: none; transition: all 0.2s; | |
| } | |
| #arcgis-marker-panel .gmap-link:hover { background: #3367D6; transform: scale(1.02); } | |
| #arcgis-marker-panel .gmap-link::before { content: '🗺️'; } | |
| #arcgis-marker-panel .btn { | |
| padding: 7px 8px; border: none; border-radius: 4px; | |
| font-size: 10px; cursor: pointer; transition: all 0.2s; | |
| } | |
| #arcgis-marker-panel .btn-primary { background: #0079C1; color: white; } | |
| #arcgis-marker-panel .btn-success { background: #34c759; color: white; } | |
| #arcgis-marker-panel .btn-danger { background: #ff3b30; color: white; } | |
| #arcgis-marker-panel .btn-secondary { background: rgba(255,255,255,0.1); color: #ccc; } | |
| #arcgis-marker-panel .btn:hover { transform: scale(1.02); } | |
| #arcgis-marker-panel .instructions { | |
| margin-top: 8px; padding: 6px; | |
| background: rgba(255,193,7,0.1); border: 1px solid rgba(255,193,7,0.3); | |
| border-radius: 4px; font-size: 9px; color: #ffc107; line-height: 1.4; | |
| } | |
| #arcgis-marker-panel .toast { | |
| position: fixed; bottom: 20px; right: 20px; background: #333; | |
| color: white; padding: 8px 14px; border-radius: 5px; | |
| font-size: 11px; z-index: 1000000; animation: slideIn 0.3s ease; | |
| } | |
| #arcgis-marker-panel .toast.success { background: #34c759; } | |
| @keyframes slideIn { | |
| from { transform: translateX(100%); opacity: 0; } | |
| to { transform: translateX(0); opacity: 1; } | |
| } | |
| </style> | |
| <div class="panel-header"> | |
| <div class="panel-title">📍 Marker Tool v3</div> | |
| <button class="panel-close">✕</button> | |
| </div> | |
| <div class="panel-body"> | |
| <div class="stats-row"> | |
| <div class="stat-item"> | |
| <div class="stat-value" id="marker-count">0</div> | |
| <div class="stat-label">Marqueurs</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-value" id="marker-index">-</div> | |
| <div class="stat-label">Dernier</div> | |
| </div> | |
| </div> | |
| <div class="coords-display"> | |
| <div class="coord-value" id="last-coords"> | |
| <span class="coord-empty">SHIFT+CLIQUEZ sur la carte</span> | |
| </div> | |
| </div> | |
| <a class="gmap-link" id="gmap-link" href="#" target="_blank" style="display: none;"> | |
| Ouvrir dans Google Maps | |
| </a> | |
| <div class="marker-list" id="marker-list"></div> | |
| <div class="btn-group"> | |
| <button class="btn btn-primary" id="btn-copy-json">📋 JSON</button> | |
| <button class="btn btn-success" id="btn-copy-csv">📊 CSV</button> | |
| <button class="btn btn-secondary" id="btn-undo">↩️ Undo</button> | |
| </div> | |
| <button class="btn btn-danger full-width" id="btn-clear-all">🗑️ Effacer tout</button> | |
| <div class="instructions"> | |
| ⚠️ <strong>SHIFT+CLIC</strong> pour ajouter un marqueur | |
| </div> | |
| </div> | |
| `; | |
| document.body.appendChild(panel); | |
| this.panel = panel; | |
| this.makeDraggable(panel, panel.querySelector('.panel-header')); | |
| this.attachEvents(); | |
| }, | |
| makeDraggable(panel, handle) { | |
| let isDragging = false, startX, startY, startLeft, startTop; | |
| handle.addEventListener('mousedown', (e) => { | |
| if (e.target.classList.contains('panel-close')) return; | |
| isDragging = true; | |
| startX = e.clientX; startY = e.clientY; | |
| startLeft = panel.offsetLeft; startTop = panel.offsetTop; | |
| panel.style.right = 'auto'; | |
| }); | |
| document.addEventListener('mousemove', (e) => { | |
| if (!isDragging) return; | |
| panel.style.left = (startLeft + e.clientX - startX) + 'px'; | |
| panel.style.top = (startTop + e.clientY - startY) + 'px'; | |
| }); | |
| document.addEventListener('mouseup', () => { isDragging = false; }); | |
| }, | |
| attachEvents() { | |
| const panel = this.panel; | |
| panel.querySelector('.panel-close').addEventListener('click', () => { | |
| this.removePanel(); | |
| MarkerTool.deactivate(); | |
| }); | |
| panel.querySelector('#btn-copy-json').addEventListener('click', () => { | |
| const json = JSON.stringify(state.markers.map(m => ({ | |
| lat: m.lat, lng: m.lng, name: m.name, timestamp: m.timestamp | |
| })), null, 2); | |
| navigator.clipboard.writeText(json).then(() => this.showToast('JSON copié !', 'success')); | |
| }); | |
| panel.querySelector('#btn-copy-csv').addEventListener('click', () => { | |
| const csv = ['lat,lng,name,timestamp', ...state.markers.map(m => | |
| `${m.lat},${m.lng},"${m.name}",${m.timestamp}` | |
| )].join('\n'); | |
| navigator.clipboard.writeText(csv).then(() => this.showToast('CSV copié !', 'success')); | |
| }); | |
| panel.querySelector('#btn-undo').addEventListener('click', () => MarkerTool.removeLastMarker()); | |
| panel.querySelector('#btn-clear-all').addEventListener('click', () => { | |
| if (state.markers.length > 0) { | |
| MarkerTool.clearAllMarkers(); | |
| this.showToast('Effacé !', 'success'); | |
| } | |
| }); | |
| }, | |
| updateMarkerList() { | |
| const list = this.panel?.querySelector('#marker-list'); | |
| if (!list) return; | |
| list.innerHTML = state.markers.map((marker, index) => { | |
| const gmapUrl = Utils.googleMapsUrl(marker.lat, marker.lng); | |
| return ` | |
| <div class="marker-item"> | |
| <div class="marker-color" style="background: rgb(${marker.color.join(',')})"></div> | |
| <span style="color:#888">#${index + 1}</span> | |
| <span class="marker-coords">${marker.lat?.toFixed(5) || '?'}, ${marker.lng?.toFixed(5) || '?'}</span> | |
| <a class="marker-link" href="${gmapUrl}" target="_blank" title="Google Maps">G</a> | |
| <button class="marker-delete" data-index="${index}">✕</button> | |
| </div> | |
| `; | |
| }).join(''); | |
| list.querySelectorAll('.marker-delete').forEach(btn => { | |
| btn.addEventListener('click', (e) => { | |
| MarkerTool.removeMarker(parseInt(e.target.dataset.index)); | |
| }); | |
| }); | |
| }, | |
| updateStats() { | |
| if (!this.panel) return; | |
| this.panel.querySelector('#marker-count').textContent = state.markers.length; | |
| this.panel.querySelector('#marker-index').textContent = state.markers.length || '-'; | |
| }, | |
| updateLastCoords(lat, lng) { | |
| if (!this.panel) return; | |
| const el = this.panel.querySelector('#last-coords'); | |
| el.innerHTML = `<strong>Lat:</strong> ${lat?.toFixed(6) || '?'} <strong>Lng:</strong> ${lng?.toFixed(6) || '?'}`; | |
| const gmapLink = this.panel.querySelector('#gmap-link'); | |
| if (gmapLink && lat && lng) { | |
| gmapLink.href = `https://www.google.com/maps?q=${lat},${lng}`; | |
| gmapLink.style.display = 'flex'; | |
| } | |
| }, | |
| showToast(message, type = '') { | |
| const toast = document.createElement('div'); | |
| toast.className = `toast ${type}`; | |
| toast.textContent = message; | |
| document.body.appendChild(toast); | |
| setTimeout(() => toast.remove(), 2000); | |
| }, | |
| removePanel() { | |
| document.getElementById('arcgis-marker-panel')?.remove(); | |
| this.panel = null; | |
| } | |
| }; | |
| const MarkerTool = { | |
| async init() { | |
| try { | |
| console.log('⏳ Initialisation...'); | |
| state.viewElement = document.querySelector('arcgis-map'); | |
| if (!state.viewElement) { | |
| throw new Error('arcgis-map non trouvé'); | |
| } | |
| await state.viewElement.viewOnReady(); | |
| state.view = state.viewElement.view; | |
| if (!state.view) { | |
| throw new Error('View non initialisée'); | |
| } | |
| // Détecter le système de référence spatial | |
| state.spatialReference = state.view.spatialReference?.wkid || state.view.spatialReference?.latestWkid || null; | |
| console.log('✓ Carte prête'); | |
| console.log(' View type:', state.view.type || 'unknown'); | |
| console.log(' Spatial Reference:', state.spatialReference || 'unknown'); | |
| this.attachEventListeners(); | |
| UI.createPanel(); | |
| state.isInitialized = true; | |
| console.log('%c✅ ArcGIS Marker Tool v4.0 prêt !', 'color: #34c759; font-weight: bold;'); | |
| console.log('%c💡 SHIFT+CLIC sur la carte pour ajouter un marqueur', 'color: #ffc107;'); | |
| return true; | |
| } catch (error) { | |
| console.error('❌ Erreur:', error); | |
| return false; | |
| } | |
| }, | |
| attachEventListeners() { | |
| this.deactivate(); | |
| // SHIFT+CLIC pour ajouter un marqueur | |
| state.dblclickHandler = async (event) => { | |
| if (event.target.closest('#arcgis-marker-panel')) return; | |
| if (!event.shiftKey) return; // Nécessite Shift | |
| event.preventDefault(); | |
| event.stopPropagation(); | |
| try { | |
| const rect = state.viewElement.getBoundingClientRect(); | |
| const x = event.clientX - rect.left; | |
| const y = event.clientY - rect.top; | |
| console.log('📍 SHIFT+CLIC détecté à:', x.toFixed(0), y.toFixed(0)); | |
| let mapPoint = null; | |
| // Méthode 1: view.toMap | |
| if (state.view.toMap) { | |
| try { | |
| mapPoint = await state.view.toMap({ x, y }); | |
| console.log(' toMap result:', mapPoint); | |
| } catch (e) { | |
| console.log(' toMap échoué:', e.message); | |
| } | |
| } | |
| // Méthode 2: view.hitTest | |
| if (!mapPoint && state.view.hitTest) { | |
| try { | |
| const hit = await state.view.hitTest({ x: event.clientX, y: event.clientY }); | |
| console.log(' hitTest result:', hit); | |
| if (hit?.results?.length > 0 && hit.results[0].graphic?.geometry) { | |
| mapPoint = hit.results[0].graphic.geometry; | |
| } | |
| } catch (e) { | |
| console.log(' hitTest échoué:', e.message); | |
| } | |
| } | |
| // Méthode 3: view.screenToMap (API ancienne) | |
| if (!mapPoint && state.view.screenToMap) { | |
| try { | |
| mapPoint = state.view.screenToMap({ x, y }); | |
| console.log(' screenToMap result:', mapPoint); | |
| } catch (e) { | |
| console.log(' screenToMap échoué:', e.message); | |
| } | |
| } | |
| // Extraire les coordonnées brutes | |
| let rawX = null, rawY = null; | |
| if (mapPoint) { | |
| // Différentes propriétés possibles selon le type de vue | |
| rawX = mapPoint.longitude ?? mapPoint.x ?? mapPoint.xmin ?? mapPoint.x; | |
| rawY = mapPoint.latitude ?? mapPoint.y ?? mapPoint.ymin ?? mapPoint.y; | |
| console.log(' Coordonnées brutes - x:', rawX, 'y:', rawY); | |
| console.log(' SR:', state.spatialReference); | |
| } | |
| // Vérifier validité | |
| if (rawX === null || isNaN(rawX) || rawY === null || isNaN(rawY)) { | |
| console.log('⚠️ Coordonnées invalides'); | |
| UI.showToast('Coordonnées invalides', ''); | |
| return; | |
| } | |
| // Convertir si nécessaire (Lambert93/UTM → WGS84) | |
| const coords = CoordinateConverter.convert(rawX, rawY, state.spatialReference); | |
| const lng = Utils.formatCoord(coords.lng); | |
| const lat = Utils.formatCoord(coords.lat); | |
| console.log('✅ Coordonnées WGS84 - lat:', lat, 'lng:', lng); | |
| console.log('🔗 Google Maps: ' + Utils.googleMapsUrl(lat, lng)); | |
| UI.updateLastCoords(lat, lng); | |
| const markerNumber = state.markers.length + 1; | |
| const color = Utils.getRandomColor(); | |
| const graphic = { | |
| geometry: { type: 'point', longitude: lng, latitude: lat }, | |
| symbol: { | |
| type: 'simple-marker', | |
| color: color, | |
| size: CONFIG.markerSize, | |
| outline: { color: CONFIG.markerOutlineColor, width: CONFIG.markerOutlineWidth } | |
| } | |
| }; | |
| state.view.graphics.add(graphic); | |
| state.markers.push({ | |
| id: Utils.generateId(), lat, lng, | |
| name: `Point #${markerNumber}`, | |
| color, timestamp: new Date().toISOString(), graphic | |
| }); | |
| state.markerCount = markerNumber; | |
| UI.updateStats(); | |
| UI.updateMarkerList(); | |
| console.log(`📍 Marqueur #${markerNumber} ajouté: [${lat}, ${lng}]`); | |
| } catch (error) { | |
| console.error('❌ Erreur ajout marqueur:', error); | |
| UI.showToast('Erreur: ' + error.message, ''); | |
| } | |
| }; | |
| // Clic droit pour voir les coordonnées | |
| state.rightClickHandler = async (event) => { | |
| event.preventDefault(); | |
| const rect = state.viewElement.getBoundingClientRect(); | |
| const x = event.clientX - rect.left; | |
| const y = event.clientY - rect.top; | |
| try { | |
| let mapPoint = null; | |
| if (state.view.toMap) { | |
| mapPoint = await state.view.toMap({ x, y }); | |
| } else if (state.view.screenToMap) { | |
| mapPoint = state.view.screenToMap({ x, y }); | |
| } | |
| if (mapPoint) { | |
| const rawX = mapPoint.longitude ?? mapPoint.x; | |
| const rawY = mapPoint.latitude ?? mapPoint.y; | |
| if (rawX && rawY) { | |
| const coords = CoordinateConverter.convert(rawX, rawY, state.spatialReference); | |
| const lng = coords.lng.toFixed(6); | |
| const lat = coords.lat.toFixed(6); | |
| console.log('%c📍 Coordonnées:%c lat: %c' + lat + '%c, lng: %c' + lng, | |
| 'color: #888;', 'color: #888;', 'color: #00ff88;', 'color: #888;', 'color: #00ff88;'); | |
| console.log('%c🔗 Google Maps: %c' + Utils.googleMapsUrl(coords.lat, coords.lng), | |
| 'color: #888;', 'color: #4285F4;'); | |
| UI.updateLastCoords(coords.lat, coords.lng); | |
| UI.showToast(`Lat: ${lat}, Lng: ${lng}`, 'success'); | |
| } | |
| } | |
| } catch (error) { | |
| console.error('Erreur coordonnées:', error); | |
| } | |
| }; | |
| // Attacher sur l'élément map et le canvas | |
| state.viewElement.addEventListener('click', state.dblclickHandler); | |
| state.viewElement.addEventListener('contextmenu', state.rightClickHandler); | |
| const canvas = state.viewElement.querySelector('canvas'); | |
| if (canvas) { | |
| canvas.addEventListener('click', state.dblclickHandler); | |
| canvas.addEventListener('contextmenu', state.rightClickHandler); | |
| console.log('✓ Canvas trouvé, événements attachés dessus aussi'); | |
| } | |
| console.log('✓ Événements attachés (click+shift, contextmenu)'); | |
| }, | |
| removeLastMarker() { | |
| if (state.markers.length === 0) return; | |
| const last = state.markers.pop(); | |
| state.view.graphics.remove(last.graphic); | |
| state.markerCount = state.markers.length; | |
| UI.updateStats(); | |
| UI.updateMarkerList(); | |
| }, | |
| removeMarker(index) { | |
| if (index < 0 || index >= state.markers.length) return; | |
| const marker = state.markers[index]; | |
| state.view.graphics.remove(marker.graphic); | |
| state.markers.splice(index, 1); | |
| UI.updateStats(); | |
| UI.updateMarkerList(); | |
| }, | |
| clearAllMarkers() { | |
| state.markers.forEach(m => state.view.graphics.remove(m.graphic)); | |
| state.markers = []; | |
| state.markerCount = 0; | |
| UI.updateStats(); | |
| UI.updateMarkerList(); | |
| }, | |
| getMarkers() { | |
| return state.markers.map(m => ({ | |
| lat: m.lat, lng: m.lng, name: m.name, timestamp: m.timestamp | |
| })); | |
| }, | |
| exportJSON() { | |
| return JSON.stringify(this.getMarkers(), null, 2); | |
| }, | |
| exportCSV() { | |
| return ['lat,lng,name,timestamp', ...state.markers.map(m => | |
| `${m.lat},${m.lng},"${m.name}",${m.timestamp}` | |
| )].join('\n'); | |
| }, | |
| deactivate() { | |
| if (state.viewElement) { | |
| state.viewElement.removeEventListener('dblclick', state.dblclickHandler); | |
| state.viewElement.removeEventListener('contextmenu', state.rightClickHandler); | |
| const canvas = state.viewElement.querySelector('canvas'); | |
| if (canvas) { | |
| canvas.removeEventListener('dblclick', state.dblclickHandler); | |
| canvas.removeEventListener('contextmenu', state.rightClickHandler); | |
| } | |
| } | |
| state.dblclickHandler = null; | |
| state.rightClickHandler = null; | |
| } | |
| }; | |
| window.MarkerTool = MarkerTool; | |
| await MarkerTool.init(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment