source: OpenWorkouts-current/ow/static/js/ow.js @ 5f05e83

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

Replaced Leaflet.Elevation with a newer, improved version (fork of the original)

Done some clean-up of the map javascript code, removed old tests and WIP code
that is not needed anymore.

IMPORTANT: After pulling this patch, run js_deps to install the new version of
leaflet elevation:

./bin/js_deps

  • Property mode set to 100644
File size: 13.6 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        });
94
95        gpx.on('loaded', function(e) {
96            map.fitBounds(e.target.getBounds());
97        });
98
99        if (elevation) {
100            gpx.on("addline",function(e){
101                elevation.addData(e.line);
102            });
103        };
104
105        gpx.addTo(map);
106    };
107
108    var render = function render() {
109        // create the map, add elevation, load gpx
110        create_map(latitude, longitude, zoom);
111        if (elevation) {
112            add_elevation_chart();
113        }
114        // load_gpx(gpx_url);
115    };
116
117    var that = {}
118    that.render = render;
119    return that
120
121};
122
123
124owjs.week_chart = function(spec) {
125
126    "use strict";
127
128    // parameters provided when creating an "instance" of the chart
129    var chart_selector = spec.chart_selector,
130        url = spec.url,
131        current_day_name = spec.current_day_name
132
133    // Helpers
134    function select_x_axis_label(d) {
135        /* Given a value, return the label associated with it */
136        return d3.select('.x-axis')
137            .selectAll('text')
138            .filter(function(x) { return x == d.name; });
139    }
140
141    // Methods
142    var render = function render() {
143        /*
144           Build a d3 bar chart, populated with data from the given url.
145         */
146        var chart = d3.select(chart_selector),
147            margin = {top: 17, right: 0, bottom: 20, left: 0},
148
149            width = +chart.attr("width") - margin.left - margin.right,
150            height = +chart.attr("height") - margin.top - margin.bottom,
151            g = chart.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"),
152            x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
153            y = d3.scaleLinear().rangeRound([height, 0]);
154
155        d3.json(url).then(function (data) {
156            x.domain(data.map(function (d) {
157                return d.name;
158            }));
159
160            y.domain([0, d3.max(data, function (d) {
161                return Number(d.distance);
162            })]);
163
164            g.append("g")
165                .attr('class', 'x-axis')
166                .attr("transform", "translate(0," + height + ")")
167                .call(d3.axisBottom(x))
168
169            g.selectAll(".bar")
170                .data(data)
171                .enter().append("rect")
172                .attr("class", function(d) {
173                    if (d.name == current_day_name){
174                        select_x_axis_label(d).attr('style', "font-weight: bold;");
175                        return 'bar current'
176                    }
177                    else {
178                        return 'bar'
179                    }
180                })
181                .attr("x", function (d) {
182                    return x(d.name);
183                })
184                .attr("y", function (d) {
185                    return y(Number(d.distance));
186                })
187                .attr("width", x.bandwidth())
188                .attr("height", function (d) {
189                    return height - y(Number(d.distance));
190                })
191                .on('mouseover', function(d) {
192                    if (d.name != current_day_name){
193                        select_x_axis_label(d).attr('style', "font-weight: bold;");
194                    }
195                })
196                .on('mouseout', function(d) {
197                    if (d.name != current_day_name){
198                        select_x_axis_label(d).attr('style', "font-weight: regular;");
199                    }
200                });
201
202            g.selectAll(".text")
203                .data(data)
204                .enter()
205                .append("text")
206                .attr("class","label")
207                .attr("x", function (d) {
208                    return x(d.name) + x.bandwidth()/2;
209                })
210                .attr("y", function (d) {
211                    /*
212                      Get the value for the current bar, then get the maximum
213                      value to be displayed in the bar, which is used to
214                      calculate the proper position of the label for this bar,
215                      relatively to its height (1% above the bar)
216                     */
217                    var max = y.domain()[1];
218                    return y(d.distance + y.domain()[1] * 0.02);
219            })
220                .text(function(d) {
221                    if (Number(d.distance) > 0) {
222                        return d.distance;
223                    }
224                });
225
226        });
227    };
228
229    var that = {}
230    that.render = render;
231    return that
232
233};
234
235
236owjs.year_chart = function(spec) {
237
238    "use strict";
239
240    // parameters provided when creating an "instance" of the chart
241    var chart_selector = spec.chart_selector,
242        filters_selector = spec.filters_selector,
243        switcher_selector = spec.switcher_selector,
244        urls = spec.urls,
245        current_month = spec.current_month,
246        current_week = spec.current_week,
247        y_axis_labels = spec.y_axis_labels,
248        filter_by = spec.filter_by,
249        url = spec.url;
250
251    // Helpers
252    function select_x_axis_label(d) {
253        /* Given a value, return the label associated with it */
254        return d3.select('.x-axis-b')
255            .selectAll('text')
256            .filter(function(x) { return x == d.name; });
257    };
258
259    function get_y_value(d, filter_by) {
260        return Number(d[filter_by]);
261    };
262
263    function get_y_axis_label(filter_by) {
264        return y_axis_labels[filter_by];
265    };
266
267    function get_name_for_x(d) {
268        if (d.week == undefined || d.week == 0) {
269            return d.name;
270        }
271        else {
272            return d.id.split('-')[2];
273        }
274    }
275
276    // Methods
277    var filters_setup = function filters_setup() {
278        $(filters_selector).on('click', function(e) {
279            e.preventDefault();
280            filter_by = $(this).attr('class').split('-')[1]
281            var chart = d3.select(chart_selector);
282            chart.selectAll("*").remove();
283            render(filter_by, url);
284        });
285    };
286
287    var switcher_setup = function switcher_setup() {
288        $(switcher_selector).on('click', function(e) {
289            e.preventDefault();
290            url = $(this).attr('class').split('-')[1]
291            var chart = d3.select(chart_selector);
292            chart.selectAll("*").remove();
293            render(filter_by, url);
294        });
295    };
296
297    var render = function render(filter_by, url) {
298        /*
299          Build a d3 bar chart, populated with data from the given url.
300        */
301        var chart = d3.select(chart_selector),
302            margin = {top: 20, right: 20, bottom: 30, left: 50},
303            width = +chart.attr("width") - margin.left - margin.right,
304            height = +chart.attr("height") - margin.top - margin.bottom,
305            g = chart.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"),
306            x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
307            y = d3.scaleLinear().rangeRound([height, 0]);
308
309        d3.json(urls[url]).then(function (data) {
310            x.domain(data.map(function (d) {
311                return get_name_for_x(d);
312                // return d.name;
313            }));
314
315            y.domain([0, d3.max(data, function (d) {
316                return get_y_value(d, filter_by);
317            })]);
318
319            g.append("g")
320                .attr('class', 'x-axis-b')
321                .attr("transform", "translate(0," + height + ")")
322                .call(d3.axisBottom(x))
323
324            g.append("g")
325                .call(d3.axisLeft(y))
326                .append("text")
327                .attr("fill", "#000")
328                .attr("transform", "rotate(-90)")
329                .attr("y", 6)
330                .attr("dy", "0.71em")
331                .attr("text-anchor", "end")
332                .text(get_y_axis_label(filter_by));
333
334            g.selectAll(".bar")
335                .data(data)
336                .enter().append("rect")
337                .attr("class", function(d) {
338                    var sel_week = current_month + '-' + current_week;
339                    if (d.id == current_month || d.id == sel_week){
340                        /* Bar for the currently selected month or week */
341                        select_x_axis_label(d).attr('style', "font-weight: bold;");
342                        return 'bar current';
343                    }
344                    else {
345                        if (!current_week && d.id.indexOf(current_month) >=0 ) {
346                            /*
347                               User selected a month, then switched to weekly
348                               view, we do highlight all the bars for weeks in
349                               that month
350                            */
351                            select_x_axis_label(d).attr('style', "font-weight: bold;");
352                            return 'bar current';
353                        }
354                        else {
355                            /* Non-selected bar */
356                            return 'bar';
357                        }
358
359                    }
360                })
361                .attr("x", function (d) {
362                    return x(get_name_for_x(d));
363                })
364                .attr("y", function (d) {
365                    return y(get_y_value(d, filter_by));
366                })
367                .attr("width", x.bandwidth())
368                .attr("height", function (d) {
369                    return height - y(get_y_value(d, filter_by));
370                })
371                .on('mouseover', function(d) {
372                    if (d.id != current_month){
373                        select_x_axis_label(d).attr('style', "font-weight: bold;");
374                    }
375                })
376                .on('mouseout', function(d) {
377                    if (d.id != current_month){
378                        select_x_axis_label(d).attr('style', "font-weight: regular;");
379                    }
380                })
381                .on('click', function(d) {
382                    window.location.href = d.url;
383                });
384
385            if (url == 'monthly') {
386                g.selectAll(".text")
387                    .data(data)
388                    .enter()
389                    .append("text")
390                    .attr("class","label")
391                    .attr("x", function (d) {
392                        return x(get_name_for_x(d)) + x.bandwidth()/2;
393                    })
394                    .attr("y", function (d) {
395                        /*
396                          Get the value for the current bar, then get the maximum
397                          value to be displayed in the bar, which is used to
398                          calculate the proper position of the label for this bar,
399                          relatively to its height (1% above the bar)
400                        */
401                        var value = get_y_value(d, filter_by);
402                        var max = y.domain()[1];
403                        return y(value + y.domain()[1] * 0.01);
404                    })
405                    .text(function(d) {
406                        var value = get_y_value(d, filter_by)
407                        if ( value > 0) {
408                            return value;
409                        }
410                    });
411            }
412
413            if (url == 'weekly') {
414                g.selectAll(".tick")
415                    .each(function (d, i) {
416                        /*
417                          Remove from the x-axis tickets those without letters
418                          on them (useful for the weekly chart)
419                        */
420                        if (d !== parseInt(d, 10)) {
421                            if(!d.match(/[a-z]/i)) {
422                                this.remove();
423                            }
424                        }
425                    });
426            }
427        });
428    };
429
430    var that = {}
431    that.filters_setup = filters_setup;
432    that.switcher_setup = switcher_setup;
433    that.render = render;
434    return that
435
436};
Note: See TracBrowser for help on using the repository browser.