diff --git a/folium/plugins/timestamped_geo_json.py b/folium/plugins/timestamped_geo_json.py index 11d1deae63..44457666e7 100644 --- a/folium/plugins/timestamped_geo_json.py +++ b/folium/plugins/timestamped_geo_json.py @@ -47,6 +47,10 @@ class TimestampedGeoJson(JSCSSMixin, MacroElement): Used to construct the array of available times starting from the first available time. Format: ISO8601 Duration ex: 'P1M' 1/month, 'P1D' 1/day, 'PT1H' 1/hour, and 'PT1M' 1/minute + show_path: bool, default True + Whether to draw animated LineString paths. Set to False to animate + only the last-point markers when add_last_point=True. The source paths + are still used to determine timestamps and marker positions. duration: str, default None Period of time which the features will be shown on the map after their time has passed. If None, all previous times will be shown. @@ -131,6 +135,14 @@ class TimestampedGeoJson(JSCSSMixin, MacroElement): } }) + {% if not this.show_path %} + // Keep full source features for time indexing, but skip recreating + // their polylines in the animated frame layers. + geoJsonLayer.options.filter = function (feature) { + return feature.geometry.type !== "LineString"; + }; + {% endif %} + var {{this.get_name()}} = L.timeDimension.layer.geoJson( geoJsonLayer, { @@ -191,6 +203,7 @@ def __init__( time_slider_drag_update=False, duration=None, speed_slider=True, + show_path=True, ): super().__init__() self._name = "TimestampedGeoJson" @@ -205,6 +218,7 @@ def __init__( self.embed = False self.data = data self.add_last_point = bool(add_last_point) + self.show_path = bool(show_path) self.period = period self.date_options = date_options self.duration = "undefined" if duration is None else '"' + duration + '"' diff --git a/tests/plugins/test_timestamped_geo_json.py b/tests/plugins/test_timestamped_geo_json.py index 24ee9a12dc..9cbbeb052e 100644 --- a/tests/plugins/test_timestamped_geo_json.py +++ b/tests/plugins/test_timestamped_geo_json.py @@ -197,3 +197,44 @@ def test_timestamped_geo_json(): bounds = m.get_bounds() assert bounds == [[-53.0, -158.0], [50.0, 158.0]], bounds + + +def test_timestamped_geo_json_can_animate_markers_without_paths(): + data = { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": {"type": "LineString", "coordinates": [[1, 2], [3, 4]]}, + "properties": { + "times": [1435708800000, 1435795200000], + "icon": "marker", + }, + } + ], + } + + map_with_paths = folium.Map(location=[2, 1]) + plugins.TimestampedGeoJson(data).add_to(map_with_paths) + original = map_with_paths.get_root().render() + assert "geoJsonLayer.options.filter" not in original + + map_with_markers = folium.Map(location=[2, 1]) + plugin = plugins.TimestampedGeoJson( + data, + show_path=False, + add_last_point=True, + ).add_to(map_with_markers) + html = map_with_markers.get_root().render() + + # Initial GeoJSON must receive every LineString so it can index all times. + # The frame-layer filter is installed only afterwards, and suppresses + # creating a polyline while allowing the generated last-point marker. + initial_layer = html.index("var geoJsonLayer = L.geoJson(") + frame_filter = html.index("geoJsonLayer.options.filter = function") + animated_layer = html.index("L.timeDimension.layer.geoJson(") + assert initial_layer < frame_filter < animated_layer + assert 'feature.geometry.type !== "LineString"' in html + assert "addlastPoint: true" in html + assert '"coordinates": [[1, 2], [3, 4]]' in html + assert plugin.show_path is False