├── .couchappignore
├── .couchapprc.dist
├── .gitignore
├── LICENSE
├── README.md
├── _attachments
├── config.json
├── error.html
├── images
│ ├── Cloudant_Icon_RGB.png
│ ├── ibm_cloudant_silver.ai
│ ├── ibm_cloudant_silver.png
│ ├── layers-2x.png
│ ├── layers.png
│ ├── location_tracker_appicon.png
│ ├── sprite.ai
│ ├── sprite.png
│ ├── world_map.ai
│ ├── world_map.png
│ ├── world_map_mask.ai
│ └── world_map_mask.png
├── index.html
├── map-result.html
├── savedata.html
├── script
│ ├── L.Control.Locate.min.js
│ ├── L.Control.Locate.min.js.map
│ ├── app.js
│ ├── images
│ │ ├── marker-icon-2x.png
│ │ ├── marker-icon-blue-2x.png
│ │ ├── marker-icon-blue.png
│ │ ├── marker-icon.png
│ │ └── marker-shadow.png
│ ├── leaflet-src.js
│ ├── leaflet.js
│ ├── pouchdb.min.js
│ ├── velocity.min.js
│ └── velocity.ui.min.js
├── style
│ ├── L.Control.Locate.min.css
│ ├── L.Control.Locate.min.css.map
│ ├── leaflet.css
│ ├── mapbox-style.less
│ └── style.css
├── success.html
├── tracking.html
└── welcome.html
├── _id
├── couchapp.json
├── language
└── tutorial
├── blog.adoc
├── graphics
├── map.png
├── map_sm.png
├── saving.png
├── saving_sm.png
├── success.png
├── success_sm.png
├── tracking.png
├── tracking_sm.png
├── welcome_button.png
└── welcome_button_sm.png
└── tutorial.adoc
/.couchappignore:
--------------------------------------------------------------------------------
1 | [
2 | // filenames matching these regexps will not be pushed to the database
3 | // uncomment to activate; separate entries with ","
4 | // ".*~$"
5 | // ".*\\.swp$"
6 | // ".*\\.bak$"
7 | ]
--------------------------------------------------------------------------------
/.couchapprc.dist:
--------------------------------------------------------------------------------
1 | # rename this file to .couchapprc and replace $USERNAME and $PASSWORD with real values
2 | {
3 | "env": {
4 | "local": {
5 | "db": "http://localhost:5984/locationtracker"
6 | },
7 | "remote": {
8 | "db": "http://$USERNAME:$PASSWORD@$USERNAME.cloudant.com/locationtracker"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .couchapprc
2 |
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 IBM
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Location Tracker Part 2: Angular.JS
2 | February, 2015
3 |
4 | ## Overview
5 |
6 | This is a tutorial on how to build a mobile app in HTML5, Javascript and Angular.JS that records a device’s location and saves the location data to IBM's Cloudant JSON database service. A simple mapping client using Leaflet is also described.
7 |
8 | ## Code
9 |
10 | The code for this tutorial is organized into a CouchApp (as described in the [tutorial](./tutorial)), so all the web files are in the [_attachments](./_attachments) directory.
11 |
12 | ## Tutorial
13 |
14 | An extensive tutorial describing the app may be found in the [tutorial](./tutorial) directory.
15 |
16 | ## License
17 |
18 | # location-tracker-angular
19 |
20 | [MIT](./LICENSE).
21 |
--------------------------------------------------------------------------------
/_attachments/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "vars": {
3 | "@gray-base": "#000",
4 | "@gray-darker": "lighten(@gray-base, 13.5%)",
5 | "@gray-dark": "lighten(@gray-base, 20%)",
6 | "@gray": "lighten(@gray-base, 33.5%)",
7 | "@gray-light": "lighten(@gray-base, 46.7%)",
8 | "@gray-lighter": "lighten(@gray-base, 93.5%)",
9 | "@brand-primary": "darken(#428bca, 6.5%)",
10 | "@brand-success": "#5cb85c",
11 | "@brand-info": "#5bc0de",
12 | "@brand-warning": "#f0ad4e",
13 | "@brand-danger": "#d9534f",
14 | "@body-bg": "#fff",
15 | "@text-color": "@gray-dark",
16 | "@link-color": "@brand-primary",
17 | "@link-hover-color": "darken(@link-color, 15%)",
18 | "@link-hover-decoration": "underline",
19 | "@font-family-sans-serif": "\"Helvetica Neue\", Helvetica, Arial, sans-serif",
20 | "@font-family-serif": "Georgia, \"Times New Roman\", Times, serif",
21 | "@font-family-monospace": "Menlo, Monaco, Consolas, \"Courier New\", monospace",
22 | "@font-family-base": "@font-family-sans-serif",
23 | "@font-size-base": "14px",
24 | "@font-size-large": "ceil((@font-size-base * 1.25))",
25 | "@font-size-small": "ceil((@font-size-base * 0.85))",
26 | "@font-size-h1": "floor((@font-size-base * 2.6))",
27 | "@font-size-h2": "floor((@font-size-base * 2.15))",
28 | "@font-size-h3": "ceil((@font-size-base * 1.7))",
29 | "@font-size-h4": "ceil((@font-size-base * 1.25))",
30 | "@font-size-h5": "@font-size-base",
31 | "@font-size-h6": "ceil((@font-size-base * 0.85))",
32 | "@line-height-base": "1.428571429",
33 | "@line-height-computed": "floor((@font-size-base * @line-height-base))",
34 | "@headings-font-family": "inherit",
35 | "@headings-font-weight": "500",
36 | "@headings-line-height": "1.1",
37 | "@headings-color": "inherit",
38 | "@icon-font-path": "\"../fonts/\"",
39 | "@icon-font-name": "\"glyphicons-halflings-regular\"",
40 | "@icon-font-svg-id": "\"glyphicons_halflingsregular\"",
41 | "@padding-base-vertical": "6px",
42 | "@padding-base-horizontal": "12px",
43 | "@padding-large-vertical": "10px",
44 | "@padding-large-horizontal": "16px",
45 | "@padding-small-vertical": "5px",
46 | "@padding-small-horizontal": "10px",
47 | "@padding-xs-vertical": "1px",
48 | "@padding-xs-horizontal": "5px",
49 | "@line-height-large": "1.33",
50 | "@line-height-small": "1.5",
51 | "@border-radius-base": "4px",
52 | "@border-radius-large": "6px",
53 | "@border-radius-small": "3px",
54 | "@component-active-color": "#fff",
55 | "@component-active-bg": "@brand-primary",
56 | "@caret-width-base": "4px",
57 | "@caret-width-large": "5px",
58 | "@table-cell-padding": "8px",
59 | "@table-condensed-cell-padding": "5px",
60 | "@table-bg": "transparent",
61 | "@table-bg-accent": "#f9f9f9",
62 | "@table-bg-hover": "#f5f5f5",
63 | "@table-bg-active": "@table-bg-hover",
64 | "@table-border-color": "#ddd",
65 | "@btn-font-weight": "normal",
66 | "@btn-default-color": "#333",
67 | "@btn-default-bg": "#fff",
68 | "@btn-default-border": "#ccc",
69 | "@btn-primary-color": "#fff",
70 | "@btn-primary-bg": "@brand-primary",
71 | "@btn-primary-border": "darken(@btn-primary-bg, 5%)",
72 | "@btn-success-color": "#fff",
73 | "@btn-success-bg": "@brand-success",
74 | "@btn-success-border": "darken(@btn-success-bg, 5%)",
75 | "@btn-info-color": "#fff",
76 | "@btn-info-bg": "@brand-info",
77 | "@btn-info-border": "darken(@btn-info-bg, 5%)",
78 | "@btn-warning-color": "#fff",
79 | "@btn-warning-bg": "@brand-warning",
80 | "@btn-warning-border": "darken(@btn-warning-bg, 5%)",
81 | "@btn-danger-color": "#fff",
82 | "@btn-danger-bg": "@brand-danger",
83 | "@btn-danger-border": "darken(@btn-danger-bg, 5%)",
84 | "@btn-link-disabled-color": "@gray-light",
85 | "@input-bg": "#fff",
86 | "@input-bg-disabled": "@gray-lighter",
87 | "@input-color": "@gray",
88 | "@input-border": "#ccc",
89 | "@input-border-radius": "@border-radius-base",
90 | "@input-border-radius-large": "@border-radius-large",
91 | "@input-border-radius-small": "@border-radius-small",
92 | "@input-border-focus": "#66afe9",
93 | "@input-color-placeholder": "#999",
94 | "@input-height-base": "(@line-height-computed + (@padding-base-vertical * 2) + 2)",
95 | "@input-height-large": "(ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2)",
96 | "@input-height-small": "(floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2)",
97 | "@legend-color": "@gray-dark",
98 | "@legend-border-color": "#e5e5e5",
99 | "@input-group-addon-bg": "@gray-lighter",
100 | "@input-group-addon-border-color": "@input-border",
101 | "@cursor-disabled": "not-allowed",
102 | "@dropdown-bg": "#fff",
103 | "@dropdown-border": "rgba(0,0,0,.15)",
104 | "@dropdown-fallback-border": "#ccc",
105 | "@dropdown-divider-bg": "#e5e5e5",
106 | "@dropdown-link-color": "@gray-dark",
107 | "@dropdown-link-hover-color": "darken(@gray-dark, 5%)",
108 | "@dropdown-link-hover-bg": "#f5f5f5",
109 | "@dropdown-link-active-color": "@component-active-color",
110 | "@dropdown-link-active-bg": "@component-active-bg",
111 | "@dropdown-link-disabled-color": "@gray-light",
112 | "@dropdown-header-color": "@gray-light",
113 | "@dropdown-caret-color": "#000",
114 | "@screen-xs": "480px",
115 | "@screen-xs-min": "@screen-xs",
116 | "@screen-phone": "@screen-xs-min",
117 | "@screen-sm": "768px",
118 | "@screen-sm-min": "@screen-sm",
119 | "@screen-tablet": "@screen-sm-min",
120 | "@screen-md": "992px",
121 | "@screen-md-min": "@screen-md",
122 | "@screen-desktop": "@screen-md-min",
123 | "@screen-lg": "1200px",
124 | "@screen-lg-min": "@screen-lg",
125 | "@screen-lg-desktop": "@screen-lg-min",
126 | "@screen-xs-max": "(@screen-sm-min - 1)",
127 | "@screen-sm-max": "(@screen-md-min - 1)",
128 | "@screen-md-max": "(@screen-lg-min - 1)",
129 | "@grid-columns": "12",
130 | "@grid-gutter-width": "30px",
131 | "@grid-float-breakpoint": "@screen-sm-min",
132 | "@grid-float-breakpoint-max": "(@grid-float-breakpoint - 1)",
133 | "@container-tablet": "(720px + @grid-gutter-width)",
134 | "@container-sm": "@container-tablet",
135 | "@container-desktop": "(940px + @grid-gutter-width)",
136 | "@container-md": "@container-desktop",
137 | "@container-large-desktop": "(1140px + @grid-gutter-width)",
138 | "@container-lg": "@container-large-desktop",
139 | "@navbar-height": "50px",
140 | "@navbar-margin-bottom": "@line-height-computed",
141 | "@navbar-border-radius": "@border-radius-base",
142 | "@navbar-padding-horizontal": "floor((@grid-gutter-width / 2))",
143 | "@navbar-padding-vertical": "((@navbar-height - @line-height-computed) / 2)",
144 | "@navbar-collapse-max-height": "340px",
145 | "@navbar-default-color": "#777",
146 | "@navbar-default-bg": "#f8f8f8",
147 | "@navbar-default-border": "darken(@navbar-default-bg, 6.5%)",
148 | "@navbar-default-link-color": "#777",
149 | "@navbar-default-link-hover-color": "#333",
150 | "@navbar-default-link-hover-bg": "transparent",
151 | "@navbar-default-link-active-color": "#555",
152 | "@navbar-default-link-active-bg": "darken(@navbar-default-bg, 6.5%)",
153 | "@navbar-default-link-disabled-color": "#ccc",
154 | "@navbar-default-link-disabled-bg": "transparent",
155 | "@navbar-default-brand-color": "@navbar-default-link-color",
156 | "@navbar-default-brand-hover-color": "darken(@navbar-default-brand-color, 10%)",
157 | "@navbar-default-brand-hover-bg": "transparent",
158 | "@navbar-default-toggle-hover-bg": "#ddd",
159 | "@navbar-default-toggle-icon-bar-bg": "#888",
160 | "@navbar-default-toggle-border-color": "#ddd",
161 | "@navbar-inverse-color": "lighten(@gray-light, 15%)",
162 | "@navbar-inverse-bg": "#222",
163 | "@navbar-inverse-border": "darken(@navbar-inverse-bg, 10%)",
164 | "@navbar-inverse-link-color": "lighten(@gray-light, 15%)",
165 | "@navbar-inverse-link-hover-color": "#fff",
166 | "@navbar-inverse-link-hover-bg": "transparent",
167 | "@navbar-inverse-link-active-color": "@navbar-inverse-link-hover-color",
168 | "@navbar-inverse-link-active-bg": "darken(@navbar-inverse-bg, 10%)",
169 | "@navbar-inverse-link-disabled-color": "#444",
170 | "@navbar-inverse-link-disabled-bg": "transparent",
171 | "@navbar-inverse-brand-color": "@navbar-inverse-link-color",
172 | "@navbar-inverse-brand-hover-color": "#fff",
173 | "@navbar-inverse-brand-hover-bg": "transparent",
174 | "@navbar-inverse-toggle-hover-bg": "#333",
175 | "@navbar-inverse-toggle-icon-bar-bg": "#fff",
176 | "@navbar-inverse-toggle-border-color": "#333",
177 | "@nav-link-padding": "10px 15px",
178 | "@nav-link-hover-bg": "@gray-lighter",
179 | "@nav-disabled-link-color": "@gray-light",
180 | "@nav-disabled-link-hover-color": "@gray-light",
181 | "@nav-tabs-border-color": "#ddd",
182 | "@nav-tabs-link-hover-border-color": "@gray-lighter",
183 | "@nav-tabs-active-link-hover-bg": "@body-bg",
184 | "@nav-tabs-active-link-hover-color": "@gray",
185 | "@nav-tabs-active-link-hover-border-color": "#ddd",
186 | "@nav-tabs-justified-link-border-color": "#ddd",
187 | "@nav-tabs-justified-active-link-border-color": "@body-bg",
188 | "@nav-pills-border-radius": "@border-radius-base",
189 | "@nav-pills-active-link-hover-bg": "@component-active-bg",
190 | "@nav-pills-active-link-hover-color": "@component-active-color",
191 | "@pagination-color": "@link-color",
192 | "@pagination-bg": "#fff",
193 | "@pagination-border": "#ddd",
194 | "@pagination-hover-color": "@link-hover-color",
195 | "@pagination-hover-bg": "@gray-lighter",
196 | "@pagination-hover-border": "#ddd",
197 | "@pagination-active-color": "#fff",
198 | "@pagination-active-bg": "@brand-primary",
199 | "@pagination-active-border": "@brand-primary",
200 | "@pagination-disabled-color": "@gray-light",
201 | "@pagination-disabled-bg": "#fff",
202 | "@pagination-disabled-border": "#ddd",
203 | "@pager-bg": "@pagination-bg",
204 | "@pager-border": "@pagination-border",
205 | "@pager-border-radius": "15px",
206 | "@pager-hover-bg": "@pagination-hover-bg",
207 | "@pager-active-bg": "@pagination-active-bg",
208 | "@pager-active-color": "@pagination-active-color",
209 | "@pager-disabled-color": "@pagination-disabled-color",
210 | "@jumbotron-padding": "30px",
211 | "@jumbotron-color": "inherit",
212 | "@jumbotron-bg": "@gray-lighter",
213 | "@jumbotron-heading-color": "inherit",
214 | "@jumbotron-font-size": "ceil((@font-size-base * 1.5))",
215 | "@state-success-text": "#3c763d",
216 | "@state-success-bg": "#dff0d8",
217 | "@state-success-border": "darken(spin(@state-success-bg, -10), 5%)",
218 | "@state-info-text": "#31708f",
219 | "@state-info-bg": "#d9edf7",
220 | "@state-info-border": "darken(spin(@state-info-bg, -10), 7%)",
221 | "@state-warning-text": "#8a6d3b",
222 | "@state-warning-bg": "#fcf8e3",
223 | "@state-warning-border": "darken(spin(@state-warning-bg, -10), 5%)",
224 | "@state-danger-text": "#a94442",
225 | "@state-danger-bg": "#f2dede",
226 | "@state-danger-border": "darken(spin(@state-danger-bg, -10), 5%)",
227 | "@tooltip-max-width": "200px",
228 | "@tooltip-color": "#fff",
229 | "@tooltip-bg": "#000",
230 | "@tooltip-opacity": ".9",
231 | "@tooltip-arrow-width": "5px",
232 | "@tooltip-arrow-color": "@tooltip-bg",
233 | "@popover-bg": "#fff",
234 | "@popover-max-width": "276px",
235 | "@popover-border-color": "rgba(0,0,0,.2)",
236 | "@popover-fallback-border-color": "#ccc",
237 | "@popover-title-bg": "darken(@popover-bg, 3%)",
238 | "@popover-arrow-width": "10px",
239 | "@popover-arrow-color": "@popover-bg",
240 | "@popover-arrow-outer-width": "(@popover-arrow-width + 1)",
241 | "@popover-arrow-outer-color": "fadein(@popover-border-color, 5%)",
242 | "@popover-arrow-outer-fallback-color": "darken(@popover-fallback-border-color, 20%)",
243 | "@label-default-bg": "@gray-light",
244 | "@label-primary-bg": "@brand-primary",
245 | "@label-success-bg": "@brand-success",
246 | "@label-info-bg": "@brand-info",
247 | "@label-warning-bg": "@brand-warning",
248 | "@label-danger-bg": "@brand-danger",
249 | "@label-color": "#fff",
250 | "@label-link-hover-color": "#fff",
251 | "@modal-inner-padding": "15px",
252 | "@modal-title-padding": "15px",
253 | "@modal-title-line-height": "@line-height-base",
254 | "@modal-content-bg": "#fff",
255 | "@modal-content-border-color": "rgba(0,0,0,.2)",
256 | "@modal-content-fallback-border-color": "#999",
257 | "@modal-backdrop-bg": "#000",
258 | "@modal-backdrop-opacity": ".5",
259 | "@modal-header-border-color": "#e5e5e5",
260 | "@modal-footer-border-color": "@modal-header-border-color",
261 | "@modal-lg": "900px",
262 | "@modal-md": "600px",
263 | "@modal-sm": "300px",
264 | "@alert-padding": "15px",
265 | "@alert-border-radius": "@border-radius-base",
266 | "@alert-link-font-weight": "bold",
267 | "@alert-success-bg": "@state-success-bg",
268 | "@alert-success-text": "@state-success-text",
269 | "@alert-success-border": "@state-success-border",
270 | "@alert-info-bg": "@state-info-bg",
271 | "@alert-info-text": "@state-info-text",
272 | "@alert-info-border": "@state-info-border",
273 | "@alert-warning-bg": "@state-warning-bg",
274 | "@alert-warning-text": "@state-warning-text",
275 | "@alert-warning-border": "@state-warning-border",
276 | "@alert-danger-bg": "@state-danger-bg",
277 | "@alert-danger-text": "@state-danger-text",
278 | "@alert-danger-border": "@state-danger-border",
279 | "@progress-bg": "#f5f5f5",
280 | "@progress-bar-color": "#fff",
281 | "@progress-border-radius": "@border-radius-base",
282 | "@progress-bar-bg": "@brand-primary",
283 | "@progress-bar-success-bg": "@brand-success",
284 | "@progress-bar-warning-bg": "@brand-warning",
285 | "@progress-bar-danger-bg": "@brand-danger",
286 | "@progress-bar-info-bg": "@brand-info",
287 | "@list-group-bg": "#fff",
288 | "@list-group-border": "#ddd",
289 | "@list-group-border-radius": "@border-radius-base",
290 | "@list-group-hover-bg": "#f5f5f5",
291 | "@list-group-active-color": "@component-active-color",
292 | "@list-group-active-bg": "@component-active-bg",
293 | "@list-group-active-border": "@list-group-active-bg",
294 | "@list-group-active-text-color": "lighten(@list-group-active-bg, 40%)",
295 | "@list-group-disabled-color": "@gray-light",
296 | "@list-group-disabled-bg": "@gray-lighter",
297 | "@list-group-disabled-text-color": "@list-group-disabled-color",
298 | "@list-group-link-color": "#555",
299 | "@list-group-link-hover-color": "@list-group-link-color",
300 | "@list-group-link-heading-color": "#333",
301 | "@panel-bg": "#fff",
302 | "@panel-body-padding": "15px",
303 | "@panel-heading-padding": "10px 15px",
304 | "@panel-footer-padding": "@panel-heading-padding",
305 | "@panel-border-radius": "@border-radius-base",
306 | "@panel-inner-border": "#ddd",
307 | "@panel-footer-bg": "#f5f5f5",
308 | "@panel-default-text": "@gray-dark",
309 | "@panel-default-border": "#ddd",
310 | "@panel-default-heading-bg": "#f5f5f5",
311 | "@panel-primary-text": "#fff",
312 | "@panel-primary-border": "@brand-primary",
313 | "@panel-primary-heading-bg": "@brand-primary",
314 | "@panel-success-text": "@state-success-text",
315 | "@panel-success-border": "@state-success-border",
316 | "@panel-success-heading-bg": "@state-success-bg",
317 | "@panel-info-text": "@state-info-text",
318 | "@panel-info-border": "@state-info-border",
319 | "@panel-info-heading-bg": "@state-info-bg",
320 | "@panel-warning-text": "@state-warning-text",
321 | "@panel-warning-border": "@state-warning-border",
322 | "@panel-warning-heading-bg": "@state-warning-bg",
323 | "@panel-danger-text": "@state-danger-text",
324 | "@panel-danger-border": "@state-danger-border",
325 | "@panel-danger-heading-bg": "@state-danger-bg",
326 | "@thumbnail-padding": "4px",
327 | "@thumbnail-bg": "@body-bg",
328 | "@thumbnail-border": "#ddd",
329 | "@thumbnail-border-radius": "@border-radius-base",
330 | "@thumbnail-caption-color": "@text-color",
331 | "@thumbnail-caption-padding": "9px",
332 | "@well-bg": "#f5f5f5",
333 | "@well-border": "darken(@well-bg, 7%)",
334 | "@badge-color": "#fff",
335 | "@badge-link-hover-color": "#fff",
336 | "@badge-bg": "@gray-light",
337 | "@badge-active-color": "@link-color",
338 | "@badge-active-bg": "#fff",
339 | "@badge-font-weight": "bold",
340 | "@badge-line-height": "1",
341 | "@badge-border-radius": "10px",
342 | "@breadcrumb-padding-vertical": "8px",
343 | "@breadcrumb-padding-horizontal": "15px",
344 | "@breadcrumb-bg": "#f5f5f5",
345 | "@breadcrumb-color": "#ccc",
346 | "@breadcrumb-active-color": "@gray-light",
347 | "@breadcrumb-separator": "\"/\"",
348 | "@carousel-text-shadow": "0 1px 2px rgba(0,0,0,.6)",
349 | "@carousel-control-color": "#fff",
350 | "@carousel-control-width": "15%",
351 | "@carousel-control-opacity": ".5",
352 | "@carousel-control-font-size": "20px",
353 | "@carousel-indicator-active-bg": "#fff",
354 | "@carousel-indicator-border-color": "#fff",
355 | "@carousel-caption-color": "#fff",
356 | "@close-font-weight": "bold",
357 | "@close-color": "#000",
358 | "@close-text-shadow": "0 1px 0 #fff",
359 | "@code-color": "#c7254e",
360 | "@code-bg": "#f9f2f4",
361 | "@kbd-color": "#fff",
362 | "@kbd-bg": "#333",
363 | "@pre-bg": "#f5f5f5",
364 | "@pre-color": "@gray-dark",
365 | "@pre-border-color": "#ccc",
366 | "@pre-scrollable-max-height": "340px",
367 | "@component-offset-horizontal": "180px",
368 | "@text-muted": "@gray-light",
369 | "@abbr-border-color": "@gray-light",
370 | "@headings-small-color": "@gray-light",
371 | "@blockquote-small-color": "@gray-light",
372 | "@blockquote-font-size": "(@font-size-base * 1.25)",
373 | "@blockquote-border-color": "@gray-lighter",
374 | "@page-header-border-color": "@gray-lighter",
375 | "@dl-horizontal-offset": "@component-offset-horizontal",
376 | "@hr-border": "@gray-lighter"
377 | },
378 | "css": [
379 | "code.less",
380 | "grid.less",
381 | "tables.less",
382 | "forms.less",
383 | "responsive-utilities.less"
384 | ],
385 | "js": [],
386 | "customizerUrl": "http://getbootstrap.com/customize/?id=ad36d62e5bee2e765f87"
387 | }
--------------------------------------------------------------------------------
/_attachments/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
Error!
7 |
{{error_message}}
8 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/_attachments/images/Cloudant_Icon_RGB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/Cloudant_Icon_RGB.png
--------------------------------------------------------------------------------
/_attachments/images/ibm_cloudant_silver.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/ibm_cloudant_silver.ai
--------------------------------------------------------------------------------
/_attachments/images/ibm_cloudant_silver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/ibm_cloudant_silver.png
--------------------------------------------------------------------------------
/_attachments/images/layers-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/layers-2x.png
--------------------------------------------------------------------------------
/_attachments/images/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/layers.png
--------------------------------------------------------------------------------
/_attachments/images/location_tracker_appicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/location_tracker_appicon.png
--------------------------------------------------------------------------------
/_attachments/images/sprite.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/sprite.ai
--------------------------------------------------------------------------------
/_attachments/images/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/sprite.png
--------------------------------------------------------------------------------
/_attachments/images/world_map.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/world_map.ai
--------------------------------------------------------------------------------
/_attachments/images/world_map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/world_map.png
--------------------------------------------------------------------------------
/_attachments/images/world_map_mask.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/world_map_mask.ai
--------------------------------------------------------------------------------
/_attachments/images/world_map_mask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/images/world_map_mask.png
--------------------------------------------------------------------------------
/_attachments/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IBM Cloudant Location Tracker Demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | Location Tracker
42 |
43 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/_attachments/map-result.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/_attachments/savedata.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
Saving local location
45 | data to Cloudant
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/_attachments/script/L.Control.Locate.min.js:
--------------------------------------------------------------------------------
1 | /*! Version: 0.38.0
2 | Date: 2014-12-31 */
3 |
4 | /*!
5 | Copyright (c) 2014 Dominik Moritz
6 |
7 | This file is part of the leaflet locate control. It is licensed under the MIT license.
8 | You can find the project at: https://github.com/domoritz/leaflet-locatecontrol
9 | */
10 | !function(a,b){"function"==typeof define&&define.amd?define(["leaflet"],a):"object"==typeof exports&&(module.exports=a(require("leaflet"))),"undefined"!=typeof b&&b.L&&(b.L.Locate=a(L))}(function(a){return a.Control.Locate=a.Control.extend({options:{position:"topleft",drawCircle:!0,follow:!1,stopFollowingOnDrag:!1,remainActive:!1,markerClass:a.circleMarker,circleStyle:{color:"#136AEC",fillColor:"#136AEC",fillOpacity:.15,weight:2,opacity:.5},markerStyle:{color:"#136AEC",fillColor:"#2A93EE",fillOpacity:.7,weight:2,opacity:.9,radius:5},followCircleStyle:{},followMarkerStyle:{},icon:"fa fa-map-marker",iconLoading:"fa fa-spinner fa-spin",circlePadding:[0,0],metric:!0,onLocationError:function(a){alert(a.message)},onLocationOutsideMapBounds:function(a){a.stop(),alert(a.options.strings.outsideMapBoundsMsg)},setView:!0,keepCurrentZoomLevel:!1,showPopup:!0,strings:{title:"Show me where I am",popup:"You are within {distance} {unit} from this point",outsideMapBoundsMsg:"You seem located outside the boundaries of the map"},locateOptions:{maxZoom:1/0,watch:!0}},initialize:function(b){a.Map.addInitHook(function(){this.options.locateControl&&(this.locateControl=a.control.locate(),this.addControl(this.locateControl))});for(var c in b)"object"==typeof this.options[c]?a.extend(this.options[c],b[c]):this.options[c]=b[c];a.extend(this.options.locateOptions,{setView:!1})},_activate:function(){this.options.setView&&(this._locateOnNextLocationFound=!0),this._active||this._map.locate(this.options.locateOptions),this._active=!0,this.options.follow&&this._startFollowing(this._map)},_deactivate:function(){this._map.stopLocate(),this._map.off("dragstart",this._stopFollowing),this.options.follow&&this._following&&this._stopFollowing(this._map)},drawMarker:function(b){void 0===this._event.accuracy&&(this._event.accuracy=0);var c=this._event.accuracy;this._locateOnNextLocationFound&&(this._isOutsideMapBounds()?this.options.onLocationOutsideMapBounds(this):b.fitBounds(this._event.bounds,{padding:this.options.circlePadding,maxZoom:this.options.keepCurrentZoomLevel?b.getZoom():this.options.locateOptions.maxZoom}),this._locateOnNextLocationFound=!1);var d,e;if(this.options.drawCircle)if(d=this._following?this.options.followCircleStyle:this.options.circleStyle,this._circle){this._circle.setLatLng(this._event.latlng).setRadius(c);for(e in d)this._circle.options[e]=d[e]}else this._circle=a.circle(this._event.latlng,c,d).addTo(this._layer);var f,g;this.options.metric?(f=c.toFixed(0),g="meters"):(f=(3.2808399*c).toFixed(0),g="feet");var h;h=this._following?this.options.followMarkerStyle:this.options.markerStyle,this._marker?this.updateMarker(this._event.latlng,h):this._marker=this.createMarker(this._event.latlng,h).addTo(this._layer);var i=this.options.strings.popup;this.options.showPopup&&i&&this._marker.bindPopup(a.Util.template(i,{distance:f,unit:g}))._popup.setLatLng(this._event.latlng),this._toggleContainerStyle()},createMarker:function(a,b){return this.options.markerClass(a,b)},updateMarker:function(a,b){this._marker.setLatLng(a);for(o in b)this._marker.options[o]=b[o]},removeMarker:function(){this._layer.clearLayers(),this._marker=void 0,this._circle=void 0},onAdd:function(b){var c=a.DomUtil.create("div","leaflet-control-locate leaflet-bar leaflet-control");this._layer=new a.LayerGroup,this._layer.addTo(b),this._event=void 0;var d={};return a.extend(d,this.options.markerStyle,this.options.followMarkerStyle),this.options.followMarkerStyle=d,d={},a.extend(d,this.options.circleStyle,this.options.followCircleStyle),this.options.followCircleStyle=d,this._link=a.DomUtil.create("a","leaflet-bar-part leaflet-bar-part-single",c),this._link.href="#",this._link.title=this.options.strings.title,this._icon=a.DomUtil.create("span",this.options.icon,this._link),a.DomEvent.on(this._link,"click",a.DomEvent.stopPropagation).on(this._link,"click",a.DomEvent.preventDefault).on(this._link,"click",function(){var a=void 0===this._event||this._map.getBounds().contains(this._event.latlng)||!this.options.setView||this._isOutsideMapBounds();!this.options.remainActive&&this._active&&a?this.stop():this.start()},this).on(this._link,"dblclick",a.DomEvent.stopPropagation),this._resetVariables(),this.bindEvents(b),c},bindEvents:function(a){a.on("locationfound",this._onLocationFound,this),a.on("locationerror",this._onLocationError,this),a.on("unload",this.stop,this)},start:function(){this._activate(),this._event?this.drawMarker(this._map):this._setClasses("requesting")},stop:function(){this._deactivate(),this._cleanClasses(),this._resetVariables(),this.removeMarker()},_onLocationError:function(a){3==a.code&&this.options.locateOptions.watch||(this.stop(),this.options.onLocationError(a))},_onLocationFound:function(a){this._event&&this._event.latlng.lat===a.latlng.lat&&this._event.latlng.lng===a.latlng.lng&&this._event.accuracy===a.accuracy||this._active&&(this._event=a,this.options.follow&&this._following&&(this._locateOnNextLocationFound=!0),this.drawMarker(this._map))},_startFollowing:function(){this._map.fire("startfollowing",this),this._following=!0,this.options.stopFollowingOnDrag&&this._map.on("dragstart",this._stopFollowing,this)},_stopFollowing:function(){this._map.fire("stopfollowing",this),this._following=!1,this.options.stopFollowingOnDrag&&this._map.off("dragstart",this._stopFollowing),this._toggleContainerStyle()},_isOutsideMapBounds:function(){return void 0===this._event?!1:this._map.options.maxBounds&&!this._map.options.maxBounds.contains(this._event.latlng)},_toggleContainerStyle:function(){this._container&&this._setClasses(this._following?"following":"active")},_setClasses:function(b){"requesting"==b?(a.DomUtil.removeClasses(this._container,"active following"),a.DomUtil.addClasses(this._container,"requesting"),a.DomUtil.removeClasses(this._icon,this.options.icon),a.DomUtil.addClasses(this._icon,this.options.iconLoading)):"active"==b?(a.DomUtil.removeClasses(this._container,"requesting following"),a.DomUtil.addClasses(this._container,"active"),a.DomUtil.removeClasses(this._icon,this.options.iconLoading),a.DomUtil.addClasses(this._icon,this.options.icon)):"following"==b&&(a.DomUtil.removeClasses(this._container,"requesting"),a.DomUtil.addClasses(this._container,"active following"),a.DomUtil.removeClasses(this._icon,this.options.iconLoading),a.DomUtil.addClasses(this._icon,this.options.icon))},_cleanClasses:function(){a.DomUtil.removeClass(this._container,"requesting"),a.DomUtil.removeClass(this._container,"active"),a.DomUtil.removeClass(this._container,"following"),a.DomUtil.removeClasses(this._icon,this.options.iconLoading),a.DomUtil.addClasses(this._icon,this.options.icon)},_resetVariables:function(){this._active=!1,this._locateOnNextLocationFound=this.options.setView,this._following=!1}}),a.Map.addInitHook(function(){this.options.locateControl&&(this.locateControl=a.control.locate(),this.addControl(this.locateControl))}),a.control.locate=function(b){return new a.Control.Locate(b)},function(){var b=function(b,c,d){d=d.split(" "),d.forEach(function(d){a.DomUtil[b].call(this,c,d)})};a.DomUtil.addClasses=function(a,c){b("addClass",a,c)},a.DomUtil.removeClasses=function(a,c){b("removeClass",a,c)}}(),a.Control.Locate},window);
11 | //# sourceMappingURL=L.Control.Locate.min.js.map
--------------------------------------------------------------------------------
/_attachments/script/L.Control.Locate.min.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"L.Control.Locate.min.js","sources":["../src/L.Control.Locate.js"],"names":["factory","window","define","amd","exports","module","require","L","Locate","Control","extend","options","position","drawCircle","follow","stopFollowingOnDrag","remainActive","markerClass","circleMarker","circleStyle","color","fillColor","fillOpacity","weight","opacity","markerStyle","radius","followCircleStyle","followMarkerStyle","icon","iconLoading","circlePadding","metric","onLocationError","err","alert","message","onLocationOutsideMapBounds","control","stop","strings","outsideMapBoundsMsg","setView","keepCurrentZoomLevel","showPopup","title","popup","locateOptions","maxZoom","Infinity","watch","initialize","Map","addInitHook","this","locateControl","locate","addControl","i","_activate","_locateOnNextLocationFound","_active","_map","_startFollowing","_deactivate","stopLocate","off","_stopFollowing","_following","drawMarker","map","undefined","_event","accuracy","_isOutsideMapBounds","fitBounds","bounds","padding","getZoom","style","o","_circle","setLatLng","latlng","setRadius","circle","addTo","_layer","distance","unit","toFixed","mStyle","_marker","updateMarker","createMarker","t","bindPopup","Util","template","_popup","_toggleContainerStyle","removeMarker","clearLayers","onAdd","container","DomUtil","create","LayerGroup","tmp","_link","href","_icon","DomEvent","on","stopPropagation","preventDefault","shouldStop","getBounds","contains","start","_resetVariables","bindEvents","_onLocationFound","_onLocationError","_setClasses","_cleanClasses","code","e","lat","lng","fire","maxBounds","_container","state","removeClasses","addClasses","removeClass","LDomUtilApplyClassesMethod","method","element","classNames","split","forEach","className","call","el","names"],"mappings":"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"}
--------------------------------------------------------------------------------
/_attachments/script/app.js:
--------------------------------------------------------------------------------
1 | // create our angular app and inject ngAnimate and ui-router
2 | // =============================================================================
3 | var u = 'https://' + window.location.host + '/locationtracker';
4 | angular.module('locationTrackingApp', ['ngAnimate', 'ngRoute'])
5 |
6 | /* VALUES */
7 | .value("map", {})
8 | .value("watchID", null)
9 | .value("remotedb", u)
10 | .value("num", 0)
11 | .value("successMessage", {})
12 | .value("errorMessage", "error")
13 |
14 |
15 | /* ROUTES */
16 | .config(['$routeProvider', function($routeProvider) {
17 |
18 | $routeProvider.
19 | when('/welcome', {
20 | templateUrl: 'welcome.html',
21 | controller: 'locationWelcomeController'
22 | }).
23 | when('/tracking', {
24 | templateUrl: 'tracking.html',
25 | controller: 'locationTrackingController'
26 | }).
27 | when('/savedata', {
28 | templateUrl: 'savedata.html',
29 | controller: 'locationTrackingSaveDataController'
30 | }).
31 | when('/success', {
32 | templateUrl: 'success.html',
33 | controller: 'locationTrackingSuccessController'
34 | }).
35 | when('/error', {
36 | templateUrl: 'error.html',
37 | controller: 'locationTrackingErrorController'
38 | }).
39 | when('/map', {
40 | templateUrl: 'map-result.html',
41 | controller: 'mapResultController'
42 | }).
43 | otherwise({
44 | redirectTo: '/welcome'
45 | })
46 |
47 | }])
48 |
49 |
50 | /* welcome.html Controller */
51 | .controller('locationWelcomeController', function($scope) {
52 | $scope.transEnter = function() {}
53 | $scope.transLeave = function() {};
54 | })
55 |
56 |
57 | /* tracking.html Controller */
58 | .controller('locationTrackingController', function($scope, map, watchID, pouchLocal, num) {
59 |
60 | /* VARS */
61 | var mapTracker; // map object
62 | var lc; // location control object
63 | var last_lon = 0;
64 | var last_lat = 0;
65 | var session_id = guid();
66 | var db = pouchLocal;
67 | var watchID = {}; //geolocation object holder
68 |
69 | /* triggered from velocity callback within the animation module `enter` hook */
70 | $scope.transEnter = function() {
71 | if (navigator.geolocation) {
72 |
73 | /* vars to pass into leaflet map object */
74 | var at = 'pk.eyJ1IjoicmFqcnNpbmdoIiwiYSI6ImpzeDhXbk0ifQ.VeSXCxcobmgfLgJAnsK3nw';
75 | var osmUrl = 'https://{s}.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token='+at;
76 | var osmAttrib = 'Map data © OpenStreetMap contributors, ' +
77 | 'CC-BY-SA , ' +
78 | 'Imagery © Mapbox ';
79 | var osm = new L.TileLayer(osmUrl, {
80 | attribution: osmAttrib,
81 | id: 'mapbox.streets-basic'
82 | });
83 |
84 | /* instantiate Leaflet tracking map */
85 | mapTracker = new L.Map('map', {
86 | layers: [osm],
87 | zoom: 18,
88 | zoomControl: true
89 | });
90 |
91 | /* Instantiate Leaflet Locate plugin */
92 | lc = L.control.locate({
93 | follow: true
94 | }).addTo(mapTracker);
95 |
96 | mapTracker.locate({
97 | setView: true
98 | });
99 |
100 | /* store geolocation in an object to */
101 | geoLoc = navigator.geolocation;
102 | var watchOptions = {
103 | maximumAge: 0,
104 | timeout: 10000,
105 | enableHighAccuracy: true
106 | };
107 | watchID = geoLoc.watchPosition(doWatch, watchError, watchOptions);
108 |
109 | /* leaflet events */
110 | mapTracker.on('locationfound', onLocationFound);
111 | mapTracker.on('startfollowing', function() {
112 | mapTracker.on('dragstart', lc._stopFollowing, lc);
113 | }).on('stopfollowing', function() {
114 | mapTracker.off('dragstart', lc._stopFollowing, lc);
115 | });
116 |
117 | } else {
118 | alert("Geolocation IS NOT available!");
119 | }
120 | };
121 |
122 | /* triggered from velocity callback within the animation module `enter` hook */
123 | $scope.transLeave = function() {
124 | geoLoc.clearWatch(watchID);
125 | mapTracker.remove();
126 | };
127 |
128 | /* locationfound event handler */
129 | function onLocationFound(e) {
130 | var radius = e.accuracy / 2;
131 | L.marker(e.latlng).addTo(mapTracker).bindPopup(
132 | 'Latitude ' + e.latlng.lat +
133 | 'Longitude ' + e.latlng.lng);
134 | lc.start();
135 | }
136 |
137 | /* geoLoc.watchPosition event handler */
138 | function doWatch(position) {
139 | var lon = Number(Math.round(position.coords.longitude + 'e' + 4) + 'e-' + 4);
140 | var lat = Number(Math.round(position.coords.latitude + 'e' + 4) + 'e-' + 4);
141 | if ((lon == last_lon) && (lat == last_lat)) return null;
142 |
143 | if (last_lon == 0) {
144 | last_lon = lon;
145 | last_lat = lat;
146 | }
147 |
148 | /* create points to connect (last and latest) */
149 | var pointA = new L.LatLng(last_lat, last_lon);
150 | var pointB = new L.LatLng(lat, lon);
151 | var pointList = [pointA, pointB];
152 |
153 | last_lon = lon;
154 | last_lat = lat;
155 |
156 | /* create line to connect points */
157 | var polyline = new L.Polyline(pointList, {
158 | color: '#e5603d',
159 | weight: 4,
160 | opacity: 0.64,
161 | smoothFactor: 1
162 | });
163 | polyline.addTo(mapTracker);
164 |
165 | /* data object to write to your NoSQL doc */
166 | var coord = {
167 | "type": "Feature",
168 | "geometry": {
169 | "type": "Point",
170 | "coordinates": [lon, lat]
171 | },
172 | "properties": {
173 | "session_id": session_id,
174 | "timestamp": position.timestamp
175 | }
176 | };
177 |
178 | /* PUT object to db */
179 | db.put(coord, position.timestamp.toString(), function callback(err, response) {
180 | if (err) {
181 | alert('PUT ERROR: ' + err);
182 | }
183 |
184 | /* get doc and update lat + lon text in the view */
185 | db.get(response.id, function callback(err, doc) {
186 | if (err) {
187 | console.log('ERROR: ' + err);
188 | }
189 | $('.longitude-coordinate').text(doc.geometry.coordinates[0]);
190 | $('.latitude-coordinate').text(doc.geometry.coordinates[1]);
191 | });
192 | });
193 | }
194 |
195 | /* geoLoc.watchPosition event error handler */
196 | function watchError(err) {
197 | $('.longitude-coordinate, .latitude-coordinate').text("permission denied...");
198 | alert('Error' + err.code + ' msg: ' + err.message);
199 | }
200 |
201 | /**
202 | * Generates a GUID string.
203 | * @returns {String} The generated GUID.
204 | * @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
205 | * @author Slavik Meltser (slavik@meltser.info).
206 | * @link http://slavik.meltser.info/?p=142
207 | */
208 | function guid() {
209 | function _p8(s) {
210 | var p = (Math.random().toString(16) + "000000000").substr(2, 8);
211 | return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p;
212 | }
213 | return _p8() + _p8(true) + _p8(true) + _p8();
214 | }
215 | })
216 |
217 |
218 | /* savedata.html Controller */
219 | .controller('locationTrackingSaveDataController', function($scope, map, watchID, pouchLocal, remotedb, successMessage, errorMessage) {
220 |
221 | var timer;
222 |
223 | /* triggered from velocity callback within the animation module `enter` hook */
224 | $scope.transEnter = function() {
225 | navigator.geolocation.clearWatch(watchID);
226 | db = pouchLocal;
227 |
228 | timer = setInterval(function() {
229 | $(".dot-anim")
230 | .velocity("transition.slideUpBigIn", {
231 | drag: true
232 | })
233 | .delay(750)
234 | .velocity({
235 | opacity: 0
236 | }, 750)
237 | }, 2000);
238 |
239 | db.replicate.to(remotedb).on('complete', function(info) {
240 | var timer = setTimeout(function() {
241 | successMessage.docs_written = info.docs_written;
242 | successMessage.start_time = info.start_time;
243 | window.location = "#/success";
244 | }, 2000)
245 |
246 | }).on('error', function(err) {
247 | errorMessage = 'error replicating: ' + err;
248 | window.location = "#/error";
249 | });
250 | };
251 |
252 | /* triggered from velocity callback within the animation module `enter` hook */
253 | $scope.transLeave = function() {
254 | clearInterval(timer);
255 | };
256 | })
257 |
258 |
259 | .controller('locationTrackingSuccessController', function($scope, successMessage) {
260 | $scope.docs_written = successMessage.docs_written;
261 | $scope.start_time = successMessage.start_time;
262 |
263 | $scope.transEnter = function() {};
264 | $scope.transLeave = function() {};
265 | })
266 |
267 |
268 | .controller('locationTrackingErrorController', function($scope, errorMessage) {
269 | $scope.error_message = errorMessage;
270 |
271 | $scope.transEnter = function() {};
272 | $scope.transLeave = function() {};
273 | })
274 |
275 |
276 | .controller('mapResultController', function($scope, pouchResult) {
277 | var mapResult = {};
278 |
279 | /* triggered from velocity callback within the animation module `enter` hook */
280 | $scope.transEnter = function() {
281 | var db = pouchResult;
282 | var _len;
283 |
284 | // get the length of docs and store it in _len
285 | db.info(function(err, info) {
286 | _len = info.doc_count;
287 | });
288 |
289 | // use alldocs to get the object rows, then run a loop to draw on the map.
290 | db.allDocs({
291 | include_docs: true,
292 | endkey: "_"
293 | }, function(err, response) {
294 | for (var i = 0; i < _len - 1; i++) {
295 | updateMovingLayer(response.rows[i].doc);
296 | };
297 | })
298 |
299 | /* instantiate Leaflet map */
300 | mapResult = new L.Map('mapResult');
301 |
302 | L.tileLayer('https://{s}.tiles.mapbox.com/v3/{id}/{z}/{x}/{y}.png', {
303 | maxZoom: 20,
304 | attribution: 'Map data © ' +
305 | 'OpenStreetMap contributors, ' +
306 | 'CC-BY-SA ',
307 | detectRetina: true,
308 | id: 'examples.map-20v6611k'
309 | }).addTo(mapResult);
310 |
311 | var last_lat = 0;
312 | var last_lon = 0;
313 |
314 | var movementLayer = L.geoJson(null, {
315 | pointToLayer: function(feature, latlng) {
316 |
317 | // setup a default lat + lng coordinate
318 | if (last_lat == 0) {
319 | last_lat = latlng.lat;
320 | last_lon = latlng.lng;
321 | }
322 |
323 | // we store coordinates so that we can have a start and end point, or pointA and pointB
324 | var pointA = [last_lat, last_lon];
325 | var pointB = [latlng.lat, latlng.lng];
326 | var pointList = [pointA, pointB];
327 |
328 | last_lat = latlng.lat;
329 | last_lon = latlng.lng;
330 |
331 | var firstpolyline = new L.Polyline(pointList, {
332 | color: '#e5603d',
333 | weight: 4,
334 | opacity: 0.64,
335 | smoothFactor: 1
336 | });
337 | firstpolyline.addTo(mapResult);
338 |
339 | markeroptions = {
340 | icon: L.icon({
341 | iconUrl: 'script/images/marker-icon-blue.png',
342 | iconRetinaUrl: 'script/images/marker-icon-blue-2x.png',
343 | iconSize: [25, 41],
344 | iconAnchor: [10, 10],
345 | shadowURL: 'script/images/marker-icon-shadow.png',
346 | shadowRetinaURL: 'script/images/marker-icon-shadow-2x.png',
347 | shadowSize: [41, 41],
348 | shadowAnchor: [10, 10]
349 | })
350 | }
351 | return L.marker(latlng, markeroptions).bindPopup(
352 | 'Latitude ' + latlng.lat +
353 | 'Longitude ' + latlng.lng);
354 | }
355 | }).addTo(mapResult);
356 |
357 | function updateMovingLayer(doc) {
358 | movementLayer.addData(doc);
359 | mapResult.fitBounds(movementLayer.getBounds());
360 | }
361 | };
362 |
363 | /* triggered from velocity callback within the animation module `enter` hook */
364 | $scope.transLeave = function() {
365 | mapResult.remove();
366 | };
367 |
368 | })
369 |
370 |
371 | /* local storage for tracking map */
372 | .factory('pouchLocal', [function() {
373 | var db = new PouchDB('localdb');
374 | return db;
375 | }])
376 |
377 |
378 | /* cloudant db storage for result map */
379 | .factory('pouchResult', ["remotedb", function(remotedb) {
380 | var db = new PouchDB(remotedb);
381 | return db;
382 | }])
383 |
384 |
385 | /* Directive used on controller items to allow for multiple trans in/out */
386 | .directive('animationdirective', ['$animate', '$timeout',
387 | function($animate, $timeout) {
388 | return {
389 | restrict: 'A',
390 | link: function(scope, element, attrs) {
391 |
392 | /* jquery button hovers added because clicks were sticking on mobile phone */
393 | $('.trans-button .btn').hover(
394 | function() {
395 | $(this).addClass('btnHover')
396 | },
397 | function() {
398 | $(this).removeClass('btnHover')
399 | }
400 | );
401 |
402 | $timeout(function() {
403 | $animate.addClass(element, 'anim-page-transition-js');
404 | }, 10);
405 | }
406 | }
407 | }
408 | ])
409 |
410 |
411 | /* animation module for running javascript transitions */
412 | .animation('.anim-page-transition-js',
413 | function() {
414 | return {
415 |
416 | enter: function(element, done) {
417 | var _element = $(element);
418 | _element.addClass("visible");
419 |
420 | /* array of items to transition in sequentially */
421 | $.each([".trans-step1", ".trans-step2", ".trans-step3", ".trans-step4"], function(index, value) {
422 | _element.find(value)
423 | .velocity({
424 | opacity: 0,
425 | translateY: "+200px"
426 | }, {
427 | duration: 0
428 | })
429 | .velocity({
430 | opacity: 1,
431 | translateY: "0"
432 | }, {
433 | easing: "easeInOutQuad",
434 | duration: 1000 + (index * 200),
435 | delay: 1000 + (index * 100),
436 | queue: false,
437 | complete: function(elements) {
438 | /**/
439 | }
440 | });
441 | });
442 |
443 | _element
444 | .velocity({
445 | opacity: 0,
446 | translateY: "100%"
447 | }, {
448 | duration: 0
449 | })
450 | .velocity({
451 | opacity: 1,
452 | translateY: "0%"
453 | }, {
454 | easing: "easeInOutQuad",
455 | duration: 500,
456 | delay: 1000,
457 | queue: false,
458 | complete: function(elements) {
459 | /* call transEnter function within the called element's controller*/
460 | angular.element(_element).scope().transEnter();
461 | }
462 | });
463 |
464 | _element.find(".trans-button")
465 | .velocity({
466 | opacity: 0,
467 | translateY: "+100%"
468 | }, {
469 | duration: 0
470 | })
471 | .velocity({
472 | opacity: 1,
473 | translateY: "0%"
474 | }, {
475 | easing: "easeInOutQuad",
476 | delay: 1500,
477 | queue: false,
478 | complete: function(elements) {
479 | /**/
480 | }
481 | });
482 | },
483 | leave: function(element, done) {
484 | var _element = $(element);
485 |
486 | /* call transLeave function within the called element's controller*/
487 | angular.element(_element).scope().transLeave();
488 |
489 | _element.find(".trans-button")
490 | .velocity({
491 | opacity: 1,
492 | translateY: "0%"
493 | }, {
494 | duration: 0
495 | })
496 | .velocity({
497 | opacity: 0,
498 | translateY: "+100%"
499 | }, {
500 | easing: "easeInOutQuad",
501 | duration: 1500,
502 | delay: 0,
503 | complete: function(elements) {
504 | /**/
505 | }
506 | });
507 |
508 | $.each([".trans-step1", ".trans-step2", ".trans-step3", ".trans-step4"], function(index, value) {
509 | _element.find(value)
510 | .velocity({
511 | opacity: 1,
512 | translateY: "0"
513 | }, {
514 | duration: 0
515 | })
516 | .velocity({
517 | opacity: 0,
518 | translateY: "-200px"
519 | }, {
520 | easing: "easeInOutQuad",
521 | duration: 1000 + (index * 200),
522 | delay: (index * 100),
523 | queue: false,
524 | complete: function(elements) {
525 | /**/
526 | }
527 | });
528 | });
529 |
530 | _element
531 | .velocity({
532 | opacity: 1,
533 | translateY: "0%"
534 | }, {
535 | duration: 0
536 | })
537 | .velocity({
538 | opacity: 0,
539 | translateY: "-100%"
540 | }, {
541 | easing: "easeInOutQuad",
542 | duration: 1000,
543 | delay: 1000,
544 | queue: false,
545 | complete: function(elements) {
546 | /**/
547 | $(element).remove();
548 | }
549 | });
550 | }
551 | }
552 | }
553 | );
--------------------------------------------------------------------------------
/_attachments/script/images/marker-icon-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/script/images/marker-icon-2x.png
--------------------------------------------------------------------------------
/_attachments/script/images/marker-icon-blue-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/script/images/marker-icon-blue-2x.png
--------------------------------------------------------------------------------
/_attachments/script/images/marker-icon-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/script/images/marker-icon-blue.png
--------------------------------------------------------------------------------
/_attachments/script/images/marker-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/script/images/marker-icon.png
--------------------------------------------------------------------------------
/_attachments/script/images/marker-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/_attachments/script/images/marker-shadow.png
--------------------------------------------------------------------------------
/_attachments/script/velocity.min.js:
--------------------------------------------------------------------------------
1 | /*! VelocityJS.org (1.2.1). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License */
2 | /*! VelocityJS.org jQuery Shim (1.0.1). (C) 2014 The jQuery Foundation. MIT @license: en.wikipedia.org/wiki/MIT_License. */
3 | !function(e){function t(e){var t=e.length,r=$.type(e);return"function"===r||$.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===r||0===t||"number"==typeof t&&t>0&&t-1 in e}if(!e.jQuery){var $=function(e,t){return new $.fn.init(e,t)};$.isWindow=function(e){return null!=e&&e==e.window},$.type=function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?a[o.call(e)]||"object":typeof e},$.isArray=Array.isArray||function(e){return"array"===$.type(e)},$.isPlainObject=function(e){var t;if(!e||"object"!==$.type(e)||e.nodeType||$.isWindow(e))return!1;try{if(e.constructor&&!n.call(e,"constructor")&&!n.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}for(t in e);return void 0===t||n.call(e,t)},$.each=function(e,r,a){var n,o=0,i=e.length,s=t(e);if(a){if(s)for(;i>o&&(n=r.apply(e[o],a),n!==!1);o++);else for(o in e)if(n=r.apply(e[o],a),n===!1)break}else if(s)for(;i>o&&(n=r.call(e[o],o,e[o]),n!==!1);o++);else for(o in e)if(n=r.call(e[o],o,e[o]),n===!1)break;return e},$.data=function(e,t,a){if(void 0===a){var n=e[$.expando],o=n&&r[n];if(void 0===t)return o;if(o&&t in o)return o[t]}else if(void 0!==t){var n=e[$.expando]||(e[$.expando]=++$.uuid);return r[n]=r[n]||{},r[n][t]=a,a}},$.removeData=function(e,t){var a=e[$.expando],n=a&&r[a];n&&$.each(t,function(e,t){delete n[t]})},$.extend=function(){var e,t,r,a,n,o,i=arguments[0]||{},s=1,l=arguments.length,u=!1;for("boolean"==typeof i&&(u=i,i=arguments[s]||{},s++),"object"!=typeof i&&"function"!==$.type(i)&&(i={}),s===l&&(i=this,s--);l>s;s++)if(null!=(n=arguments[s]))for(a in n)e=i[a],r=n[a],i!==r&&(u&&r&&($.isPlainObject(r)||(t=$.isArray(r)))?(t?(t=!1,o=e&&$.isArray(e)?e:[]):o=e&&$.isPlainObject(e)?e:{},i[a]=$.extend(u,o,r)):void 0!==r&&(i[a]=r));return i},$.queue=function(e,r,a){function n(e,r){var a=r||[];return null!=e&&(t(Object(e))?!function(e,t){for(var r=+t.length,a=0,n=e.length;r>a;)e[n++]=t[a++];if(r!==r)for(;void 0!==t[a];)e[n++]=t[a++];return e.length=n,e}(a,"string"==typeof e?[e]:e):[].push.call(a,e)),a}if(e){r=(r||"fx")+"queue";var o=$.data(e,r);return a?(!o||$.isArray(a)?o=$.data(e,r,n(a)):o.push(a),o):o||[]}},$.dequeue=function(e,t){$.each(e.nodeType?[e]:e,function(e,r){t=t||"fx";var a=$.queue(r,t),n=a.shift();"inprogress"===n&&(n=a.shift()),n&&("fx"===t&&a.unshift("inprogress"),n.call(r,function(){$.dequeue(r,t)}))})},$.fn=$.prototype={init:function(e){if(e.nodeType)return this[0]=e,this;throw new Error("Not a DOM node.")},offset:function(){var t=this[0].getBoundingClientRect?this[0].getBoundingClientRect():{top:0,left:0};return{top:t.top+(e.pageYOffset||document.scrollTop||0)-(document.clientTop||0),left:t.left+(e.pageXOffset||document.scrollLeft||0)-(document.clientLeft||0)}},position:function(){function e(){for(var e=this.offsetParent||document;e&&"html"===!e.nodeType.toLowerCase&&"static"===e.style.position;)e=e.offsetParent;return e||document}var t=this[0],e=e.apply(t),r=this.offset(),a=/^(?:body|html)$/i.test(e.nodeName)?{top:0,left:0}:$(e).offset();return r.top-=parseFloat(t.style.marginTop)||0,r.left-=parseFloat(t.style.marginLeft)||0,e.style&&(a.top+=parseFloat(e.style.borderTopWidth)||0,a.left+=parseFloat(e.style.borderLeftWidth)||0),{top:r.top-a.top,left:r.left-a.left}}};var r={};$.expando="velocity"+(new Date).getTime(),$.uuid=0;for(var a={},n=a.hasOwnProperty,o=a.toString,i="Boolean Number String Function Array Date RegExp Object Error".split(" "),s=0;sn;++n){var o=u(r,e,a);if(0===o)return r;var i=l(r,e,a)-t;r-=i/o}return r}function p(){for(var t=0;b>t;++t)w[t]=l(t*x,e,a)}function f(t,r,n){var o,i,s=0;do i=r+(n-r)/2,o=l(i,e,a)-t,o>0?n=i:r=i;while(Math.abs(o)>h&&++s=y?c(t,s):0==l?s:f(t,r,r+x)}function g(){V=!0,(e!=r||a!=n)&&p()}var m=4,y=.001,h=1e-7,v=10,b=11,x=1/(b-1),S="Float32Array"in t;if(4!==arguments.length)return!1;for(var P=0;4>P;++P)if("number"!=typeof arguments[P]||isNaN(arguments[P])||!isFinite(arguments[P]))return!1;e=Math.min(e,1),a=Math.min(a,1),e=Math.max(e,0),a=Math.max(a,0);var w=S?new Float32Array(b):new Array(b),V=!1,C=function(t){return V||g(),e===r&&a===n?t:0===t?0:1===t?1:l(d(t),r,n)};C.getControlPoints=function(){return[{x:e,y:r},{x:a,y:n}]};var T="generateBezier("+[e,r,a,n]+")";return C.toString=function(){return T},C}function u(e,t){var r=e;return g.isString(e)?v.Easings[e]||(r=!1):r=g.isArray(e)&&1===e.length?s.apply(null,e):g.isArray(e)&&2===e.length?b.apply(null,e.concat([t])):g.isArray(e)&&4===e.length?l.apply(null,e):!1,r===!1&&(r=v.Easings[v.defaults.easing]?v.defaults.easing:h),r}function c(e){if(e){var t=(new Date).getTime(),r=v.State.calls.length;r>1e4&&(v.State.calls=n(v.State.calls));for(var o=0;r>o;o++)if(v.State.calls[o]){var s=v.State.calls[o],l=s[0],u=s[2],f=s[3],d=!!f,m=null;f||(f=v.State.calls[o][3]=t-16);for(var y=Math.min((t-f)/u.duration,1),h=0,b=l.length;b>h;h++){var S=l[h],w=S.element;if(i(w)){var V=!1;if(u.display!==a&&null!==u.display&&"none"!==u.display){if("flex"===u.display){var C=["-webkit-box","-moz-box","-ms-flexbox","-webkit-flex"];$.each(C,function(e,t){x.setPropertyValue(w,"display",t)})}x.setPropertyValue(w,"display",u.display)}u.visibility!==a&&"hidden"!==u.visibility&&x.setPropertyValue(w,"visibility",u.visibility);for(var T in S)if("element"!==T){var k=S[T],A,F=g.isString(k.easing)?v.Easings[k.easing]:k.easing;if(1===y)A=k.endValue;else{var E=k.endValue-k.startValue;if(A=k.startValue+E*F(y,u,E),!d&&A===k.currentValue)continue}if(k.currentValue=A,"tween"===T)m=A;else{if(x.Hooks.registered[T]){var j=x.Hooks.getRoot(T),H=i(w).rootPropertyValueCache[j];H&&(k.rootPropertyValue=H)}var N=x.setPropertyValue(w,T,k.currentValue+(0===parseFloat(A)?"":k.unitType),k.rootPropertyValue,k.scrollData);x.Hooks.registered[T]&&(i(w).rootPropertyValueCache[j]=x.Normalizations.registered[j]?x.Normalizations.registered[j]("extract",null,N[1]):N[1]),"transform"===N[0]&&(V=!0)}}u.mobileHA&&i(w).transformCache.translate3d===a&&(i(w).transformCache.translate3d="(0px, 0px, 0px)",V=!0),V&&x.flushTransformCache(w)}}u.display!==a&&"none"!==u.display&&(v.State.calls[o][2].display=!1),u.visibility!==a&&"hidden"!==u.visibility&&(v.State.calls[o][2].visibility=!1),u.progress&&u.progress.call(s[1],s[1],y,Math.max(0,f+u.duration-t),f,m),1===y&&p(o)}}v.State.isTicking&&P(c)}function p(e,t){if(!v.State.calls[e])return!1;for(var r=v.State.calls[e][0],n=v.State.calls[e][1],o=v.State.calls[e][2],s=v.State.calls[e][4],l=!1,u=0,c=r.length;c>u;u++){var p=r[u].element;if(t||o.loop||("none"===o.display&&x.setPropertyValue(p,"display",o.display),"hidden"===o.visibility&&x.setPropertyValue(p,"visibility",o.visibility)),o.loop!==!0&&($.queue(p)[1]===a||!/\.velocityQueueEntryFlag/i.test($.queue(p)[1]))&&i(p)){i(p).isAnimating=!1,i(p).rootPropertyValueCache={};var f=!1;$.each(x.Lists.transforms3D,function(e,t){var r=/^scale/.test(t)?1:0,n=i(p).transformCache[t];i(p).transformCache[t]!==a&&new RegExp("^\\("+r+"[^.]").test(n)&&(f=!0,delete i(p).transformCache[t])}),o.mobileHA&&(f=!0,delete i(p).transformCache.translate3d),f&&x.flushTransformCache(p),x.Values.removeClass(p,"velocity-animating")}if(!t&&o.complete&&!o.loop&&u===c-1)try{o.complete.call(n,n)}catch(d){setTimeout(function(){throw d},1)}s&&o.loop!==!0&&s(n),o.loop!==!0||t||($.each(i(p).tweensContainer,function(e,t){/^rotate/.test(e)&&360===parseFloat(t.endValue)&&(t.endValue=0,t.startValue=360),/^backgroundPosition/.test(e)&&100===parseFloat(t.endValue)&&"%"===t.unitType&&(t.endValue=0,t.startValue=100)}),v(p,"reverse",{loop:!0,delay:o.delay})),o.queue!==!1&&$.dequeue(p,o.queue)}v.State.calls[e]=!1;for(var g=0,m=v.State.calls.length;m>g;g++)if(v.State.calls[g]!==!1){l=!0;break}l===!1&&(v.State.isTicking=!1,delete v.State.calls,v.State.calls=[])}var f=function(){if(r.documentMode)return r.documentMode;for(var e=7;e>4;e--){var t=r.createElement("div");if(t.innerHTML="",t.getElementsByTagName("span").length)return t=null,e}return a}(),d=function(){var e=0;return t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||function(t){var r=(new Date).getTime(),a;return a=Math.max(0,16-(r-e)),e=r+a,setTimeout(function(){t(r+a)},a)}}(),g={isString:function(e){return"string"==typeof e},isArray:Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},isFunction:function(e){return"[object Function]"===Object.prototype.toString.call(e)},isNode:function(e){return e&&e.nodeType},isNodeList:function(e){return"object"==typeof e&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(Object.prototype.toString.call(e))&&e.length!==a&&(0===e.length||"object"==typeof e[0]&&e[0].nodeType>0)},isWrapped:function(e){return e&&(e.jquery||t.Zepto&&t.Zepto.zepto.isZ(e))},isSVG:function(e){return t.SVGElement&&e instanceof t.SVGElement},isEmptyObject:function(e){for(var t in e)return!1;return!0}},$,m=!1;if(e.fn&&e.fn.jquery?($=e,m=!0):$=t.Velocity.Utilities,8>=f&&!m)throw new Error("Velocity: IE8 and below require jQuery to be loaded before Velocity.");if(7>=f)return void(jQuery.fn.velocity=jQuery.fn.animate);var y=400,h="swing",v={State:{isMobile:/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),isAndroid:/Android/i.test(navigator.userAgent),isGingerbread:/Android 2\.3\.[3-7]/i.test(navigator.userAgent),isChrome:t.chrome,isFirefox:/Firefox/i.test(navigator.userAgent),prefixElement:r.createElement("div"),prefixMatches:{},scrollAnchor:null,scrollPropertyLeft:null,scrollPropertyTop:null,isTicking:!1,calls:[]},CSS:{},Utilities:$,Redirects:{},Easings:{},Promise:t.Promise,defaults:{queue:"",duration:y,easing:h,begin:a,complete:a,progress:a,display:a,visibility:a,loop:!1,delay:!1,mobileHA:!0,_cacheValues:!0},init:function(e){$.data(e,"velocity",{isSVG:g.isSVG(e),isAnimating:!1,computedStyle:null,tweensContainer:null,rootPropertyValueCache:{},transformCache:{}})},hook:null,mock:!1,version:{major:1,minor:2,patch:1},debug:!1};t.pageYOffset!==a?(v.State.scrollAnchor=t,v.State.scrollPropertyLeft="pageXOffset",v.State.scrollPropertyTop="pageYOffset"):(v.State.scrollAnchor=r.documentElement||r.body.parentNode||r.body,v.State.scrollPropertyLeft="scrollLeft",v.State.scrollPropertyTop="scrollTop");var b=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,r,a){var n={x:t.x+a.dx*r,v:t.v+a.dv*r,tension:t.tension,friction:t.friction};return{dx:n.v,dv:e(n)}}function r(r,a){var n={dx:r.v,dv:e(r)},o=t(r,.5*a,n),i=t(r,.5*a,o),s=t(r,a,i),l=1/6*(n.dx+2*(o.dx+i.dx)+s.dx),u=1/6*(n.dv+2*(o.dv+i.dv)+s.dv);return r.x=r.x+l*a,r.v=r.v+u*a,r}return function a(e,t,n){var o={x:-1,v:0,tension:null,friction:null},i=[0],s=0,l=1e-4,u=.016,c,p,f;for(e=parseFloat(e)||500,t=parseFloat(t)||20,n=n||null,o.tension=e,o.friction=t,c=null!==n,c?(s=a(e,t),p=s/n*u):p=u;;)if(f=r(f||o,p),i.push(1+f.x),s+=16,!(Math.abs(f.x)>l&&Math.abs(f.v)>l))break;return c?function(e){return i[e*(i.length-1)|0]}:s}}();v.Easings={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},spring:function(e){return 1-Math.cos(4.5*e*Math.PI)*Math.exp(6*-e)}},$.each([["ease",[.25,.1,.25,1]],["ease-in",[.42,0,1,1]],["ease-out",[0,0,.58,1]],["ease-in-out",[.42,0,.58,1]],["easeInSine",[.47,0,.745,.715]],["easeOutSine",[.39,.575,.565,1]],["easeInOutSine",[.445,.05,.55,.95]],["easeInQuad",[.55,.085,.68,.53]],["easeOutQuad",[.25,.46,.45,.94]],["easeInOutQuad",[.455,.03,.515,.955]],["easeInCubic",[.55,.055,.675,.19]],["easeOutCubic",[.215,.61,.355,1]],["easeInOutCubic",[.645,.045,.355,1]],["easeInQuart",[.895,.03,.685,.22]],["easeOutQuart",[.165,.84,.44,1]],["easeInOutQuart",[.77,0,.175,1]],["easeInQuint",[.755,.05,.855,.06]],["easeOutQuint",[.23,1,.32,1]],["easeInOutQuint",[.86,0,.07,1]],["easeInExpo",[.95,.05,.795,.035]],["easeOutExpo",[.19,1,.22,1]],["easeInOutExpo",[1,0,0,1]],["easeInCirc",[.6,.04,.98,.335]],["easeOutCirc",[.075,.82,.165,1]],["easeInOutCirc",[.785,.135,.15,.86]]],function(e,t){v.Easings[t[0]]=l.apply(null,t[1])});var x=v.CSS={RegEx:{isHex:/^#([A-f\d]{3}){1,2}$/i,valueUnwrap:/^[A-z]+\((.*)\)$/i,wrappedValueAlreadyExtracted:/[0-9.]+ [0-9.]+ [0-9.]+( [0-9.]+)?/,valueSplit:/([A-z]+\(.+\))|(([A-z0-9#-.]+?)(?=\s|$))/gi},Lists:{colors:["fill","stroke","stopColor","color","backgroundColor","borderColor","borderTopColor","borderRightColor","borderBottomColor","borderLeftColor","outlineColor"],transformsBase:["translateX","translateY","scale","scaleX","scaleY","skewX","skewY","rotateZ"],transforms3D:["transformPerspective","translateZ","scaleZ","rotateX","rotateY"]},Hooks:{templates:{textShadow:["Color X Y Blur","black 0px 0px 0px"],boxShadow:["Color X Y Blur Spread","black 0px 0px 0px 0px"],clip:["Top Right Bottom Left","0px 0px 0px 0px"],backgroundPosition:["X Y","0% 0%"],transformOrigin:["X Y Z","50% 50% 0px"],perspectiveOrigin:["X Y","50% 50%"]},registered:{},register:function(){for(var e=0;e=f)switch(e){case"name":return"filter";case"extract":var a=r.toString().match(/alpha\(opacity=(.*)\)/i);return r=a?a[1]/100:1;case"inject":return t.style.zoom=1,parseFloat(r)>=1?"":"alpha(opacity="+parseInt(100*parseFloat(r),10)+")"}else switch(e){case"name":return"opacity";case"extract":return r;case"inject":return r}}},register:function(){9>=f||v.State.isGingerbread||(x.Lists.transformsBase=x.Lists.transformsBase.concat(x.Lists.transforms3D));for(var e=0;en&&(n=1),o=!/(\d)$/i.test(n);break;case"skew":o=!/(deg|\d)$/i.test(n);break;case"rotate":o=!/(deg|\d)$/i.test(n)}return o||(i(r).transformCache[t]="("+n+")"),i(r).transformCache[t]}}}();for(var e=0;e=f||3!==o.split(" ").length||(o+=" 1"),o;case"inject":return 8>=f?4===n.split(" ").length&&(n=n.split(/\s+/).slice(0,3).join(" ")):3===n.split(" ").length&&(n+=" 1"),(8>=f?"rgb":"rgba")+"("+n.replace(/\s+/g,",").replace(/\.(\d)+(?=,)/g,"")+")"}}}()}},Names:{camelCase:function(e){return e.replace(/-(\w)/g,function(e,t){return t.toUpperCase()})},SVGAttribute:function(e){var t="width|height|x|y|cx|cy|r|rx|ry|x1|x2|y1|y2";return(f||v.State.isAndroid&&!v.State.isChrome)&&(t+="|transform"),new RegExp("^("+t+")$","i").test(e)},prefixCheck:function(e){if(v.State.prefixMatches[e])return[v.State.prefixMatches[e],!0];for(var t=["","Webkit","Moz","ms","O"],r=0,a=t.length;a>r;r++){var n;if(n=0===r?e:t[r]+e.replace(/^\w/,function(e){return e.toUpperCase()}),g.isString(v.State.prefixElement.style[n]))return v.State.prefixMatches[e]=n,[n,!0]}return[e,!1]}},Values:{hexToRgb:function(e){var t=/^#?([a-f\d])([a-f\d])([a-f\d])$/i,r=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,a;return e=e.replace(t,function(e,t,r,a){return t+t+r+r+a+a}),a=r.exec(e),a?[parseInt(a[1],16),parseInt(a[2],16),parseInt(a[3],16)]:[0,0,0]},isCSSNullValue:function(e){return 0==e||/^(none|auto|transparent|(rgba\(0, ?0, ?0, ?0\)))$/i.test(e)},getUnitType:function(e){return/^(rotate|skew)/i.test(e)?"deg":/(^(scale|scaleX|scaleY|scaleZ|alpha|flexGrow|flexHeight|zIndex|fontWeight)$)|((opacity|red|green|blue|alpha)$)/i.test(e)?"":"px"},getDisplayType:function(e){var t=e&&e.tagName.toString().toLowerCase();return/^(b|big|i|small|tt|abbr|acronym|cite|code|dfn|em|kbd|strong|samp|var|a|bdo|br|img|map|object|q|script|span|sub|sup|button|input|label|select|textarea)$/i.test(t)?"inline":/^(li)$/i.test(t)?"list-item":/^(tr)$/i.test(t)?"table-row":/^(table)$/i.test(t)?"table":/^(tbody)$/i.test(t)?"table-row-group":"block"},addClass:function(e,t){e.classList?e.classList.add(t):e.className+=(e.className.length?" ":"")+t},removeClass:function(e,t){e.classList?e.classList.remove(t):e.className=e.className.toString().replace(new RegExp("(^|\\s)"+t.split(" ").join("|")+"(\\s|$)","gi")," ")}},getPropertyValue:function(e,r,n,o){function s(e,r){function n(){u&&x.setPropertyValue(e,"display","none")}var l=0;if(8>=f)l=$.css(e,r);else{var u=!1;if(/^(width|height)$/.test(r)&&0===x.getPropertyValue(e,"display")&&(u=!0,x.setPropertyValue(e,"display",x.Values.getDisplayType(e))),!o){if("height"===r&&"border-box"!==x.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var c=e.offsetHeight-(parseFloat(x.getPropertyValue(e,"borderTopWidth"))||0)-(parseFloat(x.getPropertyValue(e,"borderBottomWidth"))||0)-(parseFloat(x.getPropertyValue(e,"paddingTop"))||0)-(parseFloat(x.getPropertyValue(e,"paddingBottom"))||0);return n(),c}if("width"===r&&"border-box"!==x.getPropertyValue(e,"boxSizing").toString().toLowerCase()){var p=e.offsetWidth-(parseFloat(x.getPropertyValue(e,"borderLeftWidth"))||0)-(parseFloat(x.getPropertyValue(e,"borderRightWidth"))||0)-(parseFloat(x.getPropertyValue(e,"paddingLeft"))||0)-(parseFloat(x.getPropertyValue(e,"paddingRight"))||0);return n(),p}}var d;d=i(e)===a?t.getComputedStyle(e,null):i(e).computedStyle?i(e).computedStyle:i(e).computedStyle=t.getComputedStyle(e,null),"borderColor"===r&&(r="borderTopColor"),l=9===f&&"filter"===r?d.getPropertyValue(r):d[r],(""===l||null===l)&&(l=e.style[r]),n()}if("auto"===l&&/^(top|right|bottom|left)$/i.test(r)){var g=s(e,"position");("fixed"===g||"absolute"===g&&/top|left/i.test(r))&&(l=$(e).position()[r]+"px")}return l}var l;if(x.Hooks.registered[r]){var u=r,c=x.Hooks.getRoot(u);n===a&&(n=x.getPropertyValue(e,x.Names.prefixCheck(c)[0])),x.Normalizations.registered[c]&&(n=x.Normalizations.registered[c]("extract",e,n)),l=x.Hooks.extractValue(u,n)}else if(x.Normalizations.registered[r]){var p,d;p=x.Normalizations.registered[r]("name",e),"transform"!==p&&(d=s(e,x.Names.prefixCheck(p)[0]),x.Values.isCSSNullValue(d)&&x.Hooks.templates[r]&&(d=x.Hooks.templates[r][1])),l=x.Normalizations.registered[r]("extract",e,d)}if(!/^[\d-]/.test(l))if(i(e)&&i(e).isSVG&&x.Names.SVGAttribute(r))if(/^(height|width)$/i.test(r))try{l=e.getBBox()[r]}catch(g){l=0}else l=e.getAttribute(r);else l=s(e,x.Names.prefixCheck(r)[0]);return x.Values.isCSSNullValue(l)&&(l=0),v.debug>=2&&console.log("Get "+r+": "+l),l},setPropertyValue:function(e,r,a,n,o){var s=r;if("scroll"===r)o.container?o.container["scroll"+o.direction]=a:"Left"===o.direction?t.scrollTo(a,o.alternateValue):t.scrollTo(o.alternateValue,a);else if(x.Normalizations.registered[r]&&"transform"===x.Normalizations.registered[r]("name",e))x.Normalizations.registered[r]("inject",e,a),s="transform",a=i(e).transformCache[r];else{if(x.Hooks.registered[r]){var l=r,u=x.Hooks.getRoot(r);n=n||x.getPropertyValue(e,u),a=x.Hooks.injectValue(l,a,n),r=u}if(x.Normalizations.registered[r]&&(a=x.Normalizations.registered[r]("inject",e,a),r=x.Normalizations.registered[r]("name",e)),s=x.Names.prefixCheck(r)[0],8>=f)try{e.style[s]=a}catch(c){v.debug&&console.log("Browser does not support ["+a+"] for ["+s+"]")}else i(e)&&i(e).isSVG&&x.Names.SVGAttribute(r)?e.setAttribute(r,a):e.style[s]=a;v.debug>=2&&console.log("Set "+r+" ("+s+"): "+a)}return[s,a]},flushTransformCache:function(e){function t(t){return parseFloat(x.getPropertyValue(e,t))}var r="";if((f||v.State.isAndroid&&!v.State.isChrome)&&i(e).isSVG){var a={translate:[t("translateX"),t("translateY")],skewX:[t("skewX")],skewY:[t("skewY")],scale:1!==t("scale")?[t("scale"),t("scale")]:[t("scaleX"),t("scaleY")],rotate:[t("rotateZ"),0,0]};$.each(i(e).transformCache,function(e){/^translate/i.test(e)?e="translate":/^scale/i.test(e)?e="scale":/^rotate/i.test(e)&&(e="rotate"),a[e]&&(r+=e+"("+a[e].join(" ")+") ",delete a[e])})}else{var n,o;$.each(i(e).transformCache,function(t){return n=i(e).transformCache[t],"transformPerspective"===t?(o=n,!0):(9===f&&"rotateZ"===t&&(t="rotate"),void(r+=t+n+" "))}),o&&(r="perspective"+o+" "+r)}x.setPropertyValue(e,"transform",r)}};x.Hooks.register(),x.Normalizations.register(),v.hook=function(e,t,r){var n=a;return e=o(e),$.each(e,function(e,o){if(i(o)===a&&v.init(o),r===a)n===a&&(n=v.CSS.getPropertyValue(o,t));else{var s=v.CSS.setPropertyValue(o,t,r);"transform"===s[0]&&v.CSS.flushTransformCache(o),n=s}}),n};var S=function(){function e(){return l?T.promise||null:f}function n(){function e(e){function p(e,t){var r=a,i=a,s=a;return g.isArray(e)?(r=e[0],!g.isArray(e[1])&&/^[\d-]/.test(e[1])||g.isFunction(e[1])||x.RegEx.isHex.test(e[1])?s=e[1]:(g.isString(e[1])&&!x.RegEx.isHex.test(e[1])||g.isArray(e[1]))&&(i=t?e[1]:u(e[1],o.duration),e[2]!==a&&(s=e[2]))):r=e,t||(i=i||o.easing),g.isFunction(r)&&(r=r.call(n,w,P)),g.isFunction(s)&&(s=s.call(n,w,P)),[r||0,i,s]}function f(e,t){var r,a;return a=(t||"0").toString().toLowerCase().replace(/[%A-z]+$/,function(e){return r=e,""}),r||(r=x.Values.getUnitType(e)),[a,r]}function d(){var e={myParent:n.parentNode||r.body,position:x.getPropertyValue(n,"position"),fontSize:x.getPropertyValue(n,"fontSize")},a=e.position===N.lastPosition&&e.myParent===N.lastParent,o=e.fontSize===N.lastFontSize;N.lastParent=e.myParent,N.lastPosition=e.position,N.lastFontSize=e.fontSize;var s=100,l={};if(o&&a)l.emToPx=N.lastEmToPx,l.percentToPxWidth=N.lastPercentToPxWidth,l.percentToPxHeight=N.lastPercentToPxHeight;else{var u=i(n).isSVG?r.createElementNS("http://www.w3.org/2000/svg","rect"):r.createElement("div");v.init(u),e.myParent.appendChild(u),$.each(["overflow","overflowX","overflowY"],function(e,t){v.CSS.setPropertyValue(u,t,"hidden")}),v.CSS.setPropertyValue(u,"position",e.position),v.CSS.setPropertyValue(u,"fontSize",e.fontSize),v.CSS.setPropertyValue(u,"boxSizing","content-box"),$.each(["minWidth","maxWidth","width","minHeight","maxHeight","height"],function(e,t){v.CSS.setPropertyValue(u,t,s+"%")}),v.CSS.setPropertyValue(u,"paddingLeft",s+"em"),l.percentToPxWidth=N.lastPercentToPxWidth=(parseFloat(x.getPropertyValue(u,"width",null,!0))||1)/s,l.percentToPxHeight=N.lastPercentToPxHeight=(parseFloat(x.getPropertyValue(u,"height",null,!0))||1)/s,l.emToPx=N.lastEmToPx=(parseFloat(x.getPropertyValue(u,"paddingLeft"))||1)/s,e.myParent.removeChild(u)}return null===N.remToPx&&(N.remToPx=parseFloat(x.getPropertyValue(r.body,"fontSize"))||16),null===N.vwToPx&&(N.vwToPx=parseFloat(t.innerWidth)/100,N.vhToPx=parseFloat(t.innerHeight)/100),l.remToPx=N.remToPx,l.vwToPx=N.vwToPx,l.vhToPx=N.vhToPx,v.debug>=1&&console.log("Unit ratios: "+JSON.stringify(l),n),l}if(o.begin&&0===w)try{o.begin.call(m,m)}catch(y){setTimeout(function(){throw y},1)}if("scroll"===k){var S=/^x$/i.test(o.axis)?"Left":"Top",V=parseFloat(o.offset)||0,C,A,F;o.container?g.isWrapped(o.container)||g.isNode(o.container)?(o.container=o.container[0]||o.container,C=o.container["scroll"+S],F=C+$(n).position()[S.toLowerCase()]+V):o.container=null:(C=v.State.scrollAnchor[v.State["scrollProperty"+S]],A=v.State.scrollAnchor[v.State["scrollProperty"+("Left"===S?"Top":"Left")]],F=$(n).offset()[S.toLowerCase()]+V),s={scroll:{rootPropertyValue:!1,startValue:C,currentValue:C,endValue:F,unitType:"",easing:o.easing,scrollData:{container:o.container,direction:S,alternateValue:A}},element:n},v.debug&&console.log("tweensContainer (scroll): ",s.scroll,n)}else if("reverse"===k){if(!i(n).tweensContainer)return void $.dequeue(n,o.queue);"none"===i(n).opts.display&&(i(n).opts.display="auto"),"hidden"===i(n).opts.visibility&&(i(n).opts.visibility="visible"),i(n).opts.loop=!1,i(n).opts.begin=null,i(n).opts.complete=null,b.easing||delete o.easing,b.duration||delete o.duration,o=$.extend({},i(n).opts,o);var E=$.extend(!0,{},i(n).tweensContainer);for(var j in E)if("element"!==j){var H=E[j].startValue;E[j].startValue=E[j].currentValue=E[j].endValue,E[j].endValue=H,g.isEmptyObject(b)||(E[j].easing=o.easing),v.debug&&console.log("reverse tweensContainer ("+j+"): "+JSON.stringify(E[j]),n)}s=E}else if("start"===k){var E;i(n).tweensContainer&&i(n).isAnimating===!0&&(E=i(n).tweensContainer),$.each(h,function(e,t){if(RegExp("^"+x.Lists.colors.join("$|^")+"$").test(e)){var r=p(t,!0),n=r[0],o=r[1],i=r[2];if(x.RegEx.isHex.test(n)){for(var s=["Red","Green","Blue"],l=x.Values.hexToRgb(n),u=i?x.Values.hexToRgb(i):a,c=0;cO;O++){var z={delay:F.delay,progress:F.progress};O===R-1&&(z.display=F.display,z.visibility=F.visibility,z.complete=F.complete),S(m,"reverse",z)}return e()}};v=$.extend(S,v),v.animate=S;var P=t.requestAnimationFrame||d;return v.State.isMobile||r.hidden===a||r.addEventListener("visibilitychange",function(){r.hidden?(P=function(e){return setTimeout(function(){e(!0)},16)},c()):P=t.requestAnimationFrame||d}),e.Velocity=v,e!==t&&(e.fn.velocity=S,e.fn.velocity.defaults=v.defaults),$.each(["Down","Up"],function(e,t){v.Redirects["slide"+t]=function(e,r,n,o,i,s){var l=$.extend({},r),u=l.begin,c=l.complete,p={height:"",marginTop:"",marginBottom:"",paddingTop:"",paddingBottom:""},f={};l.display===a&&(l.display="Down"===t?"inline"===v.CSS.Values.getDisplayType(e)?"inline-block":"block":"none"),l.begin=function(){u&&u.call(i,i);for(var r in p){f[r]=e.style[r];var a=v.CSS.getPropertyValue(e,r);p[r]="Down"===t?[a,0]:[0,a]}f.overflow=e.style.overflow,e.style.overflow="hidden"},l.complete=function(){for(var t in f)e.style[t]=f[t];c&&c.call(i,i),s&&s.resolver(i)},v(e,p,l)}}),$.each(["In","Out"],function(e,t){v.Redirects["fade"+t]=function(e,r,n,o,i,s){var l=$.extend({},r),u={opacity:"In"===t?1:0},c=l.complete;l.complete=n!==o-1?l.begin=null:function(){c&&c.call(i,i),s&&s.resolver(i)},l.display===a&&(l.display="In"===t?"auto":"none"),v(this,u,l)}}),v}(window.jQuery||window.Zepto||window,window,document)});
--------------------------------------------------------------------------------
/_attachments/script/velocity.ui.min.js:
--------------------------------------------------------------------------------
1 | /* VelocityJS.org UI Pack (5.0.3). (C) 2014 Julian Shapiro. MIT @license: en.wikipedia.org/wiki/MIT_License. Portions copyright Daniel Eden, Christian Pucci. */
2 | !function(t){"function"==typeof require&&"object"==typeof exports?module.exports=t():"function"==typeof define&&define.amd?define(["velocity"],t):t()}(function(){return function(t,a,e,r){function n(t,a){var e=[];return t&&a?($.each([t,a],function(t,a){var r=[];$.each(a,function(t,a){for(;a.toString().length<5;)a="0"+a;r.push(a)}),e.push(r.join(""))}),parseFloat(e[0])>parseFloat(e[1])):!1}if(!t.Velocity||!t.Velocity.Utilities)return void(a.console&&console.log("Velocity UI Pack: Velocity must be loaded first. Aborting."));var i=t.Velocity,$=i.Utilities,s=i.version,o={major:1,minor:1,patch:0};if(n(o,s)){var l="Velocity UI Pack: You need to update Velocity (jquery.velocity.js) to a newer version. Visit http://github.com/julianshapiro/velocity.";throw alert(l),new Error(l)}i.RegisterEffect=i.RegisterUI=function(t,a){function e(t,a,e,r){var n=0,s;$.each(t.nodeType?[t]:t,function(t,a){r&&(e+=t*r),s=a.parentNode,$.each(["height","paddingTop","paddingBottom","marginTop","marginBottom"],function(t,e){n+=parseFloat(i.CSS.getPropertyValue(a,e))})}),i.animate(s,{height:("In"===a?"+":"-")+"="+n},{queue:!1,easing:"ease-in-out",duration:e*("In"===a?.6:1)})}return i.Redirects[t]=function(n,s,o,l,c,u){function f(){s.display!==r&&"none"!==s.display||!/Out$/.test(t)||$.each(c.nodeType?[c]:c,function(t,a){i.CSS.setPropertyValue(a,"display","none")}),s.complete&&s.complete.call(c,c),u&&u.resolver(c||n)}var p=o===l-1;a.defaultDuration="function"==typeof a.defaultDuration?a.defaultDuration.call(c,c):parseFloat(a.defaultDuration);for(var d=0;d1&&($.each(a.reverse(),function(t,e){var r=a[t+1];if(r){var n=e.options||e.o,s=r.options||r.o,o=n&&n.sequenceQueue===!1?"begin":"complete",l=s&&s[o],c={};c[o]=function(){var t=r.elements||r.e,a=t.nodeType?[t]:t;l&&l.call(a,a),i(e)},r.options=$.extend({},r.options,c)}}),a.reverse()),i(a[0])}}(window.jQuery||window.Zepto||window,window,document)});
--------------------------------------------------------------------------------
/_attachments/style/L.Control.Locate.min.css:
--------------------------------------------------------------------------------
1 | /*! Version: 0.38.0
2 | Date: 2014-12-31 */
3 |
4 | .leaflet-touch .leaflet-bar-part-single{-webkit-border-radius:7px 7px 7px 7px;border-radius:7px 7px 7px 7px;border-bottom:none}.leaflet-touch .leaflet-control-locate{box-shadow:none;border:2px solid rgba(0,0,0,0.2);background-clip:padding-box}.leaflet-control-locate a{font-size:1.4em;margin-left:1px;color:#444}.leaflet-control-locate.active a{color:#2074B6}.leaflet-control-locate.active.following a{color:#FC8428}
5 | /*# sourceMappingURL=L.Control.Locate.min.css.map */
6 |
--------------------------------------------------------------------------------
/_attachments/style/L.Control.Locate.min.css.map:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "mappings": "AAEC,uCAAyB,CACxB,qBAAqB,CAAE,eAAe,CAC9B,aAAa,CAAE,eAAe,CACtC,aAAa,CAAE,IAAI,CAGpB,sCAAwB,CACvB,UAAU,CAAE,IAAI,CAChB,MAAM,CAAE,yBAAyB,CACjC,eAAe,CAAE,WAAW,CAK7B,yBAAE,CACD,SAAS,CAAE,KAAK,CAChB,WAAW,CAAE,GAAG,CACb,KAAK,CAAE,IAAI,CAGb,gCAAE,CACF,KAAK,CAAE,OAAO,CAEf,0CAAc,CACb,KAAK,CAAE,OAAO",
4 | "sources": ["../src/L.Control.Locate.scss"],
5 | "names": [],
6 | "file": "L.Control.Locate.min.css"
7 | }
8 |
--------------------------------------------------------------------------------
/_attachments/style/leaflet.css:
--------------------------------------------------------------------------------
1 | /* required styles */
2 |
3 | .leaflet-map-pane,
4 | .leaflet-tile,
5 | .leaflet-marker-icon,
6 | .leaflet-marker-shadow,
7 | .leaflet-tile-pane,
8 | .leaflet-tile-container,
9 | .leaflet-overlay-pane,
10 | .leaflet-shadow-pane,
11 | .leaflet-marker-pane,
12 | .leaflet-popup-pane,
13 | .leaflet-overlay-pane svg,
14 | .leaflet-zoom-box,
15 | .leaflet-image-layer,
16 | .leaflet-layer {
17 | position: absolute;
18 | left: 0;
19 | top: 0;
20 | }
21 | .leaflet-container {
22 | overflow: hidden;
23 | -ms-touch-action: none;
24 | }
25 | .leaflet-tile,
26 | .leaflet-marker-icon,
27 | .leaflet-marker-shadow {
28 | -webkit-user-select: none;
29 | -moz-user-select: none;
30 | user-select: none;
31 | -webkit-user-drag: none;
32 | }
33 | .leaflet-marker-icon,
34 | .leaflet-marker-shadow {
35 | display: block;
36 | }
37 | /* map is broken in FF if you have max-width: 100% on tiles */
38 | .leaflet-container img {
39 | max-width: none !important;
40 | }
41 | /* stupid Android 2 doesn't understand "max-width: none" properly */
42 | .leaflet-container img.leaflet-image-layer {
43 | max-width: 15000px !important;
44 | }
45 | .leaflet-tile {
46 | filter: inherit;
47 | visibility: hidden;
48 | }
49 | .leaflet-tile-loaded {
50 | visibility: inherit;
51 | }
52 | .leaflet-zoom-box {
53 | width: 0;
54 | height: 0;
55 | }
56 | /* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
57 | .leaflet-overlay-pane svg {
58 | -moz-user-select: none;
59 | }
60 |
61 | .leaflet-tile-pane { z-index: 2; }
62 | .leaflet-objects-pane { z-index: 3; }
63 | .leaflet-overlay-pane { z-index: 4; }
64 | .leaflet-shadow-pane { z-index: 5; }
65 | .leaflet-marker-pane { z-index: 6; }
66 | .leaflet-popup-pane { z-index: 7; }
67 |
68 | .leaflet-vml-shape {
69 | width: 1px;
70 | height: 1px;
71 | }
72 | .lvml {
73 | behavior: url(#default#VML);
74 | display: inline-block;
75 | position: absolute;
76 | }
77 |
78 |
79 | /* control positioning */
80 |
81 | .leaflet-control {
82 | position: relative;
83 | z-index: 7;
84 | pointer-events: auto;
85 | }
86 | .leaflet-top,
87 | .leaflet-bottom {
88 | position: absolute;
89 | z-index: 1000;
90 | pointer-events: none;
91 | }
92 | .leaflet-top {
93 | top: 0;
94 | }
95 | .leaflet-right {
96 | right: 0;
97 | }
98 | .leaflet-bottom {
99 | bottom: 0;
100 | }
101 | .leaflet-left {
102 | left: 0;
103 | }
104 | .leaflet-control {
105 | float: left;
106 | clear: both;
107 | }
108 | .leaflet-right .leaflet-control {
109 | float: right;
110 | }
111 | .leaflet-top .leaflet-control {
112 | margin-top: 10px;
113 | }
114 | .leaflet-bottom .leaflet-control {
115 | margin-bottom: 10px;
116 | }
117 | .leaflet-left .leaflet-control {
118 | margin-left: 10px;
119 | }
120 | .leaflet-right .leaflet-control {
121 | margin-right: 10px;
122 | }
123 |
124 |
125 | /* zoom and fade animations */
126 |
127 | .leaflet-fade-anim .leaflet-tile,
128 | .leaflet-fade-anim .leaflet-popup {
129 | opacity: 0;
130 | -webkit-transition: opacity 0.2s linear;
131 | -moz-transition: opacity 0.2s linear;
132 | -o-transition: opacity 0.2s linear;
133 | transition: opacity 0.2s linear;
134 | }
135 | .leaflet-fade-anim .leaflet-tile-loaded,
136 | .leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
137 | opacity: 1;
138 | }
139 |
140 | .leaflet-zoom-anim .leaflet-zoom-animated {
141 | -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
142 | -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
143 | -o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
144 | transition: transform 0.25s cubic-bezier(0,0,0.25,1);
145 | }
146 | .leaflet-zoom-anim .leaflet-tile,
147 | .leaflet-pan-anim .leaflet-tile,
148 | .leaflet-touching .leaflet-zoom-animated {
149 | -webkit-transition: none;
150 | -moz-transition: none;
151 | -o-transition: none;
152 | transition: none;
153 | }
154 |
155 | .leaflet-zoom-anim .leaflet-zoom-hide {
156 | visibility: hidden;
157 | }
158 |
159 |
160 | /* cursors */
161 |
162 | .leaflet-clickable {
163 | cursor: pointer;
164 | }
165 | .leaflet-container {
166 | cursor: -webkit-grab;
167 | cursor: -moz-grab;
168 | }
169 | .leaflet-popup-pane,
170 | .leaflet-control {
171 | cursor: auto;
172 | }
173 | .leaflet-dragging .leaflet-container,
174 | .leaflet-dragging .leaflet-clickable {
175 | cursor: move;
176 | cursor: -webkit-grabbing;
177 | cursor: -moz-grabbing;
178 | }
179 |
180 |
181 | /* visual tweaks */
182 |
183 | .leaflet-container {
184 | background: #ddd;
185 | outline: 0;
186 | }
187 | .leaflet-container a {
188 | color: #0078A8;
189 | }
190 | .leaflet-container a.leaflet-active {
191 | outline: 2px solid orange;
192 | }
193 | .leaflet-zoom-box {
194 | border: 2px dotted #38f;
195 | background: rgba(255,255,255,0.5);
196 | }
197 |
198 |
199 | /* general typography */
200 | .leaflet-container {
201 | font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
202 | }
203 |
204 |
205 | /* general toolbar styles */
206 |
207 | .leaflet-bar {
208 | box-shadow: 0 1px 5px rgba(0,0,0,0.65);
209 | border-radius: 4px;
210 | }
211 | .leaflet-bar a,
212 | .leaflet-bar a:hover {
213 | background-color: #fff;
214 | border-bottom: 1px solid #ccc;
215 | width: 26px;
216 | height: 26px;
217 | line-height: 26px;
218 | display: block;
219 | text-align: center;
220 | text-decoration: none;
221 | color: black;
222 | }
223 | .leaflet-bar a,
224 | .leaflet-control-layers-toggle {
225 | background-position: 50% 50%;
226 | background-repeat: no-repeat;
227 | display: block;
228 | }
229 | .leaflet-bar a:hover {
230 | background-color: #f4f4f4;
231 | }
232 | .leaflet-bar a:first-child {
233 | border-top-left-radius: 4px;
234 | border-top-right-radius: 4px;
235 | }
236 | .leaflet-bar a:last-child {
237 | border-bottom-left-radius: 4px;
238 | border-bottom-right-radius: 4px;
239 | border-bottom: none;
240 | }
241 | .leaflet-bar a.leaflet-disabled {
242 | cursor: default;
243 | background-color: #f4f4f4;
244 | color: #bbb;
245 | }
246 |
247 | .leaflet-touch .leaflet-bar a {
248 | width: 30px;
249 | height: 30px;
250 | line-height: 30px;
251 | }
252 |
253 |
254 | /* zoom control */
255 |
256 | .leaflet-control-zoom-in,
257 | .leaflet-control-zoom-out {
258 | font: bold 18px 'Lucida Console', Monaco, monospace;
259 | text-indent: 1px;
260 | }
261 | .leaflet-control-zoom-out {
262 | font-size: 20px;
263 | }
264 |
265 | .leaflet-touch .leaflet-control-zoom-in {
266 | font-size: 22px;
267 | }
268 | .leaflet-touch .leaflet-control-zoom-out {
269 | font-size: 24px;
270 | }
271 |
272 |
273 | /* layers control */
274 |
275 | .leaflet-control-layers {
276 | box-shadow: 0 1px 5px rgba(0,0,0,0.4);
277 | background: #fff;
278 | border-radius: 5px;
279 | }
280 | .leaflet-control-layers-toggle {
281 | background-image: url(images/layers.png);
282 | width: 36px;
283 | height: 36px;
284 | }
285 | .leaflet-retina .leaflet-control-layers-toggle {
286 | background-image: url(images/layers-2x.png);
287 | background-size: 26px 26px;
288 | }
289 | .leaflet-touch .leaflet-control-layers-toggle {
290 | width: 44px;
291 | height: 44px;
292 | }
293 | .leaflet-control-layers .leaflet-control-layers-list,
294 | .leaflet-control-layers-expanded .leaflet-control-layers-toggle {
295 | display: none;
296 | }
297 | .leaflet-control-layers-expanded .leaflet-control-layers-list {
298 | display: block;
299 | position: relative;
300 | }
301 | .leaflet-control-layers-expanded {
302 | padding: 6px 10px 6px 6px;
303 | color: #333;
304 | background: #fff;
305 | }
306 | .leaflet-control-layers-selector {
307 | margin-top: 2px;
308 | position: relative;
309 | top: 1px;
310 | }
311 | .leaflet-control-layers label {
312 | display: block;
313 | }
314 | .leaflet-control-layers-separator {
315 | height: 0;
316 | border-top: 1px solid #ddd;
317 | margin: 5px -10px 5px -6px;
318 | }
319 |
320 |
321 | /* attribution and scale controls */
322 |
323 | .leaflet-container .leaflet-control-attribution {
324 | background: #fff;
325 | background: rgba(255, 255, 255, 0.7);
326 | margin: 0;
327 | }
328 | .leaflet-control-attribution,
329 | .leaflet-control-scale-line {
330 | padding: 0 5px;
331 | color: #333;
332 | }
333 | .leaflet-control-attribution a {
334 | text-decoration: none;
335 | }
336 | .leaflet-control-attribution a:hover {
337 | text-decoration: underline;
338 | }
339 | .leaflet-container .leaflet-control-attribution,
340 | .leaflet-container .leaflet-control-scale {
341 | font-size: 11px;
342 | }
343 | .leaflet-left .leaflet-control-scale {
344 | margin-left: 5px;
345 | }
346 | .leaflet-bottom .leaflet-control-scale {
347 | margin-bottom: 5px;
348 | }
349 | .leaflet-control-scale-line {
350 | border: 2px solid #777;
351 | border-top: none;
352 | line-height: 1.1;
353 | padding: 2px 5px 1px;
354 | font-size: 11px;
355 | white-space: nowrap;
356 | overflow: hidden;
357 | -moz-box-sizing: content-box;
358 | box-sizing: content-box;
359 |
360 | background: #fff;
361 | background: rgba(255, 255, 255, 0.5);
362 | }
363 | .leaflet-control-scale-line:not(:first-child) {
364 | border-top: 2px solid #777;
365 | border-bottom: none;
366 | margin-top: -2px;
367 | }
368 | .leaflet-control-scale-line:not(:first-child):not(:last-child) {
369 | border-bottom: 2px solid #777;
370 | }
371 |
372 | .leaflet-touch .leaflet-control-attribution,
373 | .leaflet-touch .leaflet-control-layers,
374 | .leaflet-touch .leaflet-bar {
375 | box-shadow: none;
376 | }
377 | .leaflet-touch .leaflet-control-layers,
378 | .leaflet-touch .leaflet-bar {
379 | border: 2px solid rgba(0,0,0,0.2);
380 | background-clip: padding-box;
381 | }
382 |
383 |
384 | /* popup */
385 |
386 | .leaflet-popup {
387 | position: absolute;
388 | text-align: center;
389 | }
390 | .leaflet-popup-content-wrapper {
391 | padding: 1px;
392 | text-align: left;
393 | border-radius: 12px;
394 | }
395 | .leaflet-popup-content {
396 | margin: 13px 19px;
397 | line-height: 1.4;
398 | }
399 | .leaflet-popup-content p {
400 | margin: 18px 0;
401 | }
402 | .leaflet-popup-tip-container {
403 | margin: 0 auto;
404 | width: 40px;
405 | height: 20px;
406 | position: relative;
407 | overflow: hidden;
408 | }
409 | .leaflet-popup-tip {
410 | width: 17px;
411 | height: 17px;
412 | padding: 1px;
413 |
414 | margin: -10px auto 0;
415 |
416 | -webkit-transform: rotate(45deg);
417 | -moz-transform: rotate(45deg);
418 | -ms-transform: rotate(45deg);
419 | -o-transform: rotate(45deg);
420 | transform: rotate(45deg);
421 | }
422 | .leaflet-popup-content-wrapper,
423 | .leaflet-popup-tip {
424 | background: white;
425 |
426 | box-shadow: 0 3px 14px rgba(0,0,0,0.4);
427 | }
428 | .leaflet-container a.leaflet-popup-close-button {
429 | position: absolute;
430 | top: 0;
431 | right: 0;
432 | padding: 4px 4px 0 0;
433 | text-align: center;
434 | width: 18px;
435 | height: 14px;
436 | font: 16px/14px Tahoma, Verdana, sans-serif;
437 | color: #c3c3c3;
438 | text-decoration: none;
439 | font-weight: bold;
440 | background: transparent;
441 | }
442 | .leaflet-container a.leaflet-popup-close-button:hover {
443 | color: #999;
444 | }
445 | .leaflet-popup-scrolled {
446 | overflow: auto;
447 | border-bottom: 1px solid #ddd;
448 | border-top: 1px solid #ddd;
449 | }
450 |
451 | .leaflet-oldie .leaflet-popup-content-wrapper {
452 | zoom: 1;
453 | }
454 | .leaflet-oldie .leaflet-popup-tip {
455 | width: 24px;
456 | margin: 0 auto;
457 |
458 | -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
459 | filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
460 | }
461 | .leaflet-oldie .leaflet-popup-tip-container {
462 | margin-top: -1px;
463 | }
464 |
465 | .leaflet-oldie .leaflet-control-zoom,
466 | .leaflet-oldie .leaflet-control-layers,
467 | .leaflet-oldie .leaflet-popup-content-wrapper,
468 | .leaflet-oldie .leaflet-popup-tip {
469 | border: 1px solid #999;
470 | }
471 |
472 |
473 | /* div icon */
474 |
475 | .leaflet-div-icon {
476 | background: #fff;
477 | border: 1px solid #666;
478 | }
479 |
--------------------------------------------------------------------------------
/_attachments/style/mapbox-style.less:
--------------------------------------------------------------------------------
1 | // Languages: name (local), name_en, name_fr, name_es, name_de
2 | @name: '[name_en]';
3 |
4 | // Fonts //
5 | @fallback: 'Source Sans Pro Regular';
6 | @sans: 'Source Sans Pro Regular', 'Arial Unicode MS Regular';
7 | @sans_md: 'Source Sans Pro Semibold', 'Arial Unicode MS Regular';
8 | @sans_bd: 'Source Sans Pro Bold','Arial Unicode MS Bold';
9 | @sans_it: 'Source Sans Pro Italic', 'Arial Unicode MS Regular';
10 | @sans_bdit: 'Source Sans Pro Bold Italic','Arial Unicode MS Bold';
11 |
12 | /*
13 | This style is designed to be easily recolored by adjusting the color
14 | variables below. For predicatable feature relationships,
15 | maintain or invert existing value (light to dark) scale.
16 | */
17 |
18 | // Color palette //
19 | @road: #3a8cc0;
20 | @land: #255b86;
21 |
22 | @fill1: #1b4668;
23 | @fill2: #1b4668;
24 | @fill3: #f2f2f2;
25 | @fill4: #ffffff;
26 | @fill5: #7a7a7a;
27 |
28 | @text: #b8c4c9;
29 |
30 | Map { background-color: @land; }
31 |
32 | // Political boundaries //
33 | #admin[admin_level=2][maritime=0] {
34 | line-join: round;
35 | line-color: @fill5;
36 | line-width: 1;
37 | [zoom>=5] { line-width: 1.4; }
38 | [zoom>=6] { line-width: 1.8; }
39 | [zoom>=8] { line-width: 2; }
40 | [zoom>=10] { line-width: 3; }
41 | [disputed=1] { line-dasharray: 4,4; }
42 | }
43 |
44 | #admin[admin_level>2][maritime=0] {
45 | line-join: round;
46 | line-color: @fill5;
47 | line-width: 1;
48 | line-dasharray: 3,2;
49 | [zoom>=6] { line-width: 1.5; }
50 | [zoom>=8] { line-width: 1.8; }
51 | }
52 |
53 | // Land Features //
54 | #landuse[class='cemetery'],
55 | #landuse[class='park'],
56 | #landuse[class='wood'],
57 | #landuse_overlay {
58 | polygon-fill: darken(@land,3);
59 | [zoom>=15] { polygon-fill:mix(@land,@fill4,95); }
60 | }
61 |
62 | #landuse[class='pitch'],
63 | #landuse[class='sand'] {
64 | polygon-fill: mix(@land,@fill4,90);
65 | }
66 |
67 | #landuse[class='hospital'],
68 | #landuse[class='industrial'],
69 | #landuse[class='school'] {
70 | polygon-fill: mix(@land,@fill1,95);
71 | }
72 |
73 | #building {
74 | polygon-fill: mix(@fill2,@land,25);
75 | [zoom>=16]{ polygon-fill: mix(@fill2,@land,50);}
76 | }
77 |
78 | #aeroway {
79 | ['mapnik::geometry_type'=3][type!='apron'] {
80 | polygon-fill: mix(@fill2,@land,25);
81 | [zoom>=16]{ polygon-fill: mix(@fill2,@land,50);}
82 | }
83 | ['mapnik::geometry_type'=2] {
84 | line-color: mix(@fill2,@land,25);
85 | line-width: 1;
86 | [zoom>=13][type='runway'] { line-width: 4; }
87 | [zoom>=16] {
88 | [type='runway'] { line-width: 6; }
89 | line-width: 3;
90 | line-color: mix(@fill2,@land,50);
91 | }
92 | }
93 | }
94 |
95 | // Water Features //
96 | #water {
97 | ::shadow {
98 | polygon-fill: mix(@land,@fill4,75);
99 |
100 | }
101 | ::fill {
102 | // a fill and overlay comp-op lighten the polygon-
103 | // fill from ::shadow.
104 | polygon-fill: @land;
105 | comp-op: soft-light;
106 | // blurring reveals the polygon fill from ::shadow around
107 | // the edges of the water
108 | image-filters: agg-stack-blur(10,10);
109 | image-filters-inflate: true;
110 | }
111 | }
112 |
113 | // Water color is calculated by sampling the resulting color from
114 | // the soft-light comp-op in the #water layer style above.
115 | @water: #2e2e2e;
116 |
117 | #waterway {
118 | [type='river'],
119 | [type='canal'] {
120 | line-color: @water;
121 | line-width: 0.5;
122 | [zoom>=12] { line-width: 1; }
123 | [zoom>=14] { line-width: 2; }
124 | [zoom>=16] { line-width: 3; }
125 | }
126 | [type='stream'] {
127 | line-color: @water;
128 | line-width: 0.5;
129 | [zoom>=14] { line-width: 1; }
130 | [zoom>=16] { line-width: 2; }
131 | [zoom>=18] { line-width: 3; }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/_attachments/style/style.css:
--------------------------------------------------------------------------------
1 | /* BASIC STYLINGS
2 | ============================================================================= */
3 |
4 | *, *:before, *:after {
5 | -webkit-box-sizing: border-box;
6 | -moz-box-sizing: border-box;
7 | box-sizing: border-box;
8 | }
9 | html, body {
10 | height: 100%;
11 | }
12 | body {
13 | margin: 0;
14 | font-family: 'helvetica-neue', helvetica;
15 | color: #f2f2f2;
16 | background: #245a85;
17 | font-size: 14px;
18 | line-height: 1.6;
19 | }
20 | nav {
21 | display: block;
22 | width: 100%;
23 | position: fixed;
24 | height: 48px;
25 | background-color: #222b33; //rgba(34, 30, 31, 0.8);
26 | ;
27 | z-index: 1;
28 | }
29 | .container {
30 | margin-right: auto;
31 | margin-left: auto;
32 | padding-left: 15px;
33 | padding-right: 15px;
34 | }
35 | .row {
36 | margin-left: -15px;
37 | margin-right: -15px;
38 | }
39 | .container:before, .container:after, .container-fluid:before, .container-fluid:after, .row:before, .row:after {
40 | content: " ";
41 | display: table;
42 | }
43 | #cloudant-logo {
44 | background: url('../images/sprite.png') no-repeat -178px 0px;
45 | width: 44px;
46 | height: 44px;
47 | position: absolute;
48 | display: inline-block;
49 | -moz-background-size: cover;
50 | -webkit-background-size: cover;
51 | background-size: cover;
52 | top: 2px;
53 | left: 5px;
54 | }
55 | nav .page-title {
56 | position: relative;
57 | height: inherit;
58 | font-size: 10px;
59 | font-weight: 400;
60 | color: #bababa;
61 | display: block;
62 | text-align: center;
63 | line-height: 48px;
64 | text-transform: uppercase;
65 | }
66 | a {
67 | color: #0ce3ac;
68 | }
69 | a, a:hover, a:active {
70 | text-decoration: none;
71 | }
72 | .btn {
73 | display: inline-block;
74 | margin-bottom: 0;
75 | font-weight: 200;
76 | text-align: center;
77 | vertical-align: middle;
78 | cursor: pointer;
79 | background-image: none;
80 | border: 1px solid transparent;
81 | white-space: nowrap;
82 | padding: 24px;
83 | font-size: 14px;
84 | line-height: 1.4;
85 | border-radius: 0;
86 | color: #f2f2f2;
87 | -webkit-user-select: none;
88 | -moz-user-select: none;
89 | -ms-user-select: none;
90 | user-select: none;
91 | -webkit-transition: all 0.5s ease-in-out;
92 | -moz-transition: all 0.5s ease-in-out;
93 | -o-transition: all 0.5s ease-in-out;
94 | transition: all 0.5s ease-in-out;
95 | }
96 | .btn.btnHover {
97 | background-color: #F3622D;
98 | color: #fff;
99 | }
100 | .btn-block {
101 | display: block;
102 | width: 100%;
103 | padding-left: 0;
104 | padding-right: 0;
105 | }
106 | .btn-primary, .btn-primary.active {
107 | background-color: #3a8cc0;
108 | }
109 | .btn-info, .btn-info.active {
110 | background-color: #329898;
111 | }
112 | .btn-save, .btn-save.active {
113 | background-color: #329898;
114 | }
115 | pre {
116 | margin-bottom: 20px;
117 | }
118 | /* WELCOME PAGE*/
119 |
120 | .content-table {
121 | display: table;
122 | height: inherit;
123 | width: 100%;
124 | }
125 | .content-table-cell {
126 | display: table-cell;
127 | vertical-align: middle;
128 | }
129 | .directional-copy {
130 | font-size: 14px;
131 | color: #6fc4e8;
132 | text-align: center;
133 | }
134 | /* LOCATION PAGE*/
135 |
136 | .center-container {
137 | width: 100%;
138 | display: table;
139 | height: inherit;
140 | position: absolute;
141 | top: 0;
142 | }
143 | .table-cell {
144 | display: table-cell;
145 | vertical-align: middle;
146 | }
147 | .center-block {
148 | width: 50%;
149 | margin: 0 auto;
150 | }
151 | .button-bottom {
152 | width: 100%;
153 | position: absolute;
154 | bottom: 0;
155 | }
156 | .button-bottom .btn {
157 | margin-top: 1px;
158 | }
159 | #map, #mapResult {
160 | background-color: #221e1f;
161 | height: auto;
162 | display: block;
163 | top: 0px;
164 | bottom: 189px;
165 | position: absolute;
166 | width: 100%;
167 | }
168 | #mapResult.result {
169 | bottom: 69px;
170 | }
171 | .location-tracker-bottom {
172 | position: absolute;
173 | bottom: 0;
174 | display: block;
175 | width: 100%;
176 | }
177 | .long-lat-container {
178 | width: 100%;
179 | display: table;
180 | height: 120px;
181 | background-color: #f2f2f2;
182 | }
183 | .longitude, .latitude {
184 | vertical-align: middle;
185 | height: 120px;
186 | display: table-cell;
187 | width: 50%;
188 | text-align: center;
189 | font-size: 28px;
190 | line-height: 8px;
191 | color: #717981;
192 | }
193 | .latitude {
194 | border-left: 1px solid #ccc;
195 | }
196 | .longitude span, .latitude span {
197 | font-size: 16px;
198 | color: #909aa5;
199 | font-weight: 200;
200 | }
201 | .save-data {
202 | top: -14px;
203 | position: relative;
204 | display: block;
205 | height: 260px;
206 | z-index: 3;
207 | }
208 | .save-data .cloudant-icon {
209 | background: url('../images/sprite.png') no-repeat -55px 0px;
210 | position: relative;
211 | margin: auto;
212 | }
213 | .save-data .arrow-icon {
214 | background: url('../images/sprite.png') no-repeat -355px 0px;
215 | position: relative;
216 | margin: -12px auto -24px auto;
217 | }
218 | .save-data .dot {
219 | display: block;
220 | position: relative;
221 | height: 8px;
222 | width: 8px;
223 | background-color: #f2f2f2;
224 | margin: 8px auto;
225 | }
226 | .save-data .location-icon {
227 | background: url('../images/sprite.png') no-repeat -5px 0px;
228 | position: absolute;
229 | bottom: 0;
230 | left: 50%;
231 | margin-left: -20px;
232 | }
233 | .save-data .cloudant-icon, .save-data .arrow-icon, .save-data .location-icon {
234 | display: block;
235 | width: 40px;
236 | height: 60px;
237 | -moz-background-size: cover;
238 | -webkit-background-size: cover;
239 | background-size: cover;
240 | }
241 | /* ANIMATION STYLINGS
242 | ============================================================================= */
243 | /* basic styling for entering and leaving */
244 | /* left and right added to ensure full width */
245 |
246 | #location-views {
247 | padding-top: 48px;
248 | top: 0;
249 | height: 100%;
250 | background-color: #245a85;
251 | position: absolute;
252 | left: 0;
253 | right: 0;
254 | overflow: hidden;
255 | opacity: 0;
256 | }
257 | .anim-page-transition-js {
258 | display: block;
259 | position: relative;
260 | height: 100%;
261 | }
262 | .globe, .message {
263 | display: block;
264 | position: relative;
265 | width: 340px;
266 | overflow-x: hidden;
267 | left: 50%;
268 | margin-left: -170px;
269 | }
270 | .globe {
271 | margin-top: -60px;
272 | height: 240px;
273 | }
274 | .globe.save-data {
275 | margin-top: 20px;
276 | }
277 | .message {
278 | text-align: center;
279 | height: 320px;
280 | margin-top: -120px;
281 | }
282 | .message .success-icon, .message .error-icon {
283 | margin-left: -21px;
284 | top: 10px;
285 | left: 50%;
286 | }
287 | .message .success-icon {
288 | background: url('../images/sprite.png') no-repeat -390px 0px;
289 | }
290 | .message .error-icon {
291 | background: url('../images/sprite.png') no-repeat -346px 0px;
292 | }
293 | .message .success-message {
294 | color: #6fc4e8;
295 | font-size: 14px;
296 | }
297 | .message h3 {
298 | margin: 0 0 20px 0;
299 | padding-bottom: 12px;
300 | font-size: 32px;
301 | border-bottom: 1px solid rgba(255, 255, 255, 0.08);
302 | }
303 | .message span {
304 | font-size: 24px;
305 | font-weight: bold;
306 | color: #f2f2f2;
307 | }
308 | .globe h1 {
309 | top: 74px;
310 | z-index: 2;
311 | text-align: center;
312 | position: inherit;
313 | font-size: 36px;
314 | text-shadow: 2px 2px 0 rgba(0, 0, 0, .4);
315 | display: block;
316 | }
317 | .globe .location-exclamation {
318 | display: block;
319 | position: absolute;
320 | left: 50%;
321 | top: -78px;
322 | margin-left: -20px;
323 | }
324 | .globe .location-icon {
325 | background: url('../images/sprite.png') no-repeat center left;
326 | top: 10px;
327 | margin-top: 21px;
328 | }
329 | .globe .location-dot {
330 | background: url('../images/sprite.png') no-repeat -260px 0px;
331 | top: -24px;
332 | }
333 | .globe .location-icon, .globe .location-dot, .message .success-icon, .message .error-icon {
334 | width: 43px;
335 | height: 52px;
336 | -moz-background-size: cover;
337 | -webkit-background-size: cover;
338 | background-size: cover;
339 | position: relative;
340 | }
341 | .globe-mask {
342 | z-index: 1;
343 | background: url('../images/world_map_mask.png') no-repeat center center;
344 | width: inherit;
345 | height: inherit;
346 | top: 0;
347 | -moz-background-size: cover;
348 | -webkit-background-size: cover;
349 | background-size: cover;
350 | }
351 | .globe-map {
352 | z-index: 0;
353 | background: url('../images/world_map.png') repeat-x top left;
354 | width: 768px;
355 | height: 240px;
356 | top: 0;
357 | left: 0;
358 | -moz-background-size: 50%;
359 | -webkit-background-size: 50%;
360 | background-size: 50%;
361 | -webkit-animation: 15.0s globeLoopAnim infinite linear;
362 | -moz-animation: 15.0s globeLoopAnim infinite linear;
363 | animation: 15.0s globeLoopAnim infinite linear;
364 | }
365 | .globe-mask, .globe-map {
366 | position: absolute;
367 | display: block;
368 | }
369 | /* Leaflet Control Overrides */
370 |
371 | .leaflet-control-container .leaflet-control-locate a {
372 | margin-left: 0px;
373 | }
374 | .leaflet-control-container .leaflet-bar {
375 | border-radius: 0;
376 | }
377 | .leaflet-control-container .leaflet-bar a, .leaflet-control-container .leaflet-bar a:hover {
378 | border-radius: 0;
379 | background-color: #222b33;
380 | border-bottom: none;
381 | width: 38px;
382 | height: 38px;
383 | line-height: 34px;
384 | display: block;
385 | text-align: center;
386 | text-decoration: none;
387 | color: #bababa;
388 | font-size: 32px;
389 | }
390 | .leaflet-control-container .leaflet-bar a.leaflet-disabled {
391 | cursor: default;
392 | background-color: #404E5B;
393 | background-color: #222b33;
394 | }
395 | .leaflet-control-container .leaflet-bar a:first-child, .leaflet-control-container .leaflet-bar a:last-child {
396 | border-radius: 0;
397 | }
398 | .leaflet-control-container .leaflet-control-locate.active.following a {
399 | color: #e5603d;
400 | }
401 | .leaflet-control-container .leaflet-control-locate.active a {
402 | color: #3a8cc0;
403 | }
404 | .leaflet-control-container .fa {
405 | font-size: 22px;
406 | }
407 | .leaflet-popup-pane .leaflet-popup-content-wrapper, .leaflet-popup-tip {
408 | background: #222b33;
409 | box-shadow: 0 3px 14px rgba(0, 0, 0, 0.4);
410 | }
411 | .leaflet-popup-pane .leaflet-popup-content-wrapper {
412 | padding: 8px;
413 | text-align: left;
414 | border-radius: 0;
415 | }
416 | .leaflet-popup-pane span {
417 | color: #999;
418 | line-height: 1.6;
419 | }
420 | /* Globe LOOP */
421 |
422 | @keyframes globeLoopAnim {
423 | from {
424 | transform: translateX(0px);
425 | }
426 | to {
427 | transform: translateX(-384px);
428 | }
429 | }
430 | @-webkit-keyframes globeLoopAnim {
431 | from {
432 | -webkit-transform: translateX(0px);
433 | }
434 | to {
435 | -webkit-transform: translateX(-384px);
436 | }
437 | }
438 | @-moz-keyframes globeLoopAnim {
439 | from {
440 | -moz-transform: translateX(0px);
441 | }
442 | to {
443 | -moz-transform: translateX(-384px);
444 | }
445 | }
446 |
--------------------------------------------------------------------------------
/_attachments/success.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
Success!
9 |
{{docs_written || '0'}} docs
10 | were replicated to your database at {{start_time || 'this time'}}
11 |
12 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/_attachments/tracking.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
Longitude
10 |
Searching...
11 |
12 |
13 |
Latitude
14 |
Searching...
15 |
16 |
17 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/_attachments/welcome.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Welcome
6 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
Track your location data and save to your IBM Cloudant database
20 |
21 |
22 |
23 |
29 |
30 |
--------------------------------------------------------------------------------
/_id:
--------------------------------------------------------------------------------
1 | _design/locationtracker
--------------------------------------------------------------------------------
/couchapp.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Location Tracker",
3 | "description": "This tutorial shows how to build a mobile app in HTML5, Javascript and Angular that records a device’s location and saves it to an IBM Cloudant database."
4 | }
5 |
--------------------------------------------------------------------------------
/language:
--------------------------------------------------------------------------------
1 | javascript
--------------------------------------------------------------------------------
/tutorial/blog.adoc:
--------------------------------------------------------------------------------
1 | = Make a mobile web app with AngularJS: Location Tracker Part 2
2 |
3 | NOTE: Sean please provide a good graphic.
4 |
5 | In Part 1 of this tutorial series, we http://cloudant.com/blog/link-to-part-1-blog[learned why location is so important to modern mobile apps] and https://github.com/cloudant-labs/location-tracker-couchapp/blob/master/tutorial/tutorial.adoc[how to build the basic functionality]. In Part 2 we take that code and transform it into a serious app using AngularJS.
6 |
7 | What is Angular and why are we using it? Glad you asked. As it states in the https://code.angularjs.org/1.2.26/docs/guide/introduction[Angular docs], AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template language and extends HTML’s syntax to express your application’s components clearly and succinctly. Not every app is a good fit for Angular. Angular was built with the CRUD application in mind. Luckily CRUD applications represent the majority of web applications. If you’re doing live, two-way data binding, Angular is a good fit. It excels in applications where the user changes data, and those changes necessitate an update to the user interface.
8 |
9 | In this simple tutorial, we don’t do much data binding, but you can imagine many cases where this would make sense in a mapping application. For example, if your application was supporting wildfire response, the map would change and alerts might get triggered when certain data events occurred. Or in a retail scenario, as a customer walked through a mall you could send them information tailored to the stores they were near, or attract shoppers away from competitors' stores and towards yours!
10 |
11 | => *https://github.com/cloudant-labs/location-tracker-angular/blob/master/tutorial/tutorial.adoc[Location Tracker Tutorial: Part 2]*
--------------------------------------------------------------------------------
/tutorial/graphics/map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/tutorial/graphics/map.png
--------------------------------------------------------------------------------
/tutorial/graphics/map_sm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/tutorial/graphics/map_sm.png
--------------------------------------------------------------------------------
/tutorial/graphics/saving.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/tutorial/graphics/saving.png
--------------------------------------------------------------------------------
/tutorial/graphics/saving_sm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/tutorial/graphics/saving_sm.png
--------------------------------------------------------------------------------
/tutorial/graphics/success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/tutorial/graphics/success.png
--------------------------------------------------------------------------------
/tutorial/graphics/success_sm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/tutorial/graphics/success_sm.png
--------------------------------------------------------------------------------
/tutorial/graphics/tracking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/tutorial/graphics/tracking.png
--------------------------------------------------------------------------------
/tutorial/graphics/tracking_sm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/tutorial/graphics/tracking_sm.png
--------------------------------------------------------------------------------
/tutorial/graphics/welcome_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/tutorial/graphics/welcome_button.png
--------------------------------------------------------------------------------
/tutorial/graphics/welcome_button_sm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudant-labs/location-tracker-angular/a191e7506ded9003881d87ca996822bfa3972b86/tutorial/graphics/welcome_button_sm.png
--------------------------------------------------------------------------------
/tutorial/tutorial.adoc:
--------------------------------------------------------------------------------
1 | image:https://cloudant.com/wp-content/themes/cloudant/images/ibm_cloudant.png["IBM Cloudant"]
2 |
3 | = Location Tracker Part 2: Angular.JS
4 | _Make a single-page mobile web app, with AngularJS_
5 |
6 | == Intro
7 |
8 | In Part 1 of the Location Tracker tutorial, we learned how to use the HTML5 geolocation API to ask the web browser to share the device's location with us and save the location of a moving device -- whether that device represents a person, vehicle, or mobile sensor -- to Cloudant. We also learned how to take that data out of Cloudant and put it on a map. Those skills are important building blocks for any number of real-world apps you might develop, but the user interface left a lot to be desired.
9 |
10 | In Part 2, we'll take the functionality developed in Part 1 and put it into a nicely polished http://en.wikipedia.org/wiki/Single-page_application[single-page app (SPA)] using the https://angularjs.org/[AngularJS] framework. This is _not_ a tutorial on AngularJS, nor a tutorial on how to create snazzy animated page effects, but you can study the code and learn how to do those on your own. The goal here is simply to take the design of our app to the next level using Angular.
11 |
12 | What is Angular and why are we using it? Glad you asked. As it states in the https://code.angularjs.org/1.2.26/docs/guide/introduction[Angular docs], AngularJS is a structural framework for dynamic web apps. It lets you use HTML as your template language and extends HTML's syntax to express your application's components clearly and succinctly. Not every app is a good fit for Angular. Angular was built with the CRUD application in mind. Luckily CRUD applications represent the majority of web applications. If you're doing live, two-way data binding, Angular is a good fit. It excels in applications where the user changes data, and those changes necessitate an update to the user interface.
13 |
14 | In this simple tutorial, we don't do much data binding, but you can imagine many cases where this would make sense in a mapping application. For example, if your application was supporting wildfire response, the map would change and alerts might get triggered when certain data events occurred. Or in a retail scenario, as a customer walked through a mall you could send them information tailored to the stores they were near, or attract shoppers away from competitors' stores and towards yours!
15 |
16 | == Getting the code
17 |
18 | In this chapter, we won't step through the code as slowly as in Part one, having you write and test a piece at a time. Instead, we'll have you download and peruse the code all at once, and explain it as a whole. Because no functionality has changed -- the code around capturing and saving location data is the same. We are simply re-organizing code into the AngularJS framework and adding UIX richness.
19 |
20 | All the code for this tutorial can be forked from GitHub from https://github.com/cloudant-labs/location-tracker-couchapp[this repository]. To download the code to your computer, run this from the command line:
21 |
22 | [source,bash]
23 | git clone https://github.com/cloudant-labs/location-tracker-angular.git
24 |
25 | [NOTE]
26 | ====
27 | If you are new to GitHub, https://help.github.com/articles/set-up-git/[get set up with these instructions].
28 | ====
29 |
30 | == Angular application overview
31 |
32 | For starters, let's look at the new Javascripts added to the HEAD
33 | [source,html]
34 | ----
35 |
36 |
37 |
38 |
39 |
40 | ----
41 |
42 | In order to use Angular, you need the base Angular.min.js framework file. Because we are levaraging routing and animation, both the angular-route.min.js and angular-animate.min.js modules have been added.
43 | To allow for fluid transitions and animation control via javascript, http://julian.com/research/velocity/[Velocity.js] has been added. It's setup to work with or without jQuery. It is simply the best of jQuery and CSS transitions combined.
44 |
45 | Both the base velocity.min.js and ui pack velocity.ui.min.js files are used.
46 |
47 | The way an Angular app gets initialized is by including the Angular Javascript code in your web page, and then putting the custom attribute `ng-app` on an element in your HTML. Angular only works on the HTML descended from this element, so you can have parts of your web page that don't depend at all on the framework. Usually, however, developers choose to have the whole page controlled by Angular, and therefore you'll find `ng-app` attached to the `html` or `body` element. In our case we put it on the body in the `index.html` file:
48 |
49 | [source,html]
50 | ----
51 |
52 | ----
53 |
54 | The value of the `ng-app` attribute is the module to use. And this is found in the Javascript file `app.js`, which was also included in the web page (and found in the `scripts` directory. App.js is the heart of any Angular app. As stated earlier, this is not a standalone Angular tutorial, so we'll just hit the high points of how functionality is laid out in the app.
55 |
56 | [NOTE]
57 | ====
58 | Some good AngularJS tutorials are https://docs.angularjs.org/tutorial/[the official one], http://campus.codeschool.com/courses/shaping-up-with-angular-js/intro[Shaping up with Angular.JS] and http://www.revillweb.com/tutorials/angularjs-in-30-minutes-angularjs-tutorial/[Learn AngularJS in 30 minutes]
59 | ====
60 |
61 | Looking at `app.js` a few main concepts stick out:
62 |
63 | . *value* definitions, which are basically global variables that can be exposed to controllers,
64 | . *routes* in `.config(['$routeProvider'...` define what HTML is included (`templateUrl`) and what Javascript is run (`controller`) when certain URLs are requested
65 | . *.controllers* where you bind model data to views (a.k.a HTML)
66 | . *.factorys* which are a great way to separate out the logic of creating objects that will be reused in multiple places
67 | . a *directive* called `animationdirective` that transforms a DOM element or changes its behavior.
68 |
69 | Let's walk through each of these major concepts to understand how the functionality of Location Tracker plays out in Angular.
70 |
71 | == Values
72 |
73 | This section is simple. We're just defining some variables we want to be accessible to multiple controllers. Some of them could be constants, like `remotedb`, but for simplicity we just make them all values, passing them into controllers and manipulating as needed.
74 |
75 | .Listing 1. Values in app.js
76 | [source,javascript]
77 | ----
78 | .value("map", {})
79 | .value("watchID", null)
80 | .value("remotedb", 'https://USERNAME:PASSWORD@USERNAME.cloudant.com/locationtracker')
81 | .value("num", 0)
82 | .value("successMessage", {})
83 | .value("errorMessage", "error")
84 | .value("trackingMapInitialized", false)
85 | .value("resultMapInitialized", false)
86 | ----
87 |
88 | == Routes
89 |
90 | This section of `app.js` basically matches up URLs with controllers. When the user accesses one of the routes -- any one of the `$routeProvider.when` statements -- the `templateUrl` file is included and the specified `controller` takes "control" of what happens in that part of the page.
91 |
92 | For example, the `/welcome` route inserts `location-welcome.html`. We're only interested in showing some user interface goodness here, so no controller is needed. However, note that there's an href to `#tracking` near the bottom of `location-welcome.html`. When the user clicks that link, the `/tracking` route is called, which inserts `location-tracking.html` and activates the controller, `locationTrackingController`. The other routes work the same.
93 |
94 | .Listing 2. Routes
95 | [source,javascript]
96 | ----
97 | .config(['$routeProvider', function($routeProvider) {
98 | $routeProvider.
99 | when('/welcome', {
100 | templateUrl: 'location-welcome.html'
101 | }).
102 | when('/tracking', {
103 | templateUrl: 'location-tracking.html',
104 | controller: 'locationTrackingController'
105 | }).
106 | when('/savedata', {
107 | templateUrl: 'location-savedata.html',
108 | controller: 'locationTrackingSaveDataController'
109 | }).
110 | when('/success', {
111 | templateUrl: 'location-success.html',
112 | controller: 'locationTrackingSuccessController'
113 | }).
114 | when('/error', {
115 | templateUrl: 'location-error.html',
116 | controller: 'locationTrackingErrorController'
117 | }).
118 | when('/map', {
119 | templateUrl: 'tutorial2-map.html',
120 | controller: 'mapResultController'
121 | }).
122 | otherwise({
123 | redirectTo: '/welcome'
124 | })
125 | }])
126 | ----
127 |
128 | == Controllers
129 |
130 | This is where the real action is. All the controllers are described in Table 1, and the graphic below depicts their interaction. The welcome route presents the introductory UI that directs the user to activate the `/tracking` route, which runs the `locationTrackingController` controller, which begins capturing device locations. Looking at the code for that controller, which starts with `.controller('locationTrackingController'...`, you see that we create a map that shows the user where they are (note that if the device you were tracking didn't have a human being in front of it, you would surely skip this part). Then you'll eventually come across the function `doWatch` in that controller. This function will be familiar to you from Part 1 of the tutorial. Except for some user interface manipulation, the code and functionality is the same -- we are taking the location given to us by the device and saving it to a local http://pouchdb.com[PouchDB] database. In addition to running the code in `locationTrackingController`, the `/tracking` route also injected HTML from the `location-tracking.html` file, which allows the user to click on a *_Stop and Save data to IBM Cloudant_* button when they are done collecting a series of locations.
131 |
132 | The *_Stop and Save data to IBM Cloudant_* button activates the `/savedata` route, which runs `locationTrackingSaveDataController`. The code for that controller, which starts with `.controller('locationTrackingSaveDataController'...`, runs some cool page animation effects and replicates our local PouchDB database to Cloudant. This is functionally equivalent to the `saveToServer` function in Part 1. When database replication is finished, the controller automatically redirects to either a success or error UI.
133 |
134 | If the process was successful, we see some metadata about how many documents were written to the database, and we get an option to see a map of all the location data saved in the Cloudant database, just like we did at the end of Part 1.
135 |
136 | .Angular routes
137 | [cols="2,2,2,2,2,2,2", frame="topbot"]
138 | |=====
139 | |*Route* |/welcome |/tracking |/savedata |/success |/map |/error
140 | |*templateUrl* |welcome.html |tracking.html |savedata.html |success.html |tutorial2-map.html |location-error.html
141 | |*controller* |n/a |locationTrackingController |locationTrackingSaveDataController |locationTrackingSuccessController |mapResultController |locationTrackingErrorController
142 | |*description* |static introductory message |captures device location in PouchDB while showing current location on a map |Saves location data to Cloudant by replicating from the local PouchDB to a remote Cloudant database account |Shows metadata about the successful replication |Shows a map of all location data in the database |Shows metadata about a failed replication
143 | | |image:graphics/welcome_button_sm.png[] |image:graphics/tracking_sm.png[] |image:graphics/saving_sm.png[] |image:graphics/success_sm.png[] |image:graphics/map_sm.png[] |
144 | |=====
145 |
146 |
147 | == Animating UI changes with the `animationdirective`
148 |
149 | This tutorial was broken up into different sections to help developers more easily digest the different functions happening, such as storing data locally, saving it, then displaying the results. Having a asynchronous based single-page app allows us to separate these functions without refreshing the page.
150 |
151 | One of the benefits of Angular when it comes to single-page applications, is that it emits event hooks when ui-views are being transitioned in and out. Specifically, `enter` and `leave`. Rather than having a simple show and hide, animated transitions have been added to help make the experience more fluid as you go through the steps of the application.
152 |
153 | Two key things were used to make the transitions: a reusable directive and the animation module. Animations in AngularJS are completely based on CSS classes. For example, each time a new ui-view component is added, Angular will add a `ng-enter` class name to the element that is being added. When removed it will apply a ng-leave class name.
154 |
155 | Directives are helpful in that they attach a specified behavior to that DOM element or even transform the DOM element and its children. The main idea here is that each html page being injected into the ui-view is leveraging the same directive. Therefore, they can take advantage of enter and leave hooks and transition views in and out.
156 |
157 | In order to modify the DOM we use the `link` option. `link` takes a function with the following, `function link(scope, element, attrs) { ... }`. Let's break things down:
158 |
159 | * `scope` is an Angular scope object.
160 | * `element` is the jqLite-wrapped element that this directive matches.
161 | * `attrs` is a hash object with key-value pairs of normalized attribute names and their corresponding attribute values.
162 |
163 | By taking advantage of a custom directive, we can take advantage of the `$animate` service to handle the transition animations when `enter` and `leave` hooks are triggered. We're using Javascript animations using http://julian.com/research/velocity/[velocity.js] to allow for a bit more fine grained control over nested elements, particularly when `leave` is triggered.
164 |
165 | The last thing to mention with animations is that there are callbacks in both `enter` and `leave` hooks, that when called will look for `transEnter` or `transLeave`. This way, you can step things out to make the app more efficient. For example, on `locationTrackingController`, we want to be able to smoothly load in the map tiles after the `enter` hook has trigged and only after the page view has transitioned in. Then we want to be able to use the `remove()` function on the map on the `leave` so that we can clear out the events and leaflet map Javascript objects.
166 |
167 |
168 | == Conclusion
169 |
170 | This tutorial has shown that you can take functional, but bare tutorial code and transform it into a highly polished application with a little background in AngularJS. By comparing the code in Parts 1 and 2 you can also begin to see a possible workflow where a core Javascript developer might work on purely functional elements, while a front-end developer worked on the user interface. In fact, that's one of the benefits of AngularJS. Controllers separate out the data processing and database access from the "view" or front-end code, so that teams can be more productive working together in parallel. Therefore the lesson of this tutorial is less about how to write an AngularJS app, and more about how to use a web development framework to make your team more efficient and productive.
171 |
172 | In https://github.com/cloudant-labs/location-tracker-nodejs/blob/master/tutorial/tutorial.md[Part 3], we'll focus on another aspect of taking the Location Tracker tutorial app closer to production quality adding a middle tier to better manage users and other moving things. We'll leave the couchapp deployment methodology behind and add a Node.js middleware layer to the app so that client code doesn't contain database credentials, and we have a more flexible set up to add other cool processing at the middle tier.
173 |
--------------------------------------------------------------------------------