Workout journals are now officially published!
All of the basic features are working. I will keep doing small adjustments and adding new features in the following weeks.
For now, the workout journals can only be accessed by clicking the “Journal” tab in a workout routine page. I will add them across the pages later.
Update (11.6.2012): Now featuring some sample code of how the graph is built!
Hello!
I’ve seen your work with Flot framework (http://www.gymling.com/en/users/5-anssi/gym/workout-journals/12-workout-journal-example?u=kg) and it’s amazing! It’s even so beautiful, that I loved a lot your small legend which shows in the right bottom coner when we hover a point.
I am trying to make something similar with my project, so I was wondering if you could be so kind to provide me with a code snippet that realizes that function. Or maybe you’ve found some example whiche treats the same functionality?
Hi
I’m glad you like it!
That functionality is custom made. Here is the code that shows and hides the details box (plus modifies the table below the graph):
HTML:
JavaScript:
var workoutJournalGraph = { // ... hoveredItem: null, // listerPlotHover is the entry point and called every time the graph is rendered (e.g. on a page load or when the graph is reloaded with ajax) listerPlotHover: function() { $("#workoutJournalGraph").bind("plothover", function (event, pos, item) { if (item === null) { workoutJournalGraph.plotHoveringStopped(item); } else { workoutJournalGraph.hoveredItem = item; workoutJournalGraph.plotIsBeingHovered(item); } }); }, // When hovering stops, hide the details box and normalize fonts in the table plotHoveringStopped: function() { if($('#entryDetails').is(':visible')) { $('table tr td').css('font-weight', 'normal'); $('#entryDetails').hide(); } }, // When a dot is being hovered, highlight the table row in question and display the details box plotIsBeingHovered: function(item) { var workoutIndex = item.seriesIndex; var entryIndex = item.dataIndex; var tr = $($('.workoutJournalEntries')[workoutIndex]).find('tr')[entryIndex]; if (tr !== undefined && !$('#entryDetails').is(':visible')) { $('td', tr).css('font-weight', 'bold'); workoutJournalGraph.displayEntryDetails(tr); } }, // Populate the details box with the data in the table displayEntryDetails: function(tr) { var performedAt = '<span class="smallTip">' + $($(tr).find('td').get(0)).text() + '</span>'; var workDone = $($(tr).find('td').get(1)).text(); var difficultyOrRepsAndWeights = $($(tr).find('td').get(2)).text(); var separator = '<span class="crumbSeparator">|</span>'; var html = performedAt + separator + workDone + separator + difficultyOrRepsAndWeights; $('#entryDetails').html(html).show(); }, // Prevent details box from flickering when the box itself is being hovered and the dot is under it listenEntryDetailsHover: function() { $('#entryDetails').mouseenter(function() { var i = workoutJournalGraph.hoveredItem; workoutJournalGraph.plotIsBeingHovered({ seriesIndex: i.seriesIndex, dataIndex: i.dataIndex }); }); } // ... }Thanks a lot!
Just three questions.
How do you position that entryDetails div? Are you using css?
And I see that there is a variable workoutJournalGraph which contains many functions. What’s the type of this variable? I have never seen a structure like that before.
Where and how do you use the variable workoutJournalGraph?
Yes, I have positioned and styled it using the following css:
#entryDetails { padding: 5px; border: 1px solid #DDDDDD; position: absolute; right: 24px; top: 432px; background-color: white; opacity: 0.85; display: none; height: 16px; line-height: 1; } #entryDetails .crumbSeparator { position: relative; top: -1px; }That kind of structure is called Literal Notation (http://www.dyn-web.com/tutorials/obj_lit.php). In practice they are objects that contain variables and functions. I like to use them because the data is encapsulated inside the object and the global scope remains clean. These kind of objects are also easy to reuse.
I reference it in the jQuery document onload event like this:
$(document).ready(function() { if ($('#workoutJournalGraph').length) { workoutJournalGraph.init(); } });The init function contains function calls that will display the graph. It also contains calls to workoutJournalGraph.listerPlotHover() and workoutJournalGraph.listenEntryDetailsHover():
var workoutJournalGraph = { // ... init: function() { $.plot($("#workoutJournalGraph"), graphDataHere, graphOptionsHere); workoutJournalGraph.listerPlotHover(); workoutJournalGraph.listenEntryDetailsHover() // .... } // ... }And the HTML for the element that is selected like this $(“#workoutJournalGraph”) in the examples above is just an empty div:
Btw. if you want to learn more about different kinds of namespacing techniques, I suggest checking these links:
- http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/
- http://stackoverflow.com/questions/881515/javascript-namespace-declaration