I have made a Pull Request introduces a new functionality for the Train view: the ability to add custom charts based on HTML/JS source code, linked in real-time with the training telemetry.
With this feature, athletes are no longer limited to predefined charts or telemetry fields when training in GC. They can now design awesome, dynamic charts that react to live telemetry—such as histograms, maps, dials, and more. Even without extensive knowledge of HTML/JS, users can easily achieve great results by leveraging generic web design tools or AI-based HTML code generators.
For developers of html, the PR HTML Chart in train view documents its usage. It is nos complete, and until it is (hopefully) in GC binary, that documentation can be a starting point. Afterwards, GC wiki will have the documentation.
In this PR, Python charts for training and Web charts hability to use telemetry updates in training functionalities have not been included, for the sake of clarity of the PR and not mixing functionalities in the PR. It was initially presented with those charts included, but finally they where removed of the PR.
The HTML Chart provides a split-pane interface allowing users to write and preview their charts instantly:
Configuration and html code are stored along the rest of the tiles of a view in training.
HTML code of the charts could be uploaded to the cloud as well as python charts can, to be shared with other users.
Example CodeBelow is the default template code generated for any new HTML chart. It serves as a simple example of how to connect to the bridge, parse the telemetry payload, and update the UI in real-time:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="qrc:///qtwebchannel/qwebchannel.js"></script> <style>body{font-family:sans-serif;padding:12px;color:#333}</style> </head> <body> <h2>GC WebChannel</h2> <div>Speed: <b id="speed">0.0</b> km/h</div> <div>Power: <b id="power">0</b> W</div> <div>HR: <b id="hr">0</b> bpm</div> <div>Cadence: <b id="cad">0</b> rpm</div> <div>Distance: <b id="dist">0.00</b> km</div> <div>State: <b id="state">Stopped</b></div> <script> if (typeof QWebChannel !== 'undefined') { new QWebChannel(qt.webChannelTransport, function(channel) { window.gc = channel.objects.gc; if (window.gc.telemetry) { window.gc.telemetry.connect(function(payload) { var d = typeof payload === 'string' ? JSON.parse(payload) : payload; document.getElementById("speed").innerText = (d.speed_kmh || 0).toFixed(1); document.getElementById("power").innerText = Math.round(d.power_w || 0); document.getElementById("hr").innerText = Math.round(d.hr_bpm || 0); document.getElementById("cad").innerText = Math.round(d.cadence_rpm || 0); document.getElementById("dist").innerText = (d.distance_km || 0).toFixed(2); }); } if (window.gc.stateChanged) { window.gc.stateChanged.connect(function(state) { document.getElementById("state").innerText = state.toUpperCase(); }); } }); } </script> </body> </html> Tests and feedback from the usersAs said, anyone without html knowledge can potentially create html views, using AI, for example (that is may case).
There are no restrictions on creating, for example, a view similar to the one shown in this issue: Gauge view in train mode
, referenced in the PR.
Although in that case, we will need to extend the current configuration and telemetry data provided to html: workout text messages defined at specific times, target power of the current lap, duration of the workout and its full definition, etc; things that will be added in next deliveries if there is interest, I guess.
This functionality is not closed with this PR.
Therefore, I’d appreciate any feedback. Binaries will be available soon, Ale is launching a build.
I am attaching the two html charts that I am showing in the video.
Please note that they are not final versions nor official files. They were created to test behavior of the code during development. In fact, unfortunately, the code for the map is mostly in spanish (sorry for that), as it was a test.
In the header of the map code, there is a description of the current variables that can be used to model the behavior of the page, in the configuration section of the chart.
I am also adding them to the tests charts of the project (test/charts path of the project).

lo, Joachim, thanks for those files! I will have a look at them and will use them for my next html for sure.
In the meanwhile, this is the status of the additional data:
sec_msecs_remaining and erg_msecs_remaining have been fetched empirically. I do not understand very well tha naming of accessors/funtions/variables that keep track of them, although they behave as my purpose, the naming does not point to that… (this is open to your more experienced knowledge, and can be changed):
qint64 sec_msecs_remaining = rt.value(RealtimeData::DataSeries::ErgTimeRemaining); qint64 erg_msecs_remaining = rt.value(RealtimeData::DataSeries::LapTimeRemaining);Except target_power_w, sec_msecs_remaining and erg_msecs_remaining that have been tested with ERG workouts and seem ok for me, those additional data have not yet (only coded).
Today it is difficult to progress on this, but I will see.
Regarding performance I do not think it is an issue, in general terms, for the computer. The webchannel is like functions that are invoked and only get data, and events to synchronize calls; html could be hard to run, but if you are conscious of it it is not likely to happen; the first versions of the real time map I put as example needed more time to render than the telemetry events period, so it behaved wrongly: it was re loading all the map tiles, re building the elevations profile, etc. The AI was told to improve it and it did the magic, only updating the trace instead of replotting all, and since then it works smoothy without performance issues in an old laptop (Linux). But, as you say, we must be arare it has been done by AI without any responsability on my side :)
lo, Joachim, thanks for those files! I will have a look at them and will use them for my next html for sure.
- Configured font in config: I do not have a clear idea of this, too. Is there any configuration that can be fetched? Perhaps you mean specific configuration for the chart? In such case, you can add configuration variables at chart level using the interface
- Dark/Light mode: you say GCColor::isDark(GColor(CPLOTBACKGROUND)); and also there is TrainBottom::isDark(), hardcoded to GColor(CCHROME). What do you think is better? You coded both :)
- sec_msecs_remaining: current section milisecs remaining (erg file selected event)
- erg_msecs_remaining: workout milisecs remaining (erg file selected event)
- Workout section text: in progress (I am trying to fetch it and show on telemetry updates), with no success for the moment, but it cannot be difficult.
sec_msecs_remaining and erg_msecs_remaining have been fetched empirically. I do not understand very well tha naming of accessors/funtions/variables that keep track of them, although they behave as my purpose, the naming does not point to that… (this is open to your more experienced knowledge, and can be changed):
qint64 sec_msecs_remaining = rt.value(RealtimeData::DataSeries::ErgTimeRemaining); qint64 erg_msecs_remaining = rt.value(RealtimeData::DataSeries::LapTimeRemaining);

Today it is difficult to progress on this, but I will see.


