Git Product home page Git Product logo

rando-planner's Introduction

Clerk viewers and utils to plan bikepacking events

This repository contains extensions and custom viewers for Clojure's Clerk, designed to help bike tourists and ultra-cyclists to plan multi-day routes.

Traditional tools (Komoot, Strava, Cycle.travel, and so on…) focus on planning the route itself, in some cases (Komoot) providing extra tools to divide the route into multiple same-length days.

rando-planner assumes the user already have a GPX track defined (provided for example by the organizers of a bike event), and let the user plan the daily effort to a higher granularity.

After a data structure called plan is defined, rando-planner provides different types of visualization that can be used to study different strategies to cover the distance.

The visualizations include:

  • A map visualization (based on Leaflet) of the route, with markers corresponding to the location reached after each day is completed.
  • A schematic diagram of the plan, showing the running count of kilometers, the corresponding elevation reached at each moment, when scheduled pauses will happen, when the Sun rises and sets (WIP), and the total amount of kilometers accumulated every day

Usage

Add rando-planner as a dependency in your project. For example:

{:paths ["src"]
 :deps {org.clojure/clojure {:mvn/version "1.10.3"}
        rando-planner/rando-planner {:git/url "https://github.com/larsen/rando-planner.git"
                                     :git/tag "tagname"
                                     :git/sha "xxxxxxxx"}}}

Then, in a src/user.clj file:

(ns user)

(require '[nextjournal.clerk :as clerk])

(clerk/serve! {:watch-paths ["notebooks" "src"]})

When jacking-in the project a HTTP server should start, answering on port 7777. At this point you can start editing notebooks (I typically use the directory notebooks to store them) using the facilities provided by rando-planner.

Defining a plan

(def plan-start-19
  {:description "Starting on April 19th"
   :gpx "gpx/route.gpx"
   :average-speed 20
   :daily-plans [{:label "Day 1"
                  :date "2024-04-19"
                  :activities [{:start "15:00" :length 6 :type :ride}]}
                 {:label "Day 2"
                  :date "2024-04-20"
                  :activities [{:start "07:00" :length 5 :type :ride}
                               {:start "17:00" :length 3 :type :ride}]}
                 {:label "Day 3"
                  :date "2024-04-21"
                  :activities [{:start "08:00" :length 6 :type :ride}]}]})

Usage examples

The screenshots below were automatically generated using plan-start-19, as defined above.

Example: plan diagram

Example: route with markers on a map

rando-planner's People

Contributors

larsen avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

rando-planner's Issues

Display segments of the GPX track, as defined by the plan

The plan implicitly defines different segments of the GPX track. I mean those defined by the different :daily-plans in the plan definition. There should be a way to display these segments, for example with a different color.
This should be possible using leaflet-gpx line styling facility.
Another option could be to just split the GPX into multiple GPX tracks, according to start and end kilometers they should represent

Non-linear km progress function

At the moment kilometers in a day calculation is solely based on the average speed parameter provided by the user.
For example:

(defn kilometers-in-a-day [day-plan average-speed]
  (reduce + (map #(* (:length %) average-speed)
                 (filter #(= (:type %) :ride)
                         (:activities day-plan)))))

I should switch to a different structure that allows more flexibility.
For example, a generator of couples (hour, speed) instead of a constant average speed.
This way, one can produce different generator functions according to different models.
One model would be the existing constant average speed.
Another model could take into account the elevation to apply a <1 multiplier to the provided average speed.
Another model could use another parameter like the Watt expressed by the cyclist, to combine it with other parameters (some suggested "bumpiness")

Performance review

Calculating a diagram is slow. I suspect I am calling points (which reads and parse a XML file)`` too many times

Elevation diagram is displayed wrongly when used as a standalone chart

When used standalone

(let [elevation (gpx/elevation gpx-resource)]
  (clerk/html
   [:svg {:width 600 :height 200}
    (diagram/elevation-diagram {:elevation elevation
                                :from 0
                                :to 400
                                :viewbox [0 0 600 200]})]))

image

but, when used in a plan diagram

(clerk/html
 (diagram/plan->diagram plan-start-19))

image

For reference, here the elevation chart displayed by Komoot for the same GPX file

image

Automatically center the map usign the GPX data

leaflet/leaflet-gpx-viewer currently requires to specify a point to center the map.

(clerk/with-viewer leaflet/leaflet-gpx-viewer
  {:gpx "https://stefanorodighiero.net/misc/VG-2024_400k_lake_provvis.gpx"
   ;; :gpx-content gpx-content
   :center [45.478431 11.439041]
   :markers (plan/points-at-daily-kilometers
             gpx-resource
             plan-start-19)
   :zoom 9})

It should not be a task of the user

Allow simplified markers in the map

The popups placed on the maps require to specify a lot of information, and that information is directly in the code composing the map.

                                            (doseq [pp (:markers value)]
                                              (.bindPopup
                                               (.addTo (.marker js/L (clj->js [(:lat pp) (:lon pp)])) @m)
                                               (str "<small>"
                                                    "<strong>" (:label pp) "</strong>"
                                                    "<br />"
                                                    (.floor js/Math (:kilometers pp))
                                                    " km / ("
                                                    (.floor js/Math (:cumulative-distance pp))
                                                    " km) ▲ "
                                                    (.floor js/Math (:elevation pp))
                                                    "</small>")))))

It should be instead provided by the user, for example as a popup-message attribute.
This way markerts could be also used when not providing a plan.

Updating a plan in the editor when it's used in a map

When updating a plan (and saving the file) after loading the notebook for the first time, an error occurs:

image

More precisely, to reproduce:

  • in a notebook, bind (def) a plan to a symbol
  • use the plan with leaflet/leaflet-gpx-viewer
  • so far so good
  • but if you change the definition in the def expression, the error occurs
  • if the literal for the plan is instead passed directly to leaflet/leaflet-gpx-viewer, no error

The last point is surprising, because I thought it would have been the same, either updating a data definition, or updating directly the viewer invocation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.