devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
270 lines (262 loc) • 8.45 kB
JavaScript
/**
* DevExtreme (cjs/viz/vector_map/layout.js)
* Version: 24.2.6
* Build date: Mon Mar 17 2025
*
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
;
exports.LayoutControl = LayoutControl;
var _iterator = require("../../core/utils/iterator");
const _round = Math.round;
const _min = Math.min;
const _max = Math.max;
const _each = _iterator.each;
const horizontalAlignmentMap = {
left: 0,
center: 1,
right: 2
};
const verticalAlignmentMap = {
top: 0,
bottom: 1
};
function getCellIndex(options) {
return 3 * verticalAlignmentMap[options.verticalAlignment] + horizontalAlignmentMap[options.horizontalAlignment]
}
function createCells(canvas, items) {
const hStep = (canvas.right - canvas.left) / 3;
const vStep = (canvas.bottom - canvas.top) / 2;
const h1 = canvas.left;
const h2 = _round(h1 + hStep);
const h3 = _round(h1 + hStep + hStep);
const h4 = canvas.right;
const v1 = canvas.top;
const v2 = _round(v1 + vStep);
const v3 = canvas.bottom;
const cells = [{
rect: [h1, v1, h2, v2]
}, {
rect: [h2, v1, h3, v2],
center: true
}, {
rect: [h3, v1, h4, v2],
horInversion: true
}, {
rect: [h1, v2, h2, v3],
verInversion: true
}, {
rect: [h2, v2, h3, v3],
center: true,
verInversion: true
}, {
rect: [h3, v2, h4, v3],
horInversion: true,
verInversion: true
}];
const itemsList = [
[],
[],
[],
[],
[],
[]
];
_each(items, (function(_, item) {
const options = item.getLayoutOptions();
if (options) {
itemsList[getCellIndex(options)].push({
item: item,
width: options.width,
height: options.height
})
}
}));
_each(cells, (function(i, cell) {
if (itemsList[i].length) {
cell.items = itemsList[i]
} else {
if (cell.center) {
cell.rect[0] = cell.rect[2] = (cell.rect[0] + cell.rect[2]) / 2
} else {
cell.rect[cell.horInversion ? 0 : 2] = cell.rect[cell.horInversion ? 2 : 0]
}
cell.rect[cell.verInversion ? 1 : 3] = cell.rect[cell.verInversion ? 3 : 1]
}
}));
return cells
}
function adjustCellSizes(cells) {
_each([0, 1, 2, 3, 4, 5], (function(_, index) {
const cell = cells[index];
const otherCell = cells[(index + 3) % 6];
if (cell.items) {
if (!otherCell.items) {
cell.rect[1] = _min(cell.rect[1], otherCell.rect[3]);
cell.rect[3] = _max(cell.rect[3], otherCell.rect[1])
}
}
}));
_each([1, 4], (function(_, index) {
const cell = cells[index];
const otherCell1 = cells[index - 1];
const otherCell2 = cells[index + 1];
let size1;
let size2;
if (cell.items) {
if (!otherCell1.items && !otherCell2.items) {
size1 = cell.rect[0] - otherCell1.rect[2];
size2 = otherCell2.rect[0] - cell.rect[2];
if (size1 > size2) {
if (size1 / size2 >= 2) {
cell.rect[0] -= size1;
cell.right = true
} else {
cell.rect[0] -= size2;
cell.rect[2] += size2
}
} else if (size2 / size1 >= 2) {
cell.rect[2] += size2;
cell.center = null
} else {
cell.rect[0] -= size1;
cell.rect[2] += size1
}
}
} else {
if (otherCell1.items) {
otherCell1.rect[2] = (cell.rect[0] + cell.rect[2]) / 2
}
if (otherCell2.items) {
otherCell2.rect[0] = (cell.rect[0] + cell.rect[2]) / 2
}
}
}))
}
function adjustCellsAndApplyLayout(cells, forceMode) {
let hasHiddenItems = false;
adjustCellSizes(cells);
_each(cells, (function(_, cell) {
if (cell.items) {
hasHiddenItems = applyCellLayout(cell, forceMode) || hasHiddenItems
}
}));
return hasHiddenItems
}
function applyCellLayout(cell, forceMode) {
const cellRect = cell.rect;
const cellWidth = cellRect[2] - cellRect[0];
const cellHeight = cellRect[3] - cellRect[1];
let xOffset = 0;
let yOffset = 0;
let currentHeight = 0;
let totalL = cellRect[2];
let totalT = cellRect[3];
let totalR = cellRect[0];
let totalB = cellRect[1];
const moves = [];
let hasHiddenItems = false;
_each(cell.items, (function(_, item) {
if (item.width > cellWidth || item.height > cellHeight) {
moves.push(null);
hasHiddenItems = true;
return forceMode || false
}
if (xOffset + item.width > cellWidth) {
yOffset += currentHeight;
xOffset = currentHeight = 0
}
if (yOffset + item.height > cellHeight) {
moves.push(null);
hasHiddenItems = true;
return forceMode || false
}
currentHeight = _max(currentHeight, item.height);
const dx = cell.horInversion ? cellRect[2] - item.width - xOffset : cellRect[0] + xOffset;
const dy = cell.verInversion ? cellRect[3] - item.height - yOffset : cellRect[1] + yOffset;
xOffset += item.width;
totalL = _min(totalL, dx);
totalT = _min(totalT, dy);
totalR = _max(totalR, dx + item.width);
totalB = _max(totalB, dy + item.height);
moves.push([dx, dy])
}));
if (forceMode || !hasHiddenItems) {
xOffset = 0;
if (cell.right) {
xOffset = cellRect[2] - cellRect[0] - totalR + totalL
} else if (cell.center) {
xOffset = _round((cellRect[2] - cellRect[0] - totalR + totalL) / 2)
}
_each(cell.items, (function(i, item) {
const move = moves[i];
if (move) {
item.item.locate(move[0] + xOffset, move[1])
} else {
item.item.resize(null)
}
}));
cell.rect = [totalL, totalT, totalR, totalB];
cell.items = null
}
return hasHiddenItems
}
function applyLayout(canvas, items) {
const cells = createCells(canvas, items);
if (adjustCellsAndApplyLayout(cells)) {
adjustCellsAndApplyLayout(cells, true)
}
}
function LayoutControl(widget) {
const that = this;
that._items = [];
that._suspended = 0;
that._widget = widget;
that._updateLayout = function() {
that._update()
}
}
LayoutControl.prototype = {
constructor: LayoutControl,
dispose: function() {
this._items = this._updateLayout = null
},
setSize: function(canvas) {
this._canvas = canvas;
this._update()
},
suspend: function() {
++this._suspended
},
resume: function() {
if (0 === --this._suspended) {
this._update()
}
},
addItem: function(item) {
this._items.push(item);
item.updateLayout = this._updateLayout
},
removeItem: function(item) {
const index = this._items.indexOf(item);
this._items.splice(index, 1);
item.updateLayout = null
},
_update: function() {
let canvas;
if (0 === this._suspended) {
canvas = this._canvas;
_each(this._items, (function(_, item) {
item.resize(canvas)
}));
this._widget.resolveItemsDeferred(this._items.filter((el => el.getTemplatesGroups && el.getTemplatesDef)));
applyLayout({
left: canvas.left,
top: canvas.top,
right: canvas.width + canvas.left,
bottom: canvas.height + canvas.top
}, this._items)
}
}
};