You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
5.6 KiB
188 lines
5.6 KiB
4 years ago
|
/**
|
||
|
* TreeMap layout
|
||
|
* @module echarts/layout/TreeMap
|
||
|
* @author loutongbing(loutongbing@126.com)
|
||
|
*/
|
||
|
define(function (require) {
|
||
|
|
||
|
function TreeMapLayout(opts) {
|
||
|
// 包含子矩形坐标与宽高的数组
|
||
|
this.rectangleList = [];
|
||
|
/**
|
||
|
* areas 每个子矩形面积
|
||
|
* x0 父矩形横坐标
|
||
|
* y0 父矩形横坐标
|
||
|
* width0 父矩形宽
|
||
|
* height0 父矩形高
|
||
|
*/
|
||
|
var row = {
|
||
|
x: opts.x0,
|
||
|
y: opts.y0,
|
||
|
width: opts.width0,
|
||
|
height: opts.height0
|
||
|
};
|
||
|
this.squarify(
|
||
|
opts.areas,
|
||
|
row
|
||
|
);
|
||
|
}
|
||
|
TreeMapLayout.prototype.squarify = function (areas, row) {
|
||
|
var layoutDirection = 'VERTICAL';
|
||
|
var width = row.width;
|
||
|
var height = row.height;
|
||
|
if (row.width < row.height) {
|
||
|
layoutDirection = 'HORIZONTAL';
|
||
|
width = row.height;
|
||
|
height = row.width;
|
||
|
}
|
||
|
// 把考虑方向与位置的因素剥离出来,只考虑怎么排列,运行完毕之后再修正
|
||
|
var shapeArr = this.getShapeListInAbstractRow(
|
||
|
areas, width, height
|
||
|
);
|
||
|
// 首先换算出虚拟的x、y坐标
|
||
|
for (var i = 0; i < shapeArr.length; i++) {
|
||
|
shapeArr[i].x = 0;
|
||
|
shapeArr[i].y = 0;
|
||
|
for (var j = 0; j < i; j++) {
|
||
|
shapeArr[i].y += shapeArr[j].height;
|
||
|
}
|
||
|
}
|
||
|
var nextRow = {};
|
||
|
// 根据虚拟的shapeArr计算真实的小矩形
|
||
|
if (layoutDirection == 'VERTICAL') {
|
||
|
for (var k = 0; k < shapeArr.length; k++) {
|
||
|
this.rectangleList.push(
|
||
|
{
|
||
|
x: shapeArr[k].x + row.x,
|
||
|
y: shapeArr[k].y + row.y,
|
||
|
width: shapeArr[k].width,
|
||
|
height: shapeArr[k].height
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
nextRow = {
|
||
|
x: shapeArr[0].width + row.x,
|
||
|
y: row.y,
|
||
|
width: row.width - shapeArr[0].width,
|
||
|
height: row.height
|
||
|
};
|
||
|
}
|
||
|
else {
|
||
|
for (var l = 0; l < shapeArr.length; l++) {
|
||
|
this.rectangleList.push(
|
||
|
{
|
||
|
x: shapeArr[l].y + row.x,
|
||
|
y: shapeArr[l].x + row.y,
|
||
|
width: shapeArr[l].height,
|
||
|
height: shapeArr[l].width
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
nextRow = {
|
||
|
x: row.x,
|
||
|
y: row.y + shapeArr[0].width, // 注意是虚拟形状下的width
|
||
|
width: row.width,
|
||
|
height: row.height - shapeArr[0].width // 注意是虚拟形状下的width
|
||
|
};
|
||
|
}
|
||
|
// 下一步的矩形数组要剔除已经填充过的矩形
|
||
|
var nextAreaArr = areas.slice(shapeArr.length);
|
||
|
if (nextAreaArr.length === 0) {
|
||
|
return;
|
||
|
}
|
||
|
else {
|
||
|
this.squarify(
|
||
|
nextAreaArr,
|
||
|
nextRow
|
||
|
);
|
||
|
}
|
||
|
};
|
||
|
TreeMapLayout.prototype.getShapeListInAbstractRow = function (
|
||
|
areas,
|
||
|
width,
|
||
|
height
|
||
|
) {
|
||
|
// 如果只剩下一个了,直接返回
|
||
|
if (areas.length === 1) {
|
||
|
return [
|
||
|
{
|
||
|
width: width,
|
||
|
height: height
|
||
|
}
|
||
|
];
|
||
|
}
|
||
|
// 填充进入的个数,从填充一个开始到填充所有小矩形,
|
||
|
// 纵横比最优时break并保留结果
|
||
|
for (var count = 1; count < areas.length; count++) {
|
||
|
|
||
|
var shapeArr0 = this.placeFixedNumberRectangles(
|
||
|
areas.slice(0, count),
|
||
|
width,
|
||
|
height
|
||
|
);
|
||
|
var shapeArr1 = this.placeFixedNumberRectangles(
|
||
|
areas.slice(0, count + 1),
|
||
|
width,
|
||
|
height
|
||
|
);
|
||
|
if (this.isFirstBetter(shapeArr0, shapeArr1)) {
|
||
|
return shapeArr0;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// 确定数量进行填充
|
||
|
TreeMapLayout.prototype.placeFixedNumberRectangles = function (
|
||
|
areaSubArr,
|
||
|
width,
|
||
|
height
|
||
|
) {
|
||
|
var count = areaSubArr.length;
|
||
|
// 声明返回值-每个矩形的形状(长宽)之数组
|
||
|
// 例如:
|
||
|
/*[
|
||
|
{
|
||
|
width: 11
|
||
|
height: 12
|
||
|
},
|
||
|
{
|
||
|
width: 11
|
||
|
height: 22
|
||
|
}
|
||
|
]*/
|
||
|
var shapeArr = [];
|
||
|
|
||
|
// 求出面积总和
|
||
|
var sum = 0;
|
||
|
for (var i = 0; i < areaSubArr.length; i++) {
|
||
|
sum += areaSubArr[i];
|
||
|
}
|
||
|
var cellWidth = sum / height;
|
||
|
for (var j = 0; j < count; j++) {
|
||
|
var cellHeight = height * areaSubArr[j] / sum;
|
||
|
shapeArr.push(
|
||
|
{
|
||
|
width: cellWidth,
|
||
|
height: cellHeight
|
||
|
}
|
||
|
);
|
||
|
}
|
||
|
return shapeArr;
|
||
|
};
|
||
|
// 相邻的两种填充方式放进去,比较是不是前一个的纵横比较小
|
||
|
TreeMapLayout.prototype.isFirstBetter = function (
|
||
|
shapeArr0,
|
||
|
shapeArr1
|
||
|
) {
|
||
|
var ratio0 = shapeArr0[0].height / shapeArr0[0].width;
|
||
|
ratio0 = (ratio0 > 1) ? 1 / ratio0 : ratio0;
|
||
|
var ratio1 = shapeArr1[0].height / shapeArr1[0].width;
|
||
|
ratio1 = (ratio1 > 1) ? 1 / ratio1 : ratio1;
|
||
|
if (Math.abs(ratio0 - 1) <= Math.abs(ratio1 - 1)) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
return TreeMapLayout;
|
||
|
});
|