diff options
-rw-r--r-- | resources/images/busstop.png | bin | 0 -> 856 bytes | |||
-rw-r--r-- | src/leaflet-soton.css | 15 | ||||
-rw-r--r-- | src/leaflet-soton.js | 581 |
3 files changed, 263 insertions, 333 deletions
diff --git a/resources/images/busstop.png b/resources/images/busstop.png Binary files differnew file mode 100644 index 0000000..1474036 --- /dev/null +++ b/resources/images/busstop.png diff --git a/src/leaflet-soton.css b/src/leaflet-soton.css index 56a8eb1..7a02f50 100644 --- a/src/leaflet-soton.css +++ b/src/leaflet-soton.css @@ -5,6 +5,12 @@ .ls-popup-title { font: 25px/16px Arial, Helvetica, sans-serif; } +.ls-popup-title-ref { + background-color: black; + color: white; + padding: 2px 5px 2px 5px; + border-radius: 3px; +} .ls-popup-uri { float: right; @@ -225,3 +231,12 @@ .ls-stop-list { padding-left: 25px; } + +.ls-popup-content { + max-height: 400px; + overflow-x: hidden; + overflow-y: auto; +} +.leaflet-popup-content { + margin: 6px 9px; +} diff --git a/src/leaflet-soton.js b/src/leaflet-soton.js index 89f82dc..a1f6ea4 100644 --- a/src/leaflet-soton.js +++ b/src/leaflet-soton.js @@ -265,6 +265,14 @@ SELECT * WHERE {\ var icons = { created: false, createIcons: function() { + this.busStop = L.icon({ + iconUrl: LS.imagePath + 'busstop.png', + + iconSize: [32, 37], // size of the icon + iconAnchor: [16, 37], // point of the icon which will correspond to marker's location + popupAnchor: [0, -35] // point from which the popup should open relative to the iconAnchor + }); + this.printer = L.icon({ iconUrl: LS.imagePath + 'printer.png', @@ -373,10 +381,35 @@ SELECT * WHERE {\ }; }; + function featureHasPopup( feature ) + { + if (feature.properties.buildingpart === "corridor") { + return; // No popup for corridors yet + } + + if( !('features' in feature.properties) ) { feature.properties.features=[]; } + if( !('contents' in feature.properties) ) { feature.properties.contents=[]; } + if( !('images' in feature.properties) ) { feature.properties.images=[]; } + + if ('buildingpart' in feature.properties) { + if( feature.properties.features.length==0 + && feature.properties.contents.length==0 + && feature.properties.images.length==0 ) { + return false; + } + } + + return true; + } + var emptyFeatureCollection = { type: "FeatureCollection", features: [] }; var transparaentStyle = function(feature) {return {weight: 0, opacity: 0, fillOpacity: 0};}; - var layerNames = ['sites', 'parking', 'bicycleParking', 'buildings']; + var layerNames = [ + 'sites', + // 'parking', + 'bicycleParking', + 'buildings']; var busRouteStyle = function(feature) { return {weight: 5, opacity: 0.5, color: feature.properties.colour}; @@ -629,7 +662,7 @@ SELECT * WHERE {\ if ("name" in part.properties && "ref" in part.properties) { content = part.properties.name + " (" + part.properties.ref + ")"; } else if ("ref" in part.properties) { - content = "Room " + part.properties.ref; + content = "<span style='font-size:90%'>room</span><br/>" + part.properties.ref; } else if ("name" in part.properties) { content = part.properties.name; } else { @@ -683,34 +716,10 @@ SELECT * WHERE {\ } }, onEachFeature: function(feature, layer) { - if (feature.properties.buildingpart === "corridor") { - return; // No popup for corridors yet - } - + if( !featureHasPopup(feature) ) { return; } layer.on('click', function(e) { - var content; - var popupOptions = {}; - - // When the feature is clicked on - if ("buildingpart" in feature.properties) { - if (feature.properties.buildingpart === "room") { - content = roomPopupTemplate(feature.properties, options, map); - } else if (feature.properties.buildingpart === "verticalpassage") { - content = verticalPassagePopupTemplate(feature.properties); - } - } else { // Assume that it is a printer - // TODO: Use different icons where appropriate - popupOptions.offset = icons.vendingHotDrinks.options.popupAnchor; - - if ('vending' in feature.properties) { - content = vendingPopupTemplate(feature.properties); - } else { - content = printerPopupTemplate(feature.properties); - } - } - - map.showInfo(content, e.latlng, popupOptions); - }); + map.showFeaturePopup( feature, e.latlng ); + } ); }, pointToLayer: function (feature, latlng) { if ('vending' in feature.properties) { @@ -871,7 +880,7 @@ SELECT * WHERE {\ return; } else if (feature.geometry.type === "Point") { - this.setView(L.GeoJSON.coordsToLatLng(feature.geometry.coordinates), 22); + this.setView(L.GeoJSON.coordsToLatLng(feature.geometry.coordinates), 20); if ("level" in feature.properties) { if (L.Util.isArray(feature.properties.level)) { @@ -896,7 +905,7 @@ SELECT * WHERE {\ throw "unable to handle " + feature.geometry.type; } }, - panByURI: function(uri) { + panByURI: function(uri,zoom,opts) { var feature = LS.getFeatureByURI(uri); if (feature === null) { @@ -907,19 +916,17 @@ SELECT * WHERE {\ throw "no location for " + uri; } + var target_loc; if (feature.geometry.type === "Polygon") { console.log(feature); - var center; if ("center" in feature.properties) { - center = feature.properties.center; + target_loc = feature.properties.center; } else { - center = feature.geometry.coordinates[0][0]; - center = [center[1], center[0]]; + target_loc = feature.geometry.coordinates[0][0]; + target_loc = [center[1], center[0]]; } - this.panTo(center); - if ("level" in feature.properties) { if (L.Util.isArray(feature.properties.level)) { this.setLevel(feature.properties.level[0]); @@ -927,12 +934,8 @@ SELECT * WHERE {\ this.setLevel(feature.properties.level); } } - - this.closePopup(); - - return; } else if (feature.geometry.type === "Point") { - this.panTo(L.GeoJSON.coordsToLatLng(feature.geometry.coordinates)); + target_loc = L.GeoJSON.coordsToLatLng(feature.geometry.coordinates); if ("level" in feature.properties) { if (L.Util.isArray(feature.properties.level)) { @@ -950,20 +953,19 @@ SELECT * WHERE {\ } } } - - this.closePopup(); - return; } else { throw "unable to handle " + feature.geometry.type; } - + this.closePopup(); + this.setView(target_loc,zoom,opts); }, showInfo: function(content, latlng, options) { var map = this; - options = options || {}; - options.maxWidth = map.getContainer().offsetWidth; + options.maxWidth = map.getContainer().offsetWidth*0.9; + options.minWidth = 320; + //options.maxHeight = map.getContainer().offsetHeight*0.8; map.closeInfo(); @@ -980,6 +982,31 @@ SELECT * WHERE {\ if (map._popup) { map.closePopup(map._popup); } + }, + showFeaturePopup: function(feature,latlng ) + { + var map = this; + var content; + var popupOptions = {}; + + // When the feature is clicked on + if ("buildingpart" in feature.properties) { + if (feature.properties.buildingpart === "room") { + content = roomPopupTemplate(feature.properties, options,map); + } else if (feature.properties.buildingpart === "verticalpassage") { + content = verticalPassagePopupTemplate(feature.properties); + } + } else { // Assume that it is a printer + // TODO: Use different icons where appropriate + popupOptions.offset = icons.vendingHotDrinks.options.popupAnchor; + + if ('vending' in feature.properties) { + content = vendingPopupTemplate(feature.properties); + } else { + content = printerPopupTemplate(feature.properties); + } + } + map.showInfo(content, latlng, popupOptions); } }); @@ -1006,8 +1033,8 @@ SELECT * WHERE {\ var popupTemplates = { sites: siteTemplate, buildings: buildingTemplate, - bicycleParking: bicycleParkingTemplate, - parking: parkingTemplate, + bicycleParking: bicycleParkingTemplate + //parking: parkingTemplate }; function roomPopupTemplate(properties, options, map) { @@ -1022,26 +1049,10 @@ SELECT * WHERE {\ return getTemplateWrapper(properties, function(content) { - var tabs = [ - { - id: 'contents', - name: 'Contents', - active: true - }, - { - id: 'features', - name: 'Features', - }, - { - id: 'bookings', - name: 'Bookings', - }, - { - id: 'pictures', - name: 'Pictures', - }]; - - tabs = createTabs(tabs, content); + var image_dom = imageTemplate( properties,options,map,close); + if( image_dom ) { content.appendChild( image_dom ); } + + return; if ('contents' in properties) { properties.contents.forEach(function(feature) { @@ -1088,59 +1099,6 @@ SELECT * WHERE {\ tabs.bookings); } - if ('images' in properties) { - properties.images.forEach(function(image) { - - var versions = image.versions; - var url, - imageWidth, - imageHeight; - - for (var i=0; i<versions.length; i++) { - var version = versions[i]; - url = version.url; - - imageWidth = version.width; - imageHeight = version.height; - - var widthBound; - var heightBound; - if ("popupWidth" in options && "popupHeight" in options) { - widthBound = options.popupWidth; - heightBound = options.popupHeight; - } else { - var mapContainer = map.getContainer(); - widthBound = mapContainer.offsetWidth; - heightBound = mapContainer.offsetHeight; - - widthBound *= 0.7; - heightBound *= 0.7; - } - - if (imageWidth < widthBound && - imageHeight < heightBound) { - break; // Use this image, as it is the first smaller - // than the screen width - } - } - - if (url !== null) { - // Link to the biggest image (versions is sorted by size on the server) - var imageLink = createBlankLink(versions[0].url, false, tabs.pictures); - - var image = document.createElement('img'); - image.setAttribute('src', url); - image.setAttribute('width', imageWidth); - image.setAttribute('height', imageHeight); - - imageLink.appendChild(image); - - //createBlankLink(properties.images[0].licence, "Licence", tabs.picture); - } else { - tabs.picture.textContent = "No Image Available"; - } - }); - } }); } @@ -1204,249 +1162,198 @@ SELECT * WHERE {\ }); } - function buildingTemplate(properties, options, map, close) { - var indoor = options.indoor; - - return getTemplateWrapper(properties, function(content) { - - var buildingTabs = [ - { - id: 'picture', - name: 'Pictures', - active: true - }, - { - id: 'energyUsage', - name: 'Energy Usage', - }]; - - if (indoor) { - buildingTabs.push({ - id: 'rooms', - name: 'Facilities', - }); - - buildingTabs.push({ - id: 'services', - name: 'Services', - }); - } - - var tabs = createTabs(buildingTabs, content); - - var imageWidth; - var imageHeight; - - if (properties.images.length !== 0) { - - var versions = properties.images[0].versions; - var url; - - var widthBound; - var heightBound; - if ("popupWidth" in options && "popupHeight" in options) { - widthBound = options.popupWidth; - heightBound = options.popupHeight; - } else { - var mapContainer = map.getContainer(); - widthBound = mapContainer.offsetWidth; - heightBound = mapContainer.offsetHeight; - - widthBound *= 0.7; - heightBound *= 0.7; - } - - for (var i=0; i<versions.length; i++) { - var version = versions[i]; - url = version.url; - - imageWidth = version.width; - imageHeight = version.height; + function imageTemplate(properties, options, map, close ) + { + if (properties.images.length == 0) { return false; } - if (imageWidth < widthBound && - imageHeight < heightBound) { - break; // Use this image, as it is the first smaller - // than the screen width - } - } + var imageWidth; + var imageHeight; - if (url !== null) { - // Link to the biggest image (versions is sorted by size on the server) - var imageLink = createBlankLink(versions[0].url, false, tabs.picture); + var versions = properties.images[0].versions; + var url; - tabs.picture.style.minWidth = imageWidth + "px"; - tabs.picture.style.minHeight = imageHeight + "px"; + var widthBound; + var heightBound; + if ("popupWidth" in options && "popupHeight" in options) { + widthBound = options.popupWidth; + heightBound = options.popupHeight; + } else { + var mapContainer = map.getContainer(); + widthBound = mapContainer.offsetWidth; + heightBound = mapContainer.offsetHeight; - var image = document.createElement('img'); - image.setAttribute('src', url); - image.setAttribute('width', imageWidth); - image.setAttribute('height', imageHeight); + widthBound *= 0.7; + heightBound *= 0.7; + } - imageLink.appendChild(image); + for (var i=0; i<versions.length; i++) { + var version = versions[i]; + url = version.url; - //createBlankLink(properties.images[0].licence, "Licence", tabs.picture); - } else { - tabs.picture.textContent = "No Image Available"; - } - } else { + imageWidth = version.width; + imageHeight = version.height; + if (imageWidth < widthBound && + imageHeight < heightBound) { + break; // Use this image, as it is the first smaller + // than the screen width } + } - var energyIFrame = document.createElement('iframe'); - energyIFrame.setAttribute('src', 'http://data.southampton.ac.uk/time-series?action=fetch&series=elec/b' + properties.loc_ref + '/ekw&type=average&format=graph&resolution=3600&startTime=1375009698000.0'); - energyIFrame.setAttribute('frameBorder', '0'); - energyIFrame.setAttribute('style', 'width: 100%; height 100%;'); - - tabs.energyUsage.style.minWidth = imageWidth + "px"; - tabs.energyUsage.style.minHeight = imageHeight + "px"; - tabs.energyUsage.appendChild(energyIFrame); - - createBlankLink('http://data.southampton.ac.uk/time-series?action=fetch&series=elec/b' + properties.loc_ref + '/ekw&type=average&format=graph&resolution=3600&startTime=0', 'Graph for all time', tabs.energyUsage); - - // Rooms - if (indoor) { - - tabs.rooms.style.minHeight = imageHeight + "px"; - tabs.rooms.style.maxHeight = imageHeight + "px"; - - tabs.rooms.style.overflow = 'auto'; - - for (var level in properties.rooms) { - var rooms = properties.rooms[level]; - - // Heading - - var panelTitle = L.DomUtil.create('h4', '', tabs.rooms); - panelTitle.textContent = "Level " + level; - - // Content - - var contentPanel = L.DomUtil.create('div', '', tabs.rooms); - - rooms.forEach(function(uri) { - var room = LS.getFeatureByURI(uri); - - if (room === null) { - console.err("Unable to find room " + uri); - return; - } - - var teachingAndBookable = ""; - - if (room.properties.teaching) { - teachingAndBookable += " (T) "; - } - - if (room.properties.teaching) { - teachingAndBookable += " (B)"; - } - - var roomProps = document.createTextNode(teachingAndBookable); + if (url == null) { return false; } - var description = room.properties.ref; - if ("name" in room.properties) { - description += ": " + room.properties.name; - } + var content = document.createElement( "div" ); - if ("center" in room.properties) { - var roomLink = createLink('#', false, tabs.rooms); + var image = document.createElement('img'); + image.setAttribute('src', url); + image.setAttribute('width', imageWidth); + image.setAttribute('height', imageHeight); + image.style.margin = 'auto'; + image.style.display = 'block'; + content.appendChild(image); - roomLink.onclick = function() { - close(); - map.showByURI(uri); - }; + // Link to the biggest image (versions is sorted by size on the server) + var imageLink = createBlankLink(versions[0].url, false, content); + imageLink.style.textAlign = 'right'; + imageLink.style.display = 'block'; + imageLink.style.width = imageWidth+"px"; + imageLink.style.margin = 'auto'; + imageLink.textContent="View fullsize photo"; - roomLink.textContent = description; - } else { - var roomText = document.createTextNode(description); + //createBlankLink(properties.images[0].licence, "Licence", content); + return content; + } - tabs.rooms.appendChild(roomText); - } + function addRoomsToFloors( floors, properties,options,map,close ) + { + for (var level in properties.rooms) { + var rooms = properties.rooms[level]; - tabs.rooms.appendChild(roomProps); + rooms.forEach(function(uri) { + var room = LS.getFeatureByURI(uri); - var moreInfo = createBlankLink(uri, "(More Information)", tabs.rooms); - moreInfo.style.cssFloat = moreInfo.style.styleFloat = "right"; + var info = { "label":"???", "uri":uri, "geo":false }; - tabs.rooms.appendChild(document.createElement('br')); - }); + if (room === null) { + console.err("Unable to find room " + uri); + return; } - tabs.services.style.minHeight = imageHeight + "px"; - tabs.services.style.maxHeight = imageHeight + "px"; + info.label = room.properties.ref; + if ("name" in room.properties) { + info.label += ": " + room.properties.name; + } - tabs.services.style.overflow = 'auto'; + if ("center" in room.properties) { + info.geo = true; + } - if ("services" in properties) { - if ("vendingMachines" in properties.services) { - title = L.DomUtil.create('h4', '', tabs.services); - title.textContent = "Vending Machines"; + if( !( level in floors ) ) { floors[level] = {}; } + floors[level][uri] = info; + }); + } + } - properties.services.vendingMachines.forEach(function(machine) { - var feature = LS.getFeatureByURI(machine); + function addVendingMachinesToFloors( floors, properties,options,map,close ) + { + if (!("services" in properties)) { return; } + if (!("vendingMachines" in properties.services)) { return; } + var level = "Unknown"; - if (feature === null) { - console.error("no feature for " + machine); - return; - } + properties.services.vendingMachines.forEach(function(machine) { + var feature = LS.getFeatureByURI(machine); - if ("geometry" in feature) { - var machineLink = createLink('#', false, tabs.services); + if (feature === null) { + console.error("no feature for " + machine); + return; + } - machineLink.onclick = function() { - close(); - map.showByURI(machine); - }; + var info = { "label":feature.properties.label, "uri":feature.properties.uri, "geo":false }; + if ("geometry" in feature) { info.geo = true; } - machineLink.textContent = feature.properties.label; - } else { - var note = document.createTextNode(feature.properties.label); + if( !( level in floors ) ) { floors[level] = {}; } + floors[level][feature.properties.uri] = info; + }); + } - tabs.services.appendChild(note); - } + function addMFDsToFloors( floors, properties,options,map,close ) + { + if (!("services" in properties)) { return; } + if (!("mfds" in properties.services)) { return; } + var level = "Unknown"; - var moreInfo = createBlankLink(machine, "(More Information)", tabs.services); - moreInfo.style.cssFloat = moreInfo.style.styleFloat = "right"; + properties.services.mfds.forEach(function(machine) { + var feature = LS.getFeatureByURI(machine); - tabs.services.appendChild(document.createElement('br')); - }); - } + if (feature === null) { + console.error("no feature for " + machine); + return; + } - if ("mfds" in properties.services) { - var title = L.DomUtil.create('h4', '', tabs.services); - title.textContent = "Multi-Function Devices"; + var info = { "label":feature.properties.label, "uri":feature.properties.uri, "geo":false }; + if ("geometry" in feature) { info.geo = true; } - properties.services.mfds.forEach(function(mfd) { - var feature = LS.getFeatureByURI(mfd); + if( !( level in floors ) ) { floors[level] = {}; } + floors[level][feature.properties.uri] = info; + }); + } - if (feature === null) { - console.error("no feature for " + mfd); - return; - } + function renderThingSet( set, map, close ) + { + var content_ids = Object.keys( set ); + var content = document.createElement( 'div' ); + content_ids.forEach(function(thing_id) { + var info = set[thing_id]; + var div = document.createElement( 'div' ); + var html = "<a title='click for more information' href='"+info.uri+"'>"+info.label+"</a>"; + div.innerHTML = html; + if( info.geo ) { + div.appendChild( document.createTextNode( ' ' ) ); + var locate_link = createLink('#', false, div); + + locate_link.onclick = function() { + var feature = LS.getFeatureByURI(info.uri); + close(); + map.panByURI(info.uri,20,{ 'animate':true }); + if( featureHasPopup(feature) ) { + map.showFeaturePopup( feature, feature.properties.center ); + } + }; - if ("geometry" in feature) { - var mfdLink = createLink('#', false, tabs.services); + locate_link.innerHTML = ' <span title="Show this on map" class="glyphicon glyphicon-screenshot"></span>'; + } - mfdLink.onclick = function() { - close(); - map.showByURI(mfd); - }; + content.appendChild( div ); + }); + return content; + } - mfdLink.textContent = feature.properties.label; - } else { - var note = document.createTextNode(feature.properties.label); + function buildingTemplate(properties, options, map, close) { + var indoor = options.indoor; - tabs.services.appendChild(note); - } + return getTemplateWrapper(properties, function(content) { - var moreInfo = createBlankLink(mfd, "(More Information)", tabs.services); - moreInfo.style.cssFloat = moreInfo.style.styleFloat = "right"; + var image_dom = imageTemplate( properties,options,map,close); + if( image_dom ) { content.appendChild( image_dom ); } - tabs.services.appendChild(document.createElement('br')); - }); - } - } + var floors = {}; + // Rooms + if (indoor) { + addRoomsToFloors( floors,properties,options,map,close ); + addVendingMachinesToFloors( floors,properties,options,map,close ); + addMFDsToFloors( floors,properties,options,map,close ); } + //content.appendChild( document.createTextNode( JSON.stringify(floors))); + + var floor_ids = Object.keys( floors ); + floor_ids.sort(); + + floor_ids.forEach(function(floor_id) { + var h4 = document.createElement( "h4" ); + content.appendChild( h4 ); + h4.textContent = "Floor "+floor_id; + content.appendChild( renderThingSet(floors[floor_id],map,close) ); + }); }); } @@ -1582,7 +1489,7 @@ SELECT * WHERE {\ link.setAttribute('href', properties.uri); link.setAttribute('target', '_blank'); link.className = 'ls-popup-uri'; - link.textContent = "(More Information)"; + link.textContent = "(Full Information)"; div.appendChild(link); } @@ -1594,16 +1501,24 @@ SELECT * WHERE {\ var titleText = ""; if ('loc_ref' in properties) { - titleText += properties.loc_ref + ' '; + var span = document.createElement( "span" ); + span.classList.add("ls-popup-title-ref"); + title.appendChild( span ); + span.textContent = properties.loc_ref; + title.appendChild( document.createTextNode( " " ) ); } if ('name' in properties) { - titleText += properties.name; + var span = document.createElement( "span" ); + span.classList.add("ls-popup-title-name"); + span.textContent = properties.name; + title.appendChild( span ); } - title.textContent = titleText; - - contentFunction(div); + var div_inner = document.createElement("div"); + div_inner.classList.add("ls-popup-content"); + contentFunction(div_inner); + div.appendChild( div_inner ); return div; } |