import os from flask import Flask, send_file, abort, Response, url_for import folium from folium import plugins from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler import json import time import re from threading import Thread, Lock # Flask 服务 app = Flask(__name__, static_folder='static') tile_dir = os.path.join(os.path.dirname(__file__), "tiles") kml_dir = os.path.join(os.path.dirname(__file__), "kml") # KML文件目录 # 确保KML目录存在 os.makedirs(kml_dir, exist_ok=True) # 用于存储文件变化事件的队列 file_changes = [] changes_lock = Lock() def extract_tile_coords(filepath): """从文件路径中提取瓦片坐标信息""" # 匹配形如 tiles/19/123_456.png 的路径 pattern = r'tiles/(\d+)/(\d+)_(\d+)\.png$' match = re.search(pattern, filepath) if match: z = int(match.group(1)) x = int(match.group(2)) y = int(match.group(3)) return {'z': z, 'x': x, 'y': y} return None class TileHandler(FileSystemEventHandler): def on_any_event(self, event): if event.is_directory: return if event.src_path.endswith('.png'): coords = extract_tile_coords(event.src_path) if coords: with changes_lock: file_changes.append({ 'coords': coords, 'time': time.time() }) # 只保留最近100个变化 if len(file_changes) > 100: file_changes.pop(0) # 启动文件监控 observer = Observer() observer.schedule(TileHandler(), tile_dir, recursive=True) observer.start() @app.route('/tiles//.png') def serve_tile(z, x_y): """提供瓦片图片服务""" print(f"请求瓦片:层级={z}, 文件名={x_y}.png") filename = f"{x_y}.png" filepath = os.path.join(tile_dir, str(z), filename) if os.path.exists(filepath): return send_file(filepath) else: abort(404) @app.route('/check_changes') def check_changes(): """检查文件变化""" with changes_lock: changes = file_changes.copy() file_changes.clear() return json.dumps(changes) @app.route('/kml/') def serve_kml(filename): """提供KML文件服务""" filepath = os.path.join(kml_dir, filename) if os.path.exists(filepath): try: with open(filepath, 'r', encoding='utf-8') as f: kml_content = f.read() return Response(kml_content, mimetype='application/vnd.google-earth.kml+xml') except Exception as e: print(f"处理KML文件 {filename} 时出错: {str(e)}") abort(500) else: abort(404) @app.route('/') def index(): """显示地图页面""" # 创建地图 m = folium.Map( location=[30.253729, 114.453506], # 武汉市中心坐标 zoom_start=19, min_zoom=1, max_zoom=23, tiles=None, # 禁用默认图层 control_scale=True # 显示比例尺 ) # 添加在线瓦片图层 folium.TileLayer( tiles='https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', attr='Google Maps', name='谷歌地图', min_zoom=1, max_zoom=20, ).add_to(m) # folium.TileLayer( # tiles='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', # attr='OpenStreetMap', # name='OpenStreetMap', # min_zoom=1, # max_zoom=19, # ).add_to(m) # folium.TileLayer( # tiles='https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', # attr='OpenTopoMap', # name='OpenTopoMap', # min_zoom=1, # max_zoom=17, # ).add_to(m) # 添加自定义瓦片层 folium.TileLayer( tiles='http://localhost:5000/tiles/{z}/{x}_{y}.png', attr='高德瓦片服务', min_zoom=1, max_zoom=23, maxNativeZoom=19, minNativeZoom=19, name='本地瓦片', ).add_to(m) # 添加KML文件 # kml_files = [f for f in os.listdir(kml_dir) if f.endswith('.kml')] # for kml_file in kml_files: # kml_url = url_for('serve_kml', filename=kml_file) # try: # plugins.Kml( # kml_url, # name=kml_file, # show=True, # overlay=True # ).add_to(m) # except Exception as e: # print(f"加载KML文件 {kml_file} 时出错: {str(e)}") # 添加控件 plugins.Fullscreen().add_to(m) # 全屏控件 plugins.MousePosition().add_to(m) # 鼠标位置显示 folium.LayerControl().add_to(m) # 添加图层控制 # 添加自定义JavaScript m.get_root().html.add_child(folium.Element(f""" """)) # 返回地图HTML return m._repr_html_() if __name__ == "__main__": try: app.run(port=5000, debug=True) finally: observer.stop() observer.join()