From 5b48b6172c9d88d4d3290c37def92efda0a60059 Mon Sep 17 00:00:00 2001 From: Christopher Baines Date: Mon, 4 Aug 2014 18:59:32 +0100 Subject: Improve bus route example Also extract the route related classes from leaflet-soton.js, in preparation to make a leaflet-route plugin. The new bus route example uses the leaflet-sidebar plugin, as this works better on multiple screen sizes. --- resources/leaflet-route/leaflet-route.js | 318 +++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 resources/leaflet-route/leaflet-route.js (limited to 'resources/leaflet-route') diff --git a/resources/leaflet-route/leaflet-route.js b/resources/leaflet-route/leaflet-route.js new file mode 100644 index 0000000..501a620 --- /dev/null +++ b/resources/leaflet-route/leaflet-route.js @@ -0,0 +1,318 @@ + +L.Route = 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) { + 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); + }, + resetRoutes: function() { + Object.keys(this._routeLayers).forEach(this.resetRoute, this); + }, + 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); + } +}); + +L.Control.Route = L.Control.Sidebar.extend({ + initialize: function (routeLayer, placeholder, options) { + L.Control.Sidebar.prototype.initialize.call(this, placeholder, options); + L.setOptions(this, options); + + this._routeLayer = routeLayer; + + var title = L.DomUtil.create('div', 'ls-routes-title', this._contentContainer); + title.textContent = "University Bus Routes"; + + var routeMasters = this._routeLayer.getRouteMasters(); + + var routeMasterRouteLists = {}; + + var ul = L.DomUtil.create('ul', 'ls-route-master-list', this._contentContainer); + + 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._contentContainer.appendChild(routeList); + } + + var activeRouteMaster = "U1"; // TODO: Dont hardcode like this + + routeMasterRouteLists[activeRouteMaster].style.display = "block"; + }, + _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() { + routeLayer.resetRoutes(); + stopLists[activeStopList].style.display = "none"; + stopLists[routeName].style.display = "block"; + activeStopList = routeName; + routeLayer.highlightRoute(routeName); + }; + })(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"; + //routeLayer.highlightRoute(activeStopList); + + 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; + } +}); + +L.Control.ShowRouteSidebar = L.Control.extend({ + options: { + position: 'topleft', + }, + + initialize: function(sidebar, options) { + this._sidebar = sidebar; + }, + + onAdd: function (map) { + var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control'); + + var link = L.DomUtil.create('a', 'leaflet-bar-part leaflet-bar-part-single', container); + link.href = '#'; + + var sidebar = this._sidebar; + + L.DomEvent + .on(link, 'click', L.DomEvent.stopPropagation) + .on(link, 'click', L.DomEvent.preventDefault) + .on(link, 'click', function() { + sidebar.toggle(); + }) + .on(link, 'dblclick', L.DomEvent.stopPropagation); + + return container; + } +}); -- cgit v1.2.3