L.Route = L.FeatureGroup.extend({ initialize: function (routes, stops, options) { L.setOptions(this, options); if (typeof(L.LayerGroup.prototype.setText) !== "function") { // Leaflet TextPath is missing console.warn("The leaflet-route library requires leaflet textpath"); } 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._lrHighlighted = true; layer.setStyle({ weight: 10, opacity: 1, }); layer.setText('\u25BA', { repeat: true, offset: 3, attributes: { fill: 'black', fontSize: 24 } }); layer.bringToFront(); }, toggleRouteHighlight: function(id) { if (this.isRouteHighlighed(id)) { this.resetRoute(id); } else { this.highlightRoute(id); } }, isRouteHighlighted: function(id) { var layer = this._routeLayers[id]; return layer._lrHighlighted === true; }, resetRoute: function(id) { var layer = this._routeLayers[id]; layer._lrHighlighted = false; 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.Route.createRouteMasterList = function(routeMasters, routeSelected, sortFunction) { var ul = L.DomUtil.create('ul', 'ls-route-list'); var routeMasterNames = Object.keys(routeMasters); if (sortFunction) { routeMasterNames.sort(sortFunction); } for (var i in routeMasterNames) { var name = routeMasterNames[i] var routeMaster = routeMasters[name]; var li = L.DomUtil.create('li', '', ul); var a = L.DomUtil.create('a', null, li); a.className = "ls-route-master-link"; a.style.background = routeMaster.routes[0].properties.colour; a.textContent = "U"; var strong = document.createElement("strong"); strong.textContent = routeMaster.name.slice(1); a.appendChild(strong); a.onclick = (function(routeName) { return function() { routeSelected(routeName); }; })(routeMaster.name); } return ul; }; L.Control.Route.createRouteLink = function(route, routeSelected) { var a = document.createElement("a"); a.className = "ls-route-link"; a.style.background = route.properties.colour; a.textContent = "U"; var strong = document.createElement("strong"); strong.textContent = route.properties.ref.slice(1); a.appendChild(strong); a.onclick = function() { routeSelected(); }; return a; }; L.Control.Route.createRouteList = function(routeMaster, routeSelected) { var ul = L.DomUtil.create('ul', 'ls-route-list'); for (var i in routeMaster.routes) { var route = routeMaster.routes[i]; var li = L.DomUtil.create('li', '', ul); li.appendChild(L.Control.Route.createRouteLink(route, (function(name) { return function() { routeSelected(name); }; })(route.properties.name))); } return ul; }; L.Control.Route.createStopList = function(route, routeLayer) { var ul = L.DomUtil.create('ul', 'ls-stop-list'); ul.style.listStyleImage = "url(" + LS.imagePath + "bus_stop.png)"; 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; li.onclick = (function(uri) { return function() { if (document.body.clientWidth <= 767) { hideSidebars(); map.invalidateSize(); } routeLayer.panToStop(uri, { animate: true }); }; })(busStop.properties.uri); li.onmouseover = (function(uri) { return function() { routeLayer.highlightStop(uri); }; })(busStop.properties.uri); li.onmouseout = (function(uri) { return function() { routeLayer.resetStop(uri); }; })(busStop.properties.uri); } else { a.textContent = "Name Unknown"; } } return ul; }; L.Control.Route.create = function(routeLayer) { function showStopList(name) { var previousActiveRoute = activeRouteForRouteMaster[activeRouteMaster]; stopLists[previousActiveRoute].style.display = "none"; descriptions[previousActiveRoute].style.display = "none" stopLists[name].style.display = "block"; descriptions[name].style.display = "block" } var busRouteSidebarContent = document.createDocumentFragment(); var routeMasters = routeLayer.getRouteMasters(); var routeMasterRouteLists = {}; var stopLists = {}; var descriptions = {}; var routeMasterNames = Object.keys(routeMasters); var sortFunction = function(a, b) { var refs = { "U1": 1, "U2": 2, "U6": 6, "U9": 9, "U1N": 10 }; return refs[a] - refs[b]; }; var activeRouteMaster = "U1"; var activeRouteForRouteMaster = {}; var showRouteMaster = function(routeMasterName) { routeMasterRouteLists[activeRouteMaster].style.display = "none"; routeMasterRouteLists[routeMasterName].style.display = "block"; var activeRoute = activeRouteForRouteMaster[routeMasterName]; showStopList(activeRoute); activeRouteMaster = routeMasterName; routeLayer.resetRoutes(); routeLayer.highlightRoute(activeRoute); }; var routeMasterControl = L.Control.Route.createRouteMasterList(routeMasters, showRouteMaster, sortFunction); busRouteSidebarContent.appendChild(routeMasterControl); for (var i in routeMasterNames) { var routeMasterName = routeMasterNames[i]; var routeMaster = routeMasters[routeMasterName]; activeRouteForRouteMaster[routeMasterName] = routeMaster.routes[0].properties.name; // The route lists var routeList = L.Control.Route.createRouteList(routeMaster, function(routeName) { routeLayer.resetRoutes(); showStopList(routeName); activeRouteForRouteMaster[activeRouteMaster] = routeName; routeLayer.highlightRoute(routeName); }); routeMasterRouteLists[routeMasterName] = routeList; routeList.style.display = "none"; busRouteSidebarContent.appendChild(routeList); // The stops for (var i in routeMaster.routes) { var route = routeMaster.routes[i]; // Add the description var description = L.DomUtil.create('div', 'ls-route-description'); description.textContent = route.properties.name.split(": ")[1].replace("=>", "\u2192"); descriptions[route.properties.name] = description; // Add the list of stops var stopList = L.Control.Route.createStopList(route, routeLayer); stopLists[route.properties.name] = stopList; if (activeRouteMaster === routeMasterName && activeRouteForRouteMaster[routeMasterName] === route.properties.name) { stopList.style.display = "block"; description.style.display = "block"; } else { stopList.style.display = "none"; description.style.display = "none"; } busRouteSidebarContent.appendChild(description); busRouteSidebarContent.appendChild(stopList); } } routeMasterRouteLists[activeRouteMaster].style.display = "block"; return busRouteSidebarContent; } if ("Sidebar" in L.Control) { L.Control.RouteSidebar = L.Control.Sidebar.extend({ initialize: function (routeLayer, placeholder, options) { L.Control.Sidebar.prototype.initialize.call(this, placeholder, options); L.setOptions(this, options); var controls = L.Control.Route.create(routeLayer); this.getContainer().appendChild(controls); } }); 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; } }); }