/*
* Copyright (C) 2016 Atlas of Living Australia
* All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* Created by Temi on 6/09/2016.
*/
(function (angular) {
'use strict';
/**
* @memberof spApp
* @ngdoc service
* @name PopupService
* @description
* Map popup generation
*/
angular.module('popup-service', ['leaflet-directive', 'map-service', 'biocache-service'])
.factory("PopupService", ['$rootScope', '$compile', '$http', '$q', '$window', '$templateRequest', 'leafletData', 'MapService', 'BiocacheService', 'LayersService',
function ($rootScope, $compile, $http, $q, $window, $templateRequest, leafletData, mapService, biocacheService, LayersService) {
var addPopupFlag = true,
popup, loc, leafletMap;
var templatePromise = $templateRequest('/spApp/intersectPopupContent.htm');
var intersects = [],
layers = [],
ssLayers = [],
speciesLayers = [],
occurrences = [],
areaLayers = [],
occurrenceList;
var occurenceBBox = []; //bbox of a popup/occurence. Need to scope level, then won't change when zooming
var processedLayers = [0];
var _httpDescription = function (method, httpconfig) {
if (httpconfig === undefined) {
httpconfig = {};
}
httpconfig.service = 'PopupService';
httpconfig.method = method;
return httpconfig;
};
function addPopupToMap(latlng, map, templatePromise, intersects, occurrences) {
var leafletmap = $('.angular-leaflet-map');
var layerCount = layers.length + speciesLayers.length + areaLayers.length;
if (addPopupFlag) {
templatePromise.then(function (content) {
var popupScope = $rootScope.$new();
popupScope.processedLayers = processedLayers;
// TODO: build a better progress indicator
popupScope.intersects = intersects;
popupScope.olist = occurrences;
var html = $compile(content)(popupScope);
popup = L.popup({maxWidth: 500, maxHeight: 600, minWidth: 410, autoPanPadding: 10})
.setLatLng(latlng)
.setContent(html[0])
.openOn(map);
addPopupFlag = false
})
}
}
function OccurrenceList(speciesLayers) {
var self = this;
this.isFirstOccurrence = true;
this.layersWithResults = [];
this.occurrences = [];
this.pageSize = 1;
this.total = 0;
this.index = 0;
this.speciesLayers = undefined;
this.config = $SH;
this.zoomedToRecord = false;
this.viewRecordUrl = '';
this.listRecordsUrl = '';
this.getFirstOccurrence = function (layer) {
if (self.isFirstOccurrence) {
self.getOccurrence(0, layer);
self.isFirstOccurrence = false
}
};
this.getOccurrence = function (index, layer) {
//var q = this.getQueryParams(layer)
//Can not use 'getQueryParams' because bbox which decides 'layer' will be overwritten
var fq = ["(latitude:[" + occurenceBBox[0][0] + " TO " + occurenceBBox[1][0] + "] AND longitude:[" + occurenceBBox[0][1] + " TO " + occurenceBBox[1][1] + "])"];
if (layer.isSelectedFacetsOnly) {// add extra fq, e.g. search selected facade occurence in the layer
//q.fqs.push(decodeURIComponent(layer.sel))
fq.push(decodeURIComponent(layer.sel))
} else if (layer.isWithoutSelectedFacetsOnly) {
//q.fqs.push('-('+decodeURIComponent(layer.sel)+')');
fq.push('-(' + decodeURIComponent(layer.sel) + ')')
}
self.layer = layer;
biocacheService.searchForOccurrences(layer, fq, 1, index).then(function (data) {
if (data.occurrences && data.occurrences.length) {
addPopupToMap(loc, leafletMap, templatePromise, intersects, occurrenceList);
// empty array
data.occurrences[0].layername = layer.name;
self.occurrences.splice(0, self.occurrences.length);
self.occurrences.push.apply(self.occurrences, data.occurrences);
//data.occurrences[0].adhocGroup = self.isAdhocGroup();
//check if ticked or in bbox
self.tickOccurence();
self.viewRecord()
}
})
};
this.tickOccurence = function () {
this.isAdhocOrBBox()
}
this.isAdhocGroup = function () {
var layer = self.layer;
var id = self.occurrences[0].uuid;
if (layer.adhocGroup === undefined) {
layer.adhocGroup = {};
layer.adhocGroupSize = 0
}
return layer.adhocGroup[id] !== undefined && layer.adhocGroup[id]
};
this.isInBBox = function () {
var layer = self.layer;
var oc = self.occurrences[0];
var id = oc.uuid;
//check if current oc is in the bboxes
//var lat = self.occurrences[0].decimalLatitude;
//var lng = self.occurrences[0].decimalLongitude;
// var isIn = false;
/* for(var i in layer.adhocBBoxes){
var bbox = layer.adhocBBoxes[i];
if (lat >= bbox[0][0] && lat<=bbox[1][0] && lng >= bbox[0][1] && lng <= bbox[1][1]){
isIn = true;
}
}*/
if (layer.adhocBBoxes && layer.adhocBBoxes.length > 0) {
var orFqs = []
var iFq = '(id:' + id + ")";
for (var i in layer.adhocBBoxes) {
var occurenceBBox = layer.adhocBBoxes[i];
var bFq = "(latitude:[" + occurenceBBox[0][0] + " TO " + occurenceBBox[1][0] + "] AND longitude:[" + occurenceBBox[0][1] + " TO " + occurenceBBox[1][1] + "])";
// Append SEL in
if (occurenceBBox[2]) {
bFq = "(" + bFq + ' AND ' + occurenceBBox[2] + ")"
}
orFqs.push(bFq)
}
var bbq = "(" + orFqs.join(' OR ') + ")";
var fqs = [iFq, bbq];
return biocacheService.count(layer, fqs).then(function (count) {
if (count == 1) {
return $q.when(true);
} else {
return $q.when(false);
}
});
} else
return $q.when(false);
}
this.isAdhocOrBBox = function () {
var oc = self.occurrences[0];
var id = oc.uuid;
if (self.isAdhocGroup()) // it is MANUALLY checked
oc.adhocGroup = true;
else if (self.layer.adhocGroup[id] == false) // Manually unchecked,
oc.adhocGroup = false;
else {
self.isInBBox().then(function (result) {
oc.adhocGroup = result;
// if ( self.layer.adhocGroup[id] == undefined && result)
// return true;
// else if ( self.layer.adhocGroup[id] == undefined && !result)
// return false;
// else
// return false;
})
}
}
this.toggleAdhocGroup = function () {
var layer = self.layer;
var oc = self.occurrences[0];
var id = self.occurrences[0].uuid;
if (layer.adhocGroup === undefined) {
layer.adhocGroup = {};
layer.adhocGroupSize = 0
}
//this variable is linked with its Checkbox
//it may be set by bbox which related to the function 'add all to adhoc'
//Todo It will causes inaccurate layer.adhocGroupSize
var isChecked = oc.adhocGroup;
layer.adhocGroup[id] = isChecked;
//Caculate adhocGroupSize
this.countAdhocOccurences();
// if (layer.adhocGroup[id] !== undefined) layer.adhocGroup[id] = !layer.adhocGroup[id];
// else layer.adhocGroup[id] = true;
//
// if (layer.adhocGroup[id]) layer.adhocGroupSize++;
// else layer.adhocGroupSize--
};
this.getNextOccurrence = function () {
var nextIndex = self.index + 1;
if (nextIndex >= self.total) {
return
}
self.index += 1;
var query = this.getSearchLayerAndIndex();
this.getOccurrence(query.index, query.layer)
};
this.getPrevOccurrence = function () {
var nextIndex = self.index - 1;
if (nextIndex >= self.total || nextIndex < 0) {
return
}
self.index -= 1;
var query = this.getSearchLayerAndIndex();
this.getOccurrence(query.index, query.layer)
};
this.getSearchLayerAndIndex = function () {
var result = {layer: undefined, index: 0},
total = 0;
_.filter(self.layersWithResults, function (layer) {
return layer.isDisplayed
})
.forEach(function (layer) {
if (layer) {
if ((self.index < (total + layer.total) && (self.index >= total))) {
result.layer = layer;
result.index = self.index - total
}
total += layer.total
}
});
return result
};
this.showThisLayerOnly = function (targetlayer) {
_.each(self.layersWithResults, function (layer) {
if (layer.name == targetlayer.name)
layer.isDisplayed = true;
else
layer.isDisplayed = false;
})
//Reset to show oc over the layer, not selected facets
targetlayer.isSelectedFacetsOnly = false;
targetlayer.isWithoutSelectedFacetsOnly = false;
this.toggleDisplayLayer(targetlayer)
}
this.showSelOfLayer = function (targetlayer, isSel) {
_.each(self.layersWithResults, function (layer) {
if (layer.name == targetlayer.name)
layer.isDisplayed = true;
else
layer.isDisplayed = false;
})
if (isSel) {
if (targetlayer.isSelectedFacetsOnly) {
self.index = 0;
self.total = targetlayer.selCount
} else if (targetlayer.isWithoutSelectedFacetsOnly) {
self.index = 0;
self.total = targetlayer.withoutSelCount;
}
this.getOccurrence(0, targetlayer);
} else {
targetlayer.isSelectedFacetsOnly = false;
targetlayer.isWithoutSelectedFacetsOnly = false;
this.toggleDisplayLayer(targetlayer)
}
// this.toggleDisplayLayer(targetlayer)
}
this.toggleDisplayLayer = function (targetedlayer) {
var result = {layer: undefined, index: 0}
var futureLayerIdx = 0;
var selectedLayerIdx = _.findIndex(self.layersWithResults, function (layer) {
return layer.name == targetedlayer.name;
})
//if check in a layer
if (targetedlayer.isDisplayed) {
futureLayerIdx = selectedLayerIdx;
} else { //check out the layer
// index jumps to the first oc of next layer. Move to first layer if the selected is the last layer
var c = self.layersWithResults.length;
if (selectedLayerIdx == c - 1) { // last one - then move to the first item of first layer
futureLayerIdx = 0;
} else {
futureLayerIdx = selectedLayerIdx + 1;
}
}
result.layer = self.layersWithResults[futureLayerIdx];
//recalculate the GLOBAL idx and total count of selected layer for display
self.total = 0;
var displayedLayers = _.filter(self.layersWithResults, function (layer) {
return layer.isDisplayed
})
for (var i = 0; i < displayedLayers.length; i++) {
// find the current layer and caculate GLOBAL idx
if (result.layer.name == displayedLayers[i].name)
self.index = self.total + result.index;
self.total += displayedLayers[i].total
}
this.getOccurrence(result.index, result.layer);
}
this.toggleSelFacadeOnLayer = function (targetedLayer) {
targetedLayer.isWithoutSelectedFacetsOnly = false;
targetedLayer.isSelectedFacetsOnly = true;
//this.showThisLayerOnly(targetedLayer)
this.showSelOfLayer(targetedLayer, true);
}
this.toggleUnSelFacadeOnLayer = function (targetedLayer) {
targetedLayer.isWithoutSelectedFacetsOnly = true;
targetedLayer.isSelectedFacetsOnly = false;
//this.showThisLayerOnly(targetedLayer)
this.showSelOfLayer(targetedLayer, true);
}
this.toggleBBox = function () {
//Match the algorithm in getQueryParams and getLatLngFq
//New feautre: bind with Sel facade
var layer = self.layer;
if (layer.adhocBBoxes == undefined) layer.adhocBBoxes = [];
if (layer.adhocGroup == undefined) layer.adhocGroup = {};
var currentOB = occurenceBBox.slice();
if (layer.isSelectedFacetsOnly)
currentOB.push('(' + decodeURIComponent(layer.sel) + ')');
else if (layer.isWithoutSelectedFacetsOnly)
currentOB.push(decodeURIComponent("-(" + layer.sel + ")"))
else
currentOB.push('')
var idx = layer.adhocBBoxes.findIndex(function (box) {
return JSON.stringify(box) == JSON.stringify(currentOB)
})
if (idx == -1) {
layer.adhocBBoxes.push(currentOB);
this.adjustAdhoc().then(function () {
self.countAdhocOccurences();
//check if current oc is in the bbox
self.tickOccurence();
});
}
}
// get ids in adhoc group and occurencebbox
//occurenceBBox MUST EXIST
this.adjustAdhoc = function () {
var layer = self.layer;
var oids = Object.keys(layer.adhocGroup);
if (occurenceBBox && oids.length > 0) {
var fqs = []
var oFq = '(id:' + oids.join(' OR id:') + ")";
var bFq = "(latitude:[" + occurenceBBox[0][0] + " TO " + occurenceBBox[1][0] + "] AND longitude:[" + occurenceBBox[0][1] + " TO " + occurenceBBox[1][1] + "])";
fqs.push(oFq)
fqs.push(bFq);
//Be AWARE OF BLACKETS, MAY NOT WORK
if (layer.isSelectedFacetsOnly)
fqs.push("(" + decodeURIComponent(layer.sel) + ")");
else if (layer.isWithoutSelectedFacetsOnly)
fqs.push(decodeURIComponent("-(" + layer.sel + ")"))
var newq = {
q: fqs,
bs: layer.bs,
ws: layer.ws
}
return biocacheService.facetGeneral('id', newq, -1, 0).then(function (data) {
if (data !== undefined) {
var id_frs = _.find(data, function (d) {
return data.fieldName = 'id'
})
if (id_frs && id_frs.count > 0) {
var frs = id_frs.fieldResult;
if (frs) {
_.each(frs, function (idfacet) {
delete layer.adhocGroup[idfacet.label];
})
}
}
}
});
}
//returned finished promise
return $q.when('Done');
}
this.countAdhocOccurences = function () {
var layer = self.layer;
var fq = this.buildAdhocQuery()
if (fq.length > 0)
biocacheService.count(layer, fq).then(function (count) {
layer.adhocGroupSize = count;
});
else
layer.adhocGroupSize = 0;
}
//Todo can fq generation in one place?
this.buildAdhocQuery = function () {
var layer = self.layer;
if (layer.adhocBBoxes)
var bboxes = layer.adhocBBoxes.slice();
else {
var bboxes = layer.adhocBBoxes = [];
}
var fqs = []
// bbox and in adhoc should use OR
var bbox_inadhoc = []
bboxes.forEach(function (bbox) {
var bbq = "(latitude:[" + bbox[0][0] + " TO " + bbox[1][0] + "] AND longitude:[" + bbox[0][1] + " TO " + bbox[1][1] + "])";
// Append SEL in
if (bbox[2]) {
bbq = "(" + bbq + ' AND ' + bbox[2] + ")"
}
bbox_inadhoc.push(bbq);
})
//Selected adhoc group items
//Caculate adhocGroup 'True' as in; 'False' as out
var inAdhocs = _.filter(_.keys(layer.adhocGroup), function (key) {
return layer.adhocGroup[key]
});
var inFq = ''
if (inAdhocs.length > 0)
var inFq = 'id:' + inAdhocs.join(' OR id:');
if (inFq !== '')
bbox_inadhoc.push(inFq);
var bboxQ = ''
if (bbox_inadhoc.length > 1)
bboxQ = '(' + bbox_inadhoc.join(' OR ') + ")";
else if (bbox_inadhoc.length == 1)
bboxQ = bbox_inadhoc[0];
// //sync q to layer, which is used by spLegend or other place
layer.inAdhocQ = bboxQ;
//all bboxes with extra included id are concated into one query, which is bboxQ
if (bboxQ !== '') {
fqs.push(bboxQ);
//Out adhoc ONLY have meaning when query has some adhocs
//Otherwise it return all records - out adhoc number
//Out adhoc should be AND
var outAdhocs = _.reject(_.keys(layer.adhocGroup), function (key) {
return layer.adhocGroup[key]
});
if (outAdhocs.length > 0) {
var outFq = '-(id:' + outAdhocs.join(' OR id:') + ')';
fqs.push(outFq);
layer.inAdhocQ = bboxQ + ' AND ' + outFq;
}
}
layer.outAdhocQ = '-(' + layer.inAdhocQ + ')';
return fqs;
}
this.getQueryParams = function (layer) {
var q = {query: {}, fqs: undefined},
fqs;
q.query.bs = layer.bs;
q.query.ws = layer.ws;
q.query.q = layer.q;
q.fqs = [];
layer.fq && layer.fq.forEach(function (fq) {
if ((fq.indexOf(/latitude/) !== -1) || (fq.indexOf(/longitude/) !== -1)) {
q.fqs.push(fq)
}
});
fqs = self.getLatLngFq(loc, layer.size);
q.fqs.push.apply(q.fqs, fqs);
return q
};
this.getLatLngFq = function (latlng, dotradius) {
var fq = [];
dotradius = dotradius * 1 + 3;
var px = leafletMap.latLngToContainerPoint(latlng);
var ll1 = leafletMap.containerPointToLatLng(L.point(px.x + dotradius, px.y + dotradius));
var ll2 = leafletMap.containerPointToLatLng(L.point(px.x + dotradius, px.y - dotradius));
var ll3 = leafletMap.containerPointToLatLng(L.point(px.x - dotradius, px.y - dotradius));
var ll4 = leafletMap.containerPointToLatLng(L.point(px.x - dotradius, px.y + dotradius));
var maxLng = Math.max(ll1.lng, ll2.lng, ll3.lng, ll4.lng);
var maxLat = Math.max(ll1.lat, ll2.lat, ll3.lat, ll4.lat);
var lonSize = Math.abs(latlng.lng - maxLng);
var latSize = Math.abs(latlng.lat - maxLat);
fq.push("latitude:[" + (latlng.lat - latSize) + " TO " + (latlng.lat + latSize) + "]");
fq.push("longitude:[" + (latlng.lng - lonSize) + " TO " + (latlng.lng + lonSize) + "]");
return fq
};
this.listRecords = function () {
if (self.layer !== undefined) {
//var q = self.getQueryParams(self.layer);
var fq = self.getLatLngFq(loc, self.layer.size)
var url = biocacheService.constructSearchResultUrl(self.layer, fq, 10, 0, true).then(function (url) {
self.listRecordsUrl = url
})
}
};
this.viewRecord = function () {
if (self.occurrences && self.occurrences.length > 0) {
var url = self.layer.ws + "/occurrences/" + self.occurrences[0].uuid;
self.viewRecordUrl = url
}
};
this.zoomToRecord = function () {
self.zoomedToRecord = true;
var occ = self.occurrences[0];
var lattng = L.latLng(occ.decimalLatitude, occ.decimalLongitude);
mapService.leafletScope.zoomToPoint(lattng, 10);
$('.leaflet-popup-close-button')[0].click()
};
this.devMode = function () {
if ($SH.enviroment === 'DEVELOPMENT')
return true;
else
return false;
}
this.showAdhocBBoxList = function () {
this.hideAhhocBBoxList = !this.hideAhhocBBoxList
}
this.removeAdhocBBox = function (idx) {
this.layer.adhocBBoxes.splice(idx, 1);
}
speciesLayers.forEach(function (layer) {
//var q = self.getQueryParams(layer);
var fq = self.getLatLngFq(loc, layer.size).slice()
biocacheService.count(layer, fq).then(function (count) {
if (count !== undefined && count > 0) {
self.layersWithResults.push(layer);
layer.total = count;
layer.isDisplayed = true;
self.total += count;
self.getFirstOccurrence(layer)
}
processedLayers[0] += 1;
self.listRecords();
self.viewRecord();
}).then(function () {
//Count occurences with facet selection
if (layer.sel) {
//layer.sel has been encoded in spLengend.js
var inFq = fq.slice();
inFq.push(decodeURIComponent(layer.sel));
biocacheService.count(layer, inFq).then(function (count) {
layer.selCount = count;
//layer.withoutSelCount = layer.total - count;
})
// sel ends
var outFq = fq.slice()
outFq.push('-(' + decodeURIComponent(layer.sel) + ')')
biocacheService.count(layer, outFq).then(function (count) {
layer.withoutSelCount = count;
})
}
})
});
var self = this;
//Watch if sel on a layer is changed
$rootScope.$watch(function () {
if (self.layer)
return self.layer.sel;
else
return ''
}, function (newValues, oldValues) {
var layer = self.layer;
//var q = self.getQueryParams(layer);
//Count occurences with facet selection
if (layer && layer.sel) {
//layer.sel has been encoded in spLengend.js
var fq = ["(latitude:[" + occurenceBBox[0][0] + " TO " + occurenceBBox[1][0] + "] AND longitude:[" + occurenceBBox[0][1] + " TO " + occurenceBBox[1][1] + "])"];
//layer.sel has been encoded in spLengend.js
var inFq = fq.slice();
inFq.push(decodeURIComponent(layer.sel));
biocacheService.count(layer, inFq).then(function (count) {
layer.selCount = count;
//layer.withoutSelCount = layer.total - count;
})
// sel ends
var outFq = fq.slice()
outFq.push('-(' + decodeURIComponent(layer.sel) + ')')
biocacheService.count(layer, outFq).then(function (count) {
layer.withoutSelCount = count
})
}// sel ends
});
}
return {
/**
* Coordinate
* @typedef {Object} latlng
* @property {number} lat - latitude
* @property {number} lng - longitude
*/
/**
* Open a popup on the map with information about a coordinate.
*
* @memberof PopupService
* @param (latlng) latlng coordinate input coordinate as lat,lng
*
* @example:
* Input:
* - latlng
* {lat:latitude, lng:longitude}
* Output:
* [{
"studyId": 92,
"focalClade": "Acacia",
"treeFormat": "newick",
"studyName": "Miller, J. T., Murphy, D. J., Brown, G. K., Richardson, D. M. and González-Orozco, C. E. (2011), The evolution and phylogenetic placement of invasive Australian Acacia species. Diversity and Distributions, 17: 848–860. doi: 10.1111/j.1472-4642.2011.00780.x",
"year": 2011,
"authors": "Acacia – Miller et al 2012",
"doi": "http://onlinelibrary.wiley.com/doi/10.1111/j.1472-4642.2011.00780.x/full",
"numberOfLeaves": 510,
"numberOfInternalNodes": 509,
"treeId": null,
"notes": null,
"treeViewUrl": "http://phylolink.ala.org.au/phylo/getTree?studyId=92&treeId=null"
}]
*/
click: function (latlng) {
if (!latlng) {
return;
}
var self = this;
loc = latlng;
// reset flag
addPopupFlag = true;
processedLayers[0] = 0;
intersects.splice(0, intersects.length);
layers.splice(0, layers.length);
occurrences.splice(0, occurrences.length);
speciesLayers.splice(0, speciesLayers.length);
areaLayers.splice(0, areaLayers.length);
ssLayers.splice(0, ssLayers.length);
leafletData.getMap().then(function (map) {
leafletMap = map;
mapService.mappedLayers && mapService.mappedLayers.forEach(function (layer) {
if (layer.visible) {
switch (layer.layertype) {
case "contextual":
var f = LayersService.getLayer(layer.id);
if (!$SH.wmsIntersect || (f && f.type === 'a')) {
ssLayers.push(layer.id)
} else {
layers.push(layer)
}
break;
case "grid":
if ($SH.wmsIntersect) {
layers.push(layer);
} else {
ssLayers.push(layer.id);
}
break;
case "area":
if (layer.type === "envelope") {
var layerid = '' + layer.id;
var f = LayersService.getLayer(layerid);
if (!$SH.wmsIntersect || (f && f.type === 'a')) {
ssLayers.push(layerid)
} else {
layers.push(layer)
}
} else {
areaLayers.push(layer);
}
break;
case "species":
speciesLayers.push(layer);
break;
}
}
});
if (ssLayers.length) {
var promiseIntersect = self.getIntersects(ssLayers, latlng);
if (promiseIntersect) {
promiseIntersect.then(function (content) {
intersects.push.apply(intersects, content.data);
addPopupToMap(loc, leafletMap, templatePromise, intersects, occurrenceList);
processedLayers[0] += intersects.length;
})
}
}
if (layers.length) {
var promiseIntersect = self.getFeatureInfo(layers, latlng);
if (promiseIntersect) {
promiseIntersect.then(function (content) {
//parse plain text content
var result = self.parseGetFeatureInfo(content.data, layers);
intersects.push.apply(intersects, result);
addPopupToMap(loc, leafletMap, templatePromise, intersects, occurrenceList);
processedLayers[0] += intersects.length;
})
}
}
if (areaLayers.length) {
areaLayers.forEach(function (layer) {
self.getAreaIntersects(layer.pid, latlng).then(function (resp) {
if (resp.data.name) {
intersects.push({layername: $i18n(402, "Area"), value: resp.data.name});
addPopupToMap(loc, leafletMap, templatePromise, intersects, occurrenceList);
}
processedLayers[0] += 1
})
})
}
//Caculate bbox of the clicked occurence - scope level
if (speciesLayers[0]) {
var layer = speciesLayers[0]
var dotradius = layer.size * 1 + 3;
var px = leafletMap.latLngToContainerPoint(loc);
var ll = leafletMap.containerPointToLatLng(L.point(px.x + dotradius, px.y + dotradius));
var lonSize = Math.abs(loc.lng - ll.lng);
var latSize = Math.abs(loc.lat - ll.lat);
occurenceBBox = [[loc.lat - latSize, loc.lng - lonSize], [loc.lat + latSize, loc.lng + lonSize]]
}
occurrenceList = new OccurrenceList(speciesLayers);
});
},
/**
* Get layer values for a coordinate.
*
* TODO: Move to LayersService
*
* @memberOf PopupService
* @param {list} layers list of layer names or fieldIds
* @param {latlng} latlng coordinate to inspect as {lat:latitude, lng:longitude}
* @returns {HttpPromise}
*
* @example:
* Input:
* - layers
* ["cl22", "el899"]
* - latlng
* {lat:-22, lng:131}
* Output:
* [{
"field": "cl22",
"layername": "Australian States and Territories",
"pid": "67620",
"value": "Northern Territory"
},
{
"field": "el899",
"layername": "Species Richness",
"units": "frequency",
"value": 0.037037037
}]
*/
getIntersects: function (layers, latlng) {
if (typeof layers === "string") {
layers = [layers]
}
return layersService.intersectLayers(layers, latlng.lng, latlng.lat)
},
getFeatureInfo: function (layers, latlng) {
// TODO: support >1 WMS sources
var url = layers[0].leaflet.layerOptions.layers[0].url;
var layerNames = '';
for (var ly in layers) {
if (layerNames.length > 0) layerNames += ',';
layerNames += layers[ly].leaflet.layerOptions.layers[0].layerOptions.layers
}
var point = leafletMap.latLngToContainerPoint(latlng, leafletMap.getZoom());
var size = leafletMap.getSize();
var crs = leafletMap.options.crs;
var sw = crs.project(leafletMap.getBounds().getSouthWest());
var ne = crs.project(leafletMap.getBounds().getNorthEast());
var params = {
request: 'GetFeatureInfo',
srs: crs.code,
bbox: sw.x + ',' + sw.y + ',' + ne.x + ',' + ne.y,
height: size.y,
width: size.x,
layers: layerNames,
query_layers: layerNames,
feature_count: layers.length * 10,
info_format: 'text/plain',
x: point.x,
i: point.x,
y: point.y,
j: point.y
};
var split = url.split('?');
var urlBase = split[0] + "?";
var existingParams = '';
if (split.length > 1) {
existingParams = split[1].split('&');
}
for (var i in existingParams) {
if (existingParams[i].match(/^layers=.*/) == null) {
urlBase += '&' + existingParams[i];
}
}
url = urlBase.replace("/gwc/service", "") + L.Util.getParamString(params, urlBase, true);
return $http.get(url, _httpDescription('getFeatureInfo'))
},
/**
* Test if an area intersects with a coordinate
*
* TODO: Move to LayersService
*
* @memberOf PopupService
* @param {list} pid area id
* @param {latlng} latlng coordinate to inspect as {lat:latitude, lng:longitude}
* @returns {HttpPromise}
*
* @example
* Input:
* - pid
* 67620
* - latlng
* {lat:-22, lng:131}
* Output:
* {
"name_id": 0,
"pid": "67620",
"id": "Northern Territory",
"fieldname": "Australian States and Territories",
"featureType": "MULTIPOLYGON",
"area_km": 1395847.4575625565,
"description": "null",
"bbox": "POLYGON((128.999222 -26.002015,128.999222 -10.902499,137.996094 -10.902499,137.996094 -26.002015,128.999222 -26.002015))",
"fid": "cl22",
"wmsurl": "https://spatial.ala.org.au/geoserver/wms?service=WMS&version=1.1.0&request=GetMap&layers=ALA:Objects&format=image/png&viewparams=s:67620",
"name": "Northern Territory"
}
*/
getAreaIntersects: function (pid, latlng) {
var url = $SH.layersServiceUrl + "/object/intersect/" + pid + "/" + latlng.lat + "/" + latlng.lng;
return $http.get(url, _httpDescription('getAreaIntersects'))
},
parseGetFeatureInfo: function (plainText, layers) {
var result = [];
var blockString = "--------------------------------------------";
for (var ly in layers) {
var layerName = layers[ly].leaflet.layerOptions.layers[0].layerOptions.layers;
layerName = layerName.replace("ALA:", "");
var field = LayersService.getLayer(layers[ly].id + '');
var sname;
if (field) {
sname = field.sname;
}
var units = undefined;
//start of layer intersect values in response from geoserver is "http.*{{layerName}}':"
var start = plainText.indexOf(layerName + "':");
var value = '';
if (start > 0) {
var blockStart = plainText.indexOf(blockString, start);
var blockEnd = plainText.indexOf(blockString, blockStart + blockString.length);
var properties = plainText.substring(blockStart + blockString.length, blockEnd - 1).trim().split("\n")
if (sname) {
for (var i in properties) {
if (properties[i].toUpperCase().match('^' + sname.toUpperCase() + ' = .*') != null) {
value = properties[i].substring(properties[i].indexOf('=') + 2, properties[i].length).trim();
}
}
} else {
value = properties[0].substring(properties[0].indexOf('=') + 2, properties[0].length).trim();
if (isNaN(value)) {
// use value as-is
} else if (field) {
// filter out nodatavalues
units = field.layer.environmentalvalueunits;
if (Number(value) < Number(field.layer.environmentalvaluemin)) {
value = '';
}
} else {
// analysis layers have nodatavalue < 0
if (Number(value) < 0) {
value = ''
}
}
}
}
// no intersect with this layer
if (units) {
result.push({
layername: layers[ly].name,
value: value,
units: units
})
} else {
result.push({
layername: layers[ly].name,
value: value
})
}
}
return result;
}
}
}])
}(angular));