From 94990194cdec4f4f9348d2323a80004e6fc82f25 Mon Sep 17 00:00:00 2001 From: Christopher Baines Date: Sun, 7 Sep 2014 18:00:23 +0100 Subject: Initial commit --- .gitignore | 4 + .gitmodules | 15 +++ Gruntfile.js | 113 ++++++++++++++++++ LICENCE | 19 ++++ README | 45 ++++++++ index.html | 238 ++++++++++++++++++++++++++++++++++++++ libraries/bootstrap | 1 + libraries/jquery | 1 + libraries/leaflet-soton | 1 + libraries/list.js | 1 + libraries/typeahead.js | 1 + package.json | 12 ++ scripts.js | 296 ++++++++++++++++++++++++++++++++++++++++++++++++ style.css | 172 ++++++++++++++++++++++++++++ 14 files changed, 919 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Gruntfile.js create mode 100644 LICENCE create mode 100644 README create mode 100644 index.html create mode 160000 libraries/bootstrap create mode 160000 libraries/jquery create mode 160000 libraries/leaflet-soton create mode 160000 libraries/list.js create mode 160000 libraries/typeahead.js create mode 100644 package.json create mode 100644 scripts.js create mode 100644 style.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f789c72 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +dist/ +*.swp +*~ +node_modules/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c758ebf --- /dev/null +++ b/.gitmodules @@ -0,0 +1,15 @@ +[submodule "libraries/leaflet-soton"] + path = libraries/leaflet-soton + url = git://git.cbaines.net/leaflet-soton +[submodule "libraries/typeahead.js"] + path = libraries/typeahead.js + url = https://github.com/twitter/typeahead.js.git +[submodule "libraries/list.js"] + path = libraries/list.js + url = https://github.com/javve/list.js.git +[submodule "libraries/jquery"] + path = libraries/jquery + url = https://github.com/jquery/jquery.git +[submodule "libraries/bootstrap"] + path = libraries/bootstrap + url = https://github.com/twbs/bootstrap.git diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..ee4e1c7 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,113 @@ +module.exports = function(grunt) { + + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + concat: { + js: { + options: { + separator: ';' + }, + src: [ + 'libraries/jquery/dist/jquery.js', + 'libraries/bootstrap/dist/js/bootstrap.js', + 'libraries/typeahead.js/dist/typeahead.bundle.js', + 'libraries/list.js/dist/list.js', + 'libraries/leaflet-soton/resources/leaflet/dist/leaflet.js', + 'libraries/leaflet-soton/resources/leaflet-markercluster/dist/leaflet.markercluster.js', + 'libraries/leaflet-soton/resources/leaflet-locatecontrol/src/L.Control.Locate.js', + 'libraries/leaflet-soton/resources/leaflet-hash/leaflet-hash.js', + 'libraries/leaflet-soton/resources/leaflet-indoor/leaflet-indoor.js', + 'libraries/leaflet-soton/resources/leaflet-route/leaflet-route.js', + 'libraries/leaflet-soton/src/leaflet-soton.js', + 'scripts.js' + ], + dest: 'dist/scripts.js', + nonull: true + }, + css: { + src: [ + 'libraries/bootstrap/dist/css/bootstrap.css', + 'libraries/leaflet-soton/resources/leaflet/dist/leaflet.css', + 'libraries/leaflet-soton/resources/leaflet-markercluster/dist/MarkerCluster.css', + 'libraries/leaflet-soton/resources/leaflet-locatecontrol/src/L.Control.Locate.css', + 'libraries/leaflet-soton/src/leaflet-soton.css', + 'style.css' + ], + dest: 'dist/css/style.css', + nonull: true + } + }, + uglify: { + options: { + banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n' + }, + dist: { + files: { + 'dist/scripts.js': ['<%= concat.js.dest %>'] + } + } + }, + cssmin: { + add_banner: { + options: { + banner: '/* My minified css file */' + }, + files: { + 'dist/css/style.css': ['<%= concat.css.dest %>'] + } + } + }, + clean: { + build: ['dist'] + }, + copy: { + index: { + src: 'index.html', + dest: 'dist/index.html', + nonull: true + }, + data: { + src: 'libraries/leaflet-soton/data.json', + dest: 'dist/data.json', + nonull: true + }, + fonts: { + src: 'libraries/bootstrap/dist/fonts/*', + dest: 'dist/fonts/', + expand: 'false', + flatten: true, + nonull: true + }, + images: { + src: 'libraries/leaflet-soton/resources/images/*', + dest: 'dist/images/', + flatten: true, + expand: 'false', + nonull: true + }, + logos: { + src: 'libraries/leaflet-soton/resources/images/logos/*', + dest: 'dist/images/logos/', + flatten: true, + expand: 'false', + nonull: true + }, + locateimage: { + src: 'libraries/leaflet-soton/resources/leaflet-locatecontrol/src/images/*', + dest: 'dist/css/images/', + flatten: true, + expand: 'false', + nonull: true + } + } + }); + + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-cssmin'); + grunt.loadNpmTasks('grunt-contrib-concat'); + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-copy'); + + grunt.registerTask('default', ['clean:build', 'concat', 'copy']); + grunt.registerTask('release', ['clean:build', 'concat', 'uglify', 'cssmin', 'copy']); +}; diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000..5c0ce0e --- /dev/null +++ b/LICENCE @@ -0,0 +1,19 @@ +Copyright (c) 2014 Christopher Baines + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README b/README new file mode 100644 index 0000000..dc1eebb --- /dev/null +++ b/README @@ -0,0 +1,45 @@ + +# Building + +First build all the libraries, described below, then run: + + grunt + +Or, to build for release (with smaller js and css files): + + grunt release + +# Building the libraries + +## jquery + + npm run build + +## bootstrap + + npm install + grunt dist + +## leaflet-soton + + git submodule update --init + +### leaflet + + npm install -g jake + npm install + +This requires a local OSM database, and to setup config.json (use the template +config.json.default). + + ./create-data.js + +## list.js + + npm install + grunt dist + +## typeahead.js + + npm install + grunt diff --git a/index.html b/index.html new file mode 100644 index 0000000..b1a03db --- /dev/null +++ b/index.html @@ -0,0 +1,238 @@ + + + + + + + + + + + Map - University of Southampton + + + + + + + +
+ + + +
+
+ + + + + + + + + + diff --git a/libraries/bootstrap b/libraries/bootstrap new file mode 160000 index 0000000..c068162 --- /dev/null +++ b/libraries/bootstrap @@ -0,0 +1 @@ +Subproject commit c068162161154a4b85110ea1e7dd3d7897ce2b72 diff --git a/libraries/jquery b/libraries/jquery new file mode 160000 index 0000000..b807aed --- /dev/null +++ b/libraries/jquery @@ -0,0 +1 @@ +Subproject commit b807aedb7fee321fb3aa5d156a5a256ab0634e2d diff --git a/libraries/leaflet-soton b/libraries/leaflet-soton new file mode 160000 index 0000000..47f0d35 --- /dev/null +++ b/libraries/leaflet-soton @@ -0,0 +1 @@ +Subproject commit 47f0d35c5d1e7b210fce4928d62cdfe0ae5b5961 diff --git a/libraries/list.js b/libraries/list.js new file mode 160000 index 0000000..1ea294a --- /dev/null +++ b/libraries/list.js @@ -0,0 +1 @@ +Subproject commit 1ea294a7dde81f92d949bc056b52d175cbaad193 diff --git a/libraries/typeahead.js b/libraries/typeahead.js new file mode 160000 index 0000000..cc561bf --- /dev/null +++ b/libraries/typeahead.js @@ -0,0 +1 @@ +Subproject commit cc561bf1c6720e6664464fa065105143523c7e78 diff --git a/package.json b/package.json new file mode 100644 index 0000000..c987bec --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "maps.southampton.ac.uk", + "version": "0.1.0", + "devDependencies": { + "grunt": "~0.4.5", + "grunt-contrib-concat": "~0.5.0", + "grunt-contrib-uglify": "~0.5.0", + "grunt-contrib-cssmin": "~0.10.0", + "grunt-contrib-copy": "~0.5.0", + "grunt-contrib-clean": "~0.6.0" + } +} diff --git a/scripts.js b/scripts.js new file mode 100644 index 0000000..982e2d7 --- /dev/null +++ b/scripts.js @@ -0,0 +1,296 @@ +(function() { + "use strict"; + + LS.imagePath = 'images/'; + LS.dataPath = 'data.json'; + + var $buildingsSidebar = $('#buildingsSidebar'); + var $sitesSidebar = $('#sitesSidebar'); + + var $navBuildingsLi = $('#navBuildingsLi'); + var $navSitesLi = $('#navSitesLi'); + + function hideSitesSidebar() { + $sitesSidebar.hide(); + $navSitesLi.removeClass("active"); + } + + function hideBuildingsSidebar() { + $buildingsSidebar.hide(); + $navBuildingsLi.removeClass("active"); + } + + var buildingsSidebarLink = document.getElementById("buildingsSidebarLink") + buildingsSidebarLink.onclick = function() { + hideSitesSidebar(); + + $navBuildingsLi.toggleClass("active"); + $buildingsSidebar.toggle(); + + map.invalidateSize(); + + return false; + }; + + var sitesSidebarLink = document.getElementById("sitesSidebarLink") + sitesSidebarLink.onclick = function() { + hideBuildingsSidebar(); + + $navSitesLi.toggleClass("active"); + $sitesSidebar.toggle(); + + map.invalidateSize(); + + return false; + }; + + var buildingsSidebarHideButton = document.getElementById("buildingsSidebarHideButton"); + buildingsSidebarHideButton.onclick = function() { + hideBuildingsSidebar(); + + map.invalidateSize(); + return false; + }; + + var sitesSidebarHideButton = document.getElementById("sitesSidebarHideButton"); + sitesSidebarHideButton.onclick = function() { + hideSitesSidebar(); + + map.invalidateSize(); + + return false; + }; + + var map = LS.map('map', { + workstations: true, + indoor: true, + popupWidth: 550, + popupHeight: 550, + zoomControl: false, + levelControlPosition: 'bottomleft' + }); + + map.showInfo = function(content, latlng, options) { + var $content = $(content); + + var contentTitle = $content.children('h2'); + var titleText = contentTitle.text(); + contentTitle.remove(); + + $("#feature-title").html(titleText); + $("#feature-info").html(content); + $("#featureModal").modal("show"); + }; + + map.closeInfo = function() { + $("#featureModal").modal("hide"); + }; + + var zoomControl = L.control.zoom({ + position: "bottomright" + }).addTo(map); + + /* GPS enabled geolocation control set to follow the user's location */ + var locateControl = L.control.locate({ + position: "bottomright", + drawCircle: true, + follow: true, + setView: true, + keepCurrentZoomLevel: true, + markerStyle: { + weight: 1, + opacity: 0.8, + fillOpacity: 0.8 + }, + circleStyle: { + weight: 1, + clickable: false + }, + icon: "icon-direction", + metric: false, + strings: { + title: "My location", + popup: "You are within {distance} {unit} from this point", + outsideMapBoundsMsg: "You seem located outside the boundaries of the map" + }, + locateOptions: { + maxZoom: 18, + watch: true, + enableHighAccuracy: true, + maximumAge: 10000, + timeout: 10000 + } + }).addTo(map); + + /* Larger screens get expanded layer control and visible sidebar */ + if (document.body.clientWidth <= 767) { + var isCollapsed = true; + } else { + var isCollapsed = false; + } + + /* Highlight search box text on click */ + $("#searchbox").click(function () { + $(this).select(); + }); + + /* Typeahead search functionality */ + LS.getData(function(data) { + + function buildRow(first, second) { + var tr = document.createElement("tr"); + tr.style = "cursor: pointer;" + + var reftd = document.createElement("td"); + reftd.className = "feature-ref"; + reftd.style.verticalAlign = "middle"; + reftd.appendChild(first); + tr.appendChild(reftd); + + var featuretd = document.createElement("td"); + featuretd.className = "feature-name"; + featuretd.appendChild(second); + tr.appendChild(featuretd); + + var arrowtd = document.createElement("td"); + arrowtd.style.verticalAlign = "middle"; + var i = document.createElement("i"); + i.className = "glyphicon glyphicon-chevron-right pull-right"; + arrowtd.appendChild(i); + tr.appendChild(arrowtd); + + return tr; + } + + function show(uri) { + return function() { + map.panByURI(uri); + + /* Hide sidebars and go to the map on small screens */ + if (document.body.clientWidth <= 767) { + hideSitesSidebar(); + hideBuildingsSidebar(); + + map.invalidateSize(); + } + }; + } + + var buildingstbody = $("#buildingsList tbody"); + + data.buildings.features.forEach(function(building) { + if (!("loc_ref" in building.properties) || + building.properties.name.length === 0) { + return; + } + + var loc_ref = document.createTextNode(building.properties.loc_ref); + var name = document.createTextNode(building.properties.name); + var tr = buildRow(loc_ref, name); + + tr.onclick = show(building.properties.uri); + + buildingstbody.append(tr); + }); + + var buildingsList = new List("buildings", { + valueNames: [ + "feature-ref", + "feature-name" + ] + }); + buildingsList.sort("feature-name", { + order:"asc" + }); + + buildingsList.on("filterStart", function() { + console.log("filterComplete"); + + console.log(buildingsList.matchingItems); + }); + + var sitestbody = $("#sitesList tbody"); + + data.sites.features.forEach(function(site) { + if (!("name" in site.properties)) { + return; + } + + var loc_ref = document.createTextNode(site.properties.loc_ref); + var name = document.createTextNode(site.properties.name); + var tr = buildRow(loc_ref, name); + + tr.onclick = show(site.properties.uri); + + sitestbody.append(tr); + }); + + var sitesList = new List("sites", {valueNames: ["feature-ref", "feature-name"]}); + sitesList.sort("feature-name", {order:"asc"}); + + var buildingsBH = new Bloodhound({ + name: "Buildings", + datumTokenizer: function (d) { + return Bloodhound.tokenizers.whitespace(d.properties.loc_ref + " " + d.properties.name); + }, + queryTokenizer: Bloodhound.tokenizers.whitespace, + local: data.buildings.features, + limit: 10 + }); + + buildingsBH.initialize(); + + var sitesBH = new Bloodhound({ + name: "Buildings", + datumTokenizer: function (d) { + return Bloodhound.tokenizers.whitespace(d.properties.loc_ref + " " +d.properties.name); + }, + queryTokenizer: Bloodhound.tokenizers.whitespace, + local: data.sites.features, + limit: 10 + }); + + sitesBH.initialize(); + + /* instantiate the typeahead UI */ + $("#searchbox").typeahead({ + minLength: 1, + highlight: true, + hint: false + }, { + name: "Buildings", + displayKey: "name", + source: buildingsBH.ttAdapter(), + templates: { + header: "

Buildings

", + suggestion: function(feature) { + return feature.properties.name + "
 " + feature.properties.loc_ref + ""; + } + } + }, { + name: "Sites", + displayKey: "name", + source: sitesBH.ttAdapter(), + templates: { + header: "

Sites

", + suggestion: function(feature) { + return feature.properties.name + "
 " + feature.properties.loc_ref + ""; + } + } + }).on("typeahead:selected", function (obj, feature) { + map.panByURI(feature.properties.uri); + + if ($(".navbar-collapse").height() > 50) { + $(".navbar-collapse").collapse("hide"); + } + }).on("typeahead:opened", function () { + $(".navbar-collapse.in").css("max-height", $(document).height() - $(".navbar-header").height()); + $(".navbar-collapse.in").css("height", $(document).height() - $(".navbar-header").height()); + }).on("typeahead:closed", function () { + $(".navbar-collapse.in").css("max-height", ""); + $(".navbar-collapse.in").css("height", ""); + }); + $(".twitter-typeahead").css("position", "static"); + $(".twitter-typeahead").css("display", "block"); + }); +})(); diff --git a/style.css b/style.css new file mode 100644 index 0000000..71cf824 --- /dev/null +++ b/style.css @@ -0,0 +1,172 @@ +html, body, #container { + height: 100%; + width: 100%; + overflow: hidden; +} + +body { + padding-top: 50px; +} + +input[type="radio"], input[type="checkbox"] { + margin: 0; +} + +#buildingsSidebar, #sitesSidebar, #busRoutesSidebar { + width: 250px; + height: 100%; + max-width: 100%; + float: left; + -webkit-transition: all 0.25s ease-out; + -moz-transition: all 0.25s ease-out; + transition: all 0.25s ease-out; +} + +#map { + width: auto; + height: 100%; + box-shadow: 0 0 10px rgba(0,0,0,0.5); +} + +.sidebar-wrapper { + width: 100%; + height: 100%; + position: relative; +} + +.sidebar-table { + position: absolute; + width: 100%; + top: 100px; + bottom: 0px; + overflow: auto; +} + +.table { + margin-bottom: 0px; +} + +.navbar-inverse .navbar-brand { + font-weight: bold; + font-size: 25px; + color: white; +} + +.navbar-nav > li > a { + color: white; +} + +.navbar-inverse .navbar-nav > .active > a, .navbar-inverse .navbar-nav > .active > a:hover, .navbar-inverse .navbar-nav > .active > a:focus { + background-color: #004462; + color: #fff; +} + +.navbar-inverse .navbar-nav > li > a { + color: #fff; +} + +.navbar-inverse { + background-color: #005c84; +} + +.navbar-collapse.in { + overflow-y: hidden; +} + +.navbar-header .navbar-icon-container { + margin-right: 15px; +} + +.navbar-header .navbar-icon { + line-height: 50px; + height: 50px; +} + +.navbar-header a.navbar-icon { + margin-left: 25px; +} + +.navbar-header .navbar-toggle .icon-bar { + background-color: #ffffff; +} + +.typeahead { + background-color: #FFFFFF; +} + +.tt-dropdown-menu { + background-color: #FFFFFF; + border: 1px solid rgba(0, 0, 0, 0.2); + border-radius: 4px 4px 4px 4px; + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + margin-top: 4px; + padding: 4px 0; + width: 100%; + max-height: 300px; + overflow: auto; +} + +.tt-suggestion { + font-size: 14px; + line-height: 20px; + padding: 3px 10px; +} + +.tt-suggestion.tt-cursor { + background-color: #0097CF; + color: #FFFFFF; + cursor: pointer; +} + +.tt-suggestion p { + margin: 0; +} + +.tt-suggestion + .tt-suggestion { + border-top: 1px solid #ccc; +} + +.typeahead-header { + margin: 0 5px 5px 5px; + padding: 3px 0; + border-bottom: 2px solid #333; +} + +.has-feedback .form-control-feedback { + position: absolute; + top: 0; + right: 0; + display: block; + width: 34px; + height: 34px; + line-height: 34px; + text-align: center; +} + +@media (max-width: 992px) { + .navbar .navbar-brand { + font-size: 18px; + } +} + +@media (max-width: 767px){ + .url-break { + word-break: break-all; + word-break: break-word; + -webkit-hyphens: auto; + hyphens: auto; + } + #sidebar { + display: none; + } +} + +/* Print Handling */ +@media print { + .navbar { + display: none !important; + } + .leaflet-control-container { + display: none !important; + } +} -- cgit v1.2.3