UNPKG

@progress/kendo-ui

Version:

This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.

1,046 lines (837 loc) 31.2 kB
import './kendo.data.js'; import './kendo.userevents.js'; import './kendo.dataviz.themes.js'; import './kendo.core.js'; import './kendo.licensing.js'; import '@progress/kendo-licensing'; import './kendo.data.odata.js'; import './kendo.data.xml.js'; import './kendo.dataviz.core.js'; import '@progress/kendo-charts/dist/es/core-export.js'; import './html-DIrOxn6k.js'; import './kendo.popup.js'; import './kendo.icons.js'; import './kendo.html.icon.js'; import './kendo.html.base.js'; import '@progress/kendo-svg-icons'; import '@progress/kendo-drawing'; import './kendo.color.js'; import '@progress/kendo-charts'; const __meta__ = { id: "dataviz.treeMap", name: "TreeMap", category: "dataviz", description: "The Kendo DataViz TreeMap", depends: [ "data", "userevents", "dataviz.themes" ] }; (function($, undefined$1) { var math = Math, isArray = Array.isArray, kendo = window.kendo, outerHeight = kendo._outerHeight, outerWidth = kendo._outerWidth, Class = kendo.Class, Widget = kendo.ui.Widget, template = kendo.template, deepExtend = kendo.deepExtend, HierarchicalDataSource = kendo.data.HierarchicalDataSource, getter = kendo.getter, dataviz = kendo.dataviz; var NS = ".kendoTreeMap", CHANGE = "change", DATA_BOUND = "dataBound", ITEM_CREATED = "itemCreated", MAX_VALUE = Number.MAX_VALUE, MOUSEOVER_NS = "mouseover" + NS, MOUSELEAVE_NS = "mouseleave" + NS, UNDEFINED = "undefined"; var TreeMap = Widget.extend({ init: function(element, options) { kendo.destroy(element); $(element).empty(); Widget.fn.init.call(this, element, options); this.wrapper = this.element; this._initTheme(this.options); this.element.addClass("k-widget k-treemap"); this._setLayout(); this._originalOptions = deepExtend({}, this.options); this._initDataSource(); this._attachEvents(); kendo.notify(this, dataviz.ui); }, options: { name: "TreeMap", theme: "sass", autoBind: true, textField: "text", valueField: "value", colorField: "color" }, events: [DATA_BOUND, ITEM_CREATED], _initTheme: function(options) { var that = this, themes = dataviz.ui.themes || {}, themeName = ((options || {}).theme || "").toLowerCase(), themeOptions = (themes[themeName] || {}).treeMap; that.options = deepExtend({}, themeOptions, options); }, _attachEvents: function() { this.element .on(MOUSEOVER_NS, this._mouseover.bind(this)) .on(MOUSELEAVE_NS, this._mouseleave.bind(this)); this._resizeHandler = this.resize.bind(this, false); kendo.onResize(this._resizeHandler); }, _setLayout: function() { if (this.options.type === "horizontal") { this._layout = new SliceAndDice(false); this._view = new SliceAndDiceView(this, this.options); } else if (this.options.type === "vertical") { this._layout = new SliceAndDice(true); this._view = new SliceAndDiceView(this, this.options); } else { this._layout = new Squarified(); this._view = new SquarifiedView(this, this.options); } }, _initDataSource: function() { var that = this, options = that.options, dataSource = options.dataSource; that._dataChangeHandler = that._onDataChange.bind(that); that.dataSource = HierarchicalDataSource .create(dataSource) .bind(CHANGE, that._dataChangeHandler); if (dataSource) { if (that.options.autoBind) { that.dataSource.fetch(); } } }, setDataSource: function(dataSource) { var that = this; that.dataSource.unbind(CHANGE, that._dataChangeHandler); that.dataSource = dataSource .bind(CHANGE, that._dataChangeHandler); if (dataSource) { if (that.options.autoBind) { that.dataSource.fetch(); } } }, _onDataChange: function(e) { var node = e.node; var items = e.items; var options = this.options; var item, i; if (!node) { this.element.empty(); item = this._wrapItem(items[0]); this._layout.createRoot( item, outerWidth(this.element), outerHeight(this.element), this.options.type === "vertical" ); this._view.createRoot(item); // Reference of the root this._root = item; this._colorIdx = 0; } else { if (items.length) { var root = this._getByUid(node.uid); root.children = []; items = new kendo.data.Query(items)._sortForGrouping(options.valueField, "desc"); for (i = 0; i < items.length; i++) { item = items[i]; root.children.push(this._wrapItem(item)); } var htmlSize = this._view.htmlSize(root); this._layout.compute(root.children, root.coord, htmlSize); this._setColors(root.children); this._view.render(root); } } for (i = 0; i < items.length; i++) { items[i].load(); } if (node) { this.trigger(DATA_BOUND, { node: node }); } }, _setColors: function(items) { var colors = this.options.colors; var colorIdx = this._colorIdx; var color = colors[colorIdx % colors.length]; var colorRange, item; if (isArray(color)) { colorRange = colorsByLength(color[0], color[1], items.length); } var leafNodes = false; for (var i = 0; i < items.length; i++) { item = items[i]; if (!defined(item.color)) { if (colorRange) { item.color = colorRange[i]; } else { item.color = color; } } if (!item.dataItem.hasChildren) { leafNodes = true; } } if (leafNodes) { this._colorIdx++; } }, _contentSize: function(root) { this.view.renderHeight(root); }, _wrapItem: function(item) { var wrap = {}; if (defined(this.options.valueField)) { wrap.value = getField(this.options.valueField, item); } if (defined(this.options.colorField)) { wrap.color = getField(this.options.colorField, item); } if (defined(this.options.textField)) { wrap.text = getField(this.options.textField, item); } wrap.level = item.level(); wrap.dataItem = item; return wrap; }, _getByUid: function(uid) { var items = [this._root]; var item; while (items.length) { item = items.pop(); if (item.dataItem.uid === uid) { return item; } if (item.children) { items = items.concat(item.children); } } }, dataItem: function(node) { var uid = $(node).attr(kendo.attr("uid")), dataSource = this.dataSource; return dataSource && dataSource.getByUid(uid); }, findByUid: function(uid) { return this.element.find(".k-treemap-tile[" + kendo.attr("uid") + "='" + uid + "']"); }, _mouseover: function(e) { var target = $(e.target); if (target.hasClass("k-leaf")) { this._removeActiveState(); target .removeClass("k-hover") .addClass("k-hover"); } }, _removeActiveState: function() { this.element .find(".k-hover") .removeClass("k-hover"); }, _mouseleave: function() { this._removeActiveState(); }, destroy: function() { Widget.fn.destroy.call(this); this.element.off(NS); if (this.dataSource) { this.dataSource.unbind(CHANGE, this._dataChangeHandler); } this._root = null; kendo.unbindResize(this._resizeHandler); kendo.destroy(this.element); }, items: function() { return $(); }, getSize: function() { return kendo.dimensions(this.element); }, _resize: function() { var root = this._root; if (root) { var element = this.element; var rootElement = element.children(); root.coord.width = outerWidth(element); root.coord.height = outerHeight(element); rootElement.css({ width: root.coord.width, height: root.coord.height }); this._resizeItems(root, rootElement); } }, _resizeItems: function(root, element) { if (root.children && root.children.length) { var elements = element.children(".k-treemap-wrap").children(); var child, childElement; this._layout.compute(root.children, root.coord, { text: this._view.titleSize(root, element) }); for (var idx = 0; idx < root.children.length; idx++) { child = root.children[idx]; childElement = elements.filter("[" + kendo.attr("uid") + "='" + child.dataItem.uid + "']"); this._view.setItemSize(child, childElement); this._resizeItems(child, childElement); } } }, setOptions: function(options) { var dataSource = options.dataSource; options.dataSource = undefined$1; this._originalOptions = deepExtend(this._originalOptions, options); this.options = deepExtend({}, this._originalOptions); this._setLayout(); this._initTheme(this.options); Widget.fn._setEvents.call(this, options); if (dataSource) { this.setDataSource(HierarchicalDataSource.create(dataSource)); } if (this.options.autoBind) { this.dataSource.fetch(); } } }); var Squarified = Class.extend({ createRoot: function(root, width, height) { root.coord = { width: width, height: height, top: 0, left: 0 }; }, leaf: function(tree) { return !tree.children; }, layoutChildren: function(items, coord) { var parentArea = coord.width * coord.height; var totalArea = 0, itemsArea = [], i; for (i = 0; i < items.length; i++) { itemsArea[i] = parseFloat(items[i].value); totalArea += itemsArea[i]; } for (i = 0; i < itemsArea.length; i++) { items[i].area = parentArea * itemsArea[i] / totalArea; } var minimumSideValue = this.layoutHorizontal() ? coord.height : coord.width; var firstElement = [items[0]]; var tail = items.slice(1); this.squarify(tail, firstElement, minimumSideValue, coord); }, squarify: function(tail, initElement, width, coord) { this.computeDim(tail, initElement, width, coord); }, computeDim: function(tail, initElement, width, coord) { if (tail.length + initElement.length == 1) { var element = tail.length == 1 ? tail : initElement; this.layoutLast(element, width, coord); return; } if (tail.length >= 2 && initElement.length === 0) { initElement = [tail[0]]; tail = tail.slice(1); } if (tail.length === 0) { if (initElement.length > 0) { this.layoutRow(initElement, width, coord); } return; } var firstElement = tail[0]; if (this.worstAspectRatio(initElement, width) >= this.worstAspectRatio([firstElement].concat(initElement), width)) { this.computeDim(tail.slice(1), initElement.concat([firstElement]), width, coord); } else { var newCoords = this.layoutRow(initElement, width, coord); this.computeDim(tail, [], newCoords.dim, newCoords); } }, layoutLast: function(items, w, coord) { items[0].coord = coord; }, layoutRow: function(items, width, coord) { if (this.layoutHorizontal()) { return this.layoutV(items, width, coord); } else { return this.layoutH(items, width, coord); } }, orientation: "h", layoutVertical: function() { return this.orientation === "v"; }, layoutHorizontal: function() { return this.orientation === "h"; }, layoutChange: function() { this.orientation = this.layoutVertical() ? "h" : "v"; }, worstAspectRatio: function(items, width) { if (!items || items.length === 0) { return MAX_VALUE; } var areaSum = 0, maxArea = 0, minArea = MAX_VALUE; for (var i = 0; i < items.length; i++) { var area = items[i].area; areaSum += area; minArea = (minArea < area) ? minArea : area; maxArea = (maxArea > area) ? maxArea : area; } return math.max( (width * width * maxArea) / (areaSum * areaSum), (areaSum * areaSum) / (width * width * minArea) ); }, compute: function(children, rootCoord, htmlSize) { if (!(rootCoord.width >= rootCoord.height && this.layoutHorizontal())) { this.layoutChange(); } if (children && children.length > 0) { var newRootCoord = { width: rootCoord.width, height: rootCoord.height - htmlSize.text, top: 0, left: 0 }; this.layoutChildren(children, newRootCoord); } }, layoutV: function(items, width, coord) { var totalArea = this._totalArea(items), top = 0; width = round(totalArea / width); for (var i = 0; i < items.length; i++) { var height = round(items[i].area / width); items[i].coord = { height: height, width: width, top: coord.top + top, left: coord.left }; top += height; } var ans = { height: coord.height, width: coord.width - width, top: coord.top, left: coord.left + width }; ans.dim = math.min(ans.width, ans.height); if (ans.dim != ans.height) { this.layoutChange(); } return ans; }, layoutH: function(items, width, coord) { var totalArea = this._totalArea(items); var height = round(totalArea / width), top = coord.top, left = 0; for (var i = 0; i < items.length; i++) { items[i].coord = { height: height, width: round(items[i].area / height), top: top, left: coord.left + left }; left += items[i].coord.width; } var ans = { height: coord.height - height, width: coord.width, top: coord.top + height, left: coord.left }; ans.dim = math.min(ans.width, ans.height); if (ans.dim != ans.width) { this.layoutChange(); } return ans; }, _totalArea: function(items) { var total = 0; for (var i = 0; i < items.length; i++) { total += items[i].area; } return total; } }); var SquarifiedView = Class.extend({ init: function(treeMap, options) { this.options = deepExtend({}, this.options, options); this.treeMap = treeMap; this.element = $(treeMap.element); this.offset = 0; }, titleSize: function(item, element) { var text = element.children(".k-treemap-title"); return text.height() || 0; }, htmlSize: function(root) { var rootElement = this._getByUid(root.dataItem.uid); var htmlSize = { text: 0 }; if (root.children) { this._clean(rootElement); var text = this._getText(root); if (text) { var title = this._createTitle(root); rootElement.append(title); this._compile(title, root.dataItem); htmlSize.text = title.height(); } rootElement.append(this._createWrap()); this.offset = (outerWidth(rootElement) - rootElement.innerWidth()) / 2; } return htmlSize; }, _compile: function(element, dataItem) { }, _getByUid: function(uid) { return this.element.find(".k-treemap-tile[" + kendo.attr("uid") + "='" + uid + "']"); }, render: function(root) { var rootElement = this._getByUid(root.dataItem.uid); var children = root.children; if (children) { var rootWrap = rootElement.find(".k-treemap-wrap"); for (var i = 0; i < children.length; i++) { var leaf = children[i]; var htmlElement = this._createLeaf(leaf); rootWrap.append(htmlElement); this._compile(htmlElement.children(), leaf.dataItem); this.treeMap.trigger(ITEM_CREATED, { element: htmlElement }); } } }, createRoot: function(root) { var htmlElement = this._createLeaf(root); this.element.append(htmlElement); this._compile(htmlElement.children(), root.dataItem); this.treeMap.trigger(ITEM_CREATED, { element: htmlElement }); }, _clean: function(root) { root.css("background-color", ""); root.removeClass("k-leaf"); root.removeClass("k-inverse"); root.empty(); }, _createLeaf: function(item) { return this._createTile(item) .css("background-color", item.color) .addClass("k-leaf") .toggleClass( "k-inverse", this._tileColorBrightness(item) > 180 ) .toggle(item.value !== 0) .append($("<div></div>") .html(this._getText(item))); }, _createTile: function(item) { var tile = $("<div class='k-treemap-tile'></div>"); this.setItemSize(item, tile); if (defined(item.dataItem) && defined(item.dataItem.uid)) { tile.attr(kendo.attr("uid"), item.dataItem.uid); } return tile; }, _itemCoordinates: function(item) { var coordinates = { width: item.coord.width, height: item.coord.height, left: item.coord.left, top: item.coord.top }; if (coordinates.left && this.offset) { coordinates.width += this.offset * 2; } else { coordinates.width += this.offset; } if (coordinates.top) { coordinates.height += this.offset * 2; } else { coordinates.height += this.offset; } return coordinates; }, setItemSize: function(item, element) { var coordinates = this._itemCoordinates(item); element.css({ width: coordinates.width, height: coordinates.height, left: coordinates.left, top: coordinates.top }); }, _getText: function(item) { if (this.options.template) { return this._renderTemplate(item); } return kendo.htmlEncode(item.text); }, _renderTemplate: function(item) { var titleTemplate = template(this.options.template); return titleTemplate({ dataItem: item.dataItem, text: item.text }); }, _createTitle: function(item) { return $("<div class='k-treemap-title'></div>") .append($("<div></div>").html(this._getText(item))); }, _createWrap: function() { return $("<div class='k-treemap-wrap'></div>"); }, _tileColorBrightness: function(item) { return colorBrightness(item.color); } }); var SliceAndDice = Class.extend({ createRoot: function(root, width, height, vertical) { root.coord = { width: width, height: height, top: 0, left: 0 }; root.vertical = vertical; }, init: function(vertical) { this.vertical = vertical; this.quotient = vertical ? 1 : 0; }, compute: function(children, rootCoord, htmlSize) { if (children.length > 0) { var width = rootCoord.width; var height = rootCoord.height; if (this.vertical) { height -= htmlSize.text; } else { width -= htmlSize.text; } var newRootCoord = { width: width, height: height, top: 0, left: 0 }; this.layoutChildren(children, newRootCoord); } }, layoutChildren: function(items, coord) { var parentArea = coord.width * coord.height; var totalArea = 0; var itemsArea = []; var i; for (i = 0; i < items.length; i++) { var item = items[i]; itemsArea[i] = parseFloat(items[i].value); totalArea += itemsArea[i]; item.vertical = this.vertical; } for (i = 0; i < itemsArea.length; i++) { items[i].area = parentArea * itemsArea[i] / totalArea; } this.sliceAndDice(items, coord); }, sliceAndDice: function(items, coord) { var totalArea = this._totalArea(items); if (items[0].level % 2 === this.quotient) { this.layoutHorizontal(items, coord, totalArea); } else { this.layoutVertical(items, coord, totalArea); } }, layoutHorizontal: function(items, coord, totalArea) { var left = 0; for (var i = 0; i < items.length; i++) { var item = items[i]; var width = item.area / (totalArea / coord.width); item.coord = { height: coord.height, width: width, top: coord.top, left: coord.left + left }; left += width; } }, layoutVertical: function(items, coord, totalArea) { var top = 0; for (var i = 0; i < items.length; i++) { var item = items[i]; var height = item.area / (totalArea / coord.height); item.coord = { height: height, width: coord.width, top: coord.top + top, left: coord.left }; top += height; } }, _totalArea: function(items) { var total = 0; for (var i = 0; i < items.length; i++) { total += items[i].area; } return total; } }); var SliceAndDiceView = SquarifiedView.extend({ htmlSize: function(root) { var rootElement = this._getByUid(root.dataItem.uid); var htmlSize = { text: 0, offset: 0 }; if (root.children) { this._clean(rootElement); var text = this._getText(root); if (text) { var title = this._createTitle(root); rootElement.append(title); this._compile(title, root.dataItem); if (root.vertical) { htmlSize.text = title.height(); } else { htmlSize.text = title.width(); } } rootElement.append(this._createWrap()); this.offset = (outerWidth(rootElement) - rootElement.innerWidth()) / 2; } return htmlSize; }, titleSize: function(item, element) { var size; if (item.vertical) { size = element.children(".k-treemap-title").height(); } else { size = element.children(".k-treemap-title-vertical").width(); } return size || 0; }, _createTitle: function(item) { var title; if (item.vertical) { title = $("<div class='k-treemap-title'></div>"); } else { title = $("<div class='k-treemap-title-vertical'></div>"); } return title.append($("<div></div>").html(this._getText(item))); } }); function getField(field, row) { if (row === null) { return row; } var get = getter(field, true); return get(row); } function defined(value) { return typeof value !== UNDEFINED; } function colorsByLength(min, max, length) { var minRGBtoDecimal = rgbToDecimal(min); var maxRGBtoDecimal = rgbToDecimal(max); var isDarker = colorBrightness(min) - colorBrightness(max) < 0; var colors = []; colors.push(min); for (var i = 0; i < length; i++) { var rgbColor = { r: colorByIndex(minRGBtoDecimal.r, maxRGBtoDecimal.r, i, length, isDarker), g: colorByIndex(minRGBtoDecimal.g, maxRGBtoDecimal.g, i, length, isDarker), b: colorByIndex(minRGBtoDecimal.b, maxRGBtoDecimal.b, i, length, isDarker) }; colors.push(buildColorFromRGB(rgbColor)); } colors.push(max); return colors; } function colorByIndex(min, max, index, length, isDarker) { var minColor = math.min(math.abs(min), math.abs(max)); var maxColor = math.max(math.abs(min), math.abs(max)); var step = (maxColor - minColor) / (length + 1); var currentStep = step * (index + 1); var color; if (isDarker) { color = minColor + currentStep; } else { color = maxColor - currentStep; } return color; } function buildColorFromRGB(color) { return "#" + decimalToRgb(color.r) + decimalToRgb(color.g) + decimalToRgb(color.b); } function rgbToDecimal(color) { color = color.replace("#", ""); var rgbColor = colorToRGB(color); return { r: rgbToHex(rgbColor.r), g: rgbToHex(rgbColor.g), b: rgbToHex(rgbColor.b) }; } function decimalToRgb(number) { var result = math.round(number).toString(16).toUpperCase(); if (result.length === 1) { result = "0" + result; } return result; } function colorToRGB(color) { var colorLength = color.length; var rgbColor = {}; if (colorLength === 3) { rgbColor.r = color[0]; rgbColor.g = color[1]; rgbColor.b = color[2]; } else { rgbColor.r = color.substring(0, 2); rgbColor.g = color.substring(2, 4); rgbColor.b = color.substring(4, 6); } return rgbColor; } function rgbToHex(rgb) { return parseInt(rgb.toString(16), 16); } function colorBrightness(color) { var brightness = 0; if (color) { color = rgbToDecimal(color); brightness = math.sqrt(0.241 * color.r * color.r + 0.691 * color.g * color.g + 0.068 * color.b * color.b); } return brightness; } function round(value) { var power = math.pow(10, 4); return math.round(value * power) / power; } dataviz.ui.plugin(TreeMap); })(window.kendo.jQuery); var kendo$1 = kendo; export { __meta__, kendo$1 as default };