(function (angular) {
'use strict';
/**
* @memberof spApp
* @ngdoc directive
* @name spLegend
* @description
* Panel displaying selected map layer information and controls
*/
angular.module('sp-legend-directive', ['map-service', 'biocache-service', 'layers-service', 'popup-service'])
.directive('spLegend', ['$timeout', '$q', 'MapService', 'BiocacheService', 'LayersService', 'ColourService', '$http', 'LayoutService', 'PopupService', 'EventService',
function ($timeout, $q, MapService, BiocacheService, LayersService, ColourService, $http, LayoutService, PopupService, EventService) {
var _httpDescription = function (method, httpconfig) {
if (httpconfig === undefined) {
httpconfig = {};
}
httpconfig.service = 'spLegend';
httpconfig.method = method;
return httpconfig;
};
return {
scope: {},
templateUrl: '/spApp/legendContent.htm',
link: function (scope, element, attrs) {
scope.baseUrl = $SH.baseUrl; // for image icons
scope.facetFilter = '';
scope.fq = [];
scope.yearMin = 1800;
scope.yearMax = new Date().getFullYear();
scope.selected = MapService.selected;
scope.selectedWatch = [MapService.selected];
scope.workflowFilters = $SH.workflowFilters;
scope.sortType = 'count';
scope.sortReverse = true;
scope.getSelected = function () {
if (scope.selected && scope.selected.layer) {
return scope.selected.layer.id
} else {
return 0
}
};
scope.$watch('selected.layer.uid', function (oldValue, newValue) {
LayoutService.closeModeless('FacetEditorModalCtrl')
scope.setAreaLayers();
scope.updateFacet();
});
scope.showLegend = function () {
scope.selected.layer.hidelegend = false
};
scope.areaLayers = [];
scope.setAreaLayers = function () {
scope.areaLayers = [{pid: null, name: ''}].concat(MapService.areaLayers());
};
scope.updateContextualList = function (_layer) {
var selectedLayer = _layer || scope.selected.layer;
// Why those two lines added, it always sets the start page of pagination to 1,
//selectedLayer.contextualPage = 1;
//selectedLayer.contextualListCount = null;
if ( selectedLayer.contextualPage == undefined){
selectedLayer.contextualPage = 1;
selectedLayer.contextualListCount = null;
}
if (selectedLayer !== undefined && selectedLayer !== null) {
LayersService.getField(selectedLayer.id,
(selectedLayer.contextualPage - 1) * selectedLayer.contextualPageSize,
selectedLayer.contextualPageSize, selectedLayer.contextualFilter).then(function (data) {
selectedLayer.contextualList = data.data.objects;
selectedLayer.contextualListCount = selectedLayer.contextualList.length
for (var i in selectedLayer.contextualList) {
if (selectedLayer.contextualList.hasOwnProperty(i)) {
selectedLayer.contextualList[i].selected = (selectedLayer.contextualSelection[selectedLayer.contextualList[i].name] !== undefined)
}
}
})
}
};
scope.info = function (item) {
bootbox.alert($i18n(397, "Metadata url") + ': <a href="' + item.url + '">' + item.url + '</a>')
};
scope.contextualClearSelection = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
var key;
for (key in selectedLayer.contextualSelection) {
if (selectedLayer.contextualSelection.hasOwnProperty(key)) {
delete selectedLayer.contextualSelection[key]
}
}
for (var i in selectedLayer.contextualList) {
if (selectedLayer.contextualList.hasOwnProperty(i)) {
selectedLayer.contextualList[i].selected = false
}
}
}
for (var i = selectedLayer.leaflet.layerOptions.layers.length - 1; i > 0; i--) {
delete selectedLayer.leaflet.layerOptions.layers[i]
}
selectedLayer.leaflet.layerOptions.layers.splice(1, selectedLayer.leaflet.layerOptions.layers.length - 1)
selectedLayer.leaflet.layerOptions.layers[0].layerParams.opacity = scope.selected.layer.leaflet.layerOptions.layers[0].opacity / 100.0
$timeout(function () {
scope.updateWMS(selectedLayer)
}, 0)
};
scope.contextualClearHighlight = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
//remove highlight layer
selectedLayer.contextualHighlight = "";
MapService.setHighlightVisible(false);
}
};
scope.scatterplotCreateInOut = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
var inFq = selectedLayer.scatterplotFq;
var outFq = '-(' + selectedLayer.scatterplotFq + ')';
EventService.scatterplotCreateInOut(selectedLayer, inFq, outFq)
}
};
scope.adhocCreateInOut = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
EventService.adhocCreateInOut(selectedLayer, selectedLayer.inAdhocQ, selectedLayer.outAdhocQ)
}
};
scope.isCreateAreaDisabled = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
for (var key in selectedLayer.contextualSelection) {
if (selectedLayer.contextualSelection.hasOwnProperty(key)) {
var item = selectedLayer.contextualSelection[key];
if (item.selected) {
return false;
}
}
}
}
return true;
};
scope.contextualCreateArea = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
var ids = [];
var fqs = [];
var objects = [];
for (var key in selectedLayer.contextualSelection) {
if (selectedLayer.contextualSelection.hasOwnProperty(key)) {
var item = selectedLayer.contextualSelection[key];
if (item.selected) {
fqs.push(selectedLayer.id + ':"' + item.name + '"');
ids.push(item.pid);
}
}
}
scope.mapObjectsList(ids, fqs, objects, 0, selectedLayer.name);
}
};
scope.mapObjectsList = function (ids, fqs, objects, pos, name) {
if (pos === ids.length) {
//merge
var metadata = $i18n(398, "Collection of areas from layer") + ': ' + name + ';';
var mappingId = '';
var areaKm = 0;
var bbox;
for (var i = 0; i < objects.length; i++) {
metadata += ', ' + objects[i].name;
areaKm += objects[i].area_km;
var bTemp = undefined;
if (i > 0) bTemp = bbox;
bbox = objects[i].bbox;
if ((objects[i].bbox + '').match(/^POLYGON/g) != null) {
//convert POLYGON box to bounds
var split = objects[i].bbox.split(',');
var p1 = split[1].split(' ');
var p2 = split[3].split(' ');
if (bTemp == undefined) {
bbox = [[Math.min(p1[1], p2[1]), Math.min(p1[0], p2[0])], [Math.max(p1[1], p2[1]), Math.max(p1[0], p2[0])]]
} else {
bbox = [[Math.min(p1[1], p2[1], bTemp[0][0]), Math.min(p1[0], p2[0], bTemp[0][1])], [Math.max(p1[1], p2[1], bTemp[1][0]), Math.max(p1[0], p2[0], bTemp[1][1])]]
}
}
if (objects[i].bbox && objects[i].bbox.length === 4) {
if (bTemp == undefined) {
bbox = [[objects[i].bbox[1], objects[i].bbox[0]], [objects[i].bbox[3], objects[i].bbox[2]]]
} else {
bbox = [[Math.min(objects[i].bbox[1], bTemp[0][0]), Math.min(objects[i].bbox[0], bTemp[0][1])], [Math.max(objects[i].bbox[3], bTemp[1][0]), Math.max(objects[i].bbox[2], bTemp[1][1])]]
}
}
if (i > 0) mappingId += '~';
mappingId += ids[i]
}
var layer = {
name: pos + ' ' + $i18n(399, "areas from") + ' ' + name,
description: '',
wkt: '',
q: [fqs.join(" OR ")],
legend: '',
area_km: areaKm,
bbox: bbox,
metadata: metadata,
pid: mappingId,
layertype: 'area'
};
MapService.add(layer)
} else {
LayersService.getObject(ids[pos]).then(function (data) {
objects[pos] = data.data;
scope.mapObjectsList(ids, fqs, objects, pos + 1, name)
})
}
};
scope.zoom = function (item) {
MapService.leafletScope.zoom(item.bbox)
};
scope.contextualHighlight = function (name, pid, item) {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
if (item.selected) {
selectedLayer.contextualHighlight = name;
var found = false
for (var i = selectedLayer.leaflet.layerOptions.layers.length - 1; i > 0; i--) {
if (selectedLayer.leaflet.layerOptions.layers[i] && selectedLayer.leaflet.layerOptions.layers[i].pid === pid) {
found = true
}
}
if (!found) {
// hide top layer in layer group
selectedLayer.leaflet.layerOptions.layers[0].layerParams.opacity = 0
MapService.mapFromPid({pid: pid}, selectedLayer, 'ff0000')
}
} else {
for (var i = selectedLayer.leaflet.layerOptions.layers.length - 1; i > 0; i--) {
if (selectedLayer.leaflet.layerOptions.layers[i] && selectedLayer.leaflet.layerOptions.layers[i].pid === pid) {
delete selectedLayer.leaflet.layerOptions.layers[i]
selectedLayer.leaflet.layerOptions.layers.splice(i, 1)
}
}
if (selectedLayer.leaflet.layerOptions.layers.length > 1) {
// hide top layer in layer group
selectedLayer.leaflet.layerOptions.layers[0].layerParams.opacity = 0
} else {
// show top layer in layer group
selectedLayer.leaflet.layerOptions.layers[0].layerParams.opacity = scope.selected.layer.leaflet.layerOptions.layers[0].opacity / 100.0
}
MapService.reloadLayer(selectedLayer)
}
}
};
scope.contextualSelectionChange = function (item) {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
if (item.selected) {
selectedLayer.contextualSelection[item.name] = item
} else {
delete selectedLayer.contextualSelection[item.name]
}
}
};
scope.updateStyle = function () {
var currentLayer = scope.selected.layer;
var selectedStyle = currentLayer.style
//Raster style
if(selectedStyle == 'non-linear') selectedStyle = currentLayer.defaultStyle //e.g geomacs_gmean
if (selectedStyle == 'linear') selectedStyle = currentLayer.defaultStyle + '_linear'
//Vector sytle
if (selectedStyle == 'default') selectedStyle = currentLayer.defaultStyle //e.g cl1084
if (selectedStyle == 'outline') selectedStyle = 'outline'
if (selectedStyle == 'filled') selectedStyle = 'polygon'
currentLayer.leaflet.layerOptions.layers[0].layerParams.styles = selectedStyle
currentLayer.leaflet.layerOptions.layers[0].legendurl = currentLayer.leaflet.layerOptions.layers[0].legendurl.replace(/&style=[^&]*/, "&style=" + encodeURIComponent(selectedStyle));
$timeout(function () {
MapService.reloadLayer(currentLayer)
}, 0)
}
scope.contextualPageBack = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined && selectedLayer.contextualPage > 1) {
selectedLayer.contextualPage--;
scope.updateContextualList(selectedLayer)
}
};
scope.contextualPageForward = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer.contextualPage < selectedLayer.contextualMaxPage) {
selectedLayer.contextualPage++;
scope.updateContextualList(selectedLayer)
}
};
scope.clearContextualFilter = function () {
var selectedLayer = scope.selected.layer;
selectedLayer.contextualPage = 1;
if (selectedLayer !== undefined) {
selectedLayer.contextualFilter = ''
scope.updateContextualList(selectedLayer)
}
};
scope.externalWmsLegendVisible = function () {
var selected = scope.selected;
return selected.layer !== undefined &&
selected.layer.layertype === 'wms' &&
(selected.layer.hidelegend === undefined || !selected.layer.hidelegend)
};
scope.wmsLegendVisible = function () {
var selected = scope.selected;
return selected.layer !== undefined &&
(selected.layer.layertype === 'grid' || selected.layer.layertype === 'contextual' || selected.layer.layertype === 'gridAsContextual') &&
(selected.layer.hidelegend === undefined || !selected.layer.hidelegend)
};
scope.hideLegend = function () {
scope.selected.layer.hidelegend = true
};
scope.popupLegend = function () {
var selected = scope.selected;
L.control.window(map, {
modal: false,
title: selected.displayname,
content: '<img src="' + selected.layer.leaflet.layerOptions.layers[0].legendurl + '"/>'
}).show()
};
scope.setColor = function (color) {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
selectedLayer.color = color;
scope.updateWMS();
scope.scatterplotUpdate()
}
};
scope.setColorType = function (colorType) {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
selectedLayer.colorType = colorType;
scope.updateWMS();
scope.scatterplotUpdate()
}
};
scope.facetNewLayer = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
EventService.facetNewLayer(selectedLayer, scope.getFacetFqs(true, selectedLayer))
}
};
scope.getFacetFqs = function (includeActiveFacet, layer) {
var selectedLayer = layer || scope.selected.layer;
var newFqs = BiocacheService.facetsToFq(selectedLayer.facets, false)
var fq = BiocacheService.facetToFq(selectedLayer.activeFacet, true);
if (fq.fq) {
var idx = newFqs.indexOf(fq.fq)
if (includeActiveFacet && selectedLayer.activeFacet) {
if (idx < 0) {
newFqs.push(fq.fq)
}
} else {
// remove active facet
if (idx >= 0) {
newFqs.splice(idx, 1)
}
}
}
return newFqs;
}
scope.facetNewLayerOut = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
EventService.facetNewLayerOut(selectedLayer, scope.getFacetFqs(true, selectedLayer))
}
};
scope.facetsSelected = function () {
var selectedLayer = scope.selected.layer;
return selectedLayer !== undefined &&
selectedLayer.facetSelectionCount !== undefined &&
selectedLayer.facetSelectionCount > 0;
};
scope.updateSelection = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined) {
var sum = 0;
for (var i = 0; selectedLayer.activeFacet &&
selectedLayer.activeFacet.data &&
i < selectedLayer.activeFacet.data.length; i++) {
sum += selectedLayer.activeFacet.data[i].count
}
selectedLayer.facetSelectionCount = sum
scope.updateWMS();
}
};
scope.getFacetItemCount = function (item, layer, fq) {
return BiocacheService.count(layer, fq).then(function (count) {
item.count = count;
return item;
});
};
scope.asyncFacetCounts = function (queue, results, selectedLayer) {
selectedLayer.facetProgress = (results.length + 1) + " of " + (queue.length + results.length);
var facetCount = queue.pop();
return scope.getFacetItemCount(facetCount[0], facetCount[1], facetCount[2]).then(
function (data) {
results.push(data);
if (queue.length > 0) {
return scope.asyncFacetCounts(queue, results, selectedLayer);
} else {
return $q.when();
}
}
);
};
scope.speciesListToFacetList = function (data, newLayer) {
var def = $q.defer();
var list = [];
var promises = [];
var queue = [];
var ci = 0;
for (var key in data) {
var item = data[key];
item.count = 0; // TODO: check if this needs to be an object
var c = ColourService.getColour(ci);
var listItem = {
name: key, displayname: key, count: item.count, min: item.min, max: item.max, isRangeDataType: item.isRangeDataType,
fq: item.fq, red: c.red, green: c.green, blue: c.blue
};
//populate count
queue.push([listItem, newLayer, item.fq]);
ci = ci + 1;
}
// async for queue
var results = [];
var selectedLayer = scope.selected.layer;
selectedLayer.facetProgress = results.length + " of " + queue.length;
promises.push(scope.asyncFacetCounts(queue, results, selectedLayer));
$q.all(promises).then(function (result) {
result = results;
result.sort(function (a, b) {
if (a.isRangeDataType) {
return a.min - b.min
} else {
return b.count - a.count
}
});
def.resolve(result);
//sort and aggregate the rest of layers after the top x number
var maxMappedFacets = $SH.numberOfIntervalsForRangeData || 5;
if (result.length < maxMappedFacets) {
for (var i in result) {
var c = result[i].isRangeDataType? ColourService.getLinearColour(i) : ColourService.getColour(i);
scope.createSubLayer(c, selectedLayer, result[i].fq)
result[i].red = c.red;
result[i].green = c.green;
result[i].blue = c.blue;
}
} else {
for (var i = 0; i < maxMappedFacets; i++) {
var c = result[i].isRangeDataType? ColourService.getLinearColour(i) : ColourService.getColour(i);
scope.createSubLayer(c, selectedLayer, result[i].fq)
result[i].red = c.red;
result[i].green = c.green;
result[i].blue = c.blue;
}
//agregate the rest
var aggreatedfq = [];
var c = result[0] && result[0].isRangeDataType? ColourService.getLinearColour(maxMappedFacets) : ColourService.getColour(i);
for (var i = maxMappedFacets; i < result.length; i++) {
aggreatedfq.push(result[i].fq);
result[i].red = c.red;
result[i].green = c.green;
result[i].blue = c.blue;
}
if (aggreatedfq.length > 0)
scope.createSubLayer(c, selectedLayer, "(" + aggreatedfq.join(' OR ') + ")")
}
selectedLayer.facetProgress = undefined;
});
return def.promise;
};
scope.createSubLayer = function (colour, layer, fq) {
return BiocacheService.newLayerAddFq(layer, fq, layer.name).then(function (subLayer) {
if (subLayer == null) {
return $q.when(null)
}
subLayer.red = colour.red;
subLayer.green = colour.green;
subLayer.blue = colour.blue;
MapService.add(subLayer, layer);
});
};
scope.createSubLayerScatterplotEnvelope = function (parentLayer, layer1, min1, max1, layer2, min2, max2) {
var sld_body = decodeURIComponent(
'%3CStyledLayerDescriptor%20version%3D%221.0.0%22%20xmlns%3D%22http%3A%2F%2Fhttp://www.opengis.net%2Fsld%22%3E' +
'%3CNamedLayer%3E%3CName%3EALA%3A' + LayersService.getLayer(layer1).layer.name + '%3C%2FName%3E%3CUserStyle%3E%3CFeatureTypeStyle%3E%3CRule%3E%3CRasterSymbolizer%3E' +
'%3CColorMap%20type=%22intervals%22%20extended=%22true%22%3E' +
'%3CColorMapEntry%20color%3D%220x00FF00%22%20opacity%3D%220%22%20quantity%3D%22' + min1 + '%22%2F%3E' +
'%3CColorMapEntry%20color%3D%220x00FF00%22%20opacity%3D%221%22%20quantity%3D%22' + max1 + '%22%2F%3E' +
'%3C%2FColorMap%3E%3C%2FRasterSymbolizer%3E%3C%2FRule%3E%3C%2FFeatureTypeStyle%3E%3C%2FUserStyle%3E%3C%2FNamedLayer%3E' +
'%3CNamedLayer%3E%3CName%3EALA%3A' + LayersService.getLayer(layer2).layer.name + '%3C%2FName%3E%3CUserStyle%3E%3CFeatureTypeStyle%3E%3CRule%3E%3CRasterSymbolizer%3E' +
'%3CColorMap%20type=%22intervals%22%20extended=%22true%22%3E' +
'%3CColorMapEntry%20color%3D%220x00FF00%22%20opacity%3D%220%22%20quantity%3D%22' + min2 + '%22%2F%3E' +
'%3CColorMapEntry%20color%3D%220x00FF00%22%20opacity%3D%221%22%20quantity%3D%22' + max2 + '%22%2F%3E' +
'%3C%2FColorMap%3E%3C%2FRasterSymbolizer%3E%3C%2FRule%3E' +
'%3CVendorOption%20name%3D%22composite%22%3Edestination-in%3C%2FVendorOption%3E' +
'%3C%2FFeatureTypeStyle%3E%3C%2FUserStyle%3E%3C%2FNamedLayer%3E' +
'%3C%2FStyledLayerDescriptor%3E')
var subLayer = {
layertype: 'scatterplotEnvelope',
id: layer1,
sld_body: sld_body,
layer1: layer1,
layer2: layer2
}
return MapService.add(subLayer, parentLayer);
};
scope.isSpeciesListFacet = function (facet) {
return facet.indexOf('species_list') === 0;
};
/**
* Update scope.selected.layer.activeFacet.data
*
* Redraws WMS of scope.selected.layer
*
* @returns promise with scope.selected.layer.activeFacet.data
*/
scope.refreshFacetData = function (ignoreFilters) {
// When refreshing take a copy of the last selection
// so it can be reapplied to the new data.
var selectedLayer = scope.selected.layer;
var fq = BiocacheService.facetToFq(selectedLayer.activeFacet, false)
if (fq.fq) {
selectedLayer.activeFacet._fq = fq.fq
}
if (ignoreFilters) {
return scope.fetchFacetData(selectedLayer.activeFacet, selectedLayer).then(function (data) {
scope.updateWMS();
return $q.when(data)
})
} else {
// do not include the active facet when updating facet data counts
var newFqs = scope.getFacetFqs(false);
return BiocacheService.newLayerAddFq(selectedLayer, newFqs).then(function (newLayer) {
if (newLayer == null) {
return $q.when(null)
}
return scope.fetchFacetData(selectedLayer.activeFacet, newLayer).then(function (data) {
scope.updateWMS();
return $q.when(data)
})
})
}
}
/**
* Set facet.data using newLayer query
*
* @param facet facet object
* @param newLayer query
* @returns promise with facet.data
*/
scope.fetchFacetData = function (facet, newLayer) {
var selectedLayer = scope.selected.layer;
if (scope.isSpeciesListFacet(selectedLayer.facet)) {
return scope.speciesListToFacetList(selectedLayer.activeFacet.species_list_facet, newLayer).then(function (data) {
scope.setFacetData(facet, data)
return data
})
} else {
if (Util.isFacetOfRangeDataType(facet.dataType)) {
return BiocacheService.getFacetMinMax(newLayer, facet).then(function (data) {
facet.ranges = Util.getRangeBetweenTwoNumber(data.min, data.max);
if (facet.dataType.toLowerCase().indexOf('date') >= 0) {
$.map(facet.ranges, function (v) {
v[0] = new Date(v[0]).toISOString()
v[1] = new Date(v[1]).toISOString()
})
}
BiocacheService.facet(facet.name, newLayer, facet.ranges).then(function (data) {
scope.setFacetData(facet, data)
return data
})
})
} else {
return BiocacheService.facet(facet.name, newLayer).then(function (data) {
scope.setFacetData(facet, data)
return data
})
}
}
}
scope.setFacetData = function (facet, data) {
// Existing facets that do not have facet.data may have a copy of the selection as facet._fq
// Delete _fq after updating the facet.data with the active selection.
if (facet._fq) {
for (var i in data) {
var fq = data[i].fq;
var isInverted = facet._fq.indexOf("-(") === 0;
if (fq.match(/^-/g) != null && (fq.match(/:\*$/g) != null || fq.match(/\[\* TO \*\]$/g) != null)) {
fq = fq.substring(1)
}
if (facet._fq.indexOf(fq) >= 0 || facet._fq.indexOf(' ' + fq) >= 0
|| facet._fq.indexOf('(' + fq) >= 0) {
// found the fq at a boundary (start of _fq, after a space, after a bracket)
data[i].selected = true;
} else if (facet._fq.indexOf('-' + fq) >= 0) {
// found inverse fq
data[i].selected = isInverted;
}
}
delete facet._fq;
}
facet.data = data;
return data
}
scope.filtersEnabled = function () {
return $SH.filtersEnabled
}
scope.showActiveFilter = function () {
if ($SH.filtersEnabled) {
return true
}
// do not show grouped facets twice in the drop down list
var selectedLayer = scope.selected.layer;
for (var i in selectedLayer.groupedFacets) {
if (selectedLayer.groupedFacets[i].facet === selectedLayer.facet) {
return false
}
}
return true
}
scope.addToFacets = function (facetName, layer) {
// add new facet
var selectedLayer = layer || scope.selected.layer;
var nextId = 0
if (selectedLayer.facets.length > 0) {
nextId = selectedLayer.facets[selectedLayer.facets.length - 1].id + 1
}
for (var i = 0; i < selectedLayer.indexFields.length; i++) {
if (selectedLayer.indexFields[i].facet === facetName) {
var facet = {
id: nextId,
name: selectedLayer.indexFields[i].facet,
dataType: selectedLayer.indexFields[i].dataType,
displayName: selectedLayer.indexFields[i].displayName,
info: selectedLayer.indexFields[i].info,
description: selectedLayer.indexFields[i].description,
data: undefined,
enabled: true,
species_list_facet: selectedLayer.indexFields[i].species_list_facet
}
if (selectedLayer.facets.length > 0 && !$SH.filtersEnabled) {
selectedLayer.facets.splice(0, selectedLayer.facets.length)
}
selectedLayer.facets.push(facet)
return facet
}
}
}
scope.updateFacet = function () {
var selectedLayer = scope.selected.layer;
if (selectedLayer !== undefined && selectedLayer.facets) {
if (selectedLayer.facet === 'search') {
scope.searchFacets()
return;
}
// is a workflow filter selected?
for (var i = 0; i < scope.workflowFilters.length; i++) {
if (scope.workflowFilters[i].workflowId == selectedLayer.facet) {
selectedLayer.facet = '-1'
LayoutService.openModal('workflow', {
speciesLayerId: selectedLayer.uid,
workflowId: scope.workflowFilters[i].workflowId
});
return;
}
}
var facet
if (selectedLayer.scatterplotUrl === undefined) {
// does it already exist?
for (var i = 0; i < selectedLayer.facets.length; i++) {
if (selectedLayer.facets[i].name === selectedLayer.facet) {
facet = selectedLayer.facets[i]
}
}
} else if (selectedLayer.facets.length > 0) {
selectedLayer.facets = []
}
if (facet === undefined && selectedLayer.facet !== "-1") {
facet = scope.addToFacets(selectedLayer.facet, selectedLayer)
}
if (facet !== undefined) {
selectedLayer.activeFacet = facet
// always update facet data
scope.refreshFacetData(false).then(function (data) {
if (data && selectedLayer.scatterplotUrl !== undefined) {
scope.scatterplotUpdate(selectedLayer);
}
})
} else {
scope.updateWMS();
if (scope.selected.layer.scatterplotUrl !== undefined) {
scope.scatterplotUpdate();
}
}
}
};
scope.searchFacets = function () {
var data = scope.selected.layer.indexFields
for (var i = 0; i < data.length; i++) {
data[i].selected = scope.isFacetSelected(data[i].facet)
}
LayoutService.openModal('facet', {
data: data,
onChange: scope.updateFacets
}, false)
}
scope.isFacetSelected = function (facet, layer) {
var selectedLayer = layer || scope.selected.layer;
for (var i = 0; i < selectedLayer.facets.length; i++) {
if (selectedLayer.facets[i].name === facet) {
return selectedLayer.facets[i].enabled;
}
}
return false;
}
scope.updateFacets = function (data, layer) {
var selectedLayer = layer || scope.selected.layer;
// identify and add new facets
var newFacet
for (var j = 0; j < data.length; j++) {
if (data[j].selected && !scope.isFacetSelected(data[j].facet)) {
scope.addToFacets(data[j].facet)
newFacet = data[j].facet
}
}
// remove facets that are not selected
for (var i = 0; i < scope.selected.layer.facets.length; i++) {
var found = false;
for (var j = 0; j < data.length; j++) {
if (data[j].facet === scope.selected.layer.facets[i].name) {
if (newFacet !== undefined) {
newFacet = data[j].facet
}
found = true;
}
}
if (!found) {
scope.selected.layer.facets.splice(i, 1);
i--;
}
}
// select a facet
if (newFacet) {
scope.selected.layer.facet = newFacet
scope.updateFacet()
} else {
// select user defined colour
scope.selected.layer.facet = '-1'
scope.updateFacet()
}
}
scope.moveUp = function () {
if (scope.selected.layer !== undefined) {
scope.selected.layer.index++;
MapService.leafletScope.moveLayer(MapService.getLayer(scope.selected.layer.uid), scope.selected.layer.index)
}
};
scope.moveDown = function () {
if (scope.selected.layer !== undefined) {
scope.selected.layer.index--;
MapService.leafletScope.moveLayer(MapService.getLayer(scope.selected.layer.uid), scope.selected.layer.index)
}
};
scope.setVisible = function (show) {
if (scope.selected.layer !== undefined) {
scope.selected.layer.visible = show;
scope.selected.layer.leaflet.layerOptions.layers[0].visible = show;
MapService.leafletScope.showLayer(MapService.getLayer(scope.selected.layer.uid), scope.selected.layer.visible);
if (show) MapService.leafletScope.moveLayer(MapService.getLayer(scope.selected.layer.uid), scope.selected.layer.index)
}
};
scope.getOpacity = function () {
if (scope.selected !== undefined && scope.selected.layer !== undefined && scope.selected.layer !== null) {
return scope.selected.layer.opacity
} else {
return 0
}
};
scope.$watch('getOpacity()', function (newValue, oldValue) {
if (scope.selected !== undefined && scope.selected.layer !== undefined && scope.selected.layer !== null) {
scope.setOpacity(scope.selected.layer.opacity)
}
});
scope.getSize = function () {
if (scope.selected !== undefined && scope.selected.layer !== undefined && scope.selected.layer !== null) {
return scope.selected.layer.size
} else {
return 0
}
};
scope.$watch('getSize()', function (newValue, oldValue) {
if (scope.selected !== undefined && scope.selected.layer !== undefined && scope.selected.layer !== null) {
scope.setSize(scope.selected.layer.size)
}
});
scope.setOpacity = function (opacity) {
if (scope.selected.layer !== undefined) {
scope.selected.layer.opacity = opacity;
scope.selected.layer.leaflet.layerOptions.layers[0].opacity = opacity;
MapService.leafletScope.changeOpacity(MapService.getLayer(scope.selected.layer.uid), scope.selected.layer.opacity / 100)
}
};
scope.setUncertainty = function (uncertainty) {
if (scope.selected.layer !== undefined) {
scope.selected.layer.uncertainty = uncertainty;
scope.updateWMS()
}
};
scope.setSize = function (size) {
if (scope.selected.layer !== undefined) {
scope.selected.layer.size = size;
scope.updateWMS();
scope.scatterplotUpdate()
}
};
scope.updateWMS = function (layer) {
var selectedLayer = layer || scope.selected.layer;
if (selectedLayer !== undefined) {
selectedLayer.wms = selectedLayer.name + ', ' + selectedLayer.color + ', '
+ selectedLayer.colorType + ', ' + selectedLayer.opacity + ', '
+ selectedLayer.uncertainty + ', ' + selectedLayer.size;
if (selectedLayer.leaflet) {
var firstLayer = selectedLayer.leaflet.layerOptions.layers[0];
if (selectedLayer.scatterplotId !== undefined && selectedLayer.leaflet.layerOptions.layers[1] !== undefined) {
firstLayer = selectedLayer.leaflet.layerOptions.layers[1];
}
// using the layer.facets selection will override the colour to -1 and red
var facetSelectionOverride = false
if (selectedLayer.facets && selectedLayer.facets.length > 0) {
firstLayer.layerParams.fq = scope.getFacetFqs(true, selectedLayer);
var activeFacet = BiocacheService.facetToFq(selectedLayer.activeFacet, true);
// override colour for this active facet selection
if (activeFacet.fq) {
var colour = "FF0000"
firstLayer.layerParams.ENV = 'color%3A' + colour + '%3Bname%3Acircle%3Bsize%3A' +
selectedLayer.size + '%3Bopacity%3A1' +
(selectedLayer.uncertainty ? "%3Buncertainty%3A1" : "")
facetSelectionOverride = true
}
} else {
delete firstLayer.layerParams["fq"]
}
if (facetSelectionOverride) {
// ENV already set
} else if (selectedLayer.colorType === 'grid') {
firstLayer.layerParams.ENV = 'colormode%3Agrid%3Bname%3Acircle%3Bsize%3A' +
selectedLayer.size + '%3Bopacity%3A1'
} else if (selectedLayer.colorType === '-1') {
// do not use layer.facet as colour mode if it is a species_list
if (selectedLayer.facet === '-1' || selectedLayer.facet.indexOf('species_list') == 0) {
firstLayer.layerParams.ENV = 'color%3A' + selectedLayer.color + '%3Bname%3Acircle%3Bsize%3A' +
selectedLayer.size + '%3Bopacity%3A1' +
(selectedLayer.uncertainty ? "%3Buncertainty%3A1" : "")
} else {
var ranges = "";
if (selectedLayer.activeFacet && Util.isFacetOfRangeDataType(selectedLayer.activeFacet.dataType) && selectedLayer.activeFacet.ranges && selectedLayer.activeFacet.ranges.length > 0) {
ranges = encodeURIComponent( "," + selectedLayer.activeFacet.ranges.join(","));
}
firstLayer.layerParams.ENV = 'colormode%3A' + selectedLayer.facet + ranges + '%3Bname%3Acircle%3Bsize%3A' +
selectedLayer.size + '%3Bopacity%3A1' +
(selectedLayer.uncertainty ? "%3Buncertainty%3A1" : "")
}
if (selectedLayer.scatterplotFq !== undefined && selectedLayer.scatterplotFq.length > 0) {
firstLayer.layerParams.ENV += '%3Bsel%3A' + encodeURIComponent(selectedLayer.scatterplotFq)
}
}
MapService.reMap(scope.selected);
}
$timeout(function () {
}, 0)
}
};
scope.startx = 0;
scope.starty = 0;
scope.endx = 0;
scope.endy = 0;
scope.resizing = false;
scope.doMouseDown = function (event) {
document.getElementById('chartDiv').UNSELECTABLE = "on";
document.getElementById('rband').UNSELECTABLE = "on";
document.getElementById('chartDivBack').UNSELECTABLE = "on";
var rband = $('#rband');
rband.offset($('#chartDivBack').offset());
scope.setPageXY(event);
scope.startx = event.pageX;
scope.starty = event.pageY;
scope.resizing = true;
rband.offset({top: scope.starty, left: scope.startx}).show();
// prevent default behavior of text selection
return false;
};
scope.setPageXY = function (event) {
if (event.pageX || event.pageY) {
} else if (event.clientX || event.clientY) {
event.pageX = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
event.pageY = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
};
scope.doMouseDrag = function (event) {
if (scope.resizing) {
var left, top, width, height;
scope.setPageXY(event);
scope.endx = event.pageX;
scope.endy = event.pageY;
if (event.pageX > scope.startx) {
left = scope.startx;
width = event.pageX - scope.startx;
}
else {
left = event.pageX;
width = scope.startx - event.pageX;
}
if (event.pageY > scope.starty) {
top = scope.starty;
height = event.pageY - scope.starty;
}
else {
top = event.pageY;
height = scope.starty - event.pageY;
}
var rband = $('#rband');
rband.offset({top: top, left: left});
rband.css({
'width': width,
'height': height
});
}
};
scope.doMouseUp = function (event) {
if (scope.resizing) {
scope.resizing = false;
scope.chartSelection(scope.startx, scope.starty, scope.endx, scope.endy);
}
};
scope.clearSelection = function () {
};
scope.chartSelection = function (x1, y1, x2, y2) {
x1 = x1 + "";
x2 = x2 + "";
y1 = y1 + "";
y2 = y2 + "";
var back = jQuery('#chartDivBack');
var value = (x1.replace("px", "") - $(back[0]).offset().left)
+ "," + (y1.replace("px", "") - $(back[0]).offset().top)
+ "," + (x2.replace("px", "") - $(back[0]).offset().left)
+ "," + (y2.replace("px", "") - $(back[0]).offset().top);
var cd = document.getElementById('chartDiv');
var ci = document.getElementById('chartDivBack');
ci.style.backgroundImage = cd.style.backgroundImage;
scope.scatterplotUpdate(value);
};
scope.scatterplotDownloadData = function () {
Util.download(scope.selected.layer.scatterplotDataUrl, "scatterplotData.zip");
};
scope.scatterplotDownloadImage = function () {
Util.download(scope.selected.layer.scatterplotUrl, "scatterplotImage.png");
};
scope.scatterplotUpdate = function (value, layer) {
var selectedLayer = layer || scope.selected.layer;
if (selectedLayer && selectedLayer.scatterplotUrl) {
selectedLayer.scatterplotUpdating = true;
var task = {
name: 'ScatterplotDraw',
input: $.extend({}, scope.selected.layer)
};
if (task.input.facet !== -1) task.input.colorType = task.input.facet;
task.input.opacity = task.input.opacity / 100;
if (value || value == null) {
selectedLayer.scatterplotSelection = value;
task.input.selection = value;
} else {
task.input.selection = selectedLayer.scatterplotSelection;
}
task.input.wkt = [{pid: selectedLayer.highlightWkt}];
$http.post($SH.baseUrl + '/portal/postTask?sessionId=' + $SH.sessionId, task, _httpDescription('updateScatterplot', {ignoreErrors: true})).then(function (response) {
scope.checkScatterplotStatus(LayersService.url() + '/tasks/status/' + response.data.id, selectedLayer)
})
}
};
scope.checkScatterplotStatus = function (url, layer) {
$http.get(url, _httpDescription('checkScatterplotStatus', {ignoreErrors: true})).then(function (response) {
scope.status = response.data.message;
if (response.data.status < 2) {
$timeout(function () {
scope.checkScatterplotStatus(url, layer)
}, 500)
} else if (response.data.status === 2) {
scope.status = 'cancelled';
layer.scatterplotUpdating = false;
} else if (response.data.status === 3) {
scope.status = 'error';
layer.scatterplotUpdating = false;
} else if (response.data.status === 4) {
$("#rband").css({
'width': 0,
'height': 0
}).hide();
scope.status = $i18n(400, "successful");
scope.finishedData = response.data;
var updateNow = true;
for (var k in scope.finishedData.output) {
if (scope.finishedData.output.hasOwnProperty(k)) {
var d = scope.finishedData.output[k];
if (d.name === 'species') {
var species = jQuery.parseJSON(d.file);
layer.scatterplotUrl = species.scatterplotUrl;
// remove scatterplot environmental envelope
while (layer.leaflet.layerOptions.layers.length > 1) {
delete layer.leaflet.layerOptions.layers[0]
layer.leaflet.layerOptions.layers.splice(0, 1)
}
if (species.scatterplotSelectionExtents && species.scatterplotLayers) {
layer.scatterplotSelectionExtents = species.scatterplotSelectionExtents;
var fq = species.scatterplotLayers[0] + ":[" + species.scatterplotSelectionExtents[1] + " TO " + species.scatterplotSelectionExtents[3] + "] AND " +
species.scatterplotLayers[1] + ":[" + species.scatterplotSelectionExtents[0] + " TO " + species.scatterplotSelectionExtents[2] + "]";
var fqs = [fq];
layer.scatterplotFq = fq;
if (species.scatterplotSelectionExtents.length === 0) {
fqs = [];
layer.scatterplotSelectionCount = 0;
scope.updateWMS(layer);
} else {
scope.createSubLayerScatterplotEnvelope(layer,
species.scatterplotLayers[0], species.scatterplotSelectionExtents[1], species.scatterplotSelectionExtents[3],
species.scatterplotLayers[1], species.scatterplotSelectionExtents[0], species.scatterplotSelectionExtents[2])
scope.updateWMS(layer);
updateNow = false;
layer.scatterplotSelectionCount = $i18n(377, "counting...");
BiocacheService.count(layer, fqs).then(function (count) {
layer.scatterplotSelectionCount = count;
layer.scatterplotUpdating = false;
});
layer.scatterplotLabel1 = BiocacheI18n.get('facet.' + species.scatterplotLayers[0]) + " : " +
species.scatterplotSelectionExtents[1].toFixed(4) + " - " + species.scatterplotSelectionExtents[3].toFixed(4);
layer.scatterplotLabel2 = BiocacheI18n.get('facet.' + species.scatterplotLayers[1]) + " : " +
species.scatterplotSelectionExtents[0].toFixed(4) + " - " + species.scatterplotSelectionExtents[2].toFixed(4);
}
} else {
layer.scatterplotSelectionExtents = null;
layer.scatterplotLabel1 = '';
layer.scatterplotLabel2 = '';
layer.scatterplotFq = [];
layer.scatterplotSelectionCount = 0;
scope.updateWMS(layer);
}
}
}
}
if (updateNow) layer.scatterplotUpdating = false;
}
}, function (error) {
// retry
$timeout(function () {
scope.checkScatterplotStatus(url, layer)
}, 500)
})
};
scope.updateScatterplot = function (width, height, background) {
var cd = document.getElementById('chartDiv');
var ci = document.getElementById('chartDivBack');
ci.style.backgroundImage = cd.style.backgroundImage;
cd.style.backgroundImage = background;
cd.style.width = width + 'px';
cd.style.height = height + 'px';
ci.style.width = cd.style.width;
ci.style.height = cd.style.height;
$("#rband").css({
'width': 0,
'height': 0
}).hide();
};
scope.colourTimeout = null;
scope.updateColour = function (layer) {
var selectedLayer = layer || scope.selected.layer;
var r = selectedLayer.red.toString(16);
if (r.length === 1) r = '0' + r;
var g = selectedLayer.green.toString(16);
if (g.length === 1) g = '0' + g;
var b = selectedLayer.blue.toString(16);
if (b.length === 1) b = '0' + b;
selectedLayer.color = r + g + b;
if (scope.colourTimeout !== null) clearTimeout(scope.colourTimeout);
scope.colourTimeout = setTimeout(function () {
scope.applyColour()
}, 500)
};
scope.applyColour = function () {
scope.updateWMS();
scope.scatterplotUpdate()
}
scope.isFilterSelected = function (layer) {
var selectedLayer = layer || scope.selected.layer;
if (selectedLayer && selectedLayer.facets) {
for (var i = 0; i < selectedLayer.facets.length; i++) {
if (selectedLayer.facets[i].name === selectedLayer.facet) {
return true;
}
}
}
return false;
}
scope.removeFacet = function (layer) {
var selectedLayer = layer || scope.selected.layer;
for (var i = 0; i < selectedLayer.facets.length; i++) {
if (selectedLayer.facets[i].name === selectedLayer.facet) {
selectedLayer.facets.splice(i, 1)
if (selectedLayer.facets.length > 0) {
selectedLayer.facet = selectedLayer.facets[0].name
} else {
selectedLayer.facet = "-1"
}
scope.updateFacet()
}
}
}
}
}
}])
}(angular));