diff --git a/src/cli/serve/legacy_config.js b/src/cli/serve/legacy_config.js index 75fbb4e407eac..591a4fd1a6f8c 100644 --- a/src/cli/serve/legacy_config.js +++ b/src/cli/serve/legacy_config.js @@ -30,6 +30,11 @@ export const legacySettings = { request_timeout: 'elasticsearch.requestTimeout', shard_timeout: 'elasticsearch.shardTimeout', startup_timeout: 'elasticsearch.startupTimeout', + tilemap_url: 'tilemap.url', + tilemap_min_zoom: 'tilemap.options.minZoom', + tilemap_max_zoom: 'tilemap.options.maxZoom', + tilemap_attribution: 'tilemap.options.attribution', + tilemap_subdomains: 'tilemap.options.subdomains', verify_ssl: 'elasticsearch.ssl.verify', }; diff --git a/src/core_plugins/kibana/index.js b/src/core_plugins/kibana/index.js index 686c55ebd099b..6b22f5271fb0a 100644 --- a/src/core_plugins/kibana/index.js +++ b/src/core_plugins/kibana/index.js @@ -31,9 +31,9 @@ module.exports = function (kibana) { injectVars: function (server, options) { let config = server.config(); - return { - kbnDefaultAppId: config.get('kibana.defaultAppId') + kbnDefaultAppId: config.get('kibana.defaultAppId'), + tilemap: config.get('tilemap') }; }, }, diff --git a/src/core_plugins/tests_bundle/tests_entry_template.js b/src/core_plugins/tests_bundle/tests_entry_template.js index 79645defda328..257ca69113c50 100644 --- a/src/core_plugins/tests_bundle/tests_entry_template.js +++ b/src/core_plugins/tests_bundle/tests_entry_template.js @@ -27,7 +27,15 @@ window.__KBN__ = { kbnIndex: '.kibana', esShardTimeout: 1500, esApiVersion: '2.0', - esRequestTimeout: '300000' + esRequestTimeout: '300000', + tilemap: { + url: 'https://tiles.elastic.co/v1/default/{z}/{x}/{y}.png?my_app_name=kibana&my_app_version=1.2.3&elastic_tile_service_tos=agree', + options: { + minZoom: 1, + maxZoom: 7, + attribution: '© [Elastic Tile Service](https://www.elastic.co/elastic_tile_service)' + } + } }, uiSettings: { defaults: ${JSON.stringify(env.defaultUiSettings, null, 2).split('\n').join('\n ')}, diff --git a/src/server/config/schema.js b/src/server/config/schema.js index 79fa6e9a62544..4caecbd75d029 100644 --- a/src/server/config/schema.js +++ b/src/server/config/schema.js @@ -8,6 +8,8 @@ import os from 'os'; import { fromRoot } from '../../utils'; import { getData } from '../path'; +import pkg from '../../../src/utils/package_json'; + module.exports = () => Joi.object({ pkg: Joi.object({ version: Joi.string().default(Joi.ref('$version')), @@ -130,6 +132,21 @@ module.exports = () => Joi.object({ status: Joi.object({ allowAnonymous: Joi.boolean().default(false) + }).default(), + + tilemap: Joi.object({ + url: Joi.string().default(`https://tiles.elastic.co/v1/default/{z}/{x}/{y}.png?my_app_name=kibana&my_app_version=${pkg.version}&elastic_tile_service_tos=agree`), + options: Joi.object({ + attribution: Joi.string().default('© [Elastic Tile Service](https://www.elastic.co/elastic-tile-service)'), + minZoom: Joi.number().min(1, 'Must not be less than 1').default(1), + maxZoom: Joi.number().default(7), + tileSize: Joi.number(), + subdomains: Joi.array().items(Joi.string()).single(), + errorTileUrl: Joi.string().uri(), + tms: Joi.boolean(), + reuseTiles: Joi.boolean(), + bounds: Joi.array().items(Joi.array().items(Joi.number()).min(2).required()).min(2) + }).default() }).default() }).default(); diff --git a/src/ui/public/vislib/styles/_tilemap.less b/src/ui/public/vislib/styles/_tilemap.less index 71887e14685aa..d3d743075d87d 100644 --- a/src/ui/public/vislib/styles/_tilemap.less +++ b/src/ui/public/vislib/styles/_tilemap.less @@ -142,6 +142,10 @@ .leaflet-control-attribution { background-color: @tilemap-leaflet-footer-bg !important; color: @tilemap-leaflet-footer-color !important; + + p { + display: inline; + } } .leaflet-left { diff --git a/src/ui/public/vislib/visualizations/_map.js b/src/ui/public/vislib/visualizations/_map.js index ce38af970b2c8..44aadba055b4b 100644 --- a/src/ui/public/vislib/visualizations/_map.js +++ b/src/ui/public/vislib/visualizations/_map.js @@ -1,24 +1,28 @@ import _ from 'lodash'; import $ from 'jquery'; import L from 'leaflet'; +import marked from 'marked'; +marked.setOptions({ + gfm: true, // Github-flavored markdown + sanitize: true // Sanitize HTML tags +}); + import VislibVisualizationsMarkerTypesScaledCirclesProvider from 'ui/vislib/visualizations/marker_types/scaled_circles'; import VislibVisualizationsMarkerTypesShadedCirclesProvider from 'ui/vislib/visualizations/marker_types/shaded_circles'; import VislibVisualizationsMarkerTypesGeohashGridProvider from 'ui/vislib/visualizations/marker_types/geohash_grid'; import VislibVisualizationsMarkerTypesHeatmapProvider from 'ui/vislib/visualizations/marker_types/heatmap'; -export default function MapFactory(Private) { +export default function MapFactory(Private, tilemap) { let defaultMapZoom = 2; let defaultMapCenter = [15, 5]; let defaultMarkerType = 'Scaled Circle Markers'; + let tilemapOptions = tilemap.options; + let attribution = marked(tilemapOptions.attribution); + let mapTiles = { - url: 'https://otile{s}-s.mqcdn.com/tiles/1.0.0/map/{z}/{x}/{y}.jpeg', - options: { - attribution: 'Tiles by MapQuest — ' + - 'Map data © OpenStreetMap contributors, ' + - 'CC-BY-SA', - subdomains: '1234' - } + url: tilemap.url, + options: _.assign({}, tilemapOptions, { attribution }) }; let markerTypes = { @@ -47,13 +51,13 @@ export default function MapFactory(Private) { this._valueFormatter = params.valueFormatter || _.identity; this._tooltipFormatter = params.tooltipFormatter || _.identity; this._geoJson = _.get(this._chartData, 'geoJson'); - this._mapZoom = params.zoom || defaultMapZoom; + this._mapZoom = Math.max(Math.min(params.zoom || defaultMapZoom, tilemapOptions.maxZoom), tilemapOptions.minZoom); this._mapCenter = params.center || defaultMapCenter; this._attr = params.attr || {}; let mapOptions = { - minZoom: 1, - maxZoom: 18, + minZoom: tilemapOptions.minZoom, + maxZoom: tilemapOptions.maxZoom, noWrap: true, maxBounds: L.latLngBounds([-90, -220], [90, 220]), scrollWheelZoom: false, @@ -277,6 +281,10 @@ export default function MapFactory(Private) { // add map tiles layer, using the mapTiles object settings if (this._attr.wms && this._attr.wms.enabled) { + _.assign(mapOptions, { + minZoom: 1, + maxZoom: 18 + }); this._tileLayer = L.tileLayer.wms(this._attr.wms.url, this._attr.wms.options); } else { this._tileLayer = L.tileLayer(mapTiles.url, mapTiles.options);