Cache parsed GPX/FIT GeoJSON to fix large POI-export loads
CI / check (push) Successful in 42s
CI / deploy (push) Successful in 14s

A several-thousand-waypoint park4night area export re-parses the
whole file with REXML on every toggle — ~2.4s for a 5k-waypoint/3.6MB
sample, so tens of seconds for a 50k-waypoint one, likely the actual
cause behind a "Could not load" report on a 41.5MB export. MapLibre
already clusters the waypoint layer client-side, so the bottleneck was
never rendering — cache the GeoJSON conversion alongside the source
file (invalidated by mtime) instead of a bigger bbox/tiling rework.
This commit is contained in:
randy committed 2026-09-07 22:21:00 +02:00
1 parent b6a9c1546e
commit ddf2ee4990
4 files changed
+94 -9

No files matched your search

+27 -1
View File
@@ -1,4 +1,5 @@
require "fileutils"
require "json"
require_relative "gpx"
require_relative "fit"
@@ -58,6 +59,7 @@ module Maptool
raise Errno::ENOENT, path unless File.file?(path)
File.delete(path)
File.delete(geojson_cache_path(path)) if File.file?(geojson_cache_path(path))
end
def delete_folder(relative_path)
@@ -79,10 +81,30 @@ module Maptool
dest_dir = resolve_dir(to_folder.to_s)
FileUtils.mkdir_p(dest_dir)
name = unique_filename(dest_dir, File.basename(source))
FileUtils.mv(source, File.join(dest_dir, name))
dest = File.join(dest_dir, name)
FileUtils.mv(source, dest)
FileUtils.mv(geojson_cache_path(source), geojson_cache_path(dest)) if File.file?(geojson_cache_path(source))
to_folder.to_s.empty? ? name : "#{to_folder}/#{name}"
end
# The GeoJSON conversion (Gpx.to_geojson/Fit.to_geojson) re-parses the
# whole file with REXML every call — fine for a small track, but a
# several-thousand-waypoint POI export (e.g. a park4night area export)
# can take tens of seconds, every single time the file is toggled
# visible. Cached alongside the source file and invalidated by mtime,
# so only the first read after a save (or edit) pays that cost.
def geojson(relative_path)
path = resolve_file(relative_path)
raise Errno::ENOENT, path unless File.file?(path)
cache = geojson_cache_path(path)
if !File.file?(cache) || File.mtime(cache) < File.mtime(path)
data = path.downcase.end_with?(".fit") ? Fit.to_geojson(path) : Gpx.to_geojson(path)
File.write(cache, JSON.generate(data))
end
File.read(cache)
end
private
def resolve_dir(folder)
@@ -96,6 +118,10 @@ module Maptool
path == @root || path.start_with?(@root + File::SEPARATOR)
end
def geojson_cache_path(path)
"#{path}.geojson"
end
TRACK_EXTENSIONS = %w[.gpx .fit].freeze
def safe_filename(filename)