this repo has no description

widget-leaflet: add bbox drawing, image overlay, and marker commands

New commands:
- enableBboxDraw: custom rectangle drawing with bbox_drawn event
- addImageOverlay/removeImageOverlay: display data URL images on map
- addMarker/clearMarkers: circle markers with labels

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+63 -2
+63 -2
widget-leaflet/widget_leaflet.ml
··· 17 17 } 18 18 return { 19 19 create: function(container, config, send) { 20 - var state = { map: null, geojsonLayer: null }; 20 + var state = { map: null, geojsonLayer: null, bboxRect: null, bboxDrawing: false, imageOverlay: null, markers: [], _send: null }; 21 21 ensureCSS(CSS_URL); 22 22 ensureScript(JS_URL, function() { 23 23 var cfg = JSON.parse(config); ··· 41 41 })); 42 42 }); 43 43 state.map = map; 44 + state._send = send; 44 45 }); 45 46 return state; 46 47 }, ··· 51 52 }, 52 53 command: function(state, cmd, data) { 53 54 if (!state.map) return; 54 - var d = JSON.parse(data); 55 + var d = data ? JSON.parse(data) : {}; 55 56 if (cmd === "flyTo") state.map.flyTo(L.latLng(d.lat, d.lng), d.zoom || state.map.getZoom()); 56 57 else if (cmd === "fitBounds") state.map.fitBounds(d); 57 58 else if (cmd === "setData") { ··· 59 60 state.geojsonLayer = L.geoJSON(d).addTo(state.map); 60 61 } 61 62 else if (cmd === "invalidateSize") state.map.invalidateSize(); 63 + else if (cmd === "enableBboxDraw") { 64 + if (state.bboxDrawing) return; 65 + state.bboxDrawing = true; 66 + state.map.getContainer().style.cursor = "crosshair"; 67 + var startLatLng = null; 68 + var tempRect = null; 69 + function onMouseDown(e) { 70 + startLatLng = e.latlng; 71 + L.DomEvent.preventDefault(e.originalEvent); 72 + } 73 + function onMouseMove(e) { 74 + if (!startLatLng) return; 75 + var bounds = L.latLngBounds(startLatLng, e.latlng); 76 + if (tempRect) state.map.removeLayer(tempRect); 77 + tempRect = L.rectangle(bounds, {color: "#ff0000", weight: 2, dashArray: "5,5", fillOpacity: 0.1}).addTo(state.map); 78 + } 79 + function onMouseUp(e) { 80 + if (!startLatLng) return; 81 + var bounds = L.latLngBounds(startLatLng, e.latlng); 82 + if (tempRect) state.map.removeLayer(tempRect); 83 + if (state.bboxRect) state.map.removeLayer(state.bboxRect); 84 + state.bboxRect = L.rectangle(bounds, {color: "#2f7d31", weight: 2, fillOpacity: 0.15}).addTo(state.map); 85 + state._send("bbox_drawn", JSON.stringify({ 86 + south: bounds.getSouth(), west: bounds.getWest(), 87 + north: bounds.getNorth(), east: bounds.getEast() 88 + })); 89 + startLatLng = null; 90 + state.bboxDrawing = false; 91 + state.map.getContainer().style.cursor = ""; 92 + state.map.off("mousedown", onMouseDown); 93 + state.map.off("mousemove", onMouseMove); 94 + state.map.off("mouseup", onMouseUp); 95 + state.map.dragging.enable(); 96 + } 97 + state.map.dragging.disable(); 98 + state.map.on("mousedown", onMouseDown); 99 + state.map.on("mousemove", onMouseMove); 100 + state.map.on("mouseup", onMouseUp); 101 + } 102 + else if (cmd === "addImageOverlay") { 103 + if (state.imageOverlay) state.map.removeLayer(state.imageOverlay); 104 + state.imageOverlay = L.imageOverlay(d.url, d.bounds, { 105 + opacity: d.opacity || 0.7 106 + }).addTo(state.map); 107 + } 108 + else if (cmd === "removeImageOverlay") { 109 + if (state.imageOverlay) { state.map.removeLayer(state.imageOverlay); state.imageOverlay = null; } 110 + } 111 + else if (cmd === "addMarker") { 112 + var marker = L.circleMarker(L.latLng(d.lat, d.lng), { 113 + radius: 6, color: d.color || "#ff0000", fillColor: d.color || "#ff0000", 114 + fillOpacity: 0.8, weight: 2 115 + }).addTo(state.map); 116 + if (d.label) marker.bindTooltip(d.label, {permanent: true, direction: "right", offset: [8, 0]}); 117 + state.markers.push(marker); 118 + } 119 + else if (cmd === "clearMarkers") { 120 + state.markers.forEach(function(m) { state.map.removeLayer(m); }); 121 + state.markers = []; 122 + } 62 123 }, 63 124 destroy: function(state) { if (state.map) state.map.remove(); } 64 125 };