feat: add label rotate

This commit is contained in:
huangtong.ht 2018-09-27 16:14:01 +08:00
parent 0ca0dbc301
commit 0b0e749045
8 changed files with 167 additions and 205 deletions

View File

@ -46,208 +46,123 @@
}
</style>
<script>
console.log(G6.version);
G6.registerNode('card', {
collapseButtonUrl:
'https://gw.alipayobjects.com/zos/rmsportal/GGzWwlTjflbJHmXhjMXg.svg',
expandButtonUrl:
'https://gw.alipayobjects.com/zos/rmsportal/DzWdTiwanggjaWKwcnWZ.svg',
draw(item) {
const group = item.getGraphicGroup();
const { main, value, percent, type, collapsed, children } = item.getModel();
const width = 170;
const height = 80;
const buttonWidth = 14;
const buttonHeight = 14;
let button = '';
if (children && children.length > 0) {
button =
'<img class="ce-button" src=' +
(collapsed ? this.expandButtonUrl : this.collapseButtonUrl) +
'>';
}
const html = G6.Util.createDOM(`
<div class="card-container">
<h1 class="main-text">${main}</h1>
<p>
<span class="value-text">${value}</span>
<span class="percent-text">${percent}</span>
</p>
</div>
`);
const keyShape = group.addShape('dom', {
attrs: {
x: 0,
y: 0,
width,
height,
html,
},
});
group.addShape('dom', {
attrs: {
x: width / 2 - buttonWidth / 2,
y: height - buttonHeight + 2,
width: buttonWidth,
height: buttonHeight,
html: button,
},
});
return group;
},
anchor: [[0.5, 0], [0.5, 1]],
});
const data = {
roots: [
"name": "Modeling Methods",
"children": [
{
main: '主指标一',
value: 123111,
percent: '100%',
type: '1',
children: [
{
main: '指标 1',
value: 12312,
percent: '39%',
type: '2',
children: [
{
main: '指标 1.1',
value: 111,
percent: '90%',
type: '3',
children: [
{
main: '指标 1.11',
value: 111,
percent: '90%',
type: '113',
},
{
main: '指标 1.12',
value: 111,
percent: '90%',
type: '14',
},
],
},
{
main: '指标 1.2',
value: 111,
percent: '90%',
type: '4',
children: [
{
main: '指标 1.21',
value: 111,
percent: '90%',
type: '5',
},
{
main: '指标 1.22',
value: 111,
percent: '90%',
type: '6',
},
{
main: '指标 1.23',
value: 111,
percent: '90%',
type: '7',
},
{
main: '指标 1.24',
value: 111,
percent: '90%',
type: '8',
},
],
},
{
main: '指标 1.3',
value: 111,
percent: '90%',
type: '9',
},
{
main: '指标 1.4',
value: 111,
percent: '90%',
type: '10',
},
],
},
{
main: '指标 2',
value: 12312,
percent: '79%',
type: '11',
},
{
main: '指标 3',
value: 12312,
percent: '79%',
type: '12',
},
],
"name": "Classification",
"children": [
{ "name": "Logistic regression" },
{ "name": "Linear discriminant analysis" },
{ "name": "Rules" },
{ "name": "Decision trees" },
{ "name": "Naive Bayes" },
{ "name": "K nearest neighbor" },
{ "name": "Probabilistic neural network" },
{ "name": "Support vector machine" }
]
},
],
{
"name": "Consensus",
"children": [
{
"name": "Models diversity",
"children": [
{ "name": "Different initializations" },
{ "name": "Different parameter choices" },
{ "name": "Different architectures" },
{ "name": "Different modeling methods" },
{ "name": "Different training sets" },
{ "name": "Different feature sets" }
]
},
{
"name": "Methods",
"children": [
{ "name": "Classifier selection" },
{ "name": "Classifier fusion" }
]
},
{
"name": "Common",
"children": [
{ "name": "Bagging" },
{ "name": "Boosting" },
{ "name": "AdaBoost" }
]
}
]
},
{
"name": "Regression",
"children": [
{ "name": "Multiple linear regression" },
{ "name": "Partial least squares" },
{ "name": "Multi-layer feedforward neural network" },
{ "name": "General regression neural network" },
{ "name": "Support vector regression" }
]
}
]
};
const tree = new G6.Tree({
container: 'mountNode',
height: 500,
renderer: 'svg',
layout: new G6.Layouts.CompactBoxTree({
// direction: 'LR', // 方向LR/RL/H/TB/BT/V
getHGap: function getHGap() /* d */ {
// 横向间距
return 20;
},
getVGap: function getVGap() /* d */ {
// 竖向间距
return 24;
},
direction: 'TB',
}),
fitView: 'tl',
G6.registerNode('treeNode', {
anchor: [
[ 0.5, 0 ],
[ 0.5, 1 ]
]
});
tree.node({
shape: 'card',
});
tree.edge({
shape: 'polyline',
});
tree.on('node:click', ev => {
const { domEvent, item } = ev;
const { target } = domEvent;
const { collapsed, type } = item.getModel();
const parent = item.getParent();
if (target.className === 'ce-button') {
if (collapsed) {
tree.update(item, {
collapsed: false,
});
} else {
tree.update(item, {
collapsed: true,
});
}
} else {
// 点击展开某个节点 同级其他节点收起
const children = parent && parent.getModel().children;
if (children && children.length > 0 && type) {
const isHideArr = children.filter(elem => type !== elem.type);
const isShowArr = children.filter(elem => type === elem.type);
isHideArr.forEach(element => {
tree.update(element.id, { collapsed: true });
});
isShowArr.forEach(element => {
tree.update(element.id, { collapsed: false });
});
}
G6.registerEdge('smooth', {
getPath(item) {
const points = item.getPoints();
const start = points[0];
const end = points[points.length - 1];
const vgap = Math.abs(end.y - start.y);
return [
[ 'M', start.x, start.y ],
[ 'C', start.x , start.y+ vgap / 2, end.x, end.y - vgap / 2, end.x, end.y ]
];
}
});
tree.read(data);
const layout = new G6.Layouts.Dendrogram({
"direction": "TB",
"rankSep": 200
});
const tree = new G6.Tree({
id: 'mountNode', // 容器ID
height: window.innerHeight, // 画布高
layout,
fitView: 'autoZoom' // 自动缩放
});
tree.node({
shape: 'treeNode',
size: 8,
label(model) {
if(model.children && model.children.length>0) {
return {
text: model.name,
textAlign: 'right'
};
}
return {
text: model.name,
textAlign: 'left'
};
},
labelRotate: Math.PI / 2,
labelOffsetX(model) {
if(model.children && model.children.length>0) {
return -10;
}
return 10;
}
});
tree.edge({
shape: 'smooth',
label: 'edge label',
labelRotate: Math.PI / 2,
});
tree.read({ roots: [data] });
</script>
</body>
</html>

View File

@ -98,7 +98,7 @@
"screenshot": "node ./bin/screenshot.js",
"start": "npm run dev",
"test": "torch --compile --renderer --recursive ./test/unit",
"test-live": "torch --compile --interactive --watch --recursive ./test/test-spec.js",
"test-live": "torch --compile --interactive --watch --recursive ./test/unit/item/*-spec.js",
"watch": "webpack --config webpack-dev.config.js",
"win-dev": "node ./bin/win-dev.js"
},

View File

@ -76,7 +76,7 @@ Shape.registerEdge('common', {
let label = this.getLabel(item);
const group = item.getGraphicGroup();
const model = item.getModel();
const { labelOffsetX, labelOffsetY } = model;
const { labelOffsetX, labelOffsetY, labelRotate } = model;
if (label) {
const center = keyShape.getPoint(0.5);
if (!center) {
@ -101,7 +101,7 @@ Shape.registerEdge('common', {
fill: 'white'
};
const style = model.labelRectStyle ? Util.mix({}, defaultStyle, model.labelRectStyle) : defaultStyle;
group.addShape('rect', {
const rect = group.addShape('rect', {
attrs: Util.mix({}, style, {
x: textBox.minX - padding[3],
y: textBox.minY - padding[0],
@ -109,6 +109,22 @@ Shape.registerEdge('common', {
height: textBox.maxY - textBox.minY + padding[0] + padding[2]
})
});
if (labelRotate) {
const centerX = (textBox.maxX + textBox.minX) / 2;
const centerY = (textBox.maxY + textBox.minY) / 2;
// labelRotate
label.transform([
[ 't', -centerX, -centerY ],
[ 'r', labelRotate, labelRotate ],
[ 't', centerX, centerY ]
]);
rect.transform([
[ 't', -centerX, -centerY ],
[ 'r', labelRotate, labelRotate ],
[ 't', centerX, centerY ]
]);
}
Util.toFront(label);
}
},

View File

@ -31,7 +31,7 @@ Shape.registerGroup('common', {
x = x + margin[0];
y = y + margin[1];
const model = item.getModel();
const { labelOffsetX, labelOffsetY } = model;
const { labelOffsetX, labelOffsetY, labelRotate } = model;
x = labelOffsetX ? labelOffsetX + x : x;
y = labelOffsetY ? labelOffsetY + y : y;
const attrs = Util.mix(true, {}, Global.labelStyle, {
@ -45,10 +45,13 @@ Shape.registerGroup('common', {
} else {
Util.mix(attrs, label);
}
group.addShape('text', {
const labelShape = group.addShape('text', {
class: 'label',
attrs
});
if (labelRotate) {
labelShape.rotate(labelRotate);
}
},
drawKeyShape(item, box) {
const { x, y, width, height } = box;

View File

@ -53,7 +53,7 @@ Shape.registerNode('common', {
const group = item.getGraphicGroup();
const label = this.getLabel(item);
const model = item.getModel();
const { labelOffsetX, labelOffsetY } = model;
const { labelOffsetX, labelOffsetY, labelRotate } = model;
if (Util.isNil(label)) {
return;
}
@ -66,10 +66,14 @@ Shape.registerNode('common', {
} else {
Util.mix(attrs, label);
}
return group.addShape('text', {
const labelShape = group.addShape('text', {
class: 'label',
attrs
});
if (labelRotate) {
labelShape.rotate(labelRotate);
}
return labelShape;
},
getPath(item) {
const size = this.getSize(item);

View File

@ -28,7 +28,7 @@ describe('edge item test', () => {
const edge = graph.find('node2->node1');
expect(edge.getTarget().id).equal('node1');
});
it('labeloffset', () => {
it('label offset', () => {
const edge = graph.find('node2->node1');
graph.update(edge, {
label: 'node2->node1',
@ -38,6 +38,14 @@ describe('edge item test', () => {
expect(edge.getLabel().attr('x')).to.almost.eql(162.23606797749977);
expect(edge.getLabel().attr('y')).to.almost.eql(136.11803398874991);
});
it('label rotate', () => {
const edge = graph.find('node2->node1');
graph.update(edge, {
label: 'node2->node1',
labelRotate: Math.PI / 2
});
expect(edge.getLabel().getMatrix()).to.almost.deep.eql([ 6.123233995736766e-17, 1, 0, -1, 6.123233995736766e-17, 0, 298.3541019662497, -26.118033988749858, 1 ]);
});
it('destroy', () => {
graph.destroy();
});

View File

@ -32,7 +32,7 @@ describe('group item test', () => {
it('getInnerEdges', () => {
expect(graph.find('group1').getInnerEdges().length).eql(2);
});
it('labeloffset', () => {
it('label offset', () => {
const group = graph.find('group1');
graph.update(group, {
label: 'group1',
@ -42,6 +42,14 @@ describe('group item test', () => {
expect(group.getLabel().attr('x')).to.almost.eql(87.5);
expect(group.getLabel().attr('y')).to.almost.eql(57.5);
});
it('label rotate', () => {
const group = graph.find('group1');
graph.update(group, {
label: 'group1',
labelRotate: Math.PI / 2
});
expect(group.getLabel().getMatrix()).to.almost.deep.eql([ 6.123233995736766e-17, 1, 0, -1, 6.123233995736766e-17, 0, 0, 0, 1 ]);
});
it('destroy', () => {
graph.destroy();
});

View File

@ -50,7 +50,7 @@ describe('node item test', () => {
41
});
});
it('labeloffset', () => {
it('label offset', () => {
const node = graph.find('node1');
graph.update(node, {
label: 'node1',
@ -60,6 +60,14 @@ describe('node item test', () => {
expect(node.getLabel().attr('x')).to.almost.eql(10);
expect(node.getLabel().attr('y')).to.almost.eql(10);
});
it('label rotate', () => {
const node = graph.find('node2');
graph.update(node, {
label: 'node2',
labelRotate: Math.PI / 2
});
expect(node.getLabel().getMatrix()).to.almost.deep.eql([ 6.123233995736766e-17, 1, 0, -1, 6.123233995736766e-17, 0, 0, 0, 1 ]);
});
it('destroy', () => {
graph.destroy();
});