source: OpenWorkouts-current/ow/static/js/ow.js @ 56caf3d

currentfeature/docs
Last change on this file since 56caf3d was 56caf3d, checked in by Borja Lopez <borja@…>, 5 years ago

Fix calls to d3.json() in both weekly and monthly charts in the dashboard
and profile pages.

We were missing a setting telling d3 to keep along the authentication
cookie when doing ajax calls.

  • Property mode set to 100644
File size: 14.3 KB
Line 
1
2/*
3
4  OpenWorkouts Javascript code
5
6*/
7
8
9// Namespace
10var owjs = {};
11
12
13owjs.map = function(spec) {
14
15    "use strict";
16
17    // parameters provided when creating an "instance" of a map
18    var map_id = spec.map_id;
19    var latitude = spec.latitude;
20    var longitude = spec.longitude;
21    var zoom = spec.zoom;
22    var gpx_url = spec.gpx_url;
23    var start_icon = spec.start_icon;
24    var end_icon = spec.end_icon;
25    var shadow = spec.shadow;
26    var elevation = spec.elevation;
27    var zoom_control = spec.zoom_control;
28
29    // OpenStreetMap urls and references
30    var openstreetmap_url = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
31    var openstreetmap_attr = 'Map data &copy; <a href="http://www.osm.org">OpenStreetMap</a>';
32
33    // Some vars reused through the code
34    var map;
35    var gpx;
36    var elevation;
37
38    var create_map = function create_map(latitude, longitude, zoom) {
39        /* Create a Leaflet map, set center point and add tiles */
40        map = L.map(map_id, {zoomControl: zoom_control});
41        map.setView([latitude, longitude], zoom);
42        var tile_layer = L.tileLayer(openstreetmap_url, {
43            attribution: openstreetmap_attr
44        });
45        tile_layer.addTo(map);
46    };
47
48    var add_elevation_chart = function add_elevation_chart() {
49        /*
50           Add the elevation chart support to the map.
51           This has to be called *after* create_map and *before* load_gpx.
52        */
53
54        elevation = L.control.elevation({
55            position: "bottomright",
56            theme: "openworkouts-theme",
57            useHeightIndicator: true, //if false a marker is drawn at map position
58            interpolation: d3.curveLinear,
59            elevationDiv: "#elevation",
60            detachedView: true,
61            responsiveView: true,
62            gpxOptions: {
63                async: true,
64                marker_options: {
65                    startIconUrl: null,
66                    endIconUrl: null,
67                    shadowUrl: null,
68                },
69                polyline_options: {
70                    color: '#EE4056',
71                    opacity: 0.75,
72                    weight: 5,
73                    lineCap: 'round'
74                },
75            },
76        });
77        elevation.loadGPX(map, gpx_url);
78        // var ele_container = elevation.addTo(map);
79    };
80
81    var load_gpx = function load_gpx(gpx_url) {
82        /*
83          Load the gpx from the given url, add it to the map and feed it to the
84          elevation chart
85        */
86        var gpx = new L.GPX(gpx_url, {
87            async: true,
88            marker_options: {
89                startIconUrl: start_icon,
90                endIconUrl: end_icon,
91                shadowUrl: shadow,
92            },
93            polyline_options: {
94                color: '#EE4056',
95                opacity: 0.75,
96                weight: 5,
97                lineCap: 'round'
98            },
99        });
100
101        gpx.on('loaded', function(e) {
102            map.fitBounds(e.target.getBounds());
103        });
104
105        if (elevation) {
106            gpx.on("addline",function(e){
107                elevation.addData(e.line);
108            });
109        };
110
111        gpx.addTo(map);
112    };
113
114    var render = function render() {
115        // create the map, add elevation, load gpx (only if needed, as the
116        // elevation plugin already loads the gpx data)
117        create_map(latitude, longitude, zoom);
118        if (elevation) {
119            add_elevation_chart();
120        }
121        else {
122            load_gpx(gpx_url);
123        }
124    };
125
126    var that = {}
127    that.render = render;
128    return that
129
130};
131
132
133owjs.week_chart = function(spec) {
134
135    "use strict";
136
137    // parameters provided when creating an "instance" of the chart
138    var chart_selector = spec.chart_selector,
139        url = spec.url,
140        current_day_name = spec.current_day_name
141
142    // Helpers
143    function select_x_axis_label(d) {
144        /* Given a value, return the label associated with it */
145        return d3.select('.x-axis')
146            .selectAll('text')
147            .filter(function(x) { return x == d.name; });
148    }
149
150    // Methods
151    var render = function render() {
152        /*
153           Build a d3 bar chart, populated with data from the given url.
154         */
155        var chart = d3.select(chart_selector),
156            margin = {top: 17, right: 0, bottom: 20, left: 0},
157
158            width = +chart.attr("width") - margin.left - margin.right,
159            height = +chart.attr("height") - margin.top - margin.bottom,
160            g = chart.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"),
161            x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
162            y = d3.scaleLinear().rangeRound([height, 0]);
163
164        d3.json(url, {credentials: "same-origin"}).then(function (data) {
165            x.domain(data.map(function (d) {
166                return d.name;
167            }));
168
169            y.domain([0, d3.max(data, function (d) {
170                return Number(d.distance);
171            })]);
172
173            g.append("g")
174                .attr('class', 'x-axis')
175                .attr("transform", "translate(0," + height + ")")
176                .call(d3.axisBottom(x))
177
178            g.selectAll(".bar")
179                .data(data)
180                .enter().append("rect")
181                .attr("class", function(d) {
182                    if (d.name == current_day_name){
183                        select_x_axis_label(d).attr('style', "font-weight: bold;");
184                        return 'bar current'
185                    }
186                    else {
187                        return 'bar'
188                    }
189                })
190                .attr("x", function (d) {
191                    return x(d.name);
192                })
193                .attr("y", function (d) {
194                    return y(Number(d.distance));
195                })
196                .attr("width", x.bandwidth())
197                .attr("height", function (d) {
198                    return height - y(Number(d.distance));
199                })
200                .on('mouseover', function(d) {
201                    if (d.name != current_day_name){
202                        select_x_axis_label(d).attr('style', "font-weight: bold;");
203                    }
204                })
205                .on('mouseout', function(d) {
206                    if (d.name != current_day_name){
207                        select_x_axis_label(d).attr('style', "font-weight: regular;");
208                    }
209                });
210
211            g.selectAll(".text")
212                .data(data)
213                .enter()
214                .append("text")
215                .attr("class","label")
216                .attr("x", function (d) {
217                    return x(d.name) + x.bandwidth()/2;
218                })
219                .attr("y", function (d) {
220                    /*
221                      Get the value for the current bar, then get the maximum
222                      value to be displayed in the bar, which is used to
223                      calculate the proper position of the label for this bar,
224                      relatively to its height (1% above the bar)
225                     */
226                    var max = y.domain()[1];
227                    return y(d.distance + y.domain()[1] * 0.02);
228            })
229                .text(function(d) {
230                    if (Number(d.distance) > 0) {
231                        return d.distance;
232                    }
233                });
234
235        });
236    };
237
238    var that = {}
239    that.render = render;
240    return that
241
242};
243
244
245owjs.year_chart = function(spec) {
246
247    "use strict";
248
249    // parameters provided when creating an "instance" of the chart
250    var chart_selector = spec.chart_selector,
251        filters_selector = spec.filters_selector,
252        switcher_selector = spec.switcher_selector,
253        is_active_class = spec.is_active_class,
254        is_active_selector = '.' + is_active_class,
255        urls = spec.urls,
256        current_month = spec.current_month,
257        current_week = spec.current_week,
258        y_axis_labels = spec.y_axis_labels,
259        filter_by = spec.filter_by,
260        url = spec.url;
261
262    // Helpers
263    function select_x_axis_label(d) {
264        /* Given a value, return the label associated with it */
265        return d3.select('.x-axis-b')
266            .selectAll('text')
267            .filter(function(x) { return x == d.name; });
268    };
269
270    function get_y_value(d, filter_by) {
271        return Number(d[filter_by]);
272    };
273
274    function get_y_axis_label(filter_by) {
275        return y_axis_labels[filter_by];
276    };
277
278    function get_name_for_x(d) {
279        if (d.week == undefined || d.week == 0) {
280            return d.name;
281        }
282        else {
283            return d.id.split('-')[2];
284        }
285    }
286
287    // Methods
288    var filters_setup = function filters_setup() {
289        $(filters_selector).on('click', function(e) {
290            e.preventDefault();
291            $(filters_selector + is_active_selector).removeClass(is_active_class);
292            /* $(this).removeClass('is-active'); */
293            filter_by = $(this).attr('class').split('-')[1]
294            $(this).addClass(is_active_class);
295            var chart = d3.select(chart_selector);
296            chart.selectAll("*").remove();
297            render(filter_by, url);
298
299        });
300    };
301
302    var switcher_setup = function switcher_setup() {
303        $(switcher_selector).on('click', function(e) {
304            e.preventDefault();
305            $(switcher_selector + is_active_selector).removeClass(is_active_class);
306            url = $(this).attr('class').split('-')[1]
307            $(this).addClass(is_active_class);
308            var chart = d3.select(chart_selector);
309            chart.selectAll("*").remove();
310            render(filter_by, url);
311        });
312    };
313
314    var render = function render(filter_by, url) {
315        /*
316          Build a d3 bar chart, populated with data from the given url.
317        */
318        var chart = d3.select(chart_selector),
319            margin = {top: 20, right: 20, bottom: 30, left: 50},
320            width = +chart.attr("width") - margin.left - margin.right,
321            height = +chart.attr("height") - margin.top - margin.bottom,
322            g = chart.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"),
323            x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
324            y = d3.scaleLinear().rangeRound([height, 0]);
325
326        d3.json(urls[url], {credentials: "same-origin"}).then(function (data) {
327            x.domain(data.map(function (d) {
328                return get_name_for_x(d);
329                // return d.name;
330            }));
331
332            y.domain([0, d3.max(data, function (d) {
333                return get_y_value(d, filter_by);
334            })]);
335
336            g.append("g")
337                .attr('class', 'x-axis-b')
338                .attr("transform", "translate(0," + height + ")")
339                .call(d3.axisBottom(x))
340
341            g.append("g")
342                .call(d3.axisLeft(y))
343                .append("text")
344                .attr("fill", "#000")
345                .attr("transform", "rotate(-90)")
346                .attr("y", 6)
347                .attr("dy", "0.71em")
348                .attr("text-anchor", "end")
349                .text(get_y_axis_label(filter_by));
350
351            g.selectAll(".bar")
352                .data(data)
353                .enter().append("rect")
354                .attr("class", function(d) {
355                    var sel_week = current_month + '-' + current_week;
356                    if (d.id == current_month || d.id == sel_week){
357                        /* Bar for the currently selected month or week */
358                        select_x_axis_label(d).attr('style', "font-weight: bold;");
359                        return 'bar current';
360                    }
361                    else {
362                        if (!current_week && d.id.indexOf(current_month) >=0 ) {
363                            /*
364                               User selected a month, then switched to weekly
365                               view, we do highlight all the bars for weeks in
366                               that month
367                            */
368                            select_x_axis_label(d).attr('style', "font-weight: bold;");
369                            return 'bar current';
370                        }
371                        else {
372                            /* Non-selected bar */
373                            return 'bar';
374                        }
375
376                    }
377                })
378                .attr("x", function (d) {
379                    return x(get_name_for_x(d));
380                })
381                .attr("y", function (d) {
382                    return y(get_y_value(d, filter_by));
383                })
384                .attr("width", x.bandwidth())
385                .attr("height", function (d) {
386                    return height - y(get_y_value(d, filter_by));
387                })
388                .on('mouseover', function(d) {
389                    if (d.id != current_month){
390                        select_x_axis_label(d).attr('style', "font-weight: bold;");
391                    }
392                })
393                .on('mouseout', function(d) {
394                    if (d.id != current_month){
395                        select_x_axis_label(d).attr('style', "font-weight: regular;");
396                    }
397                })
398                .on('click', function(d) {
399                    window.location.href = d.url;
400                });
401
402            if (url == 'monthly') {
403                g.selectAll(".text")
404                    .data(data)
405                    .enter()
406                    .append("text")
407                    .attr("class","label")
408                    .attr("x", function (d) {
409                        return x(get_name_for_x(d)) + x.bandwidth()/2;
410                    })
411                    .attr("y", function (d) {
412                        /*
413                          Get the value for the current bar, then get the maximum
414                          value to be displayed in the bar, which is used to
415                          calculate the proper position of the label for this bar,
416                          relatively to its height (1% above the bar)
417                        */
418                        var value = get_y_value(d, filter_by);
419                        var max = y.domain()[1];
420                        return y(value + y.domain()[1] * 0.01);
421                    })
422                    .text(function(d) {
423                        var value = get_y_value(d, filter_by)
424                        if ( value > 0) {
425                            return value;
426                        }
427                    });
428            }
429
430            if (url == 'weekly') {
431                g.selectAll(".tick")
432                    .each(function (d, i) {
433                        /*
434                          Remove from the x-axis tickets those without letters
435                          on them (useful for the weekly chart)
436                        */
437                        if (d !== parseInt(d, 10)) {
438                            if(!d.match(/[a-z]/i)) {
439                                this.remove();
440                            }
441                        }
442                    });
443            }
444        });
445    };
446
447    var that = {}
448    that.filters_setup = filters_setup;
449    that.switcher_setup = switcher_setup;
450    that.render = render;
451    return that
452
453};
Note: See TracBrowser for help on using the repository browser.