您的位置:首页 > Web前端 > JavaScript

透视图(pivot)数据解析逻辑(一个很low的透视图插件)

2017-08-15 10:37 441 查看
首先对透视图(pivot)作一个简单的介绍:

透视图的基本功能就是让原来表现形式单一的数据可以以用户自定义的方式来进行聚合呈现,是一种数据可视化的呈现方式。下面用笔者的代码来作进一步说明:

原始数据:

[
{
"人口":30,
"职位":"低级码农",
"工作":"码农",
"城市":"杭州",
"省份":"浙江",
"国家":"中国"
},
{
"人口":10,
"职位":"高级码农",
"工作":"码农",
"城市":"杭州",
"省份":"浙江",
"国家":"中国"
},
{
"人口":50,
"职位":"低级码畜",
"工作":"码畜",
"城市":"杭州",
"省份":"浙江",
"国家":"中国"
},
{
"人口":10,
"职位":"高级码畜",
"工作":"码畜",
"城市":"杭州",
"省份":"浙江",
"国家":"中国"
},
{
"人口":25,
"职位":"低级码农",
"工作":"码农",
"城市":"绍兴",
"省份":"浙江",
"国家":"中国"
},
{
"人口":5,
"职位":"高级码农",
"工作":"码农",
"城市":"绍兴",
"省份":"浙江",
"国家":"中国"
},
{
"人口":25,
"职位":"低级码畜",
"工作":"码畜",
"城市":"绍兴",
"省份":"浙江",
"国家":"中国"
},
{
"人口":25,
"职位":"高级码畜",
"工作":"码畜",
"城市":"绍兴",
"省份":"浙江",
"国家":"中国"
},
{
"人口":90,
"职位":"低级码农",
"工作":"码农",
"城市":"广州",
"省份":"广东",
"国家":"中国"
},
{
"人口":20,
"职位":"高级码农",
"工作":"码农",
"城市":"广州",
"省份":"广东",
"国家":"中国"
},
{
"人口":5,
"职位":"低级码畜",
"工作":"码畜",
"城市":"广州",
"省份":"广东",
"国家":"中国"
},
{
"人口":5,
"职位":"高级码畜",
"工作":"码畜",
"城市":"广州",
"省份":"广东",
"国家":"中国"
},
{
"人口":1,
"职位":"低级码农",
"工作":"码农",
"城市":"印第安纳波利斯",
"省份":"印第安纳",
"国家":"美国"
},
{
"人口":1,
"职位":"高级码农",
"工作":"码农",
"城市":"印第安纳波利斯",
"省份":"印第安纳",
"国家":"美国"
},
{
"人口":55,
"职位":"低级码畜",
"工作":"码畜",
"城市":"印第安纳波利斯",
"省份":"印第安纳",
"国家":"美国"
},
{
"人口":3,
"职位":"高级码畜",
"工作":"码畜",
"城市":"印第安纳波利斯",
"省份":"印第安纳",
"国家":"美国"
}
]


一般从数据库中取出来不作处理的数据结构都是和上图类似,直接呈现效果如下图所示:



一旦原始数据量上去了,前台在呈现的时候就必须做条件搜索和分页,否则用户用起来一定会想打人。然后我们来分析一下上面的原始数据,可以看到大部分数据都是有关联关系的(如国家-省份-城市有关联关系、工作-职位有关联关系),而当这个关联关系明确后,就可以通过透视图来对上面的原始数据进行聚合呈现,带给用户更好的体验。下面来看最高程度的聚合呈现:



可以看到聚合后有四个值(中国码农人口、美国码农人口、中国码畜人口和美国码畜人口)。在原始数据中这个四个值都是不存在的,由透视图的聚合功能生成,方便用户了解整体概况。

而当用户希望看到局部数据的详细情况时,则可以对用户选择的数据进行中度聚合(如查看中国各省的详细信息):



与原始数据相比,中国的省份数据进行了中度聚合,其他数据仍然保持高度聚合(如美国)。

同样,当用户希望看到局部更详细的情况时,则可以对用户选择的数据进行轻度聚合甚至是不聚合。

查看浙江的详细信息:



查看码农的详细信息:



OK,对透视图的介绍到此结束,下面直接上源码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>pivot</title>
<style>
table {
border-right: 1px solid #F00;
border-bottom:1px solid #F00;
}
td {
border-left: 1px solid #F00;
border-top:1px solid #F00;
}

</style>
</head>
<body>
<table id="table">
</table>
<br>
<input type="button" value="原始数据" onclick="show()">
<input type="button" value="基础数据" onclick="showB()">
<input type="button" value="模拟展开所有省份" onclick="showP()">
<input type="button" value="模拟展开所有城市" onclick="showC()">
<input type="button" value="模拟点击中国" onclick="showChina()">
<input type="button" value="模拟点击浙江" onclick="showZ()">
<input type="button" value="模拟展开所有工作" onclick="showW()">
<input type="button" value="模拟点击码农" onclick="showMN()">
</body>
</html>
<script>
var baseData = [ { "人口":30, "职位":"低级码农", "工作":"码农", "城市":"杭州", "省份":"浙江", "国家":"中国" }, { "人口":10, "职位":"高级码农", "工作":"码农", "城市":"杭州", "省份":"浙江", "国家":"中国" }, { "人口":50, "职位":"低级码畜", "工作":"码畜", "城市":"杭州", "省份":"浙江", "国家":"中国" }, { "人口":10, "职位":"高级码畜", "工作":"码畜", "城市":"杭州", "省份":"浙江", "国家":"中国" }, { "人口":25, "职位":"低级码农", "工作":"码农", "城市":"绍兴", "省份":"浙江", "国家":"中国" }, { "人口":5, "职位":"高级码农", "工作":"码农", "城市":"绍兴", "省份":"浙江", "国家":"中国" }, { "人口":25, "职位":"低级码畜", "工作":"码畜", "城市":"绍兴", "省份":"浙江", "国家":"中国" }, { "人口":25, "职位":"高级码畜", "工作":"码畜", "城市":"绍兴", "省份":"浙江", "国家":"中国" }, { "人口":90, "职位":"低级码农", "工作":"码农", "城市":"广州", "省份":"广东", "国家":"中国" }, { "人口":20, "职位":"高级码农", "工作":"码农", "城市":"广州", "省份":"广东", "国家":"中国" }, { "人口":5, "职位":"低级码畜", "工作":"码畜", "城市":"广州", "省份":"广东", "国家":"中国" }, { "人口":5, "职位":"高级码畜", "工作":"码畜", "城市":"广州", "省份":"广东", "国家":"中国" }, { "人口":1, "职位":"低级码农", "工作":"码农", "城市":"印第安纳波利斯", "省份":"印第安纳", "国家":"美国" }, { "人口":1, "职位":"高级码农", "工作":"码农", "城市":"印第安纳波利斯", "省份":"印第安纳", "国家":"美国" }, { "人口":55, "职位":"低级码畜", "工作":"码畜", "城市":"印第安纳波利斯", "省份":"印第安纳", "国家":"美国" }, { "人口":3, "职位":"高级码畜", "工作":"码畜", "城市":"印第安纳波利斯", "省份":"印第安纳", "国家":"美国" } ];
//以下的初始化数据可以在拿到baseData时写个init初始化(但哪些属性是x哪些是y必须给定)
//给定x轴 y轴 基础数据,对应的值表示该属性是否显示(x轴和y轴的属性顺序可变,即层级可变,但x和y必须有一个属性为true)
var x = {"国家":true,"省份":false,"城市":false};
var y = {"工作":true,"职位":false};
var data = ["人口"];
//xList和yList表示哪些信息会被详细展示(需要支持多个城市的同时展示)
//xList和yList依赖x和y的元素顺序,如x是国家-省份-城市,则xList应中展示省份需要声明所属国家,展示城市需要声明所属国家和省份
//对xList的补充说明(基于下面的xList):有省份,则相当于在中国上点击一下(展开中国),有城市,则相当于在浙江上点击一下(展开浙江),由于城市没有下级属性,所以虽然城市的内容为杭州,相当于在杭州上点击一下,但实际没有效果
// var xList = [{"国家":"中国","省份":"浙江","城市":"杭州"},{"国家":"美国","省份":"印第安纳"}];
var xList = [];
//对yList的补充说明(基于下面的yList):有工作,则相当于在码农上点击一下(展开码农),有职位,则相当于在高级码农上点击一下(展开高级码农)
// var yList = [{"工作":"码畜","职位":"高级码畜"}];
var yList = [];

//查看原始数据
function show() {
clear();
var table = document.getElementById("table");

var setHeader = true;
for (var i=0;i<baseData.length;i++) {
if(setHeader) {
var row = table.insertRow();
for(var item in baseData[i]) {
var col = row.insertCell(0);
col.style.width = "200px";
col.innerHTML = item;
}
setHeader = false;
}
var row = table.insertRow();
for(var item in baseData[i]) {
var col = row.insertCell(0);
col.style.width = "200px";
col.innerHTML = baseData[i][item];
}
}
}

function base() {
clear();
var results = createData(x, y, xList, yList, data, baseData);
//绘制表格
var table = document.getElementById("table");
//绘制x轴
var row = table.insertRow();
//取results任意一行生成x轴表头
var rowData = results[0];

for(var i=rowData.length-1; i>-1; i--) {
var showX = "";
//根据x轴属性的顺序决定表格显示属性的顺序
for(var item in x) {
if(rowData[i].hasOwnProperty(item)) {
showX = rowData[i][item];
}
}
var column = row.insertCell(0);
column.innerHTML = showX;
}
var base = "";
data.forEach(function(value, index, arr){
base += value;
});
var column = row.insertCell(0);
column.innerHTML = base;
column.style.width = "200px";
//生成数据
results.forEach(function(value, index, arr){
var row = table.insertRow();

for(var i=value.length-1;i>-1;i--) {
var vValue = value[i];
var values = "";
data.forEach(function(dValue, dIndex, dArr){
values += vValue[dValue]+";";
});
values = values.substring(0,values.length-1);
var column = row.insertCell(0);
column.innerHTML = values;
column.style.width = "200px";
}

var column = row.insertCell(0);
var header = "";
for(var yHeader in y) {
//任意选择一行获取y轴表头
if(value[0].hasOwnProperty(yHeader)) {
header = value[0][yHeader];
}
}
column.innerHTML = header;
column.style.width = "200px";
});
}

//重构数据
function createData(x, y, xList, yList, data, baseData) {
//生成表格数据

/*
基础数据
results例子:
[
[{"国家":"中国","工作":"码农","人口":180},{"国家":"美国","工作":"码农","人口":2}],
[{"国家":"中国","工作":"码畜","人口":120},{"国家":"美国","工作":"码畜","人口":58}]
]
*/
var results = createBaseData(x, y, data, baseData);

/*
遍历x构造基础数据列表
results例子:

*/
var checkX = [];
for(var item in x) {
if(x[item]) {
checkX.push(item);
}
}
if(checkX.length > 1) {
results = createFullXData(checkX, checkX[1], data, baseData, results);
}

/*
遍历y构造基础数据列表
results例子:
[
[
{"国家":"中国","工作":"码农","人口":180},
{"国家":"美国","工作":"码农","人口":2}
],
[
{"国家":"中国","工作":"码农","人口":35,"职位":"高级码农"},
{"国家":"美国","工作":"码农","人口":1,"职位":"高级码农"}
],
[
{"国家":"中国","工作":"码农","人口":145,"职位":"低级码农"},
{"国家":"美国","工作":"码农","人口":1,"职位":"低级码农"}
],
[
{"国家":"中国","工作":"码畜","人口":120},
{"国家":"美国","工作":"码畜","人口":58}
],
[
{"国家":"中国","工作":"码畜","人口":40,"职位":"高级码畜"},
{"国家":"美国","工作":"码畜","人口":3,"职位":"高级码畜"}
],
[
{"国家":"中国","工作":"码畜","人口":80,"职位":"低级码畜"},
{"国家":"美国","工作":"码畜","人口":55,"职位":"低级码畜"}
]
]
*/
var checkY = [];
for(var item in y) {
if(y[item]) {
checkY.push(item);
}
}
if(checkY.length > 1) {
results = createFullYData(checkY, checkY[1], data, baseData, results);
}

/*
遍历xList补充详细信息(增加列)
调用原则:例如要展示杭州,则必须x中的城市必须为false(为true时已经全部展开,没有必要单独再显示,即后面的解析逻辑都是建立在此基础上,否则会出错,下面y轴的调用原则相同)
results例子:

*/
xList.forEach(function(value, index, arr){
results = createSingleXData(value, data, baseData, results);
});

/*
遍历yList补充详细信息(增加行)
results例子:

*/
yList.forEach(function(value, index, arr){
results = createSingleYData(value, data, baseData, results);
});
console.log("遍历yList补充详细信息 "+JSON.stringify(results));
return results;
}

function createBaseData(x, y, data, baseData) {
var results = [];
var x0 = "";
var y0 = "";
for(var item in x) {
if(x[item] && x0 === "") {
x0 = item;
}
}
for(var item in y) {
if(y[item] && y0 === "") {
y0 = item;
}
}
var yList = getColumnList(y0, baseData);
var xList = getColumnList(x0, baseData);
yList.forEach(function(yValue, yIndex, yArr){
var row = [];
xList.forEach(function(xValue, xIndex, xArr){
var obj = {};
obj[x0] = xValue;
obj[y0] = yValue;
data.forEach(function(dValue, dIndex, dArr){
var result = 0;
baseData.forEach(function(baseValue, baseIndex, baseArr){
if(baseValue[x0] === xValue && baseValue[y0] === yValue) {
result = result + baseValue[dValue];
}
});
obj[dValue] = result;
});
row.push(obj);
});
results.push(row);
});
return results;
}

function createFullXData(xList, xName, data, baseData, results) {
//遍历results(每一行都要增加列)
results.forEach(function(row, index, arr){
for(var i=row.length-1;i>-1;i--) {
var column = row[i];
var newResults = getXData(xList, xName, data, baseData, column);
newResults.forEach(function(re, reIndex, reArr){
row.splice(i+1, 0, re);
});
}
});
//判断xName是否为xList的最后一个元素,是则返回results,否则递归调用本身
var flag = true;
var nextXName = "";
for(var i=0;i<xList.length;i++) {
if(xList[i] === xName && i !== xList.length - 1) {
flag = false;
nextXName = xList[i+1];
break;
}
}
if(flag) {
return results;
} else {
return createFullXData(xList, nextXName, data, baseData, results);
}
}

function createFullYData(yList, yName, data, baseData, results) {
//遍历results(每一列都要增加行)
for(var i=results.length-1; i>-1; i--) {
var row = results[i];
var newResults = getYData(yList, yName, data, baseData, row);
newResults.forEach(function(re, reIndex, reArr){
results.splice(i+1, 0, re);
});
}
//判断yName是否为yList的最后一个元素,是则返回results,否则递归调用本身
var flag = true;
var nextYName = "";
for(var i=0;i<yList.length;i++) {
if(yList[i] === yName && i !== yList.length - 1) {
flag = false;
nextYName = yList[i+1];
break;
}
}
if(flag) {
return results;
} else {
return createFullYData(yList, nextYName, data, baseData, results);
}
}

function createSingleXData(value, data, baseData, results) {
var list = [];
for(var item in value) {
//x轴不可能为空
if(list.length !== 0) {
//判断下一级x轴是否在results中已经存在(如value为{"国家":"美国","省份":"印第安纳","城市":"印第安纳波利斯"},有可能省份印第安纳已经在results中存在,也有可能不存在)
var flag = false;
results.forEach(function(row, index, arr){
for(var i=0; i<row.length; i++) {
var column = row[i];
var listFlag = true;
//判断当前节点list中属性与value是否一致
for(var j=0;j<list.length;j++) {
if(column[list[i]] !== value[list[i]]) {
listFlag = false;
break;
}
}
if(listFlag) {
if(column.hasOwnProperty(item) && column[item] === value[item]) {
flag = true;
}
}
}
});
if(flag) {
continue;
} else {
results.forEach(function(row, index, arr){
for(var i=row.length-1; i>-1; i--) {
var column = row[i];
//找到父元素
var faFlag = true;
for(var j=0; j<list.length; j++) {
if(column[list[j]] !== value[list[j]]) {
faFlag = false;
break;
}
}
if(faFlag) {
var newResults = getXData(list, item, data, baseData, column);
newResults.forEach(function(re, reIndex, reArr){
row.splice(i+1, 0, re);
});
break;
}
}
});
}
}
list.push(item);
}
return results;
}

function createSingleYData(value, data, baseData, results) {
var list = [];
for(var item in value) {
//y轴不可能为空
if (list.length !== 0) {
//判断下一级y轴是否在results中已经存在
var flag = false;
results.forEach(function(row, index, arr){
for(var i=0; i<row.length; i++) {
var column = row[i];
var listFlag = true;
//判断当前节点list中属性与value是否一致
for(var j=0; j<list.length; j++) {
if(column[list[i]] !== value[list[i]]) {
listFlag = false;
break;
}
}
if(listFlag) {
if(column.hasOwnProperty(item) && column[item] === value[item]) {
flag = true;
}
}
}
});
if(flag) {
continue;
} else {
for(var i=results.length-1; i>-1; i--) {
var row = results[i];
//找到父元素
var faFlag = true;
for(var j=0; j<list.length; j++) {
var column = row[0];
if(column[list[j]] !== value[list[j]]) {
faFlag = false;
break;
}
}
if(faFlag) {
var newResults = getYData(list, item, data, baseData, row);
newResults.forEach(function(re, reIndex, reArr){
results.splice(i+1, 0, re);
});
break;
}
}
}
}
list.push(item);
}
return results;
}

//根据xName和xList获取新增results(father是results中的节点)
function getXData(xList, xName, data, baseData, father) {
//遍历baseData查询所有符合要求的子节点
var newBaseData = [];
baseData.forEach(function(value, index, arr){
//整理父节点需要比较的属性
var atts = [];
for(var i=0; i<xList.length; i++) {
if(xName === xList[i]) {
break;
} else {
atts.push(xList[i]);
}
}
//value与父节点的atts中所有属性一致则表示该节点需要进入计算
var flag = true;
atts.forEach(function(attValue, attIndex, attArr){
if(value[attValue] !== father[attValue]) {
flag = false;
}
});
if(flag) {
newBaseData.push(value);
}
});
//再遍历newBaseData生成新增列
var newResults = [];
//newBaseData只会包含父节点下的所有信息(如父节点为中国,则newBaseData只会包含浙江、广东,而不会包含美国的某个州)
var list = getColumnList(xName, newBaseData);
list.forEach(function(lValue, lIndex, lArr){
//新增节点初始化
var item = {};
item = deepCopy(father, item);
item[xName] = lValue;
data.forEach(function(d, dIndex, dArr){
item[d] = 0;
});
newBaseData.forEach(function(value, index, arr){
//当前value是否进入计算
var flag = true;
if(value[xName] !== lValue) {
flag = false;
}
for(var yValue in y) {
if(item.hasOwnProperty(yValue) && item[yValue] !== value[yValue]) {
flag = false;
}
}
if(flag) {
data.forEach(function(d, dIndex, dArr){
item[d] += value[d];
});
}
});
newResults.push(item);
});
return newResults;
}

//根据yName和yList获取新增results(father是results中的节点)
function getYData(yList, yName, data, baseData, father) {
//遍历baseData查询所有符合要求的子节点
var newBaseData = [];
//从father的第一个节点找出当前y轴的值(father中所有节点y轴的值都相同)
var exp = father[0];
var atts = [];
for(var i=0;i<yList.length;i++) {
if(yList[i] !== yName) {
atts.push(yList[i]);
} else {
break;
}
}
baseData.forEach(function(value, index, arr){
var flag = true;
atts.forEach(function(aValue, aIndex, aArr){
if(value[aValue] !== exp[aValue]) {
flag = false;
}
});
if(flag) {
newBaseData.push(value);
}
});
var newResults = [];
//查询yName的枚举值列表(这里对数据有要求,即所有baseData的数据都必须包含职位信息,且所有节点的职位信息的枚举值必须相同,如中国有高级码农和低级码农,美国不能多出一个中级码农)
var list = getColumnList(yName, newBaseData);
//list有几个值,则每个father对应有几个新增行
list.forEach(function(value, index, arr){
//新增行初始化
var row = [];
row = deepCopy(father, row);
data.forEach(function(dValue, dIndex, dArr){
row.forEach(function(rValue, rIndex, rArr){
rValue[dValue] = 0;
});
});
row.forEach(function(rValue, rIndex, rArr){
rValue[yName] = value;
});

//计算新增行数据
newBaseData.forEach(function(bValue, bIndex, bArr){
row.forEach(function(rValue, rIndex, rArr){
//判断bValue的x轴y轴是否与rValue一致
var flag = true;
for(var item in rValue) {
//如果item是基础数据,则跳过
var isB = false;
data.forEach(function(dValue, dIndex, dArr){
if(item === dValue) {
isB = true;
}
});
if(isB) {
continue;
}
if(rValue[item] !== bValue[item]) {
flag = false;
}
}
if(flag) {
data.forEach(function(dValue, dIndex, dArr){
rValue[dValue] += bValue[dValue];
});
}
});
});
newResults.push(row);
});
return newResults;
}

//根据属性名返回属性列表(如传入工作,则返回码农和码畜)
function getColumnList(columnName, baseData) {
var list = [];
baseData.forEach(function(value, index, arr){
if(value.hasOwnProperty(columnName)) {
var alreadyInList = false;
list.forEach(function(lValue, lIndex, lArr){
if(lValue === value[columnName]) {
alreadyInList = true;
}
});
if(!alreadyInList) {
list.push(value[columnName]);
}
}
});
return list;
}

//清空表格
function clear() {
var table = document.getElementById("table");
var rowNum = table.rows.length;
for (var i=0;i<rowNum;i++) {
table.deleteRow(i);
rowNum = rowNum-1;
i = i-1;
}
}

//深度拷贝
function deepCopy(p, c) {
var c = c || {};
for (var i in p) {
if (typeof p[i] === "object") {
c[i] = (p[i].constructor === Array) ? [] : {};
deepCopy(p[i], c[i]);
} else {
c[i] = p[i];
}
}
return c;
}

show();

//演示用增加测试函数
function showP() {
//还原到基础数据状态
xList = [];
y = {"工作":true,"职位":false};
yList = [];

x = {"国家":true,"省份":true,"城市":false};
base();
}

function showC() {
//还原到基础数据状态
xList = [];
y = {"工作":true,"职位":false};
yList = [];

x = {"国家":true,"省份":true,"城市":true};
base();
}

function showChina() {
//还原到基础数据状态
x = {"国家":true,"省份":false,"城市":false};
y = {"工作":true,"职位":false};
yList = [];

xList = [{"国家":"中国","省份":""}];
base();
}

function showZ() {
//还原到基础数据状态
x = {"国家":true,"省份":false,"城市":false};
y = {"工作":true,"职位":false};
yList = [];

xList = [{"国家":"中国","省份":"浙江","城市":""}];
base();
}

function showW() {
//还原到基础数据状态
x = {"国家":true,"省份":false,"城市":false};
xList = [];
yList = [];

y = {"工作":true,"职位":true};
base();
}

function showMN() {
//还原到基础数据状态
x = {"国家":true,"省份":false,"城市":false};
y = {"工作":true,"职位":false};
xList = [];

yList = [{"工作":"码农","职位":""}];
base();
}

function showB() {
x = {"国家":true,"省份":false,"城市":false};
y = {"工作":true,"职位":false};
xList = [];
yList = [];

base();
}
</script>


PS:笔者偷懒了,部分解析的例子没有在注释里面加上,后面有空补上。

接下来是用法说明:

baseData:原始数据,在实际应用里面通常都是某个后台接口返回的信息,写个ajax包一下就可以了,但想以透视图呈现的数据结构必须与baseData保持一致(注意:baseData中各个元素的解构也必须严格保持一致,如一个元素包含国家属性另一个元素不包含国家属性,这样用透视图来呈现的时候就会出现不可预知的问题,因为笔者没验过)。

x:透视图横坐标属性(即原始数据中的哪些属性作为透视图的横坐标),对应的值(true/false)表示当前属性是否在透视图上展示,各个属性在x里的顺序对应在透视图上x轴的级联顺序,如果x写成{"城市":true,"省份":false,"国家":false},则基础数据的呈现如下图(再点击杭州则展示包含杭州的下级数据,如果下级x属性是省份,则按省份展示包含杭州的下级数据,如下级x属性是国家,则按国家展示包含杭州的下级数据):



y:透视图纵坐标属性(即原始数据中的哪些属性作为透视图的纵坐标),对应的值(true/false)表示当前属性是否在透视图上展示,各个属性在y里的顺序对应在透视图上y轴的级联顺序,如果y写成{"职位":true,"工作":false},则基础数据的呈现如下图:



注意:x和y都必须有一个属性的值为true,否则透视图无法正常展示(这个换个说法就比较容易理解了,在坐标轴上绘图的时候必须保证每个点都有x轴的值和y轴的值)。另外,返回的原始数据中,在x轴y轴中属性的顺序可以随意调整,但哪些属性可以作为x轴哪些属性可以作为y轴必须给定(一般是由接口定义好,如果是直接读数据库,则一般需要后台对数据库的字段进行预配置,并与业务数据一并返回给前台,前台在拿到原始数据的时候是无法解析出国家和省份有级联关系而不是国家和工作有级联关系的)。

data:业务数据属性,相当于横纵坐标给定后确定的这个点展示的业务数据(理论上是支持多个业务数据属性的同时展示的,不过笔者还没验证过,各位同学用的时候注意下看看有木有bug)。

xList和yList:是对x和y的补充,当x和y的值为true时,是展示某层的所有信息(具体来说,当省份为true时,中国会展示浙江和广东,美国会展示印第安纳),而不能单独展示某层的一部分信息(如只展示中国的浙江和广东而不展示美国的印第安纳),xList和yList支持配置单独展示某层的一部分信息,即对应在某一个横坐标或纵坐标点击后的展开/收起详细信息功能。

如xList配置为[{"国家":"中国","省份":"浙江","城市":"杭州"},{"国家":"美国","省份":"印第安纳"}],则相当于在基础数据的透视图上点击了中国和美国,然后在中国的详细信息中又点击了浙江,这样中国除浙江外的城市信息和美国所有省份的城市信息都不会显示。

如果只想使用数据解析部分的代码,那么把表格上的button以及演示用增加测试函数都删除就可以了(演示用增加测试函数可以帮助理解各种点击事件的调用),具体的解析逻辑有兴趣的同学可以研究下,这里就不详细介绍了,实际上写的很烂(这也是标题说low的原因,哈哈),还有非常大的优化空间。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐