mirror of
https://github.com/valitydev/redash.git
synced 2024-11-07 01:25:16 +00:00
- cache GeoJSON to avoid multiple HTTP requests; - allow to edit map bounds; - optimize update map calls (do not re-render it every time); - UI/X imporvements.
This commit is contained in:
parent
517f95fa01
commit
6a61057813
@ -6,6 +6,9 @@
|
||||
<li ng-class="{active: currentTab == 'colors'}">
|
||||
<a ng-click="changeTab('colors')">Colors</a>
|
||||
</li>
|
||||
<li ng-class="{active: currentTab == 'bounds'}">
|
||||
<a ng-click="changeTab('bounds')">Bounds</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div ng-if="currentTab == 'general'" class="m-t-10 m-b-10">
|
||||
<div class="row">
|
||||
@ -215,4 +218,34 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="currentTab == 'bounds'" class="m-t-10 m-b-10">
|
||||
<div class="form-group">
|
||||
<label>North-East latitude and longitude</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<input class="form-control" type="text"
|
||||
ng-model="options.bounds[1][0]" ng-model-options="{ allowInvalid: true, debounce: 200 }">
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<input class="form-control" type="text"
|
||||
ng-model="options.bounds[1][1]" ng-model-options="{ allowInvalid: true, debounce: 200 }">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>South-West latitude and longitude</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<input class="form-control" type="text"
|
||||
ng-model="options.bounds[0][0]" ng-model-options="{ allowInvalid: true, debounce: 200 }">
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<input class="form-control" type="text"
|
||||
ng-model="options.bounds[0][1]" ng-model-options="{ allowInvalid: true, debounce: 200 }">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -20,6 +20,13 @@ import editorTemplate from './choropleth-editor.html';
|
||||
|
||||
import countriesDataUrl from './countries.geo.json';
|
||||
|
||||
const loadCountriesData = _.bind(function loadCountriesData($http, url) {
|
||||
if (!this[url]) {
|
||||
this[url] = $http.get(url).then(response => response.data);
|
||||
}
|
||||
return this[url];
|
||||
}, {});
|
||||
|
||||
function choroplethRenderer($sanitize, $http) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
@ -29,15 +36,40 @@ function choroplethRenderer($sanitize, $http) {
|
||||
options: '=?',
|
||||
},
|
||||
link($scope, $element) {
|
||||
let countriesData;
|
||||
let map;
|
||||
let choropleth;
|
||||
let countriesData = null;
|
||||
let map = null;
|
||||
let choropleth = null;
|
||||
let updateBoundsLock = false;
|
||||
|
||||
function getBounds() {
|
||||
if (!updateBoundsLock) {
|
||||
const bounds = map.getBounds();
|
||||
$scope.options.bounds = [
|
||||
[bounds._southWest.lat, bounds._southWest.lng],
|
||||
[bounds._northEast.lat, bounds._northEast.lng],
|
||||
];
|
||||
$scope.$applyAsync();
|
||||
}
|
||||
}
|
||||
|
||||
function setBounds({ disableAnimation = false } = {}) {
|
||||
if (map && choropleth) {
|
||||
const bounds = $scope.options.bounds || choropleth.getBounds();
|
||||
const options = disableAnimation ? {
|
||||
animate: false,
|
||||
duration: 0,
|
||||
} : null;
|
||||
map.fitBounds(bounds, options);
|
||||
}
|
||||
}
|
||||
|
||||
function render() {
|
||||
if (map) {
|
||||
map.remove();
|
||||
map = null;
|
||||
choropleth = null;
|
||||
}
|
||||
if (!_.isObject(countriesData)) {
|
||||
if (!countriesData) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -114,32 +146,43 @@ function choroplethRenderer($sanitize, $http) {
|
||||
map = L.map($element[0].children[0].children[0], {
|
||||
center: choroplethBounds.getCenter(),
|
||||
zoom: 1,
|
||||
zoomSnap: 0,
|
||||
layers: [choropleth],
|
||||
scrollWheelZoom: false,
|
||||
maxBounds: choroplethBounds,
|
||||
maxBoundsViscosity: 1,
|
||||
attributionControl: false,
|
||||
});
|
||||
|
||||
map.on('focus', () => { map.on('moveend', getBounds); });
|
||||
map.on('blur', () => { map.off('moveend', getBounds); });
|
||||
|
||||
setBounds({ disableAnimation: true });
|
||||
}
|
||||
|
||||
function resize() {
|
||||
if (map) {
|
||||
map.invalidateSize(false);
|
||||
map.fitBounds(choropleth.getBounds());
|
||||
loadCountriesData($http, countriesDataUrl).then((data) => {
|
||||
if (_.isObject(data)) {
|
||||
countriesData = data;
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.handleResize = () => {
|
||||
resize();
|
||||
};
|
||||
|
||||
$http.get(countriesDataUrl).then((response) => {
|
||||
countriesData = response.data;
|
||||
render();
|
||||
});
|
||||
|
||||
$scope.handleResize = _.debounce(() => {
|
||||
if (map) {
|
||||
map.invalidateSize(false);
|
||||
setBounds({ disableAnimation: true });
|
||||
}
|
||||
}, 50);
|
||||
|
||||
$scope.$watch('queryResult && queryResult.getData()', render);
|
||||
$scope.$watch('options', render, true);
|
||||
$scope.$watch(() => _.omit($scope.options, 'bounds'), render, true);
|
||||
$scope.$watch('options.bounds', () => {
|
||||
// Prevent infinite digest loop
|
||||
const savedLock = updateBoundsLock;
|
||||
updateBoundsLock = true;
|
||||
setBounds();
|
||||
updateBoundsLock = savedLock;
|
||||
}, true);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user