web-mapping 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 27ee728028019f8710eebc786cd5decea1a037320effd25a8728cacb3013b68a
4
- data.tar.gz: b7ed102047417ae17a6c842c42a966436e3da0ae5f117c8530dada9fc8810c38
3
+ metadata.gz: 9ce5618fed49008ac82cd161ddb1d56ff047ea152c350a3e6439cd921ce792ce
4
+ data.tar.gz: 92d35b9454e710c9390248b0718f13412d39d313614398f4ed0c6289a1cc86ef
5
5
  SHA512:
6
- metadata.gz: 1b8e616755d36113b49080f9b70328e93bcdf23e66c51e896a719c90d7f251231674da2839530a50ad9b9d4b622ae6a57e8926ccf94a9f7431f6217997c8a8f8
7
- data.tar.gz: 627bcaa6b885c159d6a1b41d37ef81b4c0da77d47bdc59183e17dff535a6a4759e0b9390574535a365418496ea4a9a4567dd8ffcab42e0af6d954404f1c120ba
6
+ metadata.gz: c9c88a59afbf4fa85a55a517cf359eccc9451c16e540b2a95a23dd85ee785f447a888e2b802769c879c7b95865476587c11d2e5cae75fc8a6d54ebd3cb45a54f
7
+ data.tar.gz: 6973a77c615096e83c91e18d73bd486564d6d5d1ea6b75cbfe95abc582c556e7ba4112793a447afe30ae8ce1bc6c8276d46d415fa1d0debb402926fb4bc83bad
File without changes
File without changes
@@ -0,0 +1,9 @@
1
+ <!-- Global site tag (gtag.js) - Google Analytics -->
2
+ <script async src="https://www.googletagmanager.com/gtag/js?id={{ site.google_analytics }}"></script>
3
+ <script>
4
+ window.dataLayer = window.dataLayer || [];
5
+ function gtag(){dataLayer.push(arguments);}
6
+ gtag('js', new Date());
7
+
8
+ gtag('config', '{{ site.google_analytics }}');
9
+ </script>
@@ -0,0 +1,36 @@
1
+ <head prefix="og: http://ogp.me/ns#">
2
+ <meta charset="utf-8">
3
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
4
+ <meta name="viewport" content="width=device-width, initial-scale=1">
5
+ <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
6
+ <meta name="HandheldFriendly" content="True">
7
+ <meta name="MobileOptimized" content="320">
8
+ <meta name="Robots" content="index, follow">
9
+
10
+ <!-- - -->
11
+ {%- seo -%}
12
+ <!-- - -->
13
+
14
+ <!-- CSS -->
15
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
16
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
17
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css">
18
+ <link rel="stylesheet" href="https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v0.4.0/MarkerCluster.css">
19
+ <link rel="stylesheet" href="https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v0.4.0/MarkerCluster.Default.css">
20
+ <link rel="stylesheet" href="https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-locatecontrol/v0.43.0/L.Control.Locate.css">
21
+ <link rel="stylesheet" href="assets/leaflet-groupedlayercontrol/leaflet.groupedlayercontrol.css">
22
+ <link rel="stylesheet" href="{{ '/assets/main.css' | prepend: site.url }}">
23
+ <!-- <link rel="stylesheet" href="assets/css/main.css"> -->
24
+ <link rel="apple-touch-icon" sizes="76x76" href="assets/img/favicon-76.png">
25
+ <link rel="apple-touch-icon" sizes="120x120" href="assets/img/favicon-120.png">
26
+ <link rel="apple-touch-icon" sizes="152x152" href="assets/img/favicon-152.png">
27
+ <link rel="icon" sizes="196x196" href="assets/img/favicon-196.png">
28
+ <link rel="icon" type="image/x-icon" href="assets/img/favicon.ico">
29
+
30
+ <!-- JS -->
31
+ <script src="{{ '/assets/js/app.js' | prepend: site.url }}"></script>
32
+ <!-- <script src="assets/js/app.js"></script> -->
33
+ {%- if jekyll.environment == 'production' and site.google_analytics -%}
34
+ {%- include google-analytics.html -%}
35
+ {%- endif -%}
36
+ </head>
@@ -0,0 +1,225 @@
1
+ <div id="container">
2
+ <div id="sidebar">
3
+ <div class="sidebar-wrapper">
4
+ <div class="panel panel-default" id="features">
5
+ <div class="panel-heading">
6
+ <h3 class="panel-title">Points of Interest
7
+ <button type="button" class="btn btn-xs btn-default pull-right" id="sidebar-hide-btn"><i class="fa fa-chevron-left"></i></button></h3>
8
+ </div>
9
+ <div class="panel-body">
10
+ <div class="row">
11
+ <div class="col-xs-8 col-md-8">
12
+ <input type="text" class="form-control search" placeholder="Filter" />
13
+ </div>
14
+ <div class="col-xs-4 col-md-4">
15
+ <button type="button" class="btn btn-primary pull-right sort" data-sort="feature-name" id="sort-btn"><i class="fa fa-sort"></i>&nbsp;&nbsp;Sort</button>
16
+ </div>
17
+ </div>
18
+ </div>
19
+ <div class="sidebar-table">
20
+ <table class="table table-hover" id="feature-list">
21
+ <thead class="hidden">
22
+ <tr>
23
+ <th>Icon</th>
24
+ <tr>
25
+ <tr>
26
+ <th>Name</th>
27
+ <tr>
28
+ <tr>
29
+ <th>Chevron</th>
30
+ <tr>
31
+ </thead>
32
+ <tbody class="list"></tbody>
33
+ </table>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ <div id="map"></div>
39
+ </div>
40
+ <div id="loading">
41
+ <div class="loading-indicator">
42
+ <div class="progress progress-striped active">
43
+ <div class="progress-bar progress-bar-info progress-bar-full"></div>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ <div class="modal fade" id="aboutModal" tabindex="-1" role="dialog">
48
+ <div class="modal-dialog modal-lg">
49
+ <div class="modal-content">
50
+ <div class="modal-header">
51
+ <button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
52
+ <h4 class="modal-title">Welcome to the BootLeaf template!</h4>
53
+ </div>
54
+ <div class="modal-body">
55
+ <ul class="nav nav-tabs nav-justified" id="aboutTabs">
56
+ <li class="active"><a href="#about" data-toggle="tab"><i class="fa fa-question-circle"></i>&nbsp;About the project</a></li>
57
+ <li><a href="#contact" data-toggle="tab"><i class="fa fa-envelope"></i>&nbsp;Contact us</a></li>
58
+ <li><a href="#disclaimer" data-toggle="tab"><i class="fa fa-exclamation-circle"></i>&nbsp;Disclaimer</a></li>
59
+ <li class="dropdown">
60
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-globe"></i>&nbsp;Metadata <b class="caret"></b></a>
61
+ <ul class="dropdown-menu">
62
+ <li><a href="#boroughs-tab" data-toggle="tab">Boroughs</a></li>
63
+ <li><a href="#subway-lines-tab" data-toggle="tab">Subway Lines</a></li>
64
+ <li><a href="#theaters-tab" data-toggle="tab">Theaters</a></li>
65
+ <li><a href="#museums-tab" data-toggle="tab">Museums</a></li>
66
+ </ul>
67
+ </li>
68
+ </ul>
69
+ <div class="tab-content" id="aboutTabsContent">
70
+ <div class="tab-pane fade active in" id="about">
71
+ <p>A simple, responsive template for building web mapping applications with <a href="http://getbootstrap.com/">Bootstrap 3</a>, <a href="http://leafletjs.com/" target="_blank">Leaflet</a>, and <a href="http://twitter.github.io/typeahead.js/" target="_blank">typeahead.js</a>. Open source, MIT licensed, and available on <a href="https://github.com/bmcbride/bootleaf" target="_blank">GitHub</a>.</p>
72
+ <div class="panel panel-primary">
73
+ <div class="panel-heading">Features</div>
74
+ <ul class="list-group">
75
+ <li class="list-group-item">Fullscreen mobile-friendly map template with responsive navbar and modal placeholders</li>
76
+ <li class="list-group-item">jQuery loading of external GeoJSON files</li>
77
+ <li class="list-group-item">Logical multiple layer marker clustering via the <a href="https://github.com/Leaflet/Leaflet.markercluster" target="_blank">leaflet marker cluster plugin</a></li>
78
+ <li class="list-group-item">Elegant client-side multi-layer feature search with autocomplete using <a href="http://twitter.github.io/typeahead.js/" target="_blank">typeahead.js</a></li>
79
+ <li class="list-group-item">Responsive sidebar feature list synced with map bounds, which includes sorting and filtering via <a href="http://listjs.com/" target="_blank">list.js</a></li>
80
+ <li class="list-group-item">Marker icons included in grouped layer control via the <a href="https://github.com/ismyrnow/Leaflet.groupedlayercontrol" target="_blank">grouped layer control plugin</a></li>
81
+ </ul>
82
+ </div>
83
+ </div>
84
+ <div id="disclaimer" class="tab-pane fade text-danger">
85
+ <p>The data provided on this site is for informational and planning purposes only.</p>
86
+ <p>Absolutely no accuracy or completeness guarantee is implied or intended. All information on this map is subject to such variations and corrections as might result from a complete title search and/or accurate field survey.</p>
87
+ </div>
88
+ <div class="tab-pane fade" id="contact">
89
+ <form id="contact-form">
90
+ <div class="well well-sm">
91
+ <div class="row">
92
+ <div class="col-md-4">
93
+ <div class="form-group">
94
+ <label for="first-name">First Name:</label>
95
+ <input type="text" class="form-control" id="first-name">
96
+ </div>
97
+ <div class="form-group">
98
+ <label for="last-name">Last Name:</label>
99
+ <input type="text" class="form-control" id="last-email">
100
+ </div>
101
+ <div class="form-group">
102
+ <label for="email">Email:</label>
103
+ <input type="text" class="form-control" id="email">
104
+ </div>
105
+ </div>
106
+ <div class="col-md-8">
107
+ <label for="message">Message:</label>
108
+ <textarea class="form-control" rows="8" id="message"></textarea>
109
+ </div>
110
+ <div class="col-md-12">
111
+ <p>
112
+ <button type="submit" class="btn btn-primary pull-right" data-dismiss="modal">Submit</button>
113
+ </p>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ </form>
118
+ </div>
119
+ <div class="tab-pane fade" id="boroughs-tab">
120
+ <p>Borough data courtesy of <a href="http://www.nyc.gov/html/dcp/pdf/bytes/nybbwi_metadata.pdf" target="_blank">New York City Department of City Planning</a></p>
121
+ </div>
122
+ <div class="tab-pane fade" id="subway-lines-tab">
123
+ <p><a href="http://spatialityblog.com/2010/07/08/mta-gis-data-update/#datalinks" target="_blank">MTA Subway data</a> courtesy of the <a href="http://www.urbanresearch.org/about/cur-components/cuny-mapping-service" target="_blank">CUNY Mapping Service at the Center for Urban Research</a></p>
124
+ </div>
125
+ <div class="tab-pane fade" id="theaters-tab">
126
+ <p>Theater data courtesy of <a href="https://data.cityofnewyork.us/Recreation/Theaters/kdu2-865w" target="_blank">NYC Department of Information & Telecommunications (DoITT)</a></p>
127
+ </div>
128
+ <div class="tab-pane fade" id="museums-tab">
129
+ <p>Museum data courtesy of <a href="https://data.cityofnewyork.us/Recreation/Museums-and-Galleries/sat5-adpb" target="_blank">NYC Department of Information & Telecommunications (DoITT)</a></p>
130
+ </div>
131
+ </div>
132
+ </div>
133
+ <div class="modal-footer">
134
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
135
+ </div>
136
+ </div><!-- /.modal-content -->
137
+ </div><!-- /.modal-dialog -->
138
+ </div><!-- /.modal -->
139
+
140
+ <div class="modal fade" id="legendModal" tabindex="-1" role="dialog">
141
+ <div class="modal-dialog">
142
+ <div class="modal-content">
143
+ <div class="modal-header">
144
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
145
+ <h4 class="modal-title">Map Legend</h4>
146
+ </div>
147
+ <div class="modal-body">
148
+ <p>Map Legend goes here...</p>
149
+ </div>
150
+ <div class="modal-footer">
151
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
152
+ </div>
153
+ </div><!-- /.modal-content -->
154
+ </div><!-- /.modal-dialog -->
155
+ </div><!-- /.modal -->
156
+
157
+ <div class="modal fade" id="loginModal" tabindex="-1" role="dialog">
158
+ <div class="modal-dialog modal-sm">
159
+ <div class="modal-content">
160
+ <div class="modal-header">
161
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
162
+ <h4 class="modal-title">Login</h4>
163
+ </div>
164
+ <div class="modal-body">
165
+ <form id="contact-form">
166
+ <fieldset>
167
+ <div class="form-group">
168
+ <label for="name">Username:</label>
169
+ <input type="text" class="form-control" id="username">
170
+ </div>
171
+ <div class="form-group">
172
+ <label for="email">Password:</label>
173
+ <input type="password" class="form-control" id="password">
174
+ </div>
175
+ </fieldset>
176
+ </form>
177
+ </div>
178
+ <div class="modal-footer">
179
+ <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
180
+ <button type="submit" class="btn btn-primary" data-dismiss="modal">Login</button>
181
+ </div>
182
+ </div><!-- /.modal-content -->
183
+ </div><!-- /.modal-dialog -->
184
+ </div><!-- /.modal -->
185
+
186
+ <div class="modal fade" id="featureModal" tabindex="-1" role="dialog">
187
+ <div class="modal-dialog">
188
+ <div class="modal-content">
189
+ <div class="modal-header">
190
+ <button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
191
+ <h4 class="modal-title text-primary" id="feature-title"></h4>
192
+ </div>
193
+ <div class="modal-body" id="feature-info"></div>
194
+ <div class="modal-footer">
195
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
196
+ </div>
197
+ </div><!-- /.modal-content -->
198
+ </div><!-- /.modal-dialog -->
199
+ </div><!-- /.modal -->
200
+
201
+ <div class="modal fade" id="attributionModal" tabindex="-1" role="dialog">
202
+ <div class="modal-dialog">
203
+ <div class="modal-content">
204
+ <div class="modal-header">
205
+ <button class="close" type="button" data-dismiss="modal" aria-hidden="true">&times;</button>
206
+ <h4 class="modal-title">
207
+ Developed by <a href='http://bryanmcbride.com'>bryanmcbride.com</a>
208
+ </h4>
209
+ </div>
210
+ <div class="modal-body">
211
+ <div id="attribution"></div>
212
+ </div>
213
+ </div><!-- /.modal-content -->
214
+ </div><!-- /.modal-dialog -->
215
+ </div><!-- /.modal -->
216
+ <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
217
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
218
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.10.5/typeahead.bundle.min.js"></script>
219
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.3/handlebars.min.js"></script>
220
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/list.js/1.1.1/list.min.js"></script>
221
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js"></script>
222
+ <script src="https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v0.4.0/leaflet.markercluster.js"></script>
223
+ <script src="https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-locatecontrol/v0.43.0/L.Control.Locate.min.js"></script>
224
+ <script src="assets/leaflet-groupedlayercontrol/leaflet.groupedlayercontrol.js"></script>
225
+ <script src="assets/js/app.js"></script>
@@ -0,0 +1,41 @@
1
+ <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
2
+ <div class="container-fluid">
3
+ <div class="navbar-header">
4
+ <div class="navbar-icon-container">
5
+ <a href="#" class="navbar-icon pull-right visible-xs" id="nav-btn"><i class="fa fa-bars fa-lg white"></i></a>
6
+ <a href="#" class="navbar-icon pull-right visible-xs" id="sidebar-toggle-btn"><i class="fa fa-search fa-lg white"></i></a>
7
+ </div>
8
+ <a class="navbar-brand" href="#">BootLeaf</a>
9
+ </div>
10
+ <div class="navbar-collapse collapse">
11
+ <form class="navbar-form navbar-right" role="search">
12
+ <div class="form-group has-feedback">
13
+ <input id="searchbox" type="text" placeholder="Search" class="form-control">
14
+ <span id="searchicon" class="fa fa-search form-control-feedback"></span>
15
+ </div>
16
+ </form>
17
+ <ul class="nav navbar-nav">
18
+ <li><a href="#" data-toggle="collapse" data-target=".navbar-collapse.in" id="about-btn"><i class="fa fa-question-circle white"></i>&nbsp;&nbsp;About</a></li>
19
+ <li class="dropdown">
20
+ <a id="toolsDrop" href="#" role="button" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-globe white"></i>&nbsp;&nbsp;Tools <b class="caret"></b></a>
21
+ <ul class="dropdown-menu">
22
+ <li><a href="#" data-toggle="collapse" data-target=".navbar-collapse.in" id="full-extent-btn"><i class="fa fa-arrows-alt"></i>&nbsp;&nbsp;Zoom To Full Extent</a></li>
23
+ <li><a href="#" data-toggle="collapse" data-target=".navbar-collapse.in" id="legend-btn"><i class="fa fa-picture-o"></i>&nbsp;&nbsp;Show Legend</a></li>
24
+ <li class="divider hidden-xs"></li>
25
+ <li><a href="#" data-toggle="collapse" data-target=".navbar-collapse.in" id="login-btn"><i class="fa fa-user"></i>&nbsp;&nbsp;Login</a></li>
26
+ </ul>
27
+ </li>
28
+ <li class="dropdown">
29
+ <a class="dropdown-toggle" id="downloadDrop" href="#" role="button" data-toggle="dropdown"><i class="fa fa-cloud-download white"></i>&nbsp;&nbsp;Download <b class="caret"></b></a>
30
+ <ul class="dropdown-menu">
31
+ <li><a href="data/boroughs.geojson" download="boroughs.geojson" target="_blank" data-toggle="collapse" data-target=".navbar-collapse.in"><i class="fa fa-download"></i>&nbsp;&nbsp;Boroughs</a></li>
32
+ <li><a href="data/subways.geojson" download="subways.geojson" target="_blank" data-toggle="collapse" data-target=".navbar-collapse.in"><i class="fa fa-download"></i>&nbsp;&nbsp;Subway Lines</a></li>
33
+ <li><a href="data/DOITT_THEATER_01_13SEPT2010.geojson" download="theaters.geojson" target="_blank" data-toggle="collapse" data-target=".navbar-collapse.in"><i class="fa fa-download"></i>&nbsp;&nbsp;Theaters</a></li>
34
+ <li><a href="data/DOITT_MUSEUM_01_13SEPT2010.geojson" download="museums.geojson" target="_blank" data-toggle="collapse" data-target=".navbar-collapse.in"><i class="fa fa-download"></i>&nbsp;&nbsp;Museums</a></li>
35
+ </ul>
36
+ </li>
37
+ <li class="hidden-xs"><a href="#" data-toggle="collapse" data-target=".navbar-collapse.in" id="list-btn"><i class="fa fa-list white"></i>&nbsp;&nbsp;POI List</a></li>
38
+ </ul>
39
+ </div><!--/.navbar-collapse -->
40
+ </div>
41
+ </div>
@@ -0,0 +1 @@
1
+ @import "web-mapping";
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
data/assets/js/app.js ADDED
@@ -0,0 +1,606 @@
1
+ var map, featureList, boroughSearch = [], theaterSearch = [], museumSearch = [];
2
+
3
+ $(window).resize(function() {
4
+ sizeLayerControl();
5
+ });
6
+
7
+ $(document).on("click", ".feature-row", function(e) {
8
+ $(document).off("mouseout", ".feature-row", clearHighlight);
9
+ sidebarClick(parseInt($(this).attr("id"), 10));
10
+ });
11
+
12
+ if ( !("ontouchstart" in window) ) {
13
+ $(document).on("mouseover", ".feature-row", function(e) {
14
+ highlight.clearLayers().addLayer(L.circleMarker([$(this).attr("lat"), $(this).attr("lng")], highlightStyle));
15
+ });
16
+ }
17
+
18
+ $(document).on("mouseout", ".feature-row", clearHighlight);
19
+
20
+ $("#about-btn").click(function() {
21
+ $("#aboutModal").modal("show");
22
+ $(".navbar-collapse.in").collapse("hide");
23
+ return false;
24
+ });
25
+
26
+ $("#full-extent-btn").click(function() {
27
+ map.fitBounds(boroughs.getBounds());
28
+ $(".navbar-collapse.in").collapse("hide");
29
+ return false;
30
+ });
31
+
32
+ $("#legend-btn").click(function() {
33
+ $("#legendModal").modal("show");
34
+ $(".navbar-collapse.in").collapse("hide");
35
+ return false;
36
+ });
37
+
38
+ $("#login-btn").click(function() {
39
+ $("#loginModal").modal("show");
40
+ $(".navbar-collapse.in").collapse("hide");
41
+ return false;
42
+ });
43
+
44
+ $("#list-btn").click(function() {
45
+ animateSidebar();
46
+ return false;
47
+ });
48
+
49
+ $("#nav-btn").click(function() {
50
+ $(".navbar-collapse").collapse("toggle");
51
+ return false;
52
+ });
53
+
54
+ $("#sidebar-toggle-btn").click(function() {
55
+ animateSidebar();
56
+ return false;
57
+ });
58
+
59
+ $("#sidebar-hide-btn").click(function() {
60
+ animateSidebar();
61
+ return false;
62
+ });
63
+
64
+ function animateSidebar() {
65
+ $("#sidebar").animate({
66
+ width: "toggle"
67
+ }, 350, function() {
68
+ map.invalidateSize();
69
+ });
70
+ }
71
+
72
+ function sizeLayerControl() {
73
+ $(".leaflet-control-layers").css("max-height", $("#map").height() - 50);
74
+ }
75
+
76
+ function clearHighlight() {
77
+ highlight.clearLayers();
78
+ }
79
+
80
+ function sidebarClick(id) {
81
+ var layer = markerClusters.getLayer(id);
82
+ map.setView([layer.getLatLng().lat, layer.getLatLng().lng], 17);
83
+ layer.fire("click");
84
+ /* Hide sidebar and go to the map on small screens */
85
+ if (document.body.clientWidth <= 767) {
86
+ $("#sidebar").hide();
87
+ map.invalidateSize();
88
+ }
89
+ }
90
+
91
+ function syncSidebar() {
92
+ /* Empty sidebar features */
93
+ $("#feature-list tbody").empty();
94
+ /* Loop through theaters layer and add only features which are in the map bounds */
95
+ theaters.eachLayer(function (layer) {
96
+ if (map.hasLayer(theaterLayer)) {
97
+ if (map.getBounds().contains(layer.getLatLng())) {
98
+ $("#feature-list tbody").append('<tr class="feature-row" id="' + L.stamp(layer) + '" lat="' + layer.getLatLng().lat + '" lng="' + layer.getLatLng().lng + '"><td style="vertical-align: middle;"><img width="16" height="18" src="assets/img/theater.png"></td><td class="feature-name">' + layer.feature.properties.NAME + '</td><td style="vertical-align: middle;"><i class="fa fa-chevron-right pull-right"></i></td></tr>');
99
+ }
100
+ }
101
+ });
102
+ /* Loop through museums layer and add only features which are in the map bounds */
103
+ museums.eachLayer(function (layer) {
104
+ if (map.hasLayer(museumLayer)) {
105
+ if (map.getBounds().contains(layer.getLatLng())) {
106
+ $("#feature-list tbody").append('<tr class="feature-row" id="' + L.stamp(layer) + '" lat="' + layer.getLatLng().lat + '" lng="' + layer.getLatLng().lng + '"><td style="vertical-align: middle;"><img width="16" height="18" src="assets/img/museum.png"></td><td class="feature-name">' + layer.feature.properties.NAME + '</td><td style="vertical-align: middle;"><i class="fa fa-chevron-right pull-right"></i></td></tr>');
107
+ }
108
+ }
109
+ });
110
+ /* Update list.js featureList */
111
+ featureList = new List("features", {
112
+ valueNames: ["feature-name"]
113
+ });
114
+ featureList.sort("feature-name", {
115
+ order: "asc"
116
+ });
117
+ }
118
+
119
+ /* Basemap Layers */
120
+ var cartoLight = L.tileLayer("https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png", {
121
+ maxZoom: 19,
122
+ attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="https://cartodb.com/attributions">CartoDB</a>'
123
+ });
124
+ var usgsImagery = L.layerGroup([L.tileLayer("http://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}", {
125
+ maxZoom: 15,
126
+ }), L.tileLayer.wms("http://raster.nationalmap.gov/arcgis/services/Orthoimagery/USGS_EROS_Ortho_SCALE/ImageServer/WMSServer?", {
127
+ minZoom: 16,
128
+ maxZoom: 19,
129
+ layers: "0",
130
+ format: 'image/jpeg',
131
+ transparent: true,
132
+ attribution: "Aerial Imagery courtesy USGS"
133
+ })]);
134
+
135
+ /* Overlay Layers */
136
+ var highlight = L.geoJson(null);
137
+ var highlightStyle = {
138
+ stroke: false,
139
+ fillColor: "#00FFFF",
140
+ fillOpacity: 0.7,
141
+ radius: 10
142
+ };
143
+
144
+ var boroughs = L.geoJson(null, {
145
+ style: function (feature) {
146
+ return {
147
+ color: "black",
148
+ fill: false,
149
+ opacity: 1,
150
+ clickable: false
151
+ };
152
+ },
153
+ onEachFeature: function (feature, layer) {
154
+ boroughSearch.push({
155
+ name: layer.feature.properties.BoroName,
156
+ source: "Boroughs",
157
+ id: L.stamp(layer),
158
+ bounds: layer.getBounds()
159
+ });
160
+ }
161
+ });
162
+ $.getJSON("data/boroughs.geojson", function (data) {
163
+ boroughs.addData(data);
164
+ });
165
+
166
+ //Create a color dictionary based off of subway route_id
167
+ var subwayColors = {"1":"#ff3135", "2":"#ff3135", "3":"ff3135", "4":"#009b2e",
168
+ "5":"#009b2e", "6":"#009b2e", "7":"#ce06cb", "A":"#fd9a00", "C":"#fd9a00",
169
+ "E":"#fd9a00", "SI":"#fd9a00","H":"#fd9a00", "Air":"#ffff00", "B":"#ffff00",
170
+ "D":"#ffff00", "F":"#ffff00", "M":"#ffff00", "G":"#9ace00", "FS":"#6e6e6e",
171
+ "GS":"#6e6e6e", "J":"#976900", "Z":"#976900", "L":"#969696", "N":"#ffff00",
172
+ "Q":"#ffff00", "R":"#ffff00" };
173
+
174
+ var subwayLines = L.geoJson(null, {
175
+ style: function (feature) {
176
+ return {
177
+ color: subwayColors[feature.properties.route_id],
178
+ weight: 3,
179
+ opacity: 1
180
+ };
181
+ },
182
+ onEachFeature: function (feature, layer) {
183
+ if (feature.properties) {
184
+ var content = "<table class='table table-striped table-bordered table-condensed'>" + "<tr><th>Division</th><td>" + feature.properties.Division + "</td></tr>" + "<tr><th>Line</th><td>" + feature.properties.Line + "</td></tr>" + "<table>";
185
+ layer.on({
186
+ click: function (e) {
187
+ $("#feature-title").html(feature.properties.Line);
188
+ $("#feature-info").html(content);
189
+ $("#featureModal").modal("show");
190
+
191
+ }
192
+ });
193
+ }
194
+ layer.on({
195
+ mouseover: function (e) {
196
+ var layer = e.target;
197
+ layer.setStyle({
198
+ weight: 3,
199
+ color: "#00FFFF",
200
+ opacity: 1
201
+ });
202
+ if (!L.Browser.ie && !L.Browser.opera) {
203
+ layer.bringToFront();
204
+ }
205
+ },
206
+ mouseout: function (e) {
207
+ subwayLines.resetStyle(e.target);
208
+ }
209
+ });
210
+ }
211
+ });
212
+ $.getJSON("data/subways.geojson", function (data) {
213
+ subwayLines.addData(data);
214
+ });
215
+
216
+ /* Single marker cluster layer to hold all clusters */
217
+ var markerClusters = new L.MarkerClusterGroup({
218
+ spiderfyOnMaxZoom: true,
219
+ showCoverageOnHover: false,
220
+ zoomToBoundsOnClick: true,
221
+ disableClusteringAtZoom: 16
222
+ });
223
+
224
+ /* Empty layer placeholder to add to layer control for listening when to add/remove theaters to markerClusters layer */
225
+ var theaterLayer = L.geoJson(null);
226
+ var theaters = L.geoJson(null, {
227
+ pointToLayer: function (feature, latlng) {
228
+ return L.marker(latlng, {
229
+ icon: L.icon({
230
+ iconUrl: "assets/img/theater.png",
231
+ iconSize: [24, 28],
232
+ iconAnchor: [12, 28],
233
+ popupAnchor: [0, -25]
234
+ }),
235
+ title: feature.properties.NAME,
236
+ riseOnHover: true
237
+ });
238
+ },
239
+ onEachFeature: function (feature, layer) {
240
+ if (feature.properties) {
241
+ var content = "<table class='table table-striped table-bordered table-condensed'>" + "<tr><th>Name</th><td>" + feature.properties.NAME + "</td></tr>" + "<tr><th>Phone</th><td>" + feature.properties.TEL + "</td></tr>" + "<tr><th>Address</th><td>" + feature.properties.ADDRESS1 + "</td></tr>" + "<tr><th>Website</th><td><a class='url-break' href='" + feature.properties.URL + "' target='_blank'>" + feature.properties.URL + "</a></td></tr>" + "<table>";
242
+ layer.on({
243
+ click: function (e) {
244
+ $("#feature-title").html(feature.properties.NAME);
245
+ $("#feature-info").html(content);
246
+ $("#featureModal").modal("show");
247
+ highlight.clearLayers().addLayer(L.circleMarker([feature.geometry.coordinates[1], feature.geometry.coordinates[0]], highlightStyle));
248
+ }
249
+ });
250
+ $("#feature-list tbody").append('<tr class="feature-row" id="' + L.stamp(layer) + '" lat="' + layer.getLatLng().lat + '" lng="' + layer.getLatLng().lng + '"><td style="vertical-align: middle;"><img width="16" height="18" src="assets/img/theater.png"></td><td class="feature-name">' + layer.feature.properties.NAME + '</td><td style="vertical-align: middle;"><i class="fa fa-chevron-right pull-right"></i></td></tr>');
251
+ theaterSearch.push({
252
+ name: layer.feature.properties.NAME,
253
+ address: layer.feature.properties.ADDRESS1,
254
+ source: "Theaters",
255
+ id: L.stamp(layer),
256
+ lat: layer.feature.geometry.coordinates[1],
257
+ lng: layer.feature.geometry.coordinates[0]
258
+ });
259
+ }
260
+ }
261
+ });
262
+ $.getJSON("data/DOITT_THEATER_01_13SEPT2010.geojson", function (data) {
263
+ theaters.addData(data);
264
+ map.addLayer(theaterLayer);
265
+ });
266
+
267
+ /* Empty layer placeholder to add to layer control for listening when to add/remove museums to markerClusters layer */
268
+ var museumLayer = L.geoJson(null);
269
+ var museums = L.geoJson(null, {
270
+ pointToLayer: function (feature, latlng) {
271
+ return L.marker(latlng, {
272
+ icon: L.icon({
273
+ iconUrl: "assets/img/museum.png",
274
+ iconSize: [24, 28],
275
+ iconAnchor: [12, 28],
276
+ popupAnchor: [0, -25]
277
+ }),
278
+ title: feature.properties.NAME,
279
+ riseOnHover: true
280
+ });
281
+ },
282
+ onEachFeature: function (feature, layer) {
283
+ if (feature.properties) {
284
+ var content = "<table class='table table-striped table-bordered table-condensed'>" + "<tr><th>Name</th><td>" + feature.properties.NAME + "</td></tr>" + "<tr><th>Phone</th><td>" + feature.properties.TEL + "</td></tr>" + "<tr><th>Address</th><td>" + feature.properties.ADRESS1 + "</td></tr>" + "<tr><th>Website</th><td><a class='url-break' href='" + feature.properties.URL + "' target='_blank'>" + feature.properties.URL + "</a></td></tr>" + "<table>";
285
+ layer.on({
286
+ click: function (e) {
287
+ $("#feature-title").html(feature.properties.NAME);
288
+ $("#feature-info").html(content);
289
+ $("#featureModal").modal("show");
290
+ highlight.clearLayers().addLayer(L.circleMarker([feature.geometry.coordinates[1], feature.geometry.coordinates[0]], highlightStyle));
291
+ }
292
+ });
293
+ $("#feature-list tbody").append('<tr class="feature-row" id="' + L.stamp(layer) + '" lat="' + layer.getLatLng().lat + '" lng="' + layer.getLatLng().lng + '"><td style="vertical-align: middle;"><img width="16" height="18" src="assets/img/museum.png"></td><td class="feature-name">' + layer.feature.properties.NAME + '</td><td style="vertical-align: middle;"><i class="fa fa-chevron-right pull-right"></i></td></tr>');
294
+ museumSearch.push({
295
+ name: layer.feature.properties.NAME,
296
+ address: layer.feature.properties.ADRESS1,
297
+ source: "Museums",
298
+ id: L.stamp(layer),
299
+ lat: layer.feature.geometry.coordinates[1],
300
+ lng: layer.feature.geometry.coordinates[0]
301
+ });
302
+ }
303
+ }
304
+ });
305
+ $.getJSON("data/DOITT_MUSEUM_01_13SEPT2010.geojson", function (data) {
306
+ museums.addData(data);
307
+ });
308
+
309
+ map = L.map("map", {
310
+ zoom: 10,
311
+ center: [40.702222, -73.979378],
312
+ layers: [cartoLight, boroughs, markerClusters, highlight],
313
+ zoomControl: false,
314
+ attributionControl: false
315
+ });
316
+
317
+ /* Layer control listeners that allow for a single markerClusters layer */
318
+ map.on("overlayadd", function(e) {
319
+ if (e.layer === theaterLayer) {
320
+ markerClusters.addLayer(theaters);
321
+ syncSidebar();
322
+ }
323
+ if (e.layer === museumLayer) {
324
+ markerClusters.addLayer(museums);
325
+ syncSidebar();
326
+ }
327
+ });
328
+
329
+ map.on("overlayremove", function(e) {
330
+ if (e.layer === theaterLayer) {
331
+ markerClusters.removeLayer(theaters);
332
+ syncSidebar();
333
+ }
334
+ if (e.layer === museumLayer) {
335
+ markerClusters.removeLayer(museums);
336
+ syncSidebar();
337
+ }
338
+ });
339
+
340
+ /* Filter sidebar feature list to only show features in current map bounds */
341
+ map.on("moveend", function (e) {
342
+ syncSidebar();
343
+ });
344
+
345
+ /* Clear feature highlight when map is clicked */
346
+ map.on("click", function(e) {
347
+ highlight.clearLayers();
348
+ });
349
+
350
+ /* Attribution control */
351
+ function updateAttribution(e) {
352
+ $.each(map._layers, function(index, layer) {
353
+ if (layer.getAttribution) {
354
+ $("#attribution").html((layer.getAttribution()));
355
+ }
356
+ });
357
+ }
358
+ map.on("layeradd", updateAttribution);
359
+ map.on("layerremove", updateAttribution);
360
+
361
+ var attributionControl = L.control({
362
+ position: "bottomright"
363
+ });
364
+ attributionControl.onAdd = function (map) {
365
+ var div = L.DomUtil.create("div", "leaflet-control-attribution");
366
+ div.innerHTML = "<span class='hidden-xs'>Developed by <a href='http://bryanmcbride.com'>bryanmcbride.com</a> | </span><a href='#' onclick='$(\"#attributionModal\").modal(\"show\"); return false;'>Attribution</a>";
367
+ return div;
368
+ };
369
+ map.addControl(attributionControl);
370
+
371
+ var zoomControl = L.control.zoom({
372
+ position: "bottomright"
373
+ }).addTo(map);
374
+
375
+ /* GPS enabled geolocation control set to follow the user's location */
376
+ var locateControl = L.control.locate({
377
+ position: "bottomright",
378
+ drawCircle: true,
379
+ follow: true,
380
+ setView: true,
381
+ keepCurrentZoomLevel: true,
382
+ markerStyle: {
383
+ weight: 1,
384
+ opacity: 0.8,
385
+ fillOpacity: 0.8
386
+ },
387
+ circleStyle: {
388
+ weight: 1,
389
+ clickable: false
390
+ },
391
+ icon: "fa fa-location-arrow",
392
+ metric: false,
393
+ strings: {
394
+ title: "My location",
395
+ popup: "You are within {distance} {unit} from this point",
396
+ outsideMapBoundsMsg: "You seem located outside the boundaries of the map"
397
+ },
398
+ locateOptions: {
399
+ maxZoom: 18,
400
+ watch: true,
401
+ enableHighAccuracy: true,
402
+ maximumAge: 10000,
403
+ timeout: 10000
404
+ }
405
+ }).addTo(map);
406
+
407
+ /* Larger screens get expanded layer control and visible sidebar */
408
+ if (document.body.clientWidth <= 767) {
409
+ var isCollapsed = true;
410
+ } else {
411
+ var isCollapsed = false;
412
+ }
413
+
414
+ var baseLayers = {
415
+ "Street Map": cartoLight,
416
+ "Aerial Imagery": usgsImagery
417
+ };
418
+
419
+ var groupedOverlays = {
420
+ "Points of Interest": {
421
+ "<img src='assets/img/theater.png' width='24' height='28'>&nbsp;Theaters": theaterLayer,
422
+ "<img src='assets/img/museum.png' width='24' height='28'>&nbsp;Museums": museumLayer
423
+ },
424
+ "Reference": {
425
+ "Boroughs": boroughs,
426
+ "Subway Lines": subwayLines
427
+ }
428
+ };
429
+
430
+ var layerControl = L.control.groupedLayers(baseLayers, groupedOverlays, {
431
+ collapsed: isCollapsed
432
+ }).addTo(map);
433
+
434
+ /* Highlight search box text on click */
435
+ $("#searchbox").click(function () {
436
+ $(this).select();
437
+ });
438
+
439
+ /* Prevent hitting enter from refreshing the page */
440
+ $("#searchbox").keypress(function (e) {
441
+ if (e.which == 13) {
442
+ e.preventDefault();
443
+ }
444
+ });
445
+
446
+ $("#featureModal").on("hidden.bs.modal", function (e) {
447
+ $(document).on("mouseout", ".feature-row", clearHighlight);
448
+ });
449
+
450
+ /* Typeahead search functionality */
451
+ $(document).one("ajaxStop", function () {
452
+ $("#loading").hide();
453
+ sizeLayerControl();
454
+ /* Fit map to boroughs bounds */
455
+ map.fitBounds(boroughs.getBounds());
456
+ featureList = new List("features", {valueNames: ["feature-name"]});
457
+ featureList.sort("feature-name", {order:"asc"});
458
+
459
+ var boroughsBH = new Bloodhound({
460
+ name: "Boroughs",
461
+ datumTokenizer: function (d) {
462
+ return Bloodhound.tokenizers.whitespace(d.name);
463
+ },
464
+ queryTokenizer: Bloodhound.tokenizers.whitespace,
465
+ local: boroughSearch,
466
+ limit: 10
467
+ });
468
+
469
+ var theatersBH = new Bloodhound({
470
+ name: "Theaters",
471
+ datumTokenizer: function (d) {
472
+ return Bloodhound.tokenizers.whitespace(d.name);
473
+ },
474
+ queryTokenizer: Bloodhound.tokenizers.whitespace,
475
+ local: theaterSearch,
476
+ limit: 10
477
+ });
478
+
479
+ var museumsBH = new Bloodhound({
480
+ name: "Museums",
481
+ datumTokenizer: function (d) {
482
+ return Bloodhound.tokenizers.whitespace(d.name);
483
+ },
484
+ queryTokenizer: Bloodhound.tokenizers.whitespace,
485
+ local: museumSearch,
486
+ limit: 10
487
+ });
488
+
489
+ var geonamesBH = new Bloodhound({
490
+ name: "GeoNames",
491
+ datumTokenizer: function (d) {
492
+ return Bloodhound.tokenizers.whitespace(d.name);
493
+ },
494
+ queryTokenizer: Bloodhound.tokenizers.whitespace,
495
+ remote: {
496
+ url: "http://api.geonames.org/searchJSON?username=bootleaf&featureClass=P&maxRows=5&countryCode=US&name_startsWith=%QUERY",
497
+ filter: function (data) {
498
+ return $.map(data.geonames, function (result) {
499
+ return {
500
+ name: result.name + ", " + result.adminCode1,
501
+ lat: result.lat,
502
+ lng: result.lng,
503
+ source: "GeoNames"
504
+ };
505
+ });
506
+ },
507
+ ajax: {
508
+ beforeSend: function (jqXhr, settings) {
509
+ settings.url += "&east=" + map.getBounds().getEast() + "&west=" + map.getBounds().getWest() + "&north=" + map.getBounds().getNorth() + "&south=" + map.getBounds().getSouth();
510
+ $("#searchicon").removeClass("fa-search").addClass("fa-refresh fa-spin");
511
+ },
512
+ complete: function (jqXHR, status) {
513
+ $('#searchicon').removeClass("fa-refresh fa-spin").addClass("fa-search");
514
+ }
515
+ }
516
+ },
517
+ limit: 10
518
+ });
519
+ boroughsBH.initialize();
520
+ theatersBH.initialize();
521
+ museumsBH.initialize();
522
+ geonamesBH.initialize();
523
+
524
+ /* instantiate the typeahead UI */
525
+ $("#searchbox").typeahead({
526
+ minLength: 3,
527
+ highlight: true,
528
+ hint: false
529
+ }, {
530
+ name: "Boroughs",
531
+ displayKey: "name",
532
+ source: boroughsBH.ttAdapter(),
533
+ templates: {
534
+ header: "<h4 class='typeahead-header'>Boroughs</h4>"
535
+ }
536
+ }, {
537
+ name: "Theaters",
538
+ displayKey: "name",
539
+ source: theatersBH.ttAdapter(),
540
+ templates: {
541
+ header: "<h4 class='typeahead-header'><img src='assets/img/theater.png' width='24' height='28'>&nbsp;Theaters</h4>",
542
+ suggestion: Handlebars.compile(["{{name}}<br>&nbsp;<small>{{address}}</small>"].join(""))
543
+ }
544
+ }, {
545
+ name: "Museums",
546
+ displayKey: "name",
547
+ source: museumsBH.ttAdapter(),
548
+ templates: {
549
+ header: "<h4 class='typeahead-header'><img src='assets/img/museum.png' width='24' height='28'>&nbsp;Museums</h4>",
550
+ suggestion: Handlebars.compile(["{{name}}<br>&nbsp;<small>{{address}}</small>"].join(""))
551
+ }
552
+ }, {
553
+ name: "GeoNames",
554
+ displayKey: "name",
555
+ source: geonamesBH.ttAdapter(),
556
+ templates: {
557
+ header: "<h4 class='typeahead-header'><img src='assets/img/globe.png' width='25' height='25'>&nbsp;GeoNames</h4>"
558
+ }
559
+ }).on("typeahead:selected", function (obj, datum) {
560
+ if (datum.source === "Boroughs") {
561
+ map.fitBounds(datum.bounds);
562
+ }
563
+ if (datum.source === "Theaters") {
564
+ if (!map.hasLayer(theaterLayer)) {
565
+ map.addLayer(theaterLayer);
566
+ }
567
+ map.setView([datum.lat, datum.lng], 17);
568
+ if (map._layers[datum.id]) {
569
+ map._layers[datum.id].fire("click");
570
+ }
571
+ }
572
+ if (datum.source === "Museums") {
573
+ if (!map.hasLayer(museumLayer)) {
574
+ map.addLayer(museumLayer);
575
+ }
576
+ map.setView([datum.lat, datum.lng], 17);
577
+ if (map._layers[datum.id]) {
578
+ map._layers[datum.id].fire("click");
579
+ }
580
+ }
581
+ if (datum.source === "GeoNames") {
582
+ map.setView([datum.lat, datum.lng], 14);
583
+ }
584
+ if ($(".navbar-collapse").height() > 50) {
585
+ $(".navbar-collapse").collapse("hide");
586
+ }
587
+ }).on("typeahead:opened", function () {
588
+ $(".navbar-collapse.in").css("max-height", $(document).height() - $(".navbar-header").height());
589
+ $(".navbar-collapse.in").css("height", $(document).height() - $(".navbar-header").height());
590
+ }).on("typeahead:closed", function () {
591
+ $(".navbar-collapse.in").css("max-height", "");
592
+ $(".navbar-collapse.in").css("height", "");
593
+ });
594
+ $(".twitter-typeahead").css("position", "static");
595
+ $(".twitter-typeahead").css("display", "block");
596
+ });
597
+
598
+ // Leaflet patch to make layer control scrollable on touch browsers
599
+ var container = $(".leaflet-control-layers")[0];
600
+ if (!L.Browser.touch) {
601
+ L.DomEvent
602
+ .disableClickPropagation(container)
603
+ .disableScrollPropagation(container);
604
+ } else {
605
+ L.DomEvent.disableClickPropagation(container);
606
+ }