Skip to content

Commit

Permalink
Display regionmap attribution (#12647)
Browse files Browse the repository at this point in the history
This adds the attribution strings of vector data files to the map. It also enables the map to allow for individual attribution strings from each individual layer, so attribution gets updated correctly when adding/removing layers.
  • Loading branch information
thomasneirynck authored Jul 13, 2017
1 parent 496fd93 commit 58ef02c
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 18 deletions.
4 changes: 3 additions & 1 deletion docs/setup/settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ The file must use the WGS84 coordinate reference system and only include polygon
If the file is hosted on a separate domain from Kibana, the server needs to be CORS-enabled so Kibana can download the file.
The url field also serves as a unique identifier for the file.
Each layer can contain multiple fields to indicate what properties from the geojson features you want to expose.
The field.description is the human readable text that is shown in the Region Map visualization's field menu.
The field.description is the human readable text that is shown in the Region Map visualization's field menu.
An optional attribution value can be added as well.
The following example shows a valid regionmap configuration.

regionmap:
layers:
- name: "Departments of France"
url: "http://my.cors.enabled.server.org/france_departements.geojson"
attribution: "INRAP"
fields:
- name: "department"
description: "Full department name"
Expand Down
6 changes: 2 additions & 4 deletions src/core_plugins/region_map/public/choropleth_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import { truncatedColorMaps } from 'ui/vislib/components/color/truncated_colorma

export default class ChoroplethLayer extends KibanaMapLayer {

constructor(geojsonUrl) {
constructor(geojsonUrl, attribution) {
super();


this._metrics = null;
this._joinField = null;
this._colorRamp = truncatedColorMaps[Object.keys(truncatedColorMaps)[0]];
this._tooltipFormatter = () => '';
this._attribution = attribution;

this._geojsonUrl = geojsonUrl;
this._leafletLayer = L.geoJson(null, {
Expand Down Expand Up @@ -162,9 +162,7 @@ export default class ChoroplethLayer extends KibanaMapLayer {

jqueryDiv.append(label);
});

}

}


Expand Down
8 changes: 4 additions & 4 deletions src/core_plugins/region_map/public/region_map_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ module.controller('KbnRegionMapController', function ($scope, $element, Private,
return;
}

updateChoroplethLayer($scope.vis.params.selectedLayer.url);
updateChoroplethLayer($scope.vis.params.selectedLayer.url, $scope.vis.params.selectedLayer.attribution);
choroplethLayer.setMetrics(results, metricsAgg);
setTooltipFormatter();

Expand All @@ -74,7 +74,7 @@ module.controller('KbnRegionMapController', function ($scope, $element, Private,
return;
}

updateChoroplethLayer(visParams.selectedLayer.url);
updateChoroplethLayer(visParams.selectedLayer.url, visParams.selectedLayer.attribution);
choroplethLayer.setJoinField(visParams.selectedJoinField.name);
choroplethLayer.setColorRamp(truncatedColorMaps[visParams.colorSchema]);
setTooltipFormatter();
Expand Down Expand Up @@ -109,7 +109,7 @@ module.controller('KbnRegionMapController', function ($scope, $element, Private,
}
}

function updateChoroplethLayer(url) {
function updateChoroplethLayer(url, attribution) {

if (choroplethLayer && choroplethLayer.equalsGeoJsonUrl(url)) {//no need to recreate the layer
return;
Expand All @@ -118,7 +118,7 @@ module.controller('KbnRegionMapController', function ($scope, $element, Private,

const previousMetrics = choroplethLayer ? choroplethLayer.getMetrics() : null;
const previousMetricsAgg = choroplethLayer ? choroplethLayer.getMetricsAgg() : null;
choroplethLayer = new ChoroplethLayer(url);
choroplethLayer = new ChoroplethLayer(url, attribution);
if (previousMetrics && previousMetricsAgg) {
choroplethLayer.setMetrics(previousMetrics, previousMetricsAgg);
}
Expand Down
47 changes: 46 additions & 1 deletion src/core_plugins/tile_map/public/__tests__/kibana_map.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import expect from 'expect.js';
import { KibanaMap } from '../kibana_map';
import { KibanaMapLayer } from '../kibana_map_layer';
import L from 'leaflet';

describe('kibana_map tests', function () {

Expand Down Expand Up @@ -66,10 +68,53 @@ describe('kibana_map tests', function () {
expect(bounds.top_left.lon).to.equal(-180);

});

});


describe('KibanaMap - attributions', function () {


beforeEach(async function () {
setupDOM();
kibanaMap = new KibanaMap(domNode, {
minZoom: 1,
maxZoom: 10,
center: [0, 0],
zoom: 0
});
});

afterEach(function () {
kibanaMap.destroy();
teardownDOM();
});

function makeMockLayer(attribution) {
const layer = new KibanaMapLayer();
layer._attribution = attribution;
layer._leafletLayer = L.geoJson(null);
return layer;
}

it('should update attributions correctly', function () {
kibanaMap.addLayer(makeMockLayer('foo|bar'));
expect(domNode.querySelectorAll('.leaflet-control-attribution')[0].innerHTML).to.equal('foo, bar');

kibanaMap.addLayer(makeMockLayer('bar'));
expect(domNode.querySelectorAll('.leaflet-control-attribution')[0].innerHTML).to.equal('foo, bar');

const layer = makeMockLayer('bar,stool');
kibanaMap.addLayer(layer);
expect(domNode.querySelectorAll('.leaflet-control-attribution')[0].innerHTML).to.equal('foo, bar, stool');

kibanaMap.removeLayer(layer);
expect(domNode.querySelectorAll('.leaflet-control-attribution')[0].innerHTML).to.equal('foo, bar');


});

});

describe('KibanaMap - baseLayer', function () {

beforeEach(async function () {
Expand Down
58 changes: 50 additions & 8 deletions src/core_plugins/tile_map/public/kibana_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export class KibanaMap extends EventEmitter {
};

this._leafletMap = L.map(containerNode, leafletOptions);
this._leafletMap.attributionControl.setPrefix('');
this._leafletMap.scrollWheelZoom.disable();
const worldBounds = L.latLngBounds(L.latLng(-90, -180), L.latLng(90, 180));
this._leafletMap.setMaxBounds(worldBounds);
Expand Down Expand Up @@ -234,19 +235,49 @@ export class KibanaMap extends EventEmitter {
this._layers.push(kibanaLayer);
kibanaLayer.addToLeafletMap(this._leafletMap);
this.emit('layers:update');

this._addAttributions(kibanaLayer.getAttributions());
}

removeLayer(layer) {
const index = this._layers.indexOf(layer);
removeLayer(kibanaLayer) {

if (!kibanaLayer) {
return;
}

this._removeAttributions(kibanaLayer.getAttributions());
const index = this._layers.indexOf(kibanaLayer);
if (index >= 0) {
this._layers.splice(index, 1);
layer.removeFromLeafletMap(this._leafletMap);
kibanaLayer.removeFromLeafletMap(this._leafletMap);
}
this._listeners.forEach(listener => {
if (listener.layer === layer) {
if (listener.layer === kibanaLayer) {
listener.layer.removeListener(listener.name, listener.handle);
}
});

//must readd all attributions, because we might have removed dupes
this._layers.forEach((layer) => this._addAttributions(layer.getAttributions()));
if (this._baseLayerSettings) {
this._addAttributions(this._baseLayerSettings.options.attribution);
}
}


_addAttributions(attribution) {
const attributions = getAttributionArray(attribution);
attributions.forEach((attribution) => {
this._leafletMap.attributionControl.removeAttribution(attribution);//this ensures we do not add duplicates
this._leafletMap.attributionControl.addAttribution(attribution);
});
}

_removeAttributions(attribution) {
const attributions = getAttributionArray(attribution);
attributions.forEach((attribution) => {
this._leafletMap.attributionControl.removeAttribution(attribution);//this ensures we do not add duplicates
});
}

destroy() {
Expand Down Expand Up @@ -425,15 +456,18 @@ export class KibanaMap extends EventEmitter {
return;
}

this._baseLayerSettings = settings;

if (settings === null) {
if (this._leafletBaseLayer && this._leafletMap) {
this._removeAttributions(this._baseLayerSettings.options.attribution);
this._leafletMap.removeLayer(this._leafletBaseLayer);
this._leafletBaseLayer = null;
this._baseLayerSettings = null;
}
return;
}

this._baseLayerSettings = settings;
if (this._leafletBaseLayer) {
this._leafletMap.removeLayer(this._leafletBaseLayer);
this._leafletBaseLayer = null;
Expand Down Expand Up @@ -461,6 +495,7 @@ export class KibanaMap extends EventEmitter {
if (settings.options.minZoom > this._leafletMap.getZoom()) {
this._leafletMap.setZoom(settings.options.minZoom);
}
this._addAttributions(settings.options.attribution);
this.resize();
}

Expand Down Expand Up @@ -496,14 +531,12 @@ export class KibanaMap extends EventEmitter {
return L.tileLayer(options.url, {
minZoom: options.minZoom,
maxZoom: options.maxZoom,
subdomains: options.subdomains || [],
attribution: options.attribution
subdomains: options.subdomains || []
});
}

_getWMSBaseLayer(options) {
const wmsOptions = {
attribution: options.attribution || '',
format: options.format || '',
layers: options.layers || '',
minZoom: options.minZoom,
Expand Down Expand Up @@ -562,3 +595,12 @@ export class KibanaMap extends EventEmitter {
}


function getAttributionArray(attribution) {
const attributionString = attribution || '';
let attributions = attributionString.split('|');
if (attributions.length === 1) {//temp work-around due to inconsistency in manifests of how attributions are delimited
attributions = attributions[0].split(',');
}
return attributions;
}

4 changes: 4 additions & 0 deletions src/core_plugins/tile_map/public/kibana_map_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export class KibanaMapLayer extends EventEmitter {

movePointer() {
}

getAttributions() {
return this._attribution;
}
}


Expand Down
1 change: 1 addition & 0 deletions src/server/config/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ export default () => Joi.object({
layers: Joi.array().items(Joi.object({
url: Joi.string(),
type: Joi.string(),
attribution: Joi.string(),
name: Joi.string(),
fields: Joi.array().items(Joi.object({
name: Joi.string(),
Expand Down
1 change: 1 addition & 0 deletions src/ui/public/vis/map/service_settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ uiModules.get('kibana')
const layers = manifest.data.layers.filter(layer => layer.format === 'geojson');
layers.forEach((layer) => {
layer.url = this._extendUrlWithParams(layer.url);
layer.attribution = $sanitize(marked(layer.attribution));
});
return layers;
});
Expand Down

0 comments on commit 58ef02c

Please sign in to comment.