天津投入产出系统后端
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

/**
* 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;
});