gethue
Version:
Hue is an Open source SQL Query Editor for Databases/Warehouses
350 lines (322 loc) • 11.6 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 nv from '../../../../ext/nv.d3.1.1.15b.custom';
import Datamap from './datamap';
import huePubSub from '../../../../utils/huePubSub';
import HueColors from '../../../../utils/hueColors';
import HueGeo from '../../../../utils/hueGeo';
ko.bindingHandlers.mapChart = {
render: function (element, valueAccessor) {
const _options = valueAccessor();
const $element = $(element);
window.clearTimeout($element.data('drawThrottle'));
const timeout = window.setTimeout(() => {
$element.empty();
$element.css('position', 'relative');
$element.css('marginLeft', 'auto');
$element.css('marginRight', 'auto');
if (typeof _options.maxWidth != 'undefined') {
const _max = _options.maxWidth * 1;
$element.width(Math.min($element.parent().width(), _max));
} else {
$element.width($element.parent().width() - 10);
}
$element.height($element.width() / 2.23);
const scopeObservable = _options.data.scope || _options.data.chartScope;
const _scope = scopeObservable ? String(ko.unwrap(scopeObservable)) : 'world';
const _data = _options.transformer(_options.data);
let _is2d = false;
const _pivotCategories = [];
let _maxWeight = 0;
function comparePivotValues(a, b) {
if (a.count < b.count) {
return 1;
}
if (a.count > b.count) {
return -1;
}
return 0;
}
$(_data).each((cnt, item) => {
if (item.value > _maxWeight) {
_maxWeight = item.value;
}
if (item.obj.is2d) {
_is2d = true;
}
if (item.obj.pivot && item.obj.pivot.length > 0) {
item.obj.pivot.forEach(piv => {
let _category = null;
_pivotCategories.forEach(category => {
if (category.value === piv.value) {
_category = category;
if (piv.count > _category.count) {
_category.count = piv.count;
}
}
});
if (_category == null) {
_category = {
value: piv.value,
count: -1
};
_pivotCategories.push(_category);
}
});
}
});
_pivotCategories.sort(comparePivotValues);
const _chunk = _maxWeight / _data.length;
const _mapdata = {};
const _maphovers = {};
const _fills = {};
const _legend = [];
const _noncountries = [];
if (_options.isScale) {
_fills['defaultFill'] = HueColors.WHITE;
const _colors = _is2d
? HueColors.d3Scale()
: HueColors.scale(HueColors.LIGHT_BLUE, HueColors.DARK_BLUE, _data.length);
$(_colors).each((cnt, item) => {
_fills['fill_' + cnt] = item;
});
const getHighestCategoryValue = (cnt, item) => {
let _cat = '';
let _max = -1;
if (item.obj.pivot && item.obj.pivot.length > 0) {
item.obj.pivot.forEach(piv => {
if (piv.count > _max) {
_max = piv.count;
_cat = piv.value;
}
});
}
let _found = cnt;
if (_cat !== '') {
_pivotCategories.forEach((cat, i) => {
if (cat.value === _cat) {
_found = i;
}
});
}
return {
idx: _found,
cat: _cat
};
};
const addToLegend = category => {
let _found = false;
_legend.forEach(lg => {
if (lg.cat === category.cat) {
_found = true;
}
});
if (!_found) {
_legend.push(category);
}
};
$(_data).each((cnt, item) => {
addToLegend(getHighestCategoryValue(cnt, item));
let _place = typeof item.label == 'string' ? item.label.toUpperCase() : item.label;
if (_place != null) {
if (
_scope !== 'world' &&
_scope !== 'usa' &&
_scope !== 'europe' &&
_place.indexOf('.') === -1
) {
_place = HueGeo.getISOAlpha2(_scope) + '.' + _place;
}
if ((_scope === 'world' || _scope === 'europe') && _place.length === 2) {
_place = HueGeo.getISOAlpha3(_place);
}
_mapdata[_place] = {
fillKey:
'fill_' +
(_is2d
? getHighestCategoryValue(cnt, item).idx
: Math.ceil(item.value / _chunk) - 1),
id: _place,
cat: item.obj.cat,
value: item.obj.values ? item.obj.values : item.obj.value,
pivot: _is2d ? item.obj.pivot : [],
selected: item.obj.selected,
fields: item.obj.fields ? item.obj.fields : null
};
_maphovers[_place] = item.value;
} else {
_noncountries.push(item);
}
});
} else {
_fills['defaultFill'] = HueColors.LIGHT_BLUE;
_fills['selected'] = HueColors.DARK_BLUE;
$(_data).each((cnt, item) => {
let _place = item.label.toUpperCase();
if (_place != null) {
if (
_scope !== 'world' &&
_scope !== 'usa' &&
_scope !== 'europe' &&
_place.indexOf('.') === -1
) {
_place = HueGeo.getISOAlpha2(_scope) + '.' + _place;
}
if ((_scope === 'world' || _scope === 'europe') && _place.length === 2) {
_place = HueGeo.getISOAlpha3(_place);
}
_mapdata[_place] = {
fillKey: 'selected',
id: _place,
cat: item.obj.cat,
value: item.obj.values ? item.obj.values : item.obj.value,
pivot: [],
selected: item.obj.selected,
fields: item.obj.fields ? item.obj.fields : null
};
_maphovers[_place] = item.value;
} else {
_noncountries.push(item);
}
});
}
let _map = null;
function createDatamap(element, options, fills, mapData, nonCountries, mapHovers) {
_map = new Datamap({
element: element,
fills: fills,
scope: _scope,
data: mapData,
legendData: _legend,
onClick: function (data) {
if (typeof options.onClick != 'undefined') {
huePubSub.publish('charts.state', { updating: true });
options.onClick(data);
}
},
done: function () {
const _bubbles = [];
if (options.enableGeocoding) {
$(nonCountries).each((cnt, item) => {
HueGeo.getCityCoordinates(item.label, (lat, lng) => {
_bubbles.push({
fillKey: 'selected',
label: item.label,
value: item.value,
radius: 4,
latitude: lat,
longitude: lng
});
_map.bubbles(_bubbles, {
popupTemplate: function (geo, data) {
return (
'<div class="hoverinfo" style="text-align: center"><strong>' +
data.label +
'</strong><br/>' +
item.value +
'</div>'
);
}
});
});
});
}
},
geographyConfig: {
hideAntarctica: true,
borderWidth: 1,
borderColor: HueColors.DARK_BLUE,
highlightOnHover: true,
highlightFillColor: HueColors.DARK_BLUE,
highlightBorderColor: HueColors.BLUE,
selectedFillColor: HueColors.DARKER_BLUE,
selectedBorderColor: HueColors.DARKER_BLUE,
popupTemplate: function (geography, data) {
let _hover = '';
if (data != null) {
_hover = '<br/>';
if (data.pivot && data.pivot.length > 0) {
data.pivot.sort(comparePivotValues);
data.pivot.forEach((piv, cnt) => {
_hover +=
(cnt === 0 ? '<strong>' : '') +
piv.value +
': ' +
piv.count +
(cnt === 0 ? '</strong>' : '') +
'<br/>';
});
} else {
_hover += mapHovers[data.id];
}
}
return (
'<div class="hoverinfo" style="text-align: center"><strong>' +
geography.properties.name +
'</strong>' +
_hover +
'</div>'
);
}
}
});
if (options.onComplete != null) {
options.onComplete();
}
if (_is2d) {
_map.legend();
}
}
createDatamap(element, _options, _fills, _mapdata, _noncountries, _maphovers);
const _parentSelector =
typeof _options.parentSelector != 'undefined' ? _options.parentSelector : '.card-widget';
$element.parents(_parentSelector).one('resize', () => {
ko.bindingHandlers.mapChart.render(element, valueAccessor);
});
let _resizeTimeout = -1;
nv.utils.windowResize(() => {
window.clearTimeout(_resizeTimeout);
_resizeTimeout = window.setTimeout(() => {
ko.bindingHandlers.mapChart.render(element, valueAccessor);
}, 200);
});
huePubSub.publish('charts.state');
}, 50);
$element.data('drawThrottle', timeout);
},
init: function (element, valueAccessor) {
ko.bindingHandlers.mapChart.render(element, valueAccessor);
},
update: function (element, valueAccessor, allBindingsAccessor) {
if (typeof allBindingsAccessor().mapChart.visible != 'undefined') {
if (
(typeof allBindingsAccessor().mapChart.visible == 'boolean' &&
allBindingsAccessor().mapChart.visible) ||
(typeof allBindingsAccessor().mapChart.visible == 'function' &&
allBindingsAccessor().mapChart.visible())
) {
$(element).show();
ko.bindingHandlers.mapChart.render(element, valueAccessor);
} else {
$(element).hide();
}
} else {
ko.bindingHandlers.mapChart.render(element, valueAccessor);
}
}
};