summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristopher Baines <cb15g11@soton.ac.uk>2014-06-06 11:52:55 +0100
committerChristopher Baines <cb15g11@soton.ac.uk>2014-06-06 12:14:23 +0100
commit586cda60293cebd617f0af275d63343f68abd525 (patch)
tree8cf5b916ce24d6c35031b3fc0eb5b6a80d48c24a /src
parentcfa92e45a7f4550885917022ee8e19ee2a410de1 (diff)
downloadleaflet-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.css70
-rw-r--r--src/leaflet-soton.js376
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) {