mirror of
https://gitee.com/antv/g6.git
synced 2024-12-05 05:09:07 +08:00
feat: update svg minimap && fix svg dom event
This commit is contained in:
parent
ce239d1033
commit
5f681d8d72
@ -96,9 +96,6 @@
|
||||
renderer: 'svg',
|
||||
plugins: [ minimap ]
|
||||
});
|
||||
graph.node({
|
||||
shape: 'custom'
|
||||
});
|
||||
graph.read(data);
|
||||
</script>
|
||||
</body>
|
||||
|
@ -54,6 +54,7 @@
|
||||
container: 'mountNode',
|
||||
fitView: 'cc',
|
||||
height: window.innerHeight,
|
||||
renderer: 'svg',
|
||||
plugins: [ minimap ]
|
||||
});
|
||||
graph.read(data);
|
||||
|
@ -54,57 +54,12 @@ const data = {
|
||||
children: [
|
||||
{
|
||||
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' },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
@ -121,8 +76,8 @@ var layout = new G6.Layouts.CompactBoxTree({
|
||||
});
|
||||
var tree = new G6.Tree({
|
||||
id: 'mountNode', // 容器ID
|
||||
renderer: 'svg',
|
||||
height: 300, // 画布高
|
||||
renderer: 'svg',
|
||||
plugins: [
|
||||
new G6.Plugins['tool.minimap']({
|
||||
container: 'minimap',
|
||||
@ -139,11 +94,11 @@ G6.registerNode('transactionNode', {
|
||||
},
|
||||
draw(item) {
|
||||
const group = item.getGraphicGroup();
|
||||
const { name, id, cnt } = item.getModel();
|
||||
const { name, id, cnt,color } = item.getModel();
|
||||
const width = 100;
|
||||
const height = 40;
|
||||
const html = G6.Util.createDOM(`
|
||||
<div style="border: 1px solid #CCC;height:38px;text-align:center;">
|
||||
<div style="border: 1px solid #CCC;height:38px;text-align:center;background: ${color}">
|
||||
<strong class="main-text">${name}</strong>
|
||||
</div>
|
||||
`);
|
||||
@ -163,18 +118,19 @@ G6.registerNode('transactionNode', {
|
||||
tree.node({
|
||||
shape: 'transactionNode',
|
||||
});
|
||||
|
||||
tree.edge({
|
||||
shape: 'polyline',
|
||||
});
|
||||
tree.on('node:mouseenter', ev => {
|
||||
console.log('mouseenter');
|
||||
tree.update(ev.item, {
|
||||
color: 'orange',
|
||||
});
|
||||
});
|
||||
tree.on('node:mouseleave', ev => {
|
||||
console.log('mouseleave');
|
||||
tree.update(ev.item, {
|
||||
color: '',
|
||||
color: 'blue',
|
||||
});
|
||||
});
|
||||
tree.read({
|
||||
|
@ -106,7 +106,7 @@
|
||||
"run": []
|
||||
},
|
||||
"dependencies": {
|
||||
"@antv/g": "~3.2.0",
|
||||
"@antv/g": "~3.3.0",
|
||||
"@antv/component": "~0.0.4",
|
||||
"@antv/hierarchy": "~0.3.13",
|
||||
"@antv/scale": "^0.0.1",
|
||||
|
@ -17,34 +17,15 @@ class Plugin {
|
||||
},
|
||||
...this.options
|
||||
});
|
||||
graph.on('afterchange', () => {
|
||||
minimap.renderBackground();
|
||||
minimap.renderViewPort();
|
||||
});
|
||||
graph.on('afterlayout', () => {
|
||||
minimap.renderBackground();
|
||||
minimap.renderViewPort();
|
||||
});
|
||||
graph.on('afterviewportchange', () => {
|
||||
minimap.renderViewPort();
|
||||
});
|
||||
graph.on('afterfilter', () => {
|
||||
minimap.renderBackground();
|
||||
minimap.renderViewPort();
|
||||
});
|
||||
this.renderBackground = () => {
|
||||
minimap.renderBackground();
|
||||
};
|
||||
this.renderViewPort = () => {
|
||||
minimap.renderViewPort();
|
||||
};
|
||||
minimap.bindGraph(graph);
|
||||
this.minimap = minimap;
|
||||
}
|
||||
destroy() {
|
||||
this.minimap.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
G6.Plugins['tool.minimap'] = Plugin;
|
||||
|
||||
G6.Components.Minimap = Minimap;
|
||||
|
||||
module.exports = Plugin;
|
||||
|
@ -104,55 +104,72 @@ class Minimap {
|
||||
this._initContainer();
|
||||
this._initMiniMap();
|
||||
this._bindEvent();
|
||||
this._assignRenderBackground();
|
||||
this._assignDebounceRender();
|
||||
}
|
||||
_assignRenderBackground() {
|
||||
this.renderBackground = Util.debounce(graph => {
|
||||
if (!graph) {
|
||||
graph = this.getGraph();
|
||||
}
|
||||
const miniMapCanvas = this.miniMapCanvas;
|
||||
const width = this.width;
|
||||
const height = this.height;
|
||||
const toSmallNodes = [];
|
||||
const minSize = 2;
|
||||
|
||||
Util.graph2Canvas({
|
||||
graph,
|
||||
width,
|
||||
height,
|
||||
canvas: miniMapCanvas,
|
||||
beforeTransform(minimapMatrix) {
|
||||
const minimapScale = minimapMatrix[0];
|
||||
const nodes = graph.getNodes();
|
||||
nodes.forEach(node => {
|
||||
const bbox = node.getBBox();
|
||||
const model = node.getModel();
|
||||
const width = bbox.width;
|
||||
if (width * minimapScale < minSize) {
|
||||
const group = node.getGraphicGroup();
|
||||
const originMatrix = Util.clone(group.getMatrix());
|
||||
group.transform([
|
||||
[ 't', -model.x, -model.y ],
|
||||
[ 's', minSize / (width * minimapScale), minSize / (width * minimapScale) ],
|
||||
[ 't', model.x, model.y ]
|
||||
]);
|
||||
toSmallNodes.push({
|
||||
item: node,
|
||||
originMatrix
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
afterTransform() {
|
||||
toSmallNodes.forEach(({ item, originMatrix }) => {
|
||||
item.getGraphicGroup().setMatrix(originMatrix);
|
||||
});
|
||||
}
|
||||
});
|
||||
this.miniMapMatrix = miniMapCanvas.matrix;
|
||||
_assignDebounceRender() {
|
||||
this.debounceRender = Util.debounce(() => {
|
||||
this.renderBackground();
|
||||
this.renderViewPort();
|
||||
}, 32);
|
||||
}
|
||||
bindGraph(graph) {
|
||||
graph.on('afterchange', () => {
|
||||
this.debounceRender();
|
||||
});
|
||||
graph.on('afterlayout', () => {
|
||||
this.debounceRender();
|
||||
});
|
||||
graph.on('afterviewportchange', () => {
|
||||
this.renderViewPort();
|
||||
});
|
||||
graph.on('afterfilter', () => {
|
||||
this.debounceRender();
|
||||
});
|
||||
}
|
||||
renderBackground(graph) {
|
||||
if (!graph) {
|
||||
graph = this.getGraph();
|
||||
}
|
||||
const miniMapCanvas = this.miniMapCanvas;
|
||||
const width = this.width;
|
||||
const height = this.height;
|
||||
const toSmallNodes = [];
|
||||
const minSize = 2;
|
||||
graph.saveImage({
|
||||
graph,
|
||||
width,
|
||||
height,
|
||||
canvas: miniMapCanvas,
|
||||
beforeTransform(minimapMatrix) {
|
||||
const minimapScale = minimapMatrix[0];
|
||||
const nodes = graph.getNodes();
|
||||
nodes.forEach(node => {
|
||||
const bbox = node.getBBox();
|
||||
const model = node.getModel();
|
||||
const width = bbox.width;
|
||||
if (width * minimapScale < minSize) {
|
||||
const group = node.getGraphicGroup();
|
||||
const originMatrix = Util.clone(group.getMatrix());
|
||||
group.transform([
|
||||
[ 't', -model.x, -model.y ],
|
||||
[ 's', minSize / (width * minimapScale), minSize / (width * minimapScale) ],
|
||||
[ 't', model.x, model.y ]
|
||||
]);
|
||||
toSmallNodes.push({
|
||||
item: node,
|
||||
originMatrix
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
afterTransform() {
|
||||
toSmallNodes.forEach(({ item, originMatrix }) => {
|
||||
item.getGraphicGroup().setMatrix(originMatrix);
|
||||
});
|
||||
}
|
||||
});
|
||||
this.miniMapMatrix = miniMapCanvas.matrix;
|
||||
}
|
||||
_bindEvent() {
|
||||
const controlLayer = this.controlLayer;
|
||||
let miniMapViewPortActived = false;
|
||||
|
@ -32,6 +32,16 @@ const MouseEventTypes = [ EVENT.DBLCLICK, EVENT.MOUSEDOWN, EVENT.MOUSEUP, EVENT.
|
||||
EVENT.CONTEXTMENU, EVENT.MOUSEWHEEL ];
|
||||
const KeyboardEventTypes = [ EVENT.KEYDOWN, EVENT.KEYUP, EVENT.KEYPRESS ];
|
||||
const CANVAS = 'canvas:';
|
||||
function parentNodeHasTag(n, t) {
|
||||
let p = n.parentNode;
|
||||
while (p) {
|
||||
if (p.tagName === t) {
|
||||
return true;
|
||||
}
|
||||
p = p.parentNode;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
class Controller extends Base {
|
||||
constructor(cfg) {
|
||||
super(cfg);
|
||||
@ -76,6 +86,14 @@ class Controller extends Base {
|
||||
const _events = this._domEvents;
|
||||
Util.each(MouseEventTypes, item => {
|
||||
_events.push(Util.addEventListener(el, item, ev => {
|
||||
// Compatible with SVG
|
||||
if (ev.type === EVENT.MOUSEENTER) {
|
||||
if (ev.fromElement) {
|
||||
if (!ev.fromElement.parentNode || parentNodeHasTag(ev.fromElement, 'foreignObject')) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
const oldEventObj = this._currentEventObj;
|
||||
this._oldEventObj = oldEventObj;
|
||||
this._processEventObj(ev);
|
||||
|
@ -7,45 +7,15 @@
|
||||
|
||||
const Util = require('../../util/');
|
||||
const G = require('@antv/g/lib');
|
||||
const domToImage = require('dom-to-image');
|
||||
const Mixin = function() {};
|
||||
|
||||
Util.augment(Mixin, {
|
||||
createPath() {},
|
||||
// temporary solution
|
||||
isPointInPath(x, y) {
|
||||
if (this._cfg.el) {
|
||||
const box = this._cfg.el.getBBox();
|
||||
if (x <= box.x + box.width && y <= box.y + box.height && x >= box.x && y >= box.y) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// draw dom when canvas renderer
|
||||
drawInner(context) {
|
||||
let { html, x, y, width, height } = this._attrs;
|
||||
const canvas = this.get('canvas');
|
||||
const el = canvas.get('el');
|
||||
const tm = Util.clone(this.getTotalMatrix());
|
||||
if (Util.isString(html)) {
|
||||
html = Util.createDOM(html);
|
||||
} else {
|
||||
html = html.cloneNode(true);
|
||||
}
|
||||
el.parentNode.appendChild(html);
|
||||
domToImage.toPng(html, {
|
||||
width,
|
||||
height
|
||||
})
|
||||
.then(dataUrl => {
|
||||
const img = new Image();
|
||||
img.src = dataUrl;
|
||||
img.onload = () => {
|
||||
context.setTransform(tm[0], tm[1], tm[3], tm[4], tm[6], tm[7]);
|
||||
context.drawImage(img, x, y, width, height);
|
||||
};
|
||||
});
|
||||
html.remove();
|
||||
const { x, y, width, height } = this._attrs;
|
||||
context.setTransform(tm[0], tm[1], tm[3], tm[4], tm[6], tm[7]);
|
||||
context.drawImage(this.domImage, x, y, width, height);
|
||||
}
|
||||
});
|
||||
|
||||
|
11
src/graph.js
11
src/graph.js
@ -10,6 +10,7 @@ const Base = require('./base');
|
||||
const Item = require('./item/');
|
||||
const Shape = require('./shape/');
|
||||
const Util = require('./util/');
|
||||
const Graph2Canvas = require('./helper/graph2canvas');
|
||||
const G = require('@antv/g/lib');
|
||||
const LayoutMixin = require('./mixin/layout');
|
||||
const MappingMixin = require('./mixin/mapping');
|
||||
@ -786,17 +787,19 @@ class Graph extends Base {
|
||||
}
|
||||
/**
|
||||
* save graph image
|
||||
* @param {object} options - save options
|
||||
* @return {object} canvas dom
|
||||
*/
|
||||
saveImage() {
|
||||
saveImage(options) {
|
||||
const box = this.getBBox();
|
||||
const padding = this.getFitViewPadding();
|
||||
|
||||
return Util.graph2Canvas({
|
||||
const graph2Canvas = new Graph2Canvas({
|
||||
graph: this,
|
||||
width: box.width + padding[1] + padding[3],
|
||||
height: box.height + padding[0] + padding[2]
|
||||
height: box.height + padding[0] + padding[2],
|
||||
...options
|
||||
});
|
||||
return graph2Canvas.toCanvas();
|
||||
}
|
||||
}
|
||||
Mixins.forEach(Mixin => {
|
||||
|
124
src/helper/graph2canvas.js
Normal file
124
src/helper/graph2canvas.js
Normal file
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @fileOverview dom to canvas
|
||||
* @author huangtonger@aliyun.com
|
||||
*/
|
||||
|
||||
const Util = require('../util/');
|
||||
const G = require('@antv/g/lib');
|
||||
const domToImage = require('dom-to-image');
|
||||
|
||||
class Graph2Canvas {
|
||||
constructor(options) {
|
||||
this.options = {
|
||||
graph: null,
|
||||
width: null,
|
||||
height: null,
|
||||
canvas: null,
|
||||
beforeTransform() {},
|
||||
afterTransform() {},
|
||||
drawCount: 0,
|
||||
...options
|
||||
};
|
||||
}
|
||||
getCanvas() {
|
||||
let { width, height, canvas } = this.options;
|
||||
if (!canvas) {
|
||||
const containerDOM = Util.createDOM('<canvas></canvas>');
|
||||
canvas = new G.Canvas({
|
||||
containerDOM,
|
||||
width,
|
||||
height
|
||||
});
|
||||
}
|
||||
if (!canvas.drawCount) {
|
||||
canvas.drawCount = 0;
|
||||
}
|
||||
return canvas;
|
||||
}
|
||||
/**
|
||||
* draw canvas
|
||||
* @param {object} canvas item
|
||||
* @param {function} callback item
|
||||
*/
|
||||
drawInner(canvas, callback) {
|
||||
const { graph } = this.options;
|
||||
const graphCanvas = graph.getCanvas();
|
||||
const graphRenderer = graph.get('renderer');
|
||||
const drawCount = canvas.drawCount;
|
||||
|
||||
if (graphRenderer === 'svg') {
|
||||
const domShapes = [];
|
||||
graphCanvas.deepEach(element => {
|
||||
const type = element.get('type');
|
||||
type === 'dom' && domShapes.push(element);
|
||||
});
|
||||
if (domShapes.length > 0) {
|
||||
domShapes.forEach(domShape => {
|
||||
domShape.domImageOnload = false;
|
||||
const el = domShape.get('el');
|
||||
const width = domShape.attr('width');
|
||||
const height = domShape.attr('height');
|
||||
domToImage.toPng(el, {
|
||||
width,
|
||||
height
|
||||
})
|
||||
.then(dataUrl => {
|
||||
const img = new Image();
|
||||
img.src = dataUrl;
|
||||
img.onload = () => {
|
||||
if (drawCount === canvas.drawCount - 1) {
|
||||
domShape.domImage = img;
|
||||
domShape.domImageOnload = true;
|
||||
for (let i = 0; i < domShapes.length; i++) {
|
||||
const subShape = domShapes[i];
|
||||
if (!subShape.domImageOnload || subShape.get('destroyed')) {
|
||||
break;
|
||||
}
|
||||
if (subShape.domImageOnload && i === domShapes.length - 1) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
canvas.drawCount += 1;
|
||||
}
|
||||
toCanvas() {
|
||||
const { graph,
|
||||
width,
|
||||
height,
|
||||
beforeTransform,
|
||||
afterTransform } = this.options;
|
||||
const canvas = this.getCanvas();
|
||||
const graphBBox = graph.getBBox();
|
||||
const matrixCache = Util.cloneDeep(graph.getMatrix());
|
||||
const padding = graph.getFitViewPadding();
|
||||
const graphCanvas = graph.getCanvas();
|
||||
const matrix = Util.getAutoZoomMatrix({
|
||||
minX: 0,
|
||||
minY: 0,
|
||||
maxX: width,
|
||||
maxY: height
|
||||
}, graphBBox, padding);
|
||||
this.drawInner(canvas, () => {
|
||||
const children = graphCanvas.get('children');
|
||||
canvas.set('children', children);
|
||||
beforeTransform(matrix, matrixCache);
|
||||
graph.setMatrix(matrix);
|
||||
canvas.draw();
|
||||
graph.setMatrix(matrixCache);
|
||||
afterTransform(matrix, matrixCache);
|
||||
});
|
||||
canvas.matrix = matrix;
|
||||
return canvas.get('el');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Graph2Canvas;
|
@ -15,6 +15,7 @@ const G6 = {
|
||||
Layouts: require('./layouts/'),
|
||||
G,
|
||||
Plugins: {},
|
||||
Components: {},
|
||||
Global,
|
||||
Shape,
|
||||
registerNode: Shape.registerNode,
|
||||
|
@ -4,9 +4,6 @@
|
||||
*/
|
||||
|
||||
const BaseUtil = require('./base');
|
||||
const DomUtil = require('./dom');
|
||||
const GraphicUtil = require('./graphic');
|
||||
const G = require('@antv/g/lib');
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
@ -32,55 +29,5 @@ module.exports = {
|
||||
*/
|
||||
isGroup(item) {
|
||||
return item && BaseUtil.isObject(item) && item.type === 'group';
|
||||
},
|
||||
/**
|
||||
* graph to Canvas
|
||||
* @param {object} options item
|
||||
* @return {domobject} canvas
|
||||
*/
|
||||
graph2Canvas(options) {
|
||||
options = BaseUtil.mix({
|
||||
graph: null,
|
||||
width: null,
|
||||
height: null,
|
||||
canvas: null,
|
||||
beforeTransform() {},
|
||||
afterTransform() {}
|
||||
}, options);
|
||||
let { graph,
|
||||
width,
|
||||
height,
|
||||
canvas,
|
||||
beforeTransform,
|
||||
afterTransform } = options;
|
||||
const graphCanvas = graph.getCanvas();
|
||||
const graphBBox = graph.getBBox();
|
||||
const padding = graph.getFitViewPadding();
|
||||
const children = graphCanvas.get('children');
|
||||
const matrixCache = BaseUtil.cloneDeep(graph.getMatrix());
|
||||
if (!canvas) {
|
||||
const containerDOM = DomUtil.createDOM('<canvas></canvas>');
|
||||
canvas = new G.Canvas({
|
||||
containerDOM,
|
||||
width,
|
||||
height
|
||||
});
|
||||
}
|
||||
const matrix = GraphicUtil.getAutoZoomMatrix({
|
||||
minX: 0,
|
||||
minY: 0,
|
||||
maxX: width,
|
||||
maxY: height
|
||||
}, graphBBox, padding);
|
||||
beforeTransform(matrix, matrixCache);
|
||||
graph.setMatrix(matrix);
|
||||
canvas.set('children', children);
|
||||
canvas.matrix = matrix;
|
||||
// canvas.draw();
|
||||
canvas._cfg.painter.beforeDraw();
|
||||
canvas._cfg.painter._drawGroup(canvas);
|
||||
graph.setMatrix(matrixCache);
|
||||
afterTransform(matrix, matrixCache);
|
||||
return canvas.get('el');
|
||||
}
|
||||
};
|
||||
|
@ -72,12 +72,6 @@ describe('minimap test', () => {
|
||||
it('after layout', () => {
|
||||
graph.layout();
|
||||
});
|
||||
it('renderBackground', () => {
|
||||
minimap.renderBackground();
|
||||
});
|
||||
it('renderViewPort', () => {
|
||||
minimap.renderViewPort();
|
||||
});
|
||||
it('over min node size', () => {
|
||||
graph.update('node1', {
|
||||
x: 10000
|
||||
|
Loading…
Reference in New Issue
Block a user