diff options
author | Christopher Baines <cb15g11@soton.ac.uk> | 2014-06-06 11:52:55 +0100 |
---|---|---|
committer | Christopher Baines <cb15g11@soton.ac.uk> | 2014-06-06 12:14:23 +0100 |
commit | 586cda60293cebd617f0af275d63343f68abd525 (patch) | |
tree | 8cf5b916ce24d6c35031b3fc0eb5b6a80d48c24a /src | |
parent | cfa92e45a7f4550885917022ee8e19ee2a410de1 (diff) | |
download | leaflet-soton-586cda60293cebd617f0af275d63343f68abd525.tar leaflet-soton-586cda60293cebd617f0af275d63343f68abd525.tar.gz |
Add a RouteLayer and RouteControl
Add the leaflet-textpath submodule as it is used in the RouteLayer
Improve the bus route extraction:
- Now supports polygons for platforms
- Supports routes not in a route master
- Filter out all but one U1C route (in an attempt to make the interface less
confusing)
Add an example using the RouteLayer and RouteControl.
Hard code the centers for some "University" buildings on the Isle of White and
in Basingstoke, such that workstations listed as in these buildings appear on
the map.
Diffstat (limited to 'src')
-rw-r--r-- | src/leaflet-soton.css | 70 | ||||
-rw-r--r-- | src/leaflet-soton.js | 376 |
2 files changed, 424 insertions, 22 deletions
diff --git a/src/leaflet-soton.css b/src/leaflet-soton.css index af1ecda..336d273 100644 --- a/src/leaflet-soton.css +++ b/src/leaflet-soton.css @@ -114,6 +114,7 @@ border-bottom: 1px solid #ddd; } .ls-nav-tabs > li { + display: inline; margin-bottom: -1px; } .ls-nav-tabs > li > a { @@ -150,3 +151,72 @@ color: #ffffff; background-color: #0088cc; } + +.ls-route-control { + padding: 6px 8px; + font: 14px/16px Arial, Helvetica, sans-serif; + background: white; + background: rgba(255,255,255,1); + box-shadow: 0 0 15px rgba(0,0,0,0.2); + border-radius: 5px; +} + +.ls-routes-title { + font: 30px/32px Arial, Helvetica, sans-serif; +} + +.ls-route-description { + font: 18px/20px Arial, Helvetica, sans-serif; +} + +.ls-route-master-list { + list-style: none; + padding-left: 0px; +} + +.ls-route-master-list li { + display: inline; +} + +.ls-route-master-list li a { + font: 28px/30px Arial, Helvetica, sans-serif; + padding-right: 10px; + padding-left: 10px; + margin-right: 5px; + margin-left: 5px; + border-radius: 25px; + border: 4px; + border-style: solid; + border-color: #000000; + background: #a1a1a1; + color: white; + font-weight: bold; +} + +.ls-route-list { + list-style: none; + padding-left: 0px; +} + +.ls-route-list li { + display: inline; +} + +.ls-route-list li a { + font: 20px/22px Arial, Helvetica, sans-serif; + padding-right: 10px; + padding-left: 10px; + margin-right: 3px; + margin-left: 3px; + border-radius: 25px; + border: 3px; + border-style: solid; + border-color: #000000; + background: #a1a1a1; + color: white; + font-weight: bold; +} + +.ls-stop-list { + padding-left: 25px; +} diff --git a/src/leaflet-soton.js b/src/leaflet-soton.js index 3e030dc..aea9f1c 100644 --- a/src/leaflet-soton.js +++ b/src/leaflet-soton.js @@ -70,21 +70,25 @@ var contents = part.properties.contents; - for (var j=0; j<contents.length; j++) { - var content = contents[j]; + if (contents) { + for (var j=0; j<contents.length; j++) { + var content = contents[j]; - if (content.feature === uri) { - return part; + if (content.feature === uri) { + return part; + } } } var features = part.properties.features; - for (var j=0; j<features.length; j++) { - var feature = features[j]; + if (features) { + for (var j=0; j<features.length; j++) { + var feature = features[j]; - if (feature.feature === uri) { - return part; + if (feature.feature === uri) { + return part; + } } } } @@ -315,7 +319,7 @@ SELECT * WHERE {\ var emptyFeatureCollection = { type: "FeatureCollection", features: [] }; var transparaentStyle = function(feature) {return {weight: 0, opacity: 0, fillOpacity: 0};}; - var layerNames = ['sites', 'parking', 'bicycleParking', 'buildings', 'busStops', 'busRoutes']; + var layerNames = ['sites', 'parking', 'bicycleParking', 'buildings']; var busRouteStyle = function(feature) { return {weight: 5, opacity: 0.5, color: feature.properties.colour}; @@ -325,6 +329,8 @@ SELECT * WHERE {\ options: { center: [50.9354, -1.3964], indoor: false, + busRoutes: false, + busRouteControl: false, workstations: false, zoom: 17, tileUrl: 'http://bus.southampton.ac.uk/graphics/map/tiles/{z}/{x}/{y}.png', @@ -379,8 +385,6 @@ SELECT * WHERE {\ options.highlight[feature.properties.uri]) { return {weight: 5, opacity: 0.5, color: 'blue'}; - } else if (layerName === "busRoutes") { - return busRouteStyle(feature); } else { return blankStyle(); } @@ -421,15 +425,6 @@ SELECT * WHERE {\ }; } - if (layerName === "busStops") { - layerOptions.pointToLayer = function (feature, latlng) { - return L.circleMarker(latlng, { - radius: 8, - opacity: 1, - }); - }; - } - layers[layerName] = L.geoJson(emptyFeatureCollection, layerOptions).addTo(map); }); @@ -458,6 +453,46 @@ SELECT * WHERE {\ layer.addData(data[layerName]); } + var routeLayer = new LS.RouteLayer(data.busRoutes, data.busStops, { + routeOptions: { + onEachFeature: function(feature, layer) { + layer.on('click', function(e) { + var content = busRouteTemplate(feature.properties); + + showPopup(map, content, e.latlng); + }); + }, + style: options.busRoutes ? busRouteStyle : blankStyle + }, + stopOptions: { + onEachFeature: function(feature, layer) { + layer.on('click', function(e) { + var content = busStopTemplate(feature.properties); + + showPopup(map, content, e.latlng); + }); + } + } + }); + routeLayer.addTo(map); + + if (options.busRouteControl) { + var routeControl = new LS.RouteControl(routeLayer, { + routeMasterSort: function(a, b) { + var refs = { + "U1": 1, + "U2": 2, + "U6": 6, + "U9": 9, + "U1N": 10 + }; + + return refs[a] - refs[b]; + } + }); + routeControl.addTo(map); + } + LS.getWorkstationData(function(workstationData) { if (options.indoor) { @@ -893,8 +928,6 @@ SELECT * WHERE {\ buildings: buildingTemplate, bicycleParking: bicycleParkingTemplate, parking: parkingTemplate, - busStops: busStopTemplate, - busRoutes: busRouteTemplate }; function roomPopupTemplate(properties) { @@ -1592,6 +1625,305 @@ SELECT * WHERE {\ return window.innerWidth < 500; } + LS.RouteLayer = L.FeatureGroup.extend({ + initialize: function (routes, stops, options) { + L.setOptions(this, options); + + this._layers = {}; + + this._routeMasters = {}; + + for (var i in routes.features) { + var route = routes.features[i]; + + if ("routeMaster" in route.properties) { + var routeMaster = route.properties.routeMaster; + + if (routeMaster in this._routeMasters) { + this._routeMasters[routeMaster].routes.push(route); + } else { + this._routeMasters[routeMaster] = { + name: routeMaster, + routes: [ route ] + }; + } + } else { + this._routeMasters[route.properties.ref] = { + name: route.properties.ref, + routes: [ route ] + }; + } + } + + this._routes = routes; + this._busStops = {}; + + for (i in stops.features) { + var busStop = stops.features[i]; + + this._busStops[busStop.properties.uri] = busStop; + } + + var routeLayers = this._routeLayers = {} + this._routeLayer = new L.GeoJSON(routes, { + onEachFeature: function(feature, layer) { + routeLayers[feature.properties.name] = layer; + + if (options.routeOptions.onEachFeature) { + options.routeOptions.onEachFeature(feature, layer); + } + }, + style: options.routeOptions.style + }); + this.addLayer(this._routeLayer); + + var stopLayers = this._stopLayers = {}; + this._stopLayer = new L.GeoJSON(stops, { + onEachFeature: function(feature, layer) { + stopLayers[feature.properties.uri] = layer; + + if (options.stopOptions.onEachFeature) { + console.log("stops"); + options.stopOptions.onEachFeature(feature, layer); + } + }, + pointToLayer: function (feature, latlng) { + return L.circleMarker(latlng, { + radius: 8, + opacity: 0, + }); + }, + style: function(feature) { + return { + radius: 8, + opacity: 0, + fillOpacity: 0 + }; + } + }); + this.addLayer(this._stopLayer); + }, + getRouteMasters: function() { + return this._routeMasters; + }, + getRoutesForRouteMaster: function(id) { + return this._routeMasters[id]; + }, + getRoutes: function() { + return this._routes; + }, + getStops: function() { + return this._busStops; + }, + highlightRoute: function(id) { + var layer = this._routeLayers[id]; + + layer.setStyle({ + weight: 10, + opacity: 1, + }); + + layer.setText('\u25BA', { + repeat: true, + offset: 3, + attributes: { + fill: 'black', + fontSize: 24 + } + }); + + layer.bringToFront(); + }, + resetRoute: function(id) { + var layer = this._routeLayers[id]; + + this._routeLayer.resetStyle(layer); + + layer.setText(null); + }, + highlightStop: function(id) { + var layer = this._stopLayers[id]; + + layer.setStyle({ + color: '#ff0000', + opacity: 1, + fillOpacity: 0.3, + radius: 16, + stroke: true, + fill: true + }); + }, + resetStop: function(id) { + var layer = this._stopLayers[id]; + + this._stopLayer.resetStyle(layer); + }, + panToStop: function(id, panOptions) { + var layer = this._stopLayers[id]; + + this._map.panTo(layer._latlng, panOptions); + } + }); + + LS.RouteControl = L.Control.extend({ + initialize: function (routeLayer, options) { + L.setOptions(this, options); + + this._routeLayer = routeLayer; + }, + onAdd: function (map) { + this._div = L.DomUtil.create('div', 'ls-route-control'); + + var title = L.DomUtil.create('div', 'ls-routes-title', this._div); + title.textContent = "University Bus Routes"; + + var routeMasters = this._routeLayer.getRouteMasters(); + + var routeMasterRouteLists = {}; + + var ul = L.DomUtil.create('ul', 'ls-route-master-list', this._div); + + var routeMasterNames = Object.keys(routeMasters); + if (this.options.routeMasterSort) { + routeMasterNames.sort(this.options.routeMasterSort); + } + + for (var i in routeMasterNames) { + var routeMasterName = routeMasterNames[i]; + var routeMaster = routeMasters[routeMasterName]; + + var li = L.DomUtil.create('li', '', ul); + var a = L.DomUtil.create('a', '', li); + + a.style.background = routeMaster.routes[0].properties.colour; + + a.textContent = routeMaster.name; + a.onclick = (function(routeMasterName) { + return function() { + routeMasterRouteLists[activeRouteMaster].style.display = "none"; + routeMasterRouteLists[routeMasterName].style.display = "block"; + activeRouteMaster = routeMasterName; + }; + })(routeMasterName); + + // The route lists + + var routeList = this._createRouteList(routeMaster); + routeMasterRouteLists[routeMasterName] = routeList; + + routeList.style.display = "none"; + + this._div.appendChild(routeList); + } + + var activeRouteMaster = "U1"; // TODO: Dont hardcode like this + + routeMasterRouteLists[activeRouteMaster].style.display = "block"; + + return this._div; + }, + _createRouteList: function(routeMaster) { + var div = L.DomUtil.create('div', null); + + var ul = L.DomUtil.create('ul', 'ls-route-list', div); + + var routeLayer = this._routeLayer; + + var stopLists = {}; + for (var i in routeMaster.routes) { + var route = routeMaster.routes[i]; + + var li = L.DomUtil.create('li', '', ul); + var a = L.DomUtil.create('a', null, li); + + //a.style.borderColor = route.properties.colour; + a.style.background = route.properties.colour; + + a.textContent = route.properties.ref; + a.onclick = (function(routeName) { + return function() { + stopLists[activeStopList].style.display = "none"; + stopLists[routeName].style.display = "block"; + activeStopList = routeName; + }; + })(route.properties.name); + + a.onmouseover = (function(name) { + return function() { + routeLayer.highlightRoute(name); + }; + })(route.properties.name); + a.onmouseout = (function(name) { + return function() { + routeLayer.resetRoute(name); + }; + })(route.properties.name); + + // The stops + + var stopList = this._createStopList(route); + stopLists[route.properties.name] = stopList; + + stopList.style.display = "none"; + + div.appendChild(stopList); + } + + var activeStopList = routeMaster.routes[0].properties.name; + stopLists[activeStopList].style.display = "block"; + + return div; + }, + _createStopList: function(route) { + var div = L.DomUtil.create('div', null, this._div); + + var description = L.DomUtil.create('div', 'ls-route-description', div); + description.textContent = route.properties.name.split(": ")[1].replace("=>", "\u2192"); + + var ul = L.DomUtil.create('ul', 'ls-stop-list', div); + + ul.style.listStyleImage = "url(" + LS.imagePath + "bus_stop.png)"; + + var routeLayer = this._routeLayer; + var busStops = routeLayer.getStops(); + + for (var i in route.properties.stops) { + var stop = route.properties.stops[i]; + + var li = L.DomUtil.create('li', '', ul); + + var busStop = busStops[stop]; + + var a = L.DomUtil.create('a', '', li); + + if (typeof(busStop) !== "undefined") { + a.textContent = busStop.properties.name; + a.onclick = (function(uri) { + return function() { + routeLayer.panToStop(uri, { + animate: true + }); + }; + })(busStop.properties.uri); + a.onmouseover = (function(uri) { + return function() { + routeLayer.highlightStop(uri); + }; + })(busStop.properties.uri); + a.onmouseout = (function(uri) { + return function() { + routeLayer.resetStop(uri); + }; + })(busStop.properties.uri); + } else { + a.textContent = "Name Unknown"; + } + } + + return div; + } + }); + // Custom Hash Support if ("Hash" in L) { |