import streamlit as st import folium from streamlit_folium import folium_static import pyproj from folium.plugins import Draw, MousePosition import json st.set_page_config(layout="wide", page_title="BBoxFinder Clone") @st.cache_data def get_coordinate_systems(): return { "EPSG:4326": "WGS 84", "EPSG:3857": "Web Mercator", "EPSG:2056": "CH1903+ / LV95 (Swiss)", "EPSG:21781": "CH1903 / LV03 (Swiss)", "EPSG:2154": "RGF93 / Lambert-93 (France)", "EPSG:25832": "ETRS89 / UTM zone 32N (Germany)", } def convert_coordinates(bbox, from_crs, to_crs): transformer = pyproj.Transformer.from_crs(from_crs, to_crs, always_xy=True) min_x, min_y = transformer.transform(bbox[0], bbox[1]) max_x, max_y = transformer.transform(bbox[2], bbox[3]) return [min_x, min_y, max_x, max_y] # Styles CSS st.markdown(""" """, unsafe_allow_html=True) # Main layout st.markdown("### BBoxFinder Clone", unsafe_allow_html=True) col1, col2 = st.columns([4, 1]) with col1: # Map m = folium.Map(location=[46.8, 8.2], zoom_start=8, control_scale=True) # Add draw control draw = Draw( export=True, position='topleft', draw_options={ 'polyline': True, 'polygon': True, 'rectangle': True, 'circle': True, 'marker': True, 'circlemarker': True }, edit_options={'edit': True} ) draw.add_to(m) # Add mouse position control formatter = "function(num) {return L.Util.formatNum(num, 5);};" MousePosition( position='bottomleft', separator=' | ', empty_string='', lng_first=True, num_digits=5, prefix="Coordinates:", lat_formatter=formatter, lng_formatter=formatter, ).add_to(m) # JavaScript to handle drawing and coordinate updates m.get_root().html.add_child(folium.Element(""" """)) folium_static(m, width=800, height=600) with col2: st.markdown("### Coordinates") bbox_coords = st.text_input("", key="bbox_coords", label_visibility="collapsed") # CRS selection coordinate_systems = get_coordinate_systems() selected_crs = st.selectbox("Select Coordinate System", options=list(coordinate_systems.keys()), format_func=lambda x: f"{x} - {coordinate_systems[x]}") if bbox_coords: try: bbox = [float(coord.strip()) for coord in bbox_coords.split(',')] if len(bbox) == 4: st.markdown(f"**{selected_crs}**") converted_bbox = convert_coordinates(bbox, "EPSG:4326", selected_crs) result = f"{converted_bbox[0]:.5f},{converted_bbox[1]:.5f},{converted_bbox[2]:.5f},{converted_bbox[3]:.5f}" st.code(result, language="plaintext") if st.button(f"Copy {selected_crs}"): st.write(f"{selected_crs} coordinates copied!") # Display in other common CRSs st.markdown("**Other CRSs:**") for epsg, name in coordinate_systems.items(): if epsg != selected_crs: converted_bbox = convert_coordinates(bbox, "EPSG:4326", epsg) result = f"{converted_bbox[0]:.5f},{converted_bbox[1]:.5f},{converted_bbox[2]:.5f},{converted_bbox[3]:.5f}" st.code(f"{epsg}: {result}", language="plaintext") # Additional formats (GeoJSON, WKT) with st.expander("GeoJSON"): geojson = json.dumps({ "type": "Feature", "properties": {}, "geometry": { "type": "Polygon", "coordinates": [[ [bbox[0], bbox[1]], [bbox[2], bbox[1]], [bbox[2], bbox[3]], [bbox[0], bbox[3]], [bbox[0], bbox[1]] ]] } }, indent=2) st.code(geojson, language="json") if st.button("Copy GeoJSON"): st.write("GeoJSON copied!") with st.expander("WKT"): wkt = f"POLYGON(({bbox[0]} {bbox[1]}, {bbox[2]} {bbox[1]}, {bbox[2]} {bbox[3]}, {bbox[0]} {bbox[3]}, {bbox[0]} {bbox[1]}))" st.code(wkt, language="plaintext") if st.button("Copy WKT"): st.write("WKT copied!") else: st.error("Please enter 4 coordinates separated by commas.") except ValueError: st.error("Please enter valid coordinates (numbers separated by commas).") # Footer st.markdown("
Created with Streamlit - Inspired by bboxfinder.com
", unsafe_allow_html=True)