Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Maps] Fix tileload error messaging / Fix heatmap error message #30327

Merged
merged 7 commits into from
Feb 7, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions x-pack/plugins/maps/public/angular/get_initial_layers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('Saved object does not have layer list', () => {
const layers = getInitialLayers(null);
expect(layers).toEqual([{
"alpha": 1,
"dataRequests": [],
"__dataRequests": [],
"id": layers[0].id,
"label": null,
"maxZoom": 24,
Expand Down Expand Up @@ -122,7 +122,7 @@ describe('Saved object does not have layer list', () => {
const layers = getInitialLayers(null);
expect(layers).toEqual([{
"alpha": 1,
dataRequests: [],
__dataRequests: [],
id: layers[0].id,
label: null,
maxZoom: 24,
Expand Down
21 changes: 15 additions & 6 deletions x-pack/plugins/maps/public/angular/services/saved_gis_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,7 @@ module.factory('SavedGisMap', function (Private) {

SavedGisMap.prototype.syncWithStore = function (state) {
const layerList = getLayerListRaw(state);
// Layer list from store contains requested data.
// We do not want to store this in the saved object so it is getting removed
const layerListConfigOnly = layerList.map(layer => {
delete layer.dataRequests;
return layer;
});
const layerListConfigOnly = copyPersistentState(layerList);
this.layerListJSON = JSON.stringify(layerListConfigOnly);

this.mapStateJSON = JSON.stringify({
Expand All @@ -90,3 +85,17 @@ module.factory('SavedGisMap', function (Private) {

return SavedGisMap;
});


function copyPersistentState(input) {
if (typeof input !== 'object' && input !== null) {//primitive
return input;
}
const copyInput = Array.isArray(input) ? [] : {};
for(const key in input) {
if (!key.startsWith('__')) {
copyInput[key] = copyPersistentState(input[key]);
}
}
return copyInput;
}
6 changes: 1 addition & 5 deletions x-pack/plugins/maps/public/components/map/mb/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,7 @@ export class MBMapContainer extends React.Component {

removeOrphanedSourcesAndLayers(this._mbMap, layerList);
layerList.forEach(layer => {
if (!layer.hasErrors()) {
Promise.resolve(layer.syncLayerWithMB(this._mbMap))
.catch(({ message }) =>
this.props.setLayerErrorStatus(layer.getId(), message));
}
layer.syncLayerWithMB(this._mbMap);
});
syncLayerOrder(this._mbMap, layerList);
};
Expand Down
14 changes: 9 additions & 5 deletions x-pack/plugins/maps/public/shared/layers/layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export class AbstractLayer {
this._descriptor = AbstractLayer.createDescriptor(layerDescriptor);
this._source = source;
this._style = style;
if (this._descriptor.dataRequests) {
this._dataRequests = this._descriptor.dataRequests.map(dataRequest => new DataRequest(dataRequest));
if (this._descriptor.__dataRequests) {
this._dataRequests = this._descriptor.__dataRequests.map(dataRequest => new DataRequest(dataRequest));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems error prone to have this._dataRequests with a single underscore and this._descriptor.__dataRequests with a double underscore. Any ideas on how to avoid?

Copy link
Contributor Author

@thomasneirynck thomasneirynck Feb 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah .... it looks funny.

We could just revert to single underscore, and ditch the double underscore.

On the other hand, it's a pretty common convention to prepend _ to variables of private state or internal state. But I feel like store-state is something different altogether (just gut feeling..)

Maybe we could just leave as-is for now (?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, leaving as is for now sounds ok.

} else {
this._dataRequests = [];
}
Expand All @@ -32,7 +32,7 @@ export class AbstractLayer {
static createDescriptor(options = {}) {
const layerDescriptor = { ...options };

layerDescriptor.dataRequests = _.get(options, 'dataRequests', []);
layerDescriptor.__dataRequests = _.get(options, '__dataRequests', []);
layerDescriptor.id = _.get(options, 'id', Math.random().toString(36).substr(2, 5));
layerDescriptor.label = options.label && options.label.length > 0 ? options.label : null;
layerDescriptor.minZoom = _.get(options, 'minZoom', 0);
Expand Down Expand Up @@ -150,11 +150,11 @@ export class AbstractLayer {
}

hasErrors() {
return _.get(this._descriptor, 'isInErrorState', false);
return _.get(this._descriptor, '__isInErrorState', false);
}

getErrors() {
return this.hasErrors() ? this._descriptor.errorMessage : '';
return this.hasErrors() ? this._descriptor.__errorMessage : '';
}

toLayerDescriptor() {
Expand All @@ -165,6 +165,10 @@ export class AbstractLayer {
//no-op by default
}

syncLayerWithMb() {
//no-op by default
}

updateDueToExtent(source, meta = {}, dataFilters = {}) {
const extentAware = source.isFilterByMapBounds();
if (!extentAware) {
Expand Down
82 changes: 22 additions & 60 deletions x-pack/plugins/maps/public/shared/layers/tile_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import React from 'react';
import { EuiIcon } from '@elastic/eui';
import { TileStyle } from '../layers/styles/tile_style';

const TMS_LOAD_TIMEOUT = 32000;

export class TileLayer extends AbstractLayer {

static type = "TILE";
Expand All @@ -32,38 +30,6 @@ export class TileLayer extends AbstractLayer {
return tileLayerDescriptor;
}

_tileLoadErrorTracker(map, url) {
let tileLoad;
map.on('dataloading', ({ tile }) => {
if (tile && tile.request) {
// If at least one tile loads, endpoint/resource is valid
tile.request.onloadend = ({ loaded }) => {
if (loaded) {
tileLoad = true;
}
};
}
});

return new Promise((resolve, reject) => {
let tileLoadTimer = null;

const clearChecks = () => {
clearTimeout(tileLoadTimer);
map.off('dataloading');
};

tileLoadTimer = setTimeout(() => {
if (!tileLoad) {
reject(new Error(`Tiles from "${url}" could not be loaded`));
} else {
resolve();
}
clearChecks();
}, TMS_LOAD_TIMEOUT);
});
}

async syncData({ startLoading, stopLoading, onLoadError, dataFilters }) {
if (!this.isVisible() || !this.showAtZoomLevel(dataFilters.zoom)) {
return;
Expand All @@ -79,41 +45,37 @@ export class TileLayer extends AbstractLayer {
}
}

async syncLayerWithMB(mbMap) {
syncLayerWithMB(mbMap) {

const source = mbMap.getSource(this.getId());
const mbLayerId = this.getId() + '_raster';

if (source) {
// If source exists, just sync style
this._setTileLayerProperties(mbMap, mbLayerId);
return;
}
if (!source) {
const sourceDataRquest = this.getSourceDataRequest();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: sourceDataRquest -> sourceDataRequest

const url = sourceDataRquest.getData();
if (!url) {
return;
}

const sourceDataRquest = this.getSourceDataRequest();
const url = sourceDataRquest.getData();
if (!url) {
const sourceId = this.getId();
mbMap.addSource(sourceId, {
type: 'raster',
tiles: [url],
tileSize: 256,
scheme: 'xyz',
});

mbMap.addLayer({
id: mbLayerId,
type: 'raster',
source: sourceId,
minzoom: this._descriptor.minZoom,
maxzoom: this._descriptor.maxZoom,
});
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Good call returning before a needless call to set layer props

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, that's actually a bug...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol. I was actually just staring at it coming to the same conclusion. we would be doing an extra call to set zoom but alpha isn't covered. there might be a better way to dice those up but a redundant zoom set isn't the end of the world

}

const sourceId = this.getId();
mbMap.addSource(sourceId, {
type: 'raster',
tiles: [url],
tileSize: 256,
scheme: 'xyz',
});

mbMap.addLayer({
id: mbLayerId,
type: 'raster',
source: sourceId,
minzoom: this._descriptor.minZoom,
maxzoom: this._descriptor.maxZoom,
});
this._setTileLayerProperties(mbMap, mbLayerId);

await this._tileLoadErrorTracker(mbMap, url);
}

_setTileLayerProperties(mbMap, mbLayerId) {
Expand Down
24 changes: 11 additions & 13 deletions x-pack/plugins/maps/public/store/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ const INITIAL_STATE = {
};

export function map(state = INITIAL_STATE, action) {
window._state = state;
//todo throw actions with actual objects so this doesn't get so cluttered
switch (action.type) {
case SET_MOUSE_COORDINATES:
return {
Expand Down Expand Up @@ -251,19 +249,19 @@ export function map(state = INITIAL_STATE, action) {
const styleLayerId = action.layerId;
const styleLayerIdx = getLayerIndex(state.layerList, styleLayerId);
const layerStyle = state.layerList[styleLayerIdx].style;
const layerPrevStyle = layerStyle.previousStyle || layerStyle;
const layerPrevStyle = layerStyle.__previousStyle || layerStyle;
return updateLayerInList(state, styleLayerId, 'style',
{ ...action.style, previousStyle: { ...layerPrevStyle } });
{ ...action.style, __previousStyle: { ...layerPrevStyle } });
case PROMOTE_TEMPORARY_STYLES:
const stylePromoteIdx = getLayerIndex(state.layerList, state.selectedLayerId);
const styleToSet = {
...state.layerList[stylePromoteIdx].style,
previousStyle: null
__previousStyle: null
};
return updateLayerInList(state, state.selectedLayerId, 'style', styleToSet);
case CLEAR_TEMPORARY_STYLES:
const styleClearIdx = getLayerIndex(state.layerList, state.selectedLayerId);
const prevStyleToLoad = state.layerList[styleClearIdx].style.previousStyle || state.layerList[styleClearIdx].style || {};
const prevStyleToLoad = state.layerList[styleClearIdx].style.__previousStyle || state.layerList[styleClearIdx].style || {};
return updateLayerInList(state, state.selectedLayerId, 'style', prevStyleToLoad);
default:
return state;
Expand All @@ -274,18 +272,18 @@ function setErrorStatus(state, { layerId, errorMessage }) {
const tmsErrorLayer = state.layerList.find(({ id }) => id === layerId);
return tmsErrorLayer
? updateLayerInList(
updateLayerInList(state, tmsErrorLayer.id, 'isInErrorState', true),
tmsErrorLayer.id, 'errorMessage', errorMessage)
updateLayerInList(state, tmsErrorLayer.id, '__isInErrorState', true),
tmsErrorLayer.id, '__errorMessage', errorMessage)
: state;
}

function findDataRequest(layerDescriptor, dataRequestAction) {

if (!layerDescriptor.dataRequests) {
if (!layerDescriptor.__dataRequests) {
return;
}

return layerDescriptor.dataRequests.find(dataRequest => {
return layerDescriptor.__dataRequests.find(dataRequest => {
return dataRequest.dataId === dataRequestAction.dataId;
});
}
Expand All @@ -299,9 +297,9 @@ function updateWithDataRequest(state, action) {
dataRequest = {
dataId: action.dataId
};
layerRequestingData.dataRequests = [
...(layerRequestingData.dataRequests
? layerRequestingData.dataRequests : []), dataRequest ];
layerRequestingData.__dataRequests = [
...(layerRequestingData.__dataRequests
? layerRequestingData.__dataRequests : []), dataRequest ];
}
dataRequest.dataMetaAtStart = action.meta;
dataRequest.dataRequestToken = action.requestToken;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"title":"Italy Map",
"description":"",
"mapStateJSON":"{\"zoom\":4.82,\"center\":{\"lon\":11.41545,\"lat\":42.0865},\"timeFilters\":{\"from\":\"now-15w\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":false,\"interval\":0},\"query\":{\"language\":\"lucene\",\"query\":\"\"}}",
"layerListJSON":"[{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"temporary\":false,\"id\":\"csq5v\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.65,\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{},\"previousStyle\":null},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"EMS_FILE\",\"id\":\"italy_provinces\"},\"temporary\":false,\"id\":\"0oye8\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#0c1f70\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"id\":\"053fe296-f5ae-4cb0-9e73-a5752cb9ba74\",\"indexPatternId\":\"d3d7af60-4c81-11e8-b3d7-01146121b73d\",\"geoField\":\"DestLocation\",\"requestType\":\"point\",\"resolution\":\"COARSE\"},\"temporary\":false,\"id\":\"1gx22\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"color\":\"Greens\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"minSize\":4,\"maxSize\":32}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\"}]",
"layerListJSON":"[{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"temporary\":false,\"id\":\"csq5v\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.65,\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"EMS_FILE\",\"id\":\"italy_provinces\"},\"temporary\":false,\"id\":\"0oye8\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#0c1f70\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"type\":\"ES_GEO_GRID\",\"id\":\"053fe296-f5ae-4cb0-9e73-a5752cb9ba74\",\"indexPatternId\":\"d3d7af60-4c81-11e8-b3d7-01146121b73d\",\"geoField\":\"DestLocation\",\"requestType\":\"point\",\"resolution\":\"COARSE\"},\"temporary\":false,\"id\":\"1gx22\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"color\":\"Greens\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"DYNAMIC\",\"options\":{\"field\":{\"label\":\"Count\",\"name\":\"doc_count\",\"origin\":\"source\"},\"minSize\":4,\"maxSize\":32}}},\"temporary\":true},\"type\":\"VECTOR\"}]",
"uiStateJSON":"{}",
"bounds":{
"type":"polygon",
Expand Down Expand Up @@ -53,7 +53,7 @@
"title":"France Map",
"description":"",
"mapStateJSON":"{\"zoom\":3.43,\"center\":{\"lon\":-16.30411,\"lat\":42.88411},\"timeFilters\":{\"from\":\"now-15w\",\"to\":\"now\"},\"refreshConfig\":{\"isPaused\":false,\"interval\":0},\"query\":{\"query\":\"\",\"language\":\"lucene\"}}",
"layerListJSON":"[{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"temporary\":false,\"id\":\"csq5v\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.65,\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{},\"previousStyle\":null},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"EMS_FILE\",\"id\":\"france_departments\"},\"temporary\":false,\"id\":\"65xbw\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.25,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#19c1e6\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"id\":\"240125db-e612-4001-b853-50107e55d984\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"ff959d40-b880-11e8-a6d9-e546fe2bba5f\",\"geoField\":\"geoip.location\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[]},\"temporary\":false,\"id\":\"mdae9\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#1ce619\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\"}]",
"layerListJSON":"[{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"temporary\":false,\"id\":\"csq5v\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.65,\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"EMS_FILE\",\"id\":\"france_departments\"},\"temporary\":false,\"id\":\"65xbw\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.25,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#19c1e6\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true},\"type\":\"VECTOR\"},{\"sourceDescriptor\":{\"id\":\"240125db-e612-4001-b853-50107e55d984\",\"type\":\"ES_SEARCH\",\"indexPatternId\":\"ff959d40-b880-11e8-a6d9-e546fe2bba5f\",\"geoField\":\"geoip.location\",\"limit\":2048,\"filterByMapBounds\":true,\"tooltipProperties\":[]},\"temporary\":false,\"id\":\"mdae9\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#1ce619\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true},\"type\":\"VECTOR\"}]",
"uiStateJSON":"{}",
"bounds":{
"type":"polygon",
Expand Down Expand Up @@ -96,7 +96,7 @@
"title":"Canada Map",
"description":"",
"mapStateJSON":"{\"zoom\":2.12,\"center\":{\"lon\":-88.67592,\"lat\":34.23257},\"timeFilters\":{\"from\":\"now-15m\",\"to\":\"now\",\"mode\":\"quick\"},\"refreshConfig\":{\"isPaused\":false,\"interval\":0},\"query\":{\"query\":\"\",\"language\":\"lucene\"}}",
"layerListJSON":"[{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"temporary\":false,\"id\":\"csq5v\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.65,\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{},\"previousStyle\":null},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"EMS_FILE\",\"id\":\"canada_provinces\"},\"temporary\":false,\"id\":\"kt086\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#60895e\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true,\"previousStyle\":null},\"type\":\"VECTOR\"}]",
"layerListJSON":"[{\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"temporary\":false,\"id\":\"csq5v\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.65,\"visible\":true,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"TILE\"},{\"sourceDescriptor\":{\"type\":\"EMS_FILE\",\"id\":\"canada_provinces\"},\"temporary\":false,\"id\":\"kt086\",\"label\":null,\"minZoom\":0,\"maxZoom\":24,\"alpha\":0.75,\"visible\":true,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#60895e\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}}},\"temporary\":true},\"type\":\"VECTOR\"}]",
"uiStateJSON":"{}",
"bounds":{
"type":"polygon",
Expand Down Expand Up @@ -133,4 +133,4 @@
"version":1
}
]
}
}
Loading