mirror of
https://gitee.com/antv/g6.git
synced 2024-12-05 05:09:07 +08:00
commit
3d894df93d
@ -6,6 +6,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="mountNode"></div>
|
||||
<button id="download">点击下载图片</button>
|
||||
<script src="assets/hierarchy.js"></script>
|
||||
<script src="../build/g6.js"></script>
|
||||
<script src="./assets/jquery-3.2.1.min.js"></script>
|
||||
@ -89,6 +90,13 @@ const graph = new G6.TreeGraph({
|
||||
}
|
||||
}, 'drag-canvas']
|
||||
},
|
||||
defaultNode: {
|
||||
shape: 'tree-node',
|
||||
anchorPoints: [ [0, 0.5], [1, 0.5] ],
|
||||
},
|
||||
defaultEdge: {
|
||||
shape: 'cubic-horizontal'
|
||||
},
|
||||
edgeStyle: {
|
||||
default: {
|
||||
stroke: '#A3B1BF'
|
||||
@ -108,18 +116,11 @@ const graph = new G6.TreeGraph({
|
||||
$.getJSON('./assets/data/modeling-methods.json', data => {
|
||||
graph.data(data);
|
||||
graph.render();
|
||||
graph.getNodes().forEach(node => {
|
||||
const model = node.get('model');
|
||||
model.anchorPoints = [ [0, 0.5], [1, 0.5] ];
|
||||
model.shape = 'tree-node';
|
||||
});
|
||||
graph.getEdges().forEach((edge) => {
|
||||
edge.get('model').shape = 'cubic-horizontal';
|
||||
});
|
||||
graph.refresh();
|
||||
graph.fitView();
|
||||
});
|
||||
|
||||
document.getElementById('download').addEventListener('click', () => {
|
||||
graph.downloadImage();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -349,23 +349,25 @@
|
||||
data.edges.forEach((edge, i) => {
|
||||
edge.id = i;
|
||||
});
|
||||
G6.Global.defaultNode = {
|
||||
size: [10, 10],
|
||||
color: 'steelblue',
|
||||
style: {
|
||||
lineWidth: 2,
|
||||
fill: '#fff'
|
||||
}
|
||||
};
|
||||
G6.Global.defaultEdge = {
|
||||
size: 1,
|
||||
color: '#e2e2e2'
|
||||
};
|
||||
const graph = new G6.Graph({
|
||||
container: 'mountNode',
|
||||
width: 1000,
|
||||
height: 600,
|
||||
autoPaint: false
|
||||
autoPaint: false,
|
||||
defaultNode: {
|
||||
size: [10, 10],
|
||||
color: 'steelblue'
|
||||
},
|
||||
defaultEdge: {
|
||||
size: 1,
|
||||
color: '#e2e2e2'
|
||||
},
|
||||
nodeStyle: {
|
||||
default: {
|
||||
lineWidth: 2,
|
||||
fill: '#fff'
|
||||
}
|
||||
}
|
||||
});
|
||||
const simulation = d3.forceSimulation()
|
||||
.force("link", d3.forceLink().id(function(d) { return d.id; }).strength(0.5))
|
||||
|
@ -64,6 +64,7 @@
|
||||
stroke: '#A3B1BF'
|
||||
}
|
||||
},
|
||||
linkCenter: true,
|
||||
layout: layouts[currentLayout]
|
||||
});
|
||||
G6.Global.defaultNode.size = 16;
|
||||
|
@ -59,6 +59,7 @@
|
||||
}
|
||||
}, 'drag-canvas']
|
||||
},
|
||||
defaultNode: { size: 16 },
|
||||
nodeStyle: {
|
||||
default: {
|
||||
fill: '#40a9ff',
|
||||
@ -141,7 +142,6 @@
|
||||
}
|
||||
]
|
||||
};
|
||||
G6.Global.defaultNode.size = 16;
|
||||
graph.data(data);
|
||||
graph.render();
|
||||
graph.getNodes().forEach(node => {
|
||||
|
@ -110,7 +110,7 @@
|
||||
"silent": false
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/g": "~3.4.0-beta.13",
|
||||
"@antv/g": "~3.4.0",
|
||||
"@antv/util": "~1.3.1"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -95,7 +95,7 @@ module.exports = {
|
||||
shape.set('capture', false);
|
||||
item.set('delegateShape', shape);
|
||||
}
|
||||
shape.attr({ x, y });
|
||||
shape.attr({ x: x - bbox.width / 2, y: y - bbox.height / 2 });
|
||||
this.graph.paint();
|
||||
}
|
||||
};
|
||||
|
@ -3,6 +3,8 @@ const Item = require('../../item');
|
||||
|
||||
const NODE = 'node';
|
||||
const EDGE = 'edge';
|
||||
const CFG_PREFIX = 'default';
|
||||
const hasOwnProperty = Object.hasOwnProperty;
|
||||
|
||||
class ItemController {
|
||||
constructor(graph) {
|
||||
@ -11,8 +13,22 @@ class ItemController {
|
||||
addItem(type, model) {
|
||||
const graph = this.graph;
|
||||
const parent = graph.get(type + 'Group') || graph.get('group');
|
||||
const upperType = Util.upperFirst(type);
|
||||
let item;
|
||||
const styles = graph.get(type + 'Style');
|
||||
const defaultModel = graph.get(CFG_PREFIX + upperType);
|
||||
if (defaultModel) {
|
||||
// 很多布局会直接修改原数据模型,所以不能用 merge 的形式,逐个写入原 model 中
|
||||
Util.each(defaultModel, (val, cfg) => {
|
||||
if (!hasOwnProperty.call(model, cfg)) {
|
||||
if (Util.isObject(val)) {
|
||||
model[cfg] = Util.clone(val);
|
||||
} else {
|
||||
model[cfg] = defaultModel[cfg];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (type === EDGE) {
|
||||
let source = model.source;
|
||||
let target = model.target;
|
||||
@ -26,7 +42,7 @@ class ItemController {
|
||||
console.warn('The source or target node of edge ' + model.id + ' does not exist!');
|
||||
return;
|
||||
}
|
||||
item = new Item[Util.upperFirst(type)]({
|
||||
item = new Item[upperType]({
|
||||
model,
|
||||
source,
|
||||
target,
|
||||
@ -35,7 +51,7 @@ class ItemController {
|
||||
group: parent.addGroup()
|
||||
});
|
||||
} else {
|
||||
item = new Item[Util.upperFirst(type)]({
|
||||
item = new Item[upperType]({
|
||||
model,
|
||||
styles,
|
||||
group: parent.addGroup()
|
||||
|
@ -109,6 +109,22 @@ class Graph extends EventEmitter {
|
||||
* @type {Boolean}
|
||||
*/
|
||||
linkCenter: false,
|
||||
/**
|
||||
* 默认的节点配置,data 上定义的配置会覆盖这些配置。例如:
|
||||
* defaultNode: {
|
||||
* shape: 'rect',
|
||||
* size: [60, 40]
|
||||
* }
|
||||
* 若数据项为 { id: 'node', x: 100, y: 100 }
|
||||
* 实际创建的节点模型是 { id: 'node', x: 100, y: 100, shape: 'rect', size: [60, 40] }
|
||||
* 若数据项为 { id: 'node', x: 100, y: 100, shape: 'circle' }
|
||||
* 实际创建的节点模型是 { id: 'node', x: 100, y: 100, shape: 'circle', size: [60, 40] }
|
||||
*/
|
||||
defaultNode: {},
|
||||
/**
|
||||
* 默认边配置,data 上定义的配置会覆盖这些配置。用法同 defaultNode
|
||||
*/
|
||||
defaultEdge: {},
|
||||
/**
|
||||
* 节点默认样式,也可以添加状态样式
|
||||
* 例如:
|
||||
@ -805,6 +821,75 @@ class Graph extends EventEmitter {
|
||||
this.set('autoPaint', auto);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回图表的 dataUrl 用于生成图片
|
||||
* @return {string/Object} 图片 dataURL
|
||||
*/
|
||||
toDataURL() {
|
||||
const canvas = this.get('canvas');
|
||||
const renderer = canvas.getRenderer();
|
||||
const canvasDom = canvas.get('el');
|
||||
let dataURL = '';
|
||||
if (renderer === 'svg') {
|
||||
const clone = canvasDom.cloneNode(true);
|
||||
const svgDocType = document.implementation.createDocumentType(
|
||||
'svg', '-//W3C//DTD SVG 1.1//EN', 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'
|
||||
);
|
||||
const svgDoc = document.implementation.createDocument('http://www.w3.org/2000/svg', 'svg', svgDocType);
|
||||
svgDoc.replaceChild(clone, svgDoc.documentElement);
|
||||
const svgData = (new XMLSerializer()).serializeToString(svgDoc);
|
||||
dataURL = 'data:image/svg+xml;charset=utf8,' + encodeURIComponent(svgData);
|
||||
} else if (renderer === 'canvas') {
|
||||
dataURL = canvasDom.toDataURL('image/png');
|
||||
}
|
||||
return dataURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 画布导出图片
|
||||
* @param {String} name 图片的名称
|
||||
*/
|
||||
downloadImage(name) {
|
||||
const self = this;
|
||||
if (self.isAnimating()) {
|
||||
self.stopAnimate();
|
||||
}
|
||||
const canvas = self.get('canvas');
|
||||
const renderer = canvas.getRenderer();
|
||||
const fileName = (name || 'graph') + (renderer === 'svg' ? '.svg' : '.png');
|
||||
const link = document.createElement('a');
|
||||
setTimeout(() => {
|
||||
const dataURL = self.toDataURL();
|
||||
if (window.Blob && window.URL && renderer !== 'svg') {
|
||||
const arr = dataURL.split(',');
|
||||
const mime = arr[0].match(/:(.*?);/)[1];
|
||||
const bstr = atob(arr[1]);
|
||||
let n = bstr.length;
|
||||
const u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
const blobObj = new Blob([ u8arr ], { type: mime });
|
||||
if (window.navigator.msSaveBlob) {
|
||||
window.navigator.msSaveBlob(blobObj, fileName);
|
||||
} else {
|
||||
link.addEventListener('click', function() {
|
||||
link.download = fileName;
|
||||
link.href = window.URL.createObjectURL(blobObj);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
link.addEventListener('click', function() {
|
||||
link.download = fileName;
|
||||
link.href = dataURL;
|
||||
});
|
||||
}
|
||||
const e = document.createEvent('MouseEvents');
|
||||
e.initEvent('click', false, false);
|
||||
link.dispatchEvent(e);
|
||||
}, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除画布元素
|
||||
* @return {object} this
|
||||
|
@ -15,6 +15,7 @@ const BaseUtil = {
|
||||
isArray: require('@antv/util/lib/type/is-array'),
|
||||
createDom: require('@antv/util/lib/dom/create-dom'),
|
||||
modifyCSS: require('@antv/util/lib/dom/modify-css'),
|
||||
isObject: require('@antv/util/lib/type/is-object'),
|
||||
isPlainObject: require('@antv/util/lib/type/is-plain-object'),
|
||||
isNumber: require('@antv/util/lib/type/is-number'),
|
||||
isString: require('@antv/util/lib/type/is-string'),
|
||||
|
@ -461,6 +461,63 @@ describe('all node link center', () => {
|
||||
expect(edgeKeyShape.attr('shadowColor')).to.be.null;
|
||||
graph.destroy();
|
||||
});
|
||||
it('graph with default cfg', () => {
|
||||
const graph = new G6.Graph({
|
||||
container: div,
|
||||
width: 500,
|
||||
height: 500,
|
||||
defaultNode: {
|
||||
shape: 'rect',
|
||||
size: [ 60, 40 ],
|
||||
color: '#ccc',
|
||||
labelCfg: {
|
||||
position: 'right',
|
||||
offset: 5,
|
||||
style: {
|
||||
fontSize: 14,
|
||||
fill: 'blue'
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultEdge: {
|
||||
shape: 'cubic',
|
||||
color: '#666'
|
||||
}
|
||||
});
|
||||
const node = graph.addItem('node', { id: 'node1', x: 100, y: 150, label: '111' });
|
||||
let model = node.get('model');
|
||||
expect(model.id).to.equal('node1');
|
||||
expect(model.x).to.equal(100);
|
||||
expect(model.y).to.equal(150);
|
||||
expect(model.shape).to.equal('rect');
|
||||
expect(model.size[0]).to.equal(60);
|
||||
expect(model.size[1]).to.equal(40);
|
||||
expect(model.color).to.equal('#ccc');
|
||||
expect(model.labelCfg.position).to.equal('right');
|
||||
expect(model.labelCfg.style.fill).to.equal('blue');
|
||||
const node2 = graph.addItem('node', { id: 'node2', x: 150, y: 100, label: '222', color: '#666', shape: 'circle' });
|
||||
model = node2.get('model');
|
||||
expect(model.shape).to.equal('circle');
|
||||
expect(model.size[0]).to.equal(60);
|
||||
expect(model.size[1]).to.equal(40);
|
||||
expect(model.color).to.equal('#666');
|
||||
model.size[1] = 50;
|
||||
expect(model.size[1]).to.equal(50);
|
||||
expect(node.get('model').size[1]).to.equal(40);
|
||||
expect(model.labelCfg.position).to.equal('right');
|
||||
expect(model.labelCfg.style.fill).to.equal('blue');
|
||||
model.labelCfg.position = 'left';
|
||||
model.labelCfg.style.fill = 'red';
|
||||
expect(node.get('model').labelCfg.position).to.equal('right');
|
||||
expect(node.get('model').labelCfg.style.fill).to.equal('blue');
|
||||
const edge = graph.addItem('edge', { id: 'edge', source: 'node1', target: 'node2', shape: 'line' });
|
||||
model = edge.get('model');
|
||||
expect(model.id).to.equal('edge');
|
||||
expect(model.source).to.equal('node1');
|
||||
expect(model.shape).to.equal('line');
|
||||
expect(model.color).to.equal('#666');
|
||||
graph.destroy();
|
||||
});
|
||||
it('clear', () => {
|
||||
graph.destroy();
|
||||
expect(graph.destroyed).eql(true);
|
||||
|
Loading…
Reference in New Issue
Block a user