<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script data-require="jquery@*" data-semver="2.1.3" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<link data-require="bootstrap-css@3.1.*" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
<link data-require="bootstrap@*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<script data-require="bootstrap@*" data-semver="3.3.1" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ol3/3.4.0/ol.js"></script>
<!-- <script src="http://openlayers.org/en/v3.1.0/build/ol-debug.js"></script> -->
<link rel="stylesheet" href="http://openlayers.org/en/v3.4.0/css/ol.css" />
<script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.11/angular.js" data-semver="1.3.11"></script>
<script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.11/angular-sanitize.js" data-semver="1.3.11"></script>
<script data-require="ui-bootstrap@*" data-semver="0.12.0" src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js"></script>
<script src="app.js"></script>
<script src="highlightFilter.js"></script>
<script src="multipleFilter.js"></script>
<script src="mapService.js"></script>
<script src="MainController.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="//cdn.jsdelivr.net/angular-material-icons/0.3.0/angular-material-icons.min.js"></script>
<link href="http://fonts.googleapis.com/css?family=Open+Sans:400,600" rel="stylesheet" type="text/css" />
</head>
<body ng-controller="mainController as mc">
<div id="map"></div>
<div class="row-fluid">
<tabset class="tabset">
<div>
<a class="pull-right vcenter" ng-show="mc.search.length>0" ng-click="mc.cancelSearch()">Cancel Search</a>
</div>
<tab heading="Search" active="mc.staticTabs.search">
<div class="search-tab">
<div class="input-group">
<span class="input-group-addon">
<ng-md-icon icon="search" style="fill: #000;" size="18"></ng-md-icon>
</span>
<input type="text" class="form-control" ng-model="mc.search" ng-model-options="{ debounce: 1000 }" aria-describedby="inputGroupSuccess1Status" />
<div class="input-group-addon">
<span ng-show="mc.features.length>0">
<span>{{filtered.length}}</span>
Result/s</span>
</div>
</div>
<div class="list" ng-show="filtered.length>0">
<ul>
<li ng-repeat="f in filtered = (mc.features | multiple: mc.search)" class="feature-result" ng-click="mc.selectFeature(f.name);">
<div>
<span>{{f.name}}</span>
</div>
</li>
</ul>
</div>
</div>
</tab>
<tab heading="Details" active="mc.staticTabs.details">
<div class="span4 offset4 details-tab">
<div ng-show="mc.feature">
<h2>
<span ng-bind-html="mc.feature.name | highlight:mc.search"></span>
</h2>
<p ng-bind-html="mc.feature.description | highlight:mc.search"></p>
</div>
<div ng-show="!mc.feature">
<h2>No Details available.</h2>
<p>Select a marker on the map to see the details.</p>
</div>
</div>
</tab>
</tabset>
</div>
<div style="display: none;">
<!-- Popup -->
<div id="popup"></div>
</div>
<!-- move to template -->
<!-- https://klarsys.github.io/angular-material-icons/ -->
<div id="svgmarker" ng-show="mc.features>0">
<ng-md-icon icon="place" style="fill: #7b98bc;" size="64"></ng-md-icon>
</div>
<!-- svg shadow filter definition -->
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
<filter id="blur" y="-2" height="64" x="-10" width="150">
<feoffset in="SourceAlpha" dx="0" dy="0.25" result="offset2"></feoffset>
<fegaussianblur in="offset2" stdDeviation="0.5" result="blur2"></fegaussianblur>
<femerge>
<femergenode in="blur2"></femergenode>
<femergenode in="SourceGraphic"></femergenode>
</femerge>
</filter>
</svg>
</body>
</html>
// Code goes here
/*----------------------------------------*/
/* map styles
*/
html, body, #map {
padding: 0;
margin: 0;
font-family: "Open Sans", Helvetica, Arial;
}
#map {
width: 100%;
height: 200px;
}
#map .popover {
width: 200px;
z-index: 9999999;
}
/* custom svg marker styles */
#map svg .icon {
cursor: pointer;
}
#map svg .icon.selected {
fill: #dd1c77;
}
/* custom zoom to extent control */
#map .ol-control, .ol-scale-line {
z-index: 9999999;
}
/*----------------------------------------*/
/* tabs
*/
/* remove bootstrap rounded tab corners */
.tabset .nav-tabs > li > a {
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
}
.tabset .details-tab .highlighted {
background: yellow;
/* background: #dd1c77;
color: white; */
}
.tabset .search-tab, .tabset .details-tab {
margin: 15px;
}
/* search tab */
.tabset .search-tab ul {
list-style-type: none;
padding: 0px;
}
.tabset .search-tab .input-group .input-group-addon {
padding-bottom: 4px;
}
.tabset .list {
margin-top: 2px;
max-height: 150px;
width: 100%;
overflow-y: auto;
background-color: #fff;
border: 1px solid #eee;
}
.tabset .feature-result {
padding: 10px;
cursor: pointer;
}
.tabset .feature-result:hover {
background-color: #dd1c77;
border: 1px solid #ddd;
color: #fff;
}
/* cancel search link */
.tabset .vcenter {
padding: 10px 15px;
cursor: pointer;
}
/**
* Main app module
*/
;angular
.module('app', [
'ngMdIcons',
'ui.bootstrap',
'ngSanitize'
]);
/*
Tb. Tb.
:$$b. $$$b.
:$$$$b. :$$$$b.
:$$$$$$b :$$$$$$b
$$$$$$$b $$$$$$$b
$$$$$$$$b :$$$$$$$b
:$$$$$$$$b---^$$$$$$$$b
:$$$$$$$$$b ""^Tb
$$$$$$$$$$b __...__`.
$$$$$$$$$$$b.g$$$$$$$$$pb
$$$$$$$$$$$$$$$$$$$$$$$$$b
$$$$$$$$$$$$$$$$$$$$$$$$$$b
:$$$$$$$$$$$$$$$$$$$$$$$$$$;
:$$$$$$$$$$$$$^T$$$$$$$$$$P;
:$$$$$$$$$$$$$b "^T$$$$P' :
:$$$$$$$$$$$$$$b._.g$$$$$p.db
:$$$$$$$$$$$$$$$$$$$$$$$$$$$$;
:$$$$$$$$"""^^T$$$$$$$$$$$$P^;
:$$$$$$$$ ""^^T$$$P^' ;
:$$$$$$$$ .' `" ;
$$$$$$$$; / :
$$$$$$$$; .----, :
$$$$$$$$; ," ;
$$$$$$$$$p. |
:$$$$$$$$$$$$p. :
:$$$$$$$$$$$$$$$p. .'
:$$$$$$$$$$$$$$$$$$p...___..-"
$$$$$$$$$$$$$$$$$$$$$$$$$; "To the Bat Mobile, Robin!"
.db. bug $$$$$$$$$$$$$$$$$$$$$$$$$$
d$$$$bp. $$$$$$$$$$$$$$$$$$$$$$$$$$;
d$$$$$$$$$$pp..__..gg$$$$$$$$$$$$$$$$$$$$$$$$$$$
d$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$p._ .gp.
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$p._.ggp._.d$$$$b
*/
(function() {
'use strict';
/**
* Highlight filter
*/
angular
.module('app')
.filter('highlight', [
'$sce',
filter
]);
/**
* Creates a filter that wraps each search term occurrence in a span element with the 'highlighted' css class
*
* @param {$sceProvider} $sce
* @returns {returnedFunction} highlight filter
*
* See [$sce]{@link https://docs.angularjs.org/api/ng/service/$sce}
* Credits [higlight filter]{@link http://stackoverflow.com/questions/15519713/highlighting-a-filtered-result-in-angularjs/27798600#27798600}
*/
function filter($sce) {
return highlight;
/**
* Highlight filter
* @param {String} inputText - filter expression
* @param {String} searchTerms - search
*/
function highlight(inputText, searchTerms) {
if (!searchTerms) return inputText;
// split search terms by space character
var terms = searchTerms.split(' ') || [searchTerms];
terms.forEach(function(item){
// avoid messing with HTML tags
// needs a clever regular expression that skips HTML tags matches altogether
if (inputText && inputText.indexOf("<")===-1)
inputText = inputText.replace(new RegExp('(' + item + ')', 'gi'),
'<span class="highlighted">$1</span>')
});
return $sce.trustAsHtml(inputText);
}
}
})();
(function() {
'use strict';
/**
* Multiple terms search filter
*/
angular
.module('app')
.filter('multiple', [
'$rootScope',
filter
]);
/**
* Creates a filter that takes into account multiple search terms
*
* @param {$rootScope} $rootScope
* @returns {Function} multiple filter
*
* Credits [multiple filter]{@link http://stackoverflow.com/questions/23504757/angular-js-filter-by-logical-and-using-multiple-terms}
*/
function filter($rootScope) {
return multiple;
/**
* Multiple filter
* @param {String} items - filter expression
* @param {String} searchTerms - search
*/
function multiple(items, searchTerms) {
// return all items if searchTerms is empty
if (!searchTerms) {
triggerHideFeatures([], $rootScope);
return items;
}
var terms = searchTerms.split(' '),
matchingItems = [],
passTest;
items.forEach(function(item){
passTest = true;
terms.forEach(function(term){
// we check the default KML properties
passTest = passTest && (
(item.name.toLowerCase().indexOf(term.toLowerCase()) > -1) ||
(item.description.toLowerCase().indexOf(term.toLowerCase()) > -1)
);
});
// Add item to return array only if passTest is true,
// all search terms were found in item
if (passTest) { matchingItems.push(item); }
});
triggerHideFeatures(matchingItems, $rootScope);
return matchingItems;
}
/**
* Notifies the application with the matching features
* @param {Array} matchingItems - filtered features
* @param {Object} $rootScope - $rootScope
*/
function triggerHideFeatures(matchingItems, $rootScope){
var featuresArray = matchingItems.map(function(feature){
return feature.name;
})
$rootScope.$broadcast("global.hide-features", featuresArray);
}
}
})();
(function() {
'use strict';
/**
* Map Service
*/
angular
.module('app')
.factory('mapService', service);
function service(){
// check openlayers is available on service instantiation
// this can be handled with Require later on
if (!ol) return {};
var map = {}, //convenience reference
defaults = {
zoom: 15,
startLocation: [0,40],
extractStylesKml: false,
popupOffset: [0,0],
featurePropertiesMap: ['name', 'description', 'address', 'phoneNumber', 'styleUrl'],
onFeatureSelected: function(feature) { console.log("feature selected", feature);}
},
zIndex = 9999,
popup,
selectedFeature,
myZoomToExtentControl;
// public API
var ms = {
map: map, // ol.Map
init: init,
getFeatures: getFeatures,
selectFeature: selectFeature,
hideFeatures: hideFeatures,
unselectFeature: unselectFeature
};
return ms;
///////////////////////////////////////////////////////////
// helper functions
function olMapFeatures() {
var featuresArray = map //ol.Map
.getLayers() //ol.Collection
.getArray()[1] //ol.layer.Vector
.getSource() //ol.source.KML
.getFeatures() //ol.Feature
return featuresArray;
}
function getFeatures() {
var f = [];
olMapFeatures()
.forEach(function(olFeature, i) {
var feature = {id: olFeature.getId()};
f.push(mapFeatureProperties(feature, olFeature));
});
return f;
}
function unselectFeature(zoom) {
var undefined;
selectedFeature = undefined;
$("#map path").each(function(index, item){
item.setAttribute("class", "icon");
});
if (zoom)
zoomToExtent();
}
function selectFeature(name, pan){
var feature;
if (!name) return;
var target = $("#map path[feature='" + escape(name) + "']")[0];
//search for feature
olMapFeatures()
.forEach(function(item, i) {
var f = item.get('name');
if (name==f)
feature = item;
});
selectedFeature = feature;
if (feature) {
unselectFeature();
target.setAttribute("class", "icon selected");
//put on top
$(target.parentNode.parentNode)
.parent().parent()
.css('z-index', ++zIndex);
}
//display feature details and pan
if (pan && feature) {
onFeatureSelected(feature);
panToFeature(feature, map.getView().getZoom());
var element = angular.element('#popup');
$(element).popover('destroy');
//show popup for feature or hide any previous one
if (feature) {
setTimeout(function(){
var coord = feature.getGeometry().getCoordinates();
var title = feature.get('name');
popup.setPosition(coord);
$(element).popover({
'title': title,
'placement': 'top',
'animation': false,
'html': true
//'content': feature.get('description')
});
$(element).popover('show');
}, 1000);
}
}
return feature;
}
function hideFeatures(features, search){
//hide any popups
var element = angular.element('#popup');
$(element).popover('destroy');
if (!features || features.length===0) {
if (search && search.length>0)
//search with no results: filters all
$("#map path.icon").hide();
else
//reset after having results
$("#map path.icon").show();
return;
}
features.forEach(function(item){
$("#map path[feature!='" + escape(item) + "'].icon").hide();
});
features.forEach(function(item){
$("#map path[feature='" + escape(item) + "'].icon").show();
});
}
function mapFeatureProperties(feature, olFeature) {
if (!olFeature) return feature;
if (!feature) feature = {};
defaults.featurePropertiesMap.forEach(function(key){
feature[key] = olFeature.get(key);
});
return feature;
}
function onFeatureSelected(olFeature) {
if (!olFeature) return;
var feature = mapFeatureProperties({}, olFeature);
if(defaults.onFeatureSelected)
defaults.onFeatureSelected(feature);
}
// Creates an overlays in the given coordinates
function createSVGOverlay(position, feature) {
if (defaults.extractStylesKml) return;
var elem = document.createElement('div');
var svg = angular.element('#svgmarker ng-md-icon').clone();
//change path attributes
var path = svg.find('path');
path.attr('class', 'icon');
path.attr('filter', 'url(#blur)');
path.attr('feature', escape(feature.get('name')) );
var filter = document.createElement('filter');
var fe = document.createElement('feGaussianBlur');
filter.setAttribute('id', 'blur');
fe.setAttribute('stdDeviation', 3);
filter.appendChild(fe);
svg.find('svg')[0].appendChild(filter);
elem.appendChild(svg[0]);
return new ol.Overlay({
offset: [-2, 12],
element: elem,
position: position,
positioning: 'bottom-center',
stopEvent: false,
});
}
function renderSVGFeatures(){
if (defaults.extractStylesKml) return;
//wait till directive renders svg element
setTimeout(function() {
olMapFeatures()
.forEach(function(item, i, arr){
var hidden = item.get('hidden');
if (!hidden) {
var coordinates = item.getGeometry().getCoordinates();
var overlay = createSVGOverlay(coordinates, item);
map.addOverlay(overlay);
}
});
}, 0);
}
function popupSetup() {
var element = angular.element('#popup');
// Add popup showing the position the user clicked
popup = new ol.Overlay({
element: element,
stopEvent: true,
offset: defaults.popupOffset
});
map.addOverlay(popup);
var displayPopup = function(evt){
var element = popup.getElement();
var coordinate = evt.coordinate;
var hdms = ol.coordinate.toStringHDMS(ol.proj.transform(
coordinate, 'EPSG:3857', 'EPSG:4326'));
$(element).popover('destroy');
popup.setPosition(coordinate);
// the keys are quoted to prevent renaming in ADVANCED mode.
$(element).popover({
'placement': 'top',
'animation': false,
'html': true,
'content': '<p>The location you clicked was:</p><code>' + hdms + '</code>'
});
$(element).popover('show');
}
// display popup on click
map.on('click', function(evt) {
if (defaults.extractStylesKml) {
// Regular rendered feature find on click coordinates
var feature = map.forEachFeatureAtPixel(evt.pixel,
function(feature, layer) {
return feature;
});
} else {
// SVG marker. Search at element attributes
if (!feature && evt.originalEvent.target && evt.originalEvent.target.nodeName == "path") {
var target = evt.originalEvent.target;
var featureId = unescape(target.getAttribute('feature'));
feature = selectFeature(featureId, false);
};
};
//trigger onFeatureSelected event
selectedFeature = feature;
onFeatureSelected(feature);
$(element).popover('destroy');
//show popup for feature or hide any previous one
if (feature) {
setTimeout(function(){
var coord = feature.getGeometry().getCoordinates();
popup.setPosition(coord);
var title = feature.get('name');
$(element).popover({
'title': title,
'placement': 'top',
'animation': false,
'html': true
//'content': feature.get('description')
});
$(element).popover('show');
}, 1000);
}
if (feature) {
panToFeature(feature, map.getView().getZoom());
}
});
}
function panToFeature(feature, zoom) {
var lonLat = feature.getGeometry().getCoordinates()
var olPixel = map.getPixelFromCoordinate(lonLat);
olPixel[1] -= 40;
lonLat = map.getCoordinateFromPixel(olPixel);
if (map.getView().getZoom() < zoom)
map.getView().setZoom(zoom);
var animation = ol.animation.pan({
duration: 1000,
easing: eval(ol.easing.inAndOut),
source: map.getView().getCenter()
});
// Add animation to the render pipeline
map.beforeRender(animation);
// Change center location
map.getView().setCenter(lonLat);
};
function init(config){
var config = angular.extend(defaults, config);
createMyZoomToExtentControl();
// map initialisation
map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.transform(config.startLocation, 'EPSG:4326', 'EPSG:3857'),
zoom: config.zoom
}),
controls: ol.control.defaults().extend([
new myZoomToExtentControl({tipLabel: "Fit to extent"}),
new ol.control.ScaleLine()
])
});
popupSetup();
loadKML();
zoomToExtent();
}
function createMyZoomToExtentControl(){
/**
* @constructor
* @extends {ol.control.Control}
* @param {Object} opt_options - Control options.
*/
myZoomToExtentControl = function (opt_options) {
var options = opt_options || {};
var button = document.createElement('button');
button.id = 'zoom-to-extent';
button.setAttribute("title","Zoom to Extent");
var span = document.createElement('span');
//span.setAttribute("class", "glyphicon glyphicon-record");
span.innerHTML = 'E';
button.appendChild(span);
var this_ = this;
var handler = function(e) {
e.preventDefault(); //cancel click event
zoomToExtent();
document.getElementById("zoom-to-extent").disabled = true;
setTimeout(function() {
document.getElementById("zoom-to-extent").disabled = false;
}, 1);
};
button.addEventListener('click', handler, true);
button.addEventListener('touchstart', handler, true);
var element = document.createElement('div');
element.className = 'zoom-to-extent ol-zoom-extent ol-unselectable ol-control';
element.appendChild(button);
ol.control.Control.call(this, {
element: element,
target: options.target
});
};
ol.inherits(myZoomToExtentControl, ol.control.ZoomToExtent);
}
function zoomToExtent() {
var bounds = ol.extent.createEmpty();
olMapFeatures()
.forEach(function(item, i, arr){
var ext = ol.extent.createEmpty();
ext = item.getGeometry().getExtent();
bounds = ol.extent.extend(bounds, ext);
});
if (bounds) {
// increase bounds using a tenth of the
// maximum distance between coordinates
var incX = Math.abs(bounds[2] - bounds[0]);
var incY = Math.abs(bounds[3] - bounds[1]);
var buffer = (incX>incY)? incX: incY;
var bounds10 = ol.extent.createEmpty();
ol.extent.buffer(bounds, buffer/5, bounds10);
var animation = ol.animation.pan({
easing: eval(ol.easing.inAndOut),
source: map.getView().getCenter()
});
map.beforeRender(animation);
map.getView().fitExtent(bounds10, map.getSize());
}
};
function loadKML(){
var kml = '<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://earth.google.com/kml/2.2"><Document><name><![CDATA[Coworking spaces]]></name><description><![CDATA[]]></description><Style id="style1"><IconStyle><Icon><href>http://geoklubb.se/foursquare-lists-kml-export/img/geoklubb-pin.png</href></Icon></IconStyle></Style><Placemark><name><![CDATA[Ziferblat]]></name><description><![CDATA[<a href="http://london.ziferblat.net">Venue URL</a><br />Phone: 07984 693440<br />]]></description><styleUrl>#style1</styleUrl><Point><coordinates>-0.078374147415161,51.526985282303,0</coordinates></Point></Placemark><Placemark><name><![CDATA[Campus London]]></name><description><![CDATA[<a href="http://campuslondon.com">Venue URL</a><br />]]></description><styleUrl>#style1</styleUrl><Point><coordinates>-0.085487365722656,51.522703131223,0</coordinates></Point></Placemark><Placemark><name><![CDATA[Rainmaking Loft]]></name><description><![CDATA[<a href="http://www.rainmakingloft.com">Venue URL</a><br />]]></description><styleUrl>#style1</styleUrl><Point><coordinates>-0.073642730712891,51.50764732314,0</coordinates></Point></Placemark><Placemark><name><![CDATA[TechHub]]></name><description><![CDATA[Phone: 020 7490 0764<br />]]></description><styleUrl>#style1</styleUrl><Point><coordinates>-0.087708234786987,51.525032831563,0</coordinates></Point></Placemark><Placemark><name><![CDATA[Innovation Warehouse London]]></name><description><![CDATA[<a href="http://innovationwarehouse.org">Venue URL</a><br />Phone: 020 7248 0199<br />]]></description><styleUrl>#style1</styleUrl><Point><coordinates>-0.10269641876221,51.518998061413,0</coordinates></Point></Placemark><Placemark><name><![CDATA[Hub Westminster]]></name><description><![CDATA[<a href="http://westminster.impacthub.net">Venue URL</a><br />Phone: 020 7148 6720<br />]]></description><styleUrl>#style1</styleUrl><Point><coordinates>-0.13124592579464,51.507792367419,0</coordinates></Point></Placemark></Document></kml>';
var kmlSource = new ol.source.KML({
projection: 'EPSG:3857',
text: kml,
//url: 'source.kml',
extractStyles: defaults.extractStylesKml
});
var vectorLayer = new ol.layer.Vector({
source: kmlSource,
style: kmlStyle
});
function kmlStyle(feature, resolution){
// use default styles if using kml icons
if (!defaults.extractStylesKml) return [];
return [new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({
color: 'rgba(123, 152, 188, 0)'
}),
stroke: new ol.style.Stroke({
color: 'rgba(123, 152, 188, 0)',
width: 1
})
})
})];
}
// Add vectory layer to map
map.addLayer(vectorLayer);
//render custom markers
renderSVGFeatures();
}
}
})();
(function() {
'use strict';
/**
* Main Controller
*/
angular
.module('app')
.controller('mainController', Controller);
Controller.$inject = [
'mapService',
'$timeout',
'$rootScope'
];
function Controller(mapService, $timeout, $rootScope) {
var vm = this;
// map initialisation
mapService.init({
extractStylesKml: false,
popupOffset: [-4,-43],
featurePropertiesMap: ['name', 'description'], //override default mapping
onFeatureSelected: onFeatureSelected //override default event handler
});
vm.staticTabs = { search: true, details: false };
vm.features = mapService.getFeatures();
vm.selectFeature = selectFeature;
vm.hideFeatures = hideFeatures;
vm.cancelSearch = cancelSearch;
///////////////////////////////////////////////////////////
// map to view interactions
/**
* Event handler triggered when a feature is selected
*
* @param {Object} feature - feature selected.
*
* Feature properties are defined by config.featurePropertiesMap.
*/
function onFeatureSelected(feature) {
console.log("feature selected", feature);
// safely run after digest cycle
// needed to handle list selection
$timeout(function(){
vm.feature = feature;
selectTab("details");
});
}
/**
* Activates tab
*
* @param {String} key - tab id
*/
function selectTab(key){
if (vm.staticTabs.hasOwnProperty(key))
vm.staticTabs[key] = true;
}
///////////////////////////////////////////////////////////
// view to map interactions
// subscribe to event
$rootScope.$on("global.hide-features", vm.hideFeatures);
/**
* Selects a single feature on the map
*
* @param {String} id - feature id
*/
function selectFeature(id){
mapService.selectFeature(id, true);
}
/**
* Hides features on the map
*
* @param {Event} event - event object
* @param {Array} features - feature ids that should be shown
*/
function hideFeatures(event, features){
mapService.hideFeatures(features, vm.search);
};
/**
* Cancels search and zoom to extent
*/
function cancelSearch(){
var undefined,
zoomToExtent = true;
selectTab("search");
vm.search = "";
vm.feature = undefined;
mapService.unselectFeature(zoomToExtent);
};
}
})();
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<name><![CDATA[Coworking spaces]]></name>
<description />
<Style id="style1">
<IconStyle>
<Icon>
<href>http://geoklubb.se/foursquare-lists-kml-export/img/geoklubb-pin.png</href>
</Icon>
</IconStyle>
</Style>
<Placemark>
<name><![CDATA[Ziferblat]]></name>
<description><![CDATA[<a href="http://london.ziferblat.net">Venue URL</a><br />Phone: 07984 693440<br />]]></description>
<styleUrl>#style1</styleUrl>
<Point>
<coordinates>-0.078374147415161,51.526985282303,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name><![CDATA[Campus London]]></name>
<description><![CDATA[<a href="http://campuslondon.com">Venue URL</a><br />]]></description>
<styleUrl>#style1</styleUrl>
<Point>
<coordinates>-0.085487365722656,51.522703131223,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name><![CDATA[Rainmaking Loft]]></name>
<description><![CDATA[<a href="http://www.rainmakingloft.com">Venue URL</a><br />]]></description>
<styleUrl>#style1</styleUrl>
<Point>
<coordinates>-0.073642730712891,51.50764732314,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name><![CDATA[TechHub]]></name>
<description><![CDATA[Phone: 020 7490 0764<br />]]></description>
<styleUrl>#style1</styleUrl>
<Point>
<coordinates>-0.087708234786987,51.525032831563,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name><![CDATA[Innovation Warehouse London]]></name>
<description><![CDATA[<a href="http://innovationwarehouse.org">Venue URL</a><br />Phone: 020 7248 0199<br />]]></description>
<styleUrl>#style1</styleUrl>
<Point>
<coordinates>-0.10269641876221,51.518998061413,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name><![CDATA[Hub Westminster]]></name>
<description><![CDATA[<a href="http://westminster.impacthub.net">Venue URL</a><br />Phone: 020 7148 6720<br />]]></description>
<styleUrl>#style1</styleUrl>
<Point>
<coordinates>-0.13124592579464,51.507792367419,0</coordinates>
</Point>
</Placemark>
</Document>
</kml>