gethue
Version:
Hue is an Open source SQL Query Editor for Databases/Warehouses
327 lines (295 loc) • 11.2 kB
JavaScript
// Licensed to Cloudera, Inc. under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. Cloudera, Inc. licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import $ from 'jquery';
import * as ko from 'knockout';
import 'ext/leaflet/leaflet';
import 'ext/leaflet/leaflet.markercluster';
import 'ext/leaflet/leaflet.heat';
import 'ext/leaflet/leaflet.zoombox';
import huePubSub from '../../../utils/huePubSub';
ko.bindingHandlers.leafletMapChart = {
update: function (element, valueAccessor) {
const L = window.L;
const _options = valueAccessor();
const _data = _options.transformer(valueAccessor().datum);
function toggleVisibility() {
if (
!_data.message &&
((_options.visible != null && _options.visible) ||
_options.visible == null ||
typeof _options == 'undefined')
) {
$(element).show();
$(element).siblings('.leaflet-nodata').remove();
} else {
$(element).hide();
if (
(_data.message || (_options.visible != null && _options.visible)) &&
!_options.isLoading
) {
$(element).siblings('.leaflet-nodata').remove();
$(element).before(
$('<div>')
.addClass('leaflet-nodata')
.css({ textAlign: 'center', fontSize: '18px', fontWeight: 700, marginTop: '20px' })
.text(_data.message || window.I18n('No Data Available.'))
);
}
}
}
if (
$(element).data('mapData') == null ||
$(element).data('mapData') !== ko.toJSON(_data) ||
_options.forceRedraw
) {
$(element).data('mapData', ko.toJSON(_data));
let _hasAtLeastOneLat = false;
_data.forEach(item => {
if (item.lat != null && $.isNumeric(item.lat)) {
_hasAtLeastOneLat = true;
}
});
let _hasAtLeastOneLng = false;
_data.forEach(item => {
if (item.lng != null && $.isNumeric(item.lng)) {
_hasAtLeastOneLng = true;
}
});
if (_options.height != null) {
$(element).height(_options.height * 1);
} else if ($(element).parents('.tab-pane').length > 0) {
$(element).height($(element).parents('.tab-pane').height() - 100);
} else {
$(element).height(300);
}
toggleVisibility();
let _map = null;
if ($(element).data('_map') != null) {
_map = $(element).data('_map');
_map.removeLayer($(element).data('_markerLayer'));
if ($(element).data('_heatLayer')) {
_map.removeLayer($(element).data('_heatLayer'));
$(element).data('_heatLayer', null);
}
}
const _clusterGroup = L.markerClusterGroup({
maxClusterRadius: 10,
polygonOptions: {
weight: 1.5
}
});
let heat;
if (_hasAtLeastOneLat && _hasAtLeastOneLng) {
try {
if (_map == null) {
if (window.LEAFLET_DEFAULTS.mapOptions.crs) {
window.LEAFLET_DEFAULTS.mapOptions.crs =
L.CRS[window.LEAFLET_DEFAULTS.mapOptions.crs];
}
_map = L.map(element, window.LEAFLET_DEFAULTS.mapOptions);
let tileLayerOptions = {
layer: 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
attribution:
'© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
};
if (window.LEAFLET_DEFAULTS.layer) {
tileLayerOptions.layer = window.LEAFLET_DEFAULTS.layer;
}
if (window.LEAFLET_DEFAULTS.attribution) {
tileLayerOptions.attribution = window.LEAFLET_DEFAULTS.attribution;
}
if (window.LEAFLET_DEFAULTS.layerOptions) {
tileLayerOptions = $.extend(tileLayerOptions, window.LEAFLET_DEFAULTS.layerOptions);
}
L.tileLayer(tileLayerOptions.layer, tileLayerOptions).addTo(_map);
if (L.control.zoomBox) {
const _zoomBox = L.control.zoomBox({
modal: true
});
_map.addControl(_zoomBox);
}
if (_options.showMoveCheckbox) {
const _command = L.control({
position: $(element).width() > 300 ? 'topright' : 'bottomleft'
});
_command.onAdd = function (map) {
const div = L.DomUtil.create(
'div',
'leaflet-search-command leaflet-bar leaflet-move-label'
);
div.innerHTML =
'<button id="command' +
$(element).parents('.card-widget').attr('id') +
'" type="button" class="btn btn-mini disable-feedback"><i class="fa fa-fw fa-square-o"></i> ' +
(_options.moveCheckboxLabel
? _options.moveCheckboxLabel
: 'Search as I move the map') +
'</button>';
return div;
};
_command.addTo(_map);
if (_options.onRegionChange == null) {
_options.onRegionChange = function () {};
}
let _onRegionChange = function () {};
$('#command' + $(element).parents('.card-widget').attr('id')).on(
'click',
function (e) {
$(this).toggleClass('btn-primary');
$(this).find('.fa-fw').toggleClass('fa-check-square');
if ($(this).hasClass('btn-primary')) {
if (_options.onRegionChange != null) {
_onRegionChange = _options.onRegionChange;
}
} else {
_onRegionChange = function () {};
}
}
);
ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
$('#command' + $(element).parents('.card-widget').attr('id')).off('click');
});
_map.on('boxzoomend', e => {
_onRegionChange(e.boxZoomBounds);
});
_map.on('dragend', () => {
_onRegionChange(_map.getBounds());
});
_map.on('zoomend', () => {
_onRegionChange(_map.getBounds());
});
_map.on('viewreset', () => {
huePubSub.publish('leaflet.afterplot', element);
});
}
}
let heatData = [];
const sumHeatData = data => {
const sumData = [];
data.forEach(d => {
let found = false;
if (d.length === 3) {
sumData.forEach(s => {
if (d[0] === s[0] && d[1] === s[1]) {
found = true;
s[2] += d[2];
}
});
}
if (!found) {
sumData.push(d);
}
});
return sumData;
};
const getMaxIntensity = data => {
let maxIntensity = 0;
data.forEach(d => {
if (d[2] > maxIntensity) {
maxIntensity = d[2];
}
});
return maxIntensity;
};
_data.forEach(item => {
if (item && item.lng != null && item.lat != null) {
let _addMarker = false;
try {
const _latLngObj = L.latLng(item.lat, item.lng);
_addMarker = true;
} catch (e) {
if (typeof console != 'undefined') {
console.error(e);
}
}
if (_addMarker) {
const _marker = L.marker([item.lat, item.lng]);
if (item.isHeat) {
if (item.intensity != null) {
heatData.push([item.lat, item.lng, item.intensity]);
} else {
heatData.push([item.lat, item.lng]);
}
} else if (item.label != null) {
_marker.bindPopup($.isArray(item.label) ? item.label.join('') : item.label);
}
_clusterGroup.addLayer(_marker);
}
}
});
if (heatData.length > 0) {
heatData = sumHeatData(heatData);
heat = L.heatLayer(heatData);
if (heatData[0].length === 3) {
// it has intensity
heat.setOptions(getMaxIntensity(heatData));
}
}
window.setTimeout(() => {
if (!$('#command' + $(element).parents('.card-widget').attr('id')).is(':checked')) {
_map.fitBounds(_clusterGroup.getBounds());
}
if ($(element).find('.leaflet-tile-pane').children().length > 0) {
if (heatData.length == 0) {
_map.addLayer(_clusterGroup);
$('.leaflet-heatmap-layer').remove();
} else {
try {
$('.leaflet-heatmap-layer').remove();
heat.addTo(_map);
} catch (e) {} // context2D not initialized yet
}
}
if (_options.onComplete != null) {
_options.onComplete();
}
}, 0);
const resizeSubscription = huePubSub.subscribe('resize.leaflet.map', () => {
if ($(element).data('_map')) {
$(element).data('_map').invalidateSize();
if ($(element).data('_markerLayer')) {
try {
$(element).data('_map').fitBounds($(element).data('_markerLayer').getBounds());
} catch (e) {}
}
}
});
ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
resizeSubscription.remove();
});
} catch (err) {
$.jHueNotify.error(err.message);
}
}
const previousMarkerLayer = $(element).data('_markerLayer');
if (previousMarkerLayer) {
window.setTimeout(() => {
try {
previousMarkerLayer.removeLayers(previousMarkerLayer.getLayers());
} catch (e) {}
}, 0);
}
$(element).data('_map', _map);
$(element).data('_markerLayer', _clusterGroup);
$(element).data('_heatLayer', heat);
if (_options.onComplete != null) {
_options.onComplete();
}
} else {
toggleVisibility();
}
}
};