fineui是帆软报表和BI产品线所使用的前端框架。
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.
 
 
 

491 lines
16 KiB

/**
* 路径选择
*
* Created by GUY on 2015/12/4.
* @class BI.PathChooser
* @extends BI.Widget
*/
BI.PathChooser = BI.inherit(BI.Widget, {
_const: {
lineColor: "#d4dadd",
selectLineColor: "#3f8ce8"
},
_defaultConfig: function () {
return BI.extend(BI.PathChooser.superclass._defaultConfig.apply(this, arguments), {
baseCls: "bi-path-chooser",
items: []
});
},
_init: function () {
BI.PathChooser.superclass._init.apply(this, arguments);
this.populate(this.options.items);
},
_createRegions: function (regions) {
var self = this;
this.regions = BI.createWidgets(BI.map(regions, function (i, region) {
return {
type: "bi.path_region",
title: self.texts[region] || region
};
}));
this.regionMap = {};
BI.each(regions, function (i, region) {
self.regionMap[region] = i;
});
this.container = BI.createWidget({
type: "bi.horizontal",
verticalAlign: "top",
scrollx: false,
scrolly: false,
hgap: 10,
items: this.regions
});
BI.createWidget({
type: "bi.vertical_adapt",
element: this,
scrollable: true,
hgap: 10,
items: [this.container]
});
},
getRegionIndexById: function (id) {
var node = this.cache[id];
var regionType = node.get("region");
return this.regionMap[regionType];
},
_drawPath: function (start, offset, index) {
var self = this;
var starts = [];
if (BI.contains(this.start, start)) {
starts = this.start;
} else {
starts = [start];
}
BI.each(starts, function (i, s) {
BI.each(self.radios[s], function (i, rad) {
rad.setSelected(false);
});
BI.each(self.lines[s], function (i, line) {
line.attr("stroke", self._const.lineColor);
});
BI.each(self.regionIndexes[s], function (i, idx) {
self.regions[idx].reset();
});
});
BI.each(this.routes[start][index], function (i, id) {
var regionIndex = self.getRegionIndexById(id);
self.regions[regionIndex].setSelect(offset + index, id);
});
var current = BI.last(this.routes[start][index]);
while (current && this.routes[current] && this.routes[current].length === 1) {
BI.each(this.routes[current][0], function (i, id) {
var regionIndex = self.getRegionIndexById(id);
self.regions[regionIndex].setSelect(0, id);
});
this.lines[current][0].attr("stroke", self._const.selectLineColor).toFront();
current = BI.last(this.routes[current][0]);
}
this.lines[start][index].attr("stroke", self._const.selectLineColor).toFront();
this.radios[start] && this.radios[start][index] && this.radios[start][index].setSelected(true);
},
_drawRadio: function (start, offset, index, x, y) {
var self = this;
var radio = BI.createWidget({
type: "bi.radio",
cls: "path-chooser-radio",
selected: offset + index === 0,
start: start,
index: index
});
radio.on(BI.Radio.EVENT_CHANGE, function () {
self._drawPath(start, offset, index);
self.fireEvent(BI.PathChooser.EVENT_CHANGE, start, index);
});
if (!this.radios[start]) {
this.radios[start] = [];
}
this.radios[start].push(radio);
BI.createWidget({
type: "bi.absolute",
element: this.container,
items: [{
el: radio,
left: x - 6.5,
top: y - 6.5
}]
});
},
_drawLine: function (start, lines) {
var self = this;
if (!this.lines[start]) {
this.lines[start] = [];
}
if (!this.pathes[start]) {
this.pathes[start] = [];
}
var startRegionIndex = this.getRegionIndexById(start);
// start所在的位置,然后接着往下画其他的路径
var offset = this.regions[startRegionIndex].getIndexByValue(start);
BI.each(lines, function (i, line) {
self.pathes[start][i] = [];
var idx = i + offset;
var path = "";
var stop = 47.5 + 29 * idx;
var sleft = 50 + 100 * startRegionIndex;
var radioStartX = sleft, radioStartY = stop;
var etop = stop;
var endRegionIndex = self.getRegionIndexById(BI.last(line));
var endOffset = self.regions[endRegionIndex].getIndexByValue(BI.last(line));
var eleft = 50 + 100 * endRegionIndex;
if (BI.contains(self.start, start)) {
radioStartX = sleft - 50;
path += "M" + (sleft - 50) + "," + stop;
self.pathes[start][i].push({
x: sleft - 50,
y: stop
});
} else if (idx === 0) {
radioStartX = sleft + 50;
path += "M" + sleft + "," + stop;
self.pathes[start][i].push({
x: sleft,
y: stop
});
} else {
radioStartX = sleft + 50;
path += "M" + sleft + "," + 47.5 + "L" + (sleft + 50) + "," + 47.5 + "L" + (sleft + 50) + "," + stop;
self.pathes[start][i].push({
x: sleft,
y: 47.5
});
self.pathes[start][i].push({
x: sleft + 50,
y: 47.5
});
self.pathes[start][i].push({
x: sleft + 50,
y: stop
});
}
if (idx > 0) {
var endY = endOffset * 29 + 47.5;
path += "L" + (eleft - 50) + "," + etop + "L" + (eleft - 50) + "," + endY + "L" + eleft + "," + endY;
self.pathes[start][i].push({
x: eleft - 50,
y: etop
});
self.pathes[start][i].push({
x: eleft - 50,
y: endY
});
self.pathes[start][i].push({
x: eleft,
y: endY
});
} else {
path += "L" + eleft + "," + etop;
self.pathes[start][i].push({
x: eleft,
y: etop
});
}
var graph = self.svg.path(path)
.attr({
stroke: idx === 0 ? self._const.selectLineColor : self._const.lineColor,
"stroke-dasharray": "-"
});
self.lines[start].push(graph);
if (lines.length > 1) {
self.lines[start][0].toFront();
}
// 第一个元素无论有多少个都要显示radio
if (BI.contains(self.start, start)) {
self.lines[self.regions[0].getValueByIndex(0)][0].toFront();
}
if (lines.length > 1 || BI.contains(self.start, start)) {
self._drawRadio(start, offset, i, radioStartX, radioStartY);
}
});
},
_drawLines: function (routes) {
var self = this;
this.lines = {};
this.pathes = {};
this.radios = {};
this.regionIndexes = {};
BI.each(routes, function (k, route) {
if (!self.regionIndexes[k]) {
self.regionIndexes[k] = [];
}
BI.each(route, function (i, rs) {
BI.each(rs, function (j, id) {
var regionIndex = self.getRegionIndexById(id);
if (!BI.contains(self.regionIndexes[k], regionIndex)) {
self.regionIndexes[k].push(regionIndex);
}
});
});
});
BI.each(routes, function (k, route) {
self._drawLine(k, route);
});
},
_pushNodes: function (nodes) {
var self = this;
var indexes = [];
for (var i = 0; i < nodes.length; i++) {
var id = nodes[i];
var index = self.getRegionIndexById(id);
indexes.push(index);
var region = self.regions[index];
if (i === nodes.length - 1) {
if (!region.hasItem(id)) {
region.addItem(id, self.texts[id]);
}
break;
}
if (i > 0 || BI.contains(self.start, id)) {
region.addItem(id, self.texts[id]);
}
}
for (var i = BI.first(indexes); i < BI.last(indexes); i++) {
if (!BI.contains(indexes, i)) {
self.regions[i].addItem("");
}
}
},
_createNodes: function () {
var self = this, o = this.options;
this.cache = {};
this.texts = {};
this.start = [];
this.end = [];
BI.each(o.items, function (i, item) {
self.start.push(BI.first(item).value);
self.end.push(BI.last(item).value);
});
this.start = BI.uniq(this.start);
this.end = BI.uniq(this.end);
var regions = [];
var tree = new BI.Tree();
var branches = {}, max = 0;
BI.each(o.items, function (i, items) {
BI.each(items, function (j, item) {
if (!BI.has(branches, item.value)) {
branches[item.value] = 0;
}
branches[item.value]++;
max = Math.max(max, branches[item.value]);
var prev = {};
if (j > 0) {
prev = items[j - 1];
}
var parent = self.cache[prev.value || ""];
var node = self.cache[item.value] || new BI.Node(item.value);
node.set(item);
self.cache[item.value] = node;
self.texts[item.value] = item.text;
self.texts[item.region] = item.regionText;
parent = BI.isNull(parent) ? tree.getRoot() : parent;
if (parent.getChildIndex(item.value) === -1) {
tree.addNode(parent, node);
}
});
});
// 算出区域列表
tree.traverse(function (node) {
BI.each(node.getChildren(), function (i, child) {
if (BI.contains(regions, child.get("region"))) {
var index1 = BI.indexOf(regions, node.get("region"));
var index2 = BI.indexOf(regions, child.get("region"));
// 交换区域
if (index1 > index2) {
var t = regions[index2];
for (var j = index2; j < index1; j++) {
regions[j] = regions[j + 1];
}
regions[index1] = t;
}
} else {
regions.push(child.get("region"));
}
});
});
this._createRegions(regions);
// 算出节点
BI.each(branches, function (k, branch) {
if (branch < max) {
delete branches[k];
}
});
// 过滤节点
var nodes = [];
var n = tree.getRoot();
while (n && n.getChildrenLength() === 1) {
if (BI.has(branches, n.getChildren()[0].id)) {
delete branches[n.getChildren()[0].id];
n = n.getChildren()[0];
} else {
n = null;
}
}
tree.traverse(function (node) {
if (BI.has(branches, node.id)) {
nodes.push(node.id);
delete branches[node.id];
}
});
// 填充节点
var routes = {};
var s, e;
for (var i = 0, len = nodes.length; i < len + 1; i++) {
if (len === 0) {
s = [];
BI.each(this.start, function (i, id) {
s.push(tree.search(id));
});
e = [];
BI.each(this.end, function (i, id) {
e.push(tree.search(id));
});
} else if (i === len) {
s = e;
e = [];
BI.each(this.end, function (i, id) {
e.push(tree.search(id));
});
} else if (i === 0) {
s = [];
BI.each(this.start, function (i, id) {
s.push(tree.search(id));
});
e = [tree.search(nodes[i])];
} else {
s = [tree.search(e[0] || tree.getRoot(), nodes[i - 1])];
e = [tree.search(s[0], nodes[i])];
}
BI.each(s, function (i, n) {
tree._recursion(n, [n.id], function (node, route) {
if (BI.contains(e, node)) {
if (!routes[n.id]) {
routes[n.id] = [];
}
routes[n.id].push(route);
self._pushNodes(route);
if (e.length <= 1) {
return true;
}
}
});
});
}
this.routes = routes;
this._drawLines(routes);
},
_unselectAllPath: function () {
var self = this;
BI.each(this.radios, function (idx, rad) {
BI.each(rad, function (i, r) {
r.setSelected(false);
});
});
BI.each(this.lines, function (idx, line) {
BI.each(line, function (i, li) {
li.attr("stroke", self._const.lineColor);
});
});
BI.each(this.regions, function (idx, region) {
region.reset();
});
},
populate: function (items) {
this.options.items = items || [];
var self = this;
this.empty();
if (this.options.items.length <= 0) {
return;
}
this.svg = BI.createWidget({
type: "bi.svg"
});
this._createNodes();
BI.createWidget({
type: "bi.absolute",
element: this.container,
items: [{
el: this.svg,
top: 0,
left: 0,
right: 0,
bottom: 0
}]
});
},
setValue: function (v) {
this._unselectAllPath();
var nodes = BI.keys(this.routes), self = this;
var result = [], array = [];
BI.each(v, function (i, val) {
if (BI.contains(nodes, val)) {
if (array.length > 0) {
array.push(val);
result.push(array);
array = [];
}
}
array.push(val);
});
if (array.length > 0) {
result.push(array);
}
// 画这n条路径
BI.each(result, function (idx, path) {
var start = path[0];
var index = BI.findIndex(self.routes[start], function (idx, p) {
if (BI.isEqual(path, p)) {
return true;
}
});
if (index >= 0) {
var startRegionIndex = self.getRegionIndexById(start);
var offset = self.regions[startRegionIndex].getIndexByValue(start);
self._drawPath(start, offset, index);
}
});
},
getValue: function () {
var path = [];
BI.each(this.regions, function (i, region) {
var val = region.getValue();
if (BI.isKey(val)) {
path.push(val);
}
});
return path;
}
});
BI.PathChooser.EVENT_CHANGE = "PathChooser.EVENT_CHANGE";
BI.shortcut("bi.path_chooser", BI.PathChooser);